Sylius plugins: How to get to the starting blocks
”A good developer is lazy”
When we want to add new features to Sylius it is rarely a unique set of needs we want to address. Sure, the particular project will have its unique set of demands and we will address them with different solutions, but these solutions will have been used in other settings before. This is why we have reusable libraries and frameworks such as Symfony and Sylius.
When we face a particular problem in Symfony, re-usable code can be built as ”bundles”. Allowing us to reuse our solution within the context of other Symfony projects. When we face a particular problem in Sylius we write a variant of a Symfony bundle called a ”Sylius plugin”.
Being able to reuse or make public our solution will benefit many developers. Our future selves won’t have to build a solution from scratch anymore, which is how lazily good it is to build a Sylius plugin.
Building a Sylius plugin is not as easy as plug-and-play
It’s generally a good idea to start off with the official documentation on building a plugin when you want to extend Sylius. This article will highlight a few pain points to consider when we build a Sylius plugin, as this will complement the official documentation. These pain points are most readily addressed by following these recommendations:
- Follow the documentation.
- Symfony assumptions are being made, take heed.
- Gettings started is the hardest part.
A problem - a solution - a plugin
Recently I found myself in need of adding a payment method to Sylius. In my particular case, it was a Klarna Checkout payment method that I needed. No existing solution addressed my need. As Klarna is a popular payment provider in Sweden (and Nordic countries), it does not have as a wide spread customer base as Stripe or PayPal, but it serves millions of customers each year. Building a solution (a payment method for Klarna Checkout) would probably be re-used by third parties or in other projects where I will build an e-commerce solution for the Nordics. This is a pretty clear-cut case of where a Sylius plugin would be a suitable recourse.
We will set up the skeleton of a Klarna Checkout plugin! Note that this will not be an officially supported plugin or show up in the Sylius plugin store - these require Behat tests which we won’t be delving into in this article.
Getting to the starting block
We will start by creating a new project with the help of Composer and sylius/plugin-skeleton:
composer create-project sylius/plugin-skeleton VendorNameSyliusKlarnaGatewayPlugin
Note that it’s important to follow the naming convention. Symfony requires a "Bundle" postfix to load associated services. Sylius stipulates a vendor-name prefix and "Plugin" postfix. In my case, I would name it
This will make use of a skeleton project, packed with a full Sylius project to test your plugin against. It has an example plugin from the get-go which we will have to clear out if we do not want to browse it first. As Sylius requires BDD-tests for plugins to appear in the Sylius Plugin Store we will also see that it comes packed with a bunch of Behat tests to go along with the example plugin. So remember, clearing out the example plugin you should also clear out the tests too.
The skeleton plugin has some boilerplate to support its example plugin. You will want to make changes in composer.json and a bunch of files in both your project and in test/Application. The whole list of required changes to setup you up is listed at Sylius Plugins - Naming changes.
Set up name and namespaces
src/AcmeSyliusExamplePlugin.php -> src/AndersBjorklandSyliusKlarnaGatewayPlugin.php
src/DependencyInjection/AcmeSyliusExampleExtension.php -> src/DependencyInjection/AndersBjorklandSyliusKlarnaGatewayExtension.php
The current namespaces will be
Acme\SyliusExamplePlugin\…, you can search and replace or manually edit these. For me, this will become
AndersBjorkland\SyliusKlarnaGatewayPlugin\… and I would change this in the files below.
Similarly will be done for the Sylius application residing under the
tests/Application/Kernel.php has the namespace
Tests\Acme\SyliusExamplePlugin\Application, it would become
Do not adjust the namespace for src/Kernel.php. It is set to work under the
Appnamespace and is not required to be configured to work with the plugin. The same goes for
Adjust use statements
When we change namespaces we will also have to update how the classes are loaded in different files. So update the following files with the correct use statements.
Add a plugin to load with the test-application
The test application will load bundles and Sylius plugins via the file tests/Application/config/bundles.php. The example plugin is present here, so change its name accordingly:
Modify services configuration
If you are someone that prefers YAML over XML you will want to modify the Extension-file that is tasked with loading service configuration. So instead of using XmlFileLoader which is the current default in the example-plugin, make use of
YamlFileLoader instead. Where you want to store the services.yaml file is up to you, I prefer to have it at src/Resources/config/services.yaml. We will tell the loader to load the correct file:
public function load(array $configs, ContainerBuilder $container): void
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
And more configuration!
Almost done with setting up a starting point for building a new plugin. We need to add a configuration node for the plugin. We will do that by modifying src/DependencyInjection/Configuration.php:
acme_sylius_example_plugin to something akin to
Update composer autoloading
Update Composer, so it will autoload all the files correctly:
Install assets and get some services running
The plugin skeleton addresses how to get started. There is a walk-through for a docker setup as well as a non-docker setup. I usually run a database in a Docker container and the application off of a native system. Minding this, here’s how we can set up such a system.
- Disable all services but the database in docker-compose.yaml.
- Start the Docker container from the project root with
docker-compose up -d.
- If dependencies have not been installed, from project-root, run
- Change directory to tests/Application.
- Install assets and UI component. In tests/Application:
bin/console assets:install public
- Set up database and load fixtures. In tests/Application:
- Start the web server. I prefer Symfony’s local web server. In tests/Application run
symfony serve -d, alternatively
php -S localhost:8000 public/index.php
- You can now view the Sylius test application at
Login credentials loaded with the fixtures:
It’s a long way to set up a development environment for Sylius plugins, and it is important to follow the instructions carefully. But doing it this way means we will have reusable components that we can use repeatedly, and more people can benefit from our work.
I hope your development goes well and I’m looking forward to seeing your work in the Sylius eco-system.