How to organize code in Shopware 6 projects

Care to share?

Shopware 6 comes with a plugin system to extend and adjust its basic functionalities but doesn’t impose how your plugins should be organized. This freedom in creating plugins and organizing them provides you with excellent flexibility and allows you to use your own practices and conventions. 

On the other hand, it can lead to chaos. You can end up without any conventions, and as the system develops, it'll be more and more difficult and expensive to maintain. 

In this article, we share our best practices for developing plugins for Shopware 6 and organizing code. You can use this as a checklist for your own project. Applying proper plugin management will help you not only to maintain the current project but also develop future ones faster.

Treat plugins as classes

The simplest approach to plugin development is to treat them like classes in object-oriented programming (OOP). This allows for applying good practices to plugins which developers use for implementing classes during software development, such as the SOLID principles

Plugins, like classes, should have one well-known responsibility, and they should provide one specific functionality. This helps keep plugins simple and easy to maintain. Another advantage is that small packages are reusable and can be used in future projects.

Let’s consider a store with prices for different sales units, for example, piece, box, and palette, imported from the enterprise resources planning (ERP) system named Camel. You need a plugin for integration with this system, which will fetch sales units and prices for existing products. Since Shopware 6 doesn’t support multiple prices for multiple sales units, you must extend the product model. The simplest solution is to create a single integration plugin named Camel.

Shopware plugin as class example

The problem arises when you add further functionalities related to prices or sales units. Let’s say you want to create advanced promotions using sales units prices. For this purpose, you can create another plugin named Promotion, which must depend on the Camel plugin.

This approach leads to a few problems: 

  • First of all, promotions shouldn’t depend on ERP integration. This is a separate functionality not connected with the ERP system. Promotions are fully configurable in Shopware and not in the ERP system. These complications will appear whenever you want to use advanced prices or sales units in other plugins. 
  • The second problem arises when you need to change the ERP system. The natural way is to create the new plugin for the new ERP system. This makes it necessary to move all the code responsible for prices and sales units to the new plugin and to update all dependent packages. 

You can avoid these situations by applying an approach similar to the OOP good practices. You can create two additional plugins for sales units and prices.

clear dependencies example in Shopware 6

In this situation, you have more clear dependencies. You can also more easily replace each piece of the application, such as the ERP system integration plugin. You can just add a new plugin for the new ERP system and remove the old one. This should not affect the rest of the system. On top of that, the SalesUnit and the Price plugins can be used in future projects.

Create plugins for Shopware Store

To help achieve the goals described above, you should think about every created plugin as if it were designed for Shopware Store. This approach helps to develop plugins that are focused on one functionality. This mindset also leads to producing more generic solutions that lead to an increase in reusability. It also encourages making more elements configurable. 

A valuable tip can be to create a plugin configuration for every constant value that appears in the source code, such as numbers, statuses, URLs, or labels. It’s also always worth checking whether a developed plugin complies with the rules described in the Shopware 6 quality guidelines for plugins.

Extend, don’t override

Often, it happens that a plugin purchased from Shopware Store doesn’t meet project requirements one hundred percent but covers most of the needs. In this situation, you can adjust some of the plugin mechanisms and change the way it works. 

Most of the time, the easiest way is to override one of the plugin services and, in effect, override one of its features. The better way to accomplish this is to keep the original functionality and add another one. Often, it requires a little more work but reduces the risk of introducing bugs into the plugin's core features and leaves open the possibility of their future use. This is, of course, not always possible because sometimes you want to change how something works, but let's consider the following example.

You bought a plugin that allows you to generate coupons for customers who have bought products exceeding a certain value. In the configuration, you can set the expiration date of the coupon counted from the day it was generated, but you want to have a fixed date until which all generated coupons are valid. Instead of overriding the configuration, you can add another option to set the due date while keeping the original feature. This gives you more flexibility to create promotions in the future.

Since, as written above, you should develop plugins as if they were created for Shopware Store, the same rules apply to the packages we created. If you have created a plugin that gives you some general functionality and want to adjust it for a specific project, you should create another one that extends the first one. 

In other words, you shouldn’t be afraid to extend your own plugins. Additionally, you should create plugins that can be easily enhanced if needed. Besides good practices that apply to any type of software, we can take advantage of the mechanisms offered by Shopware. You should always consider adding custom fields to your entities. They are very helpful when it comes to saving simple additional data. 

Another thing worth doing is to create as many blocks in Twig templates as possible. This is advised for both the front end and administration. It allows you to customize the user interface without copying large code blocks.

Remember that plugins aren’t your only option

Each store based on Shopware 6 is managed by the composer. Each Shopware 6 plugin is also a composer package. This means that during development you can use not only plugins but also all other types of composer packages. 

If there is a functionality you want to separate and it is not directly connected with Shopware, you shouldn’t create a Shopware 6 plugin. The intent of plugins is to extend native Shopware 6 possibilities. You can use Symfony bundles or composer libraries. This approach helps keep code more reusable and allows it to be used in projects based on other frameworks. This can be especially useful in companies that offer a wide range of technologies. They can create, for example, a software development kit (SDK) for integration with a specific external system and use it in Shopware and Magento projects.

Regarding the above example, you can separate the SDK for the Camel system from the created plugin. This can be a simple composer library containing a HTTP client that allows for performing basic operations in the ERP system. Next time, even if you need to create a very specific integration with Camel for some project, you can still use the created SDK and save time.

using SDK in organizing Shopware code

Leverage core plugins

Sometimes, you need some smaller or larger generic mechanisms not directly related to any specific functionality. They can be extensions of basic Shopware features like additional functions in entity repository, console commands, collection extensions, or services that help to perform plugin installation. 

It's a good idea to section off this kind of thing to a separate package or plugin and share it across different projects. To achieve this, it’s worth creating a separate git repository for it, putting it in the composer package repository, and adding it as a project dependency. This allows you to easily include new functionality in all your projects.

Make sure that composer is your friend

The presented approach leads to a code structure that consists of a large number of small plugins and forces you to manage dependencies between them more carefully. Fortunately, Shopware 6 uses the composer package manager to track plugins dependencies. All you need to do is to keep the plugin composer.json file up to date. 

You should keep an eye on two major things: increasing the version every time the plugin code changes and adding other plugins whose code you used to the require section of the composer.json file. The composer will do the rest for you when you’ll need to install some specific plugin. Another advantage is that Shopware doesn’t allow you to install a plugin when its dependencies aren’t installed.

Takeaway

A thoughtful plugin structure can help you avoid architectural problems in future project development and reuse created components in other projects to deliver them faster. 

You can achieve this structure by chosing more general solutions to specific problems and by splitting big ones into smaller ones. This approach not only gives you tangible benefits and saves your time but also allows you to develop your architectural skills and provides much more satisfaction.

Published March 15, 2023