Diese Seite ist auch auf Deutsch verfügbar. Zur deutschen Seite wechseln

How to develop Apps for the Shopware Cloud?

Shopware 6

Test Shopware now

Create onlineshop
Copy-of-SW6-DEV-Blog_Apps_EN-860x325px-Blog

To the German article

Why a new app system?

Short answer: The cloud changes things.

A new way of creating a Shopware extension does not mean that plugins are a thing of yesterday. Quite the opposite even: Plugins are a great way to directly interact with and extend the Shopware Core.

But in cloud environments, every line of code is a liability that can take down every user's instances. This necessitates a more decoupled interface between Shopware instances and extensions.

So what do I mean by this coupling?

When you write plugins, they depend on individual facts. Some of them are very obvious, like the version of Shopware your plugin requires. Others are transitive, like dealing with symfony 4 and PHP 7, these are not put in place by yourself but through the Shopware platform. The last type of dependencies is the most dangerous: the implicit ones.

These are easy to miss due to their hidden nature. Take, for example, the order of a query result without any sorting algorithm explicitly applied.

Those results might adhere to a default order, but when your logic needs this ordering without adding it explicitly, it becomes hard to spot this dependency. Thus it's easy for someone else to break this assumption by accident.

Now coupling in this context translates to the number of dependencies of the above kinds that exist in your code; that is not to say they are outright wrong. Most of the time, dependencies are needed to get anything done. But it also ties your software closely to everything it literally depends on. A new version of any of those things might break your code, not to mention that there are lots of ways of combining versions of different dependencies.

Still, there are ways to mitigate this coupling and make systems less brittle.

A common way is to reduce the area of possible breakage. This means making the least amount of assumptions, e.g., there is no assertion that an incoming array is filled with precisely two items 'names' and 'ids'. Instead, the system asserts that those fields are there, but it simply ignores all extra fields. This means future changes that just add items like 'timestamp' don't affect your code. The other common way is to formalize dependencies, this means making it clear what your code assumes to be true at a language or at least a configuration level.

This is basically what interfaces in PHP and other languages do.

These were some of our guiding ideas when developing the new app system. The app system is entirely HTTP based. This allows us to reduce the contact area between your app and the Shopware Core.

A network-based interface helps not only to distribute the complexity across devices and domains, which is basically the idea behind microservice architecture, but it helps with stability in both directions. The app becomes more resilient towards code changes because it no longer needs to know about the Shopware code at all. Shopware instances are less affected by the implementation of your app because apps do not interact with their source code.

There is also an explicit definition of the interface between your app and the Shopware instance. It is defined by an XML file that defines the events that your app needs to be notified about. This 'manifest.xml' makes it clear what your app needs and how it might change the behavior of the Shopware instance.

To further solidify the interface, we try to keep it lean. An HTTP interface, for example, makes it is easier to spot how changes of the plugin system interfere with apps, thus reducing the risk of unexpectedly breaking them.

Apps all the way?

All of this allows you to build apps that run in self-hosted environments and in the Shopware Cloud, using the same code. Still, there are cases in which a plugin might be the better choice.

This is why we won't replace the plugin system. Plugins are a valuable way to interact deeply with the Shopware core, and we are as committed as ever to keep this type of extension.

But keep in mind, apps allow you to reach a bigger group of merchants due to their ability to run in the cloud.

Demo time

But let's start with apps themselves. An app has to be modeled using an event-based workflow. Let's say, for example, we want to generate a picklist for incoming orders.

So how do we implement this? Many programs work with roughly the same interaction pattern as follows:

1.)  Read data
2.) Calculate a result
3.) Output the result

And apps follow the same pattern. After all, they are web applications, so they receive a request, work on it, and return a response.

Let's start by reading the relevant data for our app. The app system can notify our app of changes to the shops that installed it, so the app does not need to poll the shops. To be notified of all new orders we add a few lines to the manifest.xml:

The webhook element describes all events the app needs to be notified of, in this case, every time an order is placed, a request will be sent to our app server residing at the given URL.

Next up: Our app needs to handle the events it's subscribed to. You could use any kind of tech stack for that. But since I'm mainly a PHP developer, excuse my laziness and let us assume a standard symfony skeleton. This is how the controller might look like:

Here the event data gets unpacked, and the order id is retrieved. Now that our app knows which order was created it can easily fetch all the extra data it needs like so:

Our code is creating a criteria to read the order that was created and to add all the line items this order contains. The 'searchOrders' method then sends this criteria JSON serialized to the shops API and returns the order as an array.

Now that we've finished part one of our workflow we add the code that builts the actual picklist:

This loop iterates over all line items we fetched above and builds a line of our picklist from each one.

Just like that, we finished part two of our app. The last thing that is left is to write back to our picklist.

We cannot simply return it from our request, the app system has no idea where to put it.

To output data back to the shop, we're at crossroads. The app system has currently two ways to send custom data back to the shop:

1.)  A custom administration module embedding your own web UI through an iframe.
2.) Adding custom fields to existing entities.

The first option is undoubtedly compelling but also a bit overkill for our little picklist.

To use option number two we need to add our picklist to the order entity and we can do this by extending the manifest.xml again:

As you can see, this is a fully declarative way to extend entities, based on the already established feature of custom fieldsets.

Also, you can see that through the label elements in the above example that the app system has built-in internationalization.

With the custom field on every order, there is now a way to show the picklists. But how are these fields filled?

Here we come back to the controller for our webhook:

We can use the API to update the order with our picklist through a small PATCH request.

As you can see, apps mostly depend on the functionality already in the Shopware 6 core, the new part is just how your app can define its interface with the Showpare instance and its API and UI.

Even though I'm genuinely excited about this system's possibilities, I have to finish this post in time so allow me to just list some more abilities of the app system without going into to much detail:

  • Apps need to define permissions to further solidify the contract with the target shop.
  • Apps can deploy complete themes in the exact same way plugins do now.
  • You can add buttons to listing and detail pages in the administration.
  • The manifest.xml is entirely defined by an XSD schema for IDE integration.

So where are we now?

Right now, you can start experimenting with the app system. We've published it as a Plugin.

With this plugin, you can patch a shop with a bleeding-edge version of the app system. We are currently working on bringing it to a production-ready state. As a matter of fact, I'm writing this post while developing the actual code for the app system. But as it is, this system is not only new to you but also to us. Therefore we're looking forward to receiving some feedback from you.

In fact, since we've announced the app system for the first time at this year's community day, we already received valuable feedback that helped us prioritize features to make apps a veritable alternative to starting with a new plugin.

What the future holds

We're working on two things right now. First, we want to polish the app system with its current feature set and integrate it into the Shopware core in the next couple of months. Secondly, we are building an app store directly integrated into the administration, so shop owners can extend their Shopware instance directly from within the administration.

We are also aware that creating and maintaining an app is quite the paradigm shift from building plugins, that is why we've partnered up with platform.sh to provide you with a template to start developing apps.

You can expect to hear more about that soon. In the same way, we're also planning extensive help materials to get you started.

As with all things iterative, we're also continually evaluating new possible features to extend the system.

Last, I have listed some further info to get you up to speed with the app system below.

Resources