Most PHP Programming frameworks (and, by extension, PHP CMS systems) have a boundary between “code that makes the system run” and “code third parties can add to the system to build features”.
Sometimes this boundary is clear. Other times this boundary blurs beyond recognition. WordPress has a plugin system which is nothing more complex than a single PHP file that WordPress will load before rendering a page. On the other end of the spectrum systems like Magento or Symfony allow you to add folders with a hierarchy of controllers, models, templates, and configuration to enable, disable or even implement features (called modules by Magento, bundles by Symfony).
Part of learning any new PHP system is learning which code belongs to the framework, and which code belongs to you. Today we’ll take a quick look at the tools Shopware gives you to add “code that’s yours” to the system.
Apps and Plugins
Shopware’s developer documents name two broad categories of “code that’s yours” — plugins and apps. Shopware also has a themes system, but we’re interested in backend application code today.
If you’re a traditional PHP MVC developer, the system you’re interested in is the plugin system. The other extension system, “Apps”, allows you to register an external URL endpoint with a Shopware system in order to exchange API credentials and register webhooks that Shopware will call when certain things happen in a Shopware system. Apps allow you to setup an independent system that will interact with a Shopware system, but Apps will not allow you to execute your own PHP code in the context of a Shopware system. For that, you want Shopware plugins. You can read more about the App System in Shopware’s docs.
Shopware plugins are a thin abstraction layer on top of Symfony’s bundle system. A Shopware plugin is (at minimum) two files.
- A PHP class that extends the
composer.jsonfile with plugin information and the PHP class from #1 entered in the
We’ll leave the Shopware docs to describe both the unique features of Shopware’s plugins as well as how you can use plugins to tap into the Symfony service container. There’s only a few distinct things we need you to take away today.
First — despite a plugin file having a
composer.json file and that file including a
require section Shopware or composer does not appear to use these dependencies when deciding which packages to install. However, if you attempt to activate a local plugin via
$ php bin/console plugin:install --activate SwagBasicExample
and there’s a mismatch between your project dependencies and your plugin’s
composer.json file, Shopware won’t let the activation proceed
% php bin/console plugin:install --activate SwagBasicExample Shopware Plugin Lifecycle Service ================================= Install 1 plugin(s): * The displayed readable name for the plugin (v1.0.0) ! [NOTE] Plugin "SwagBasicExample" is already installed. Activating. 15:52:11 CRITICAL [console] Error thrown while running command "plugin:install --activate SwagBasicExample". Message: "Could not activate plugin, got 1 failure(s). Required plugin/package "shopware/core 6.3.*" does not match installed version == 188.8.131.52." ...snip,,, Required plugin/package "shopware/core 6.3.*" does not match installed version == 184.108.40.206. """] In RequirementExceptionStack.php line 28: Could not activate plugin, got 1 failure(s). Required plugin/package "shopware/core 6.3.*" does not match installed version == 220.127.116.11.
Second — while the Shopware docs have you place your plugins in the
custom/plugins folder, you can also place your plugins in the
custom/static-plugin folder. The difference between these two folders is unclear, but if (long time Magento developer) Peter Jaap Blaakmeer is right, these folders serve a similar purpose to the old
app/code/local folders in Magento 1. The
custom/static-plugins folder is for your plugins, and
custom/plugins is for plugins bought from vendors via the Shopware Store.
Finally, this structure seems to suggest (as does Peter’s article) that these plugins don’t need to be in these local folders, and can be distributed directly as composer packages via packagist.org or other composer repositories.
The fact that plugins use a
composer.json files creates some ambiguity around how plugin dependencies are meant to be managed in the various contexts (installed via composer vs. installed locally in the system;installed into
./plugin/*/vendor, installed manually or installed via. a store purchase). Despite some helpful suggestions I haven’t been able to come up with a complete story for how a plugin’s dependencies should be managed. That’s a problem left for another day