You might have already heard about it – Sylius v1.11 is live! This release comes with a long-expected feature – Catalog Promotions, but it is not all that has changed since the previous release. Also, the feature itself comes with a few details that you may be curious about. All these will be covered in this blog post!
Anyone who has been following Sylius’ evolution over the years could have noticed it already. For newcomers, let me put it straight – we strive to always provide support for the newest Symfony and PHP versions. This has several reasons. First of all, doing gradable upgrades over the months is much easier than now and then with big batches. Secondly, it keeps Sylius secure ⛑ 🦺. And last but not least, all developers love new, shiny features. 🤩
We’ve bumped the minimal requirement of Sylius to PHP 8.0. The last version of the PHP 7.x branch reached its end of maintenance period [EOM] in November 2021. Nonetheless, it will be supported with security fixes until December 1, 2022. For more information, go here.
Are you still on PHP 7.4? Don’t worry! You can still use it with Sylius v1.10, which is supported:
Although we do encourage you to update to PHP 8.0 as soon as possible, as it is required to take advantage of Sylius v1.11, we believe in the rolling updates of dependencies; thus, you don’t have to make both PHP and Sylius bumps at the same time. Take your time, update your servers to PHP 8.0, and then, in the next iteration – update Sylius.
For us, bumping the minimal versions means that we can finally introduce new syntax to the code base and reduce the cartesian matrix of possible combinations to check with every PR.
From developer to developer – we love new features too! And to be honest… We don’t want to go back now that we’ve introduced new syntax to the Sylius codebase.
As Sylius does not have just a small code base, and we all have important stuff to do all the time, it would be wasteful and cumbersome to migrate it manually. Therefore, I would like to thank Rector for automating work for us 😉 I would say that it also falls under the umbrella of the minimal waste paradigm🌳♻️
Sylius v.1.11 supports 2 LTS versions of Symfony – 4.4 and 5.4. As Symfony released its latest LTS version in autumn 2021, supporting it by Sylius was a no-brainer for us (as already mentioned in the release blog post).
We do advise you to plan the migration to 5.4 ahead, as the next Sylius version will drop Symfony 4.4 support. To be precise, we have already done it on our master branch.
It’s been a while since such a big, meaty feature landed in the Sylius codebase. It comes with several additional improvements and details that I would like to share with you. But first – some context. Before diving into consecutive development sprints for catalog promotions, we have taken a deep breath and have scratched a few ideas in their architecture. Slowing down to speed up has undoubtedly been a good idea.
The first concern we needed to solve was how to calculate catalog promotions? The two options we took into account were: on the fly or pre-processing it. The heuristic we made was that our catalog promotions needed to be usable for both small and big merchants. The “on the fly” concept seemed to us a solution that would complicate things and could lead to some feature regression (like sorting and filtration of products by price). On a top of that, it would be probably not performant at all. That’s why we decided to go for the other approach.
Sylius catalog promotions in their current implementation are prepared to handle large product catalogs and therefore are run asynchronously by default. This was achieved using Symfony Messenger with Doctrine’s transport. It’s great that it can be used both asynchronously and synchronously, depending on the config.
The catalog size among our users may vary very much. For those with less than 1k SKUs, some of the concerns simply do not exist. In such a scenario, you may decide on synchronous processing of catalog promotions. They will still be pre-processed for customers, but the operation will be executed exactly at the moment of update.
However, for those with tens or hundreds of thousands of SKUs (there are Sylius-based shops with over a million SKUs!) or those who would like to schedule promotion in advance, asynchronous processing is the way to go. For them, we had to do some initial processing performance improvements as well.
First, we decided on async processing by default, as this was more typical behavior for us. Would you prefer it the other way round?? As mentioned above, you may change it with one environmental variable.
Once the command is picked, there are two dimensions that we need to take into account: catalog promotions and product variants. As catalog promotions are fragile for the execution order (due to exclusiveness, priorities, and overlapping promotions), we could not parallel execution among catalog promotions. In the end, we can neither be sure about the order of messages processing nor the time of each execution or retry. The rest of the catalog promotions had to wait for the previous one in any of these cases.
Therefore, we decided to process batches of product variants, as thanks to that, each processed batch is totally independent of others. This allows you to easily scale our solution horizontally, just by adding more workers to process your catalog. We’ve decided that 100 variants per batch will be a good starting point for most, but you can easily modify the size in the Sylius configuration.
We also improved queries to avoid N+1 problems. Be careful of it if you decide to customize catalog promotion processing logic! In addition, we found quite an old bug that required the locale context to be called each time the translatable entity would be fetched from the repository, which leads to fetching channels and other entities.
Eventually, we fixed this behaviour by setting the current locale of all translations to default app locale if only there is no current request in the request stack. This is something that all existing projects may benefit from.
In terms of processing optimization, a lot was achieved thanks to Blackfire profiling. If you’d like to get more insights on this and what we’ve done to make it more performant, we’re preparing a new blog post, so stay vigilant!
👏🏻 to the whole Sylius Development Team for making it within (just?) half a year! It was a pleasure to work with you on that, folks!
We were planning to stabilize our API in Sylius v1.11, but we didn’t fully succeed. We pushed it forward, though. As you already know, the new release comes with an 85% coverage of Shop features. What else has changed?
We’ve introduced contract tests for our API. With them, we aim to protect ourselves with changes to API contracts in the future, as it is a part of our Backward Policy. It led us to find a few mistakes already! We can totally recommend this approach!
We have also embedded the translation of all entities into main objects for all shop endpoints. From now on, the products (and all the other translatable resources) will have a name, description, short description, and so on included in the main body with values related to the currently selected language. We believe databases should not determine what our resources look like, but that is a topic for another blog post.
Moreover, we’ve introduced several new command enrichments. These classes are mutating commands created by API Platform based on the customer-provided data to add some more execution information.
You may see the pattern here. Now, adding a new interface to your command will automatically lead to receiving the requested data. Keep in mind that this will work only if the command originated in the API Platform. Sounds interesting? Let me know if you would like to read the whole article about it 🙂
The main changes executed on the shop checkout are important improvements. First of all, we are finally adding items to the cart with the POST method. Previously, it was PATCH due to some API Platform limitations over sub resource handling. Luckily, from what we know, API 3.0 will be awesome. We cannot wait to test it out.
What is more, we’ve merged the locale change, applying coupon codes, and addressing endpoints to one. This makes much more sense in the API context.
Moreover, we plan to improve the checkout process even further, so we don’t force the selection of shipping and payment methods at all. This should provide a neat way to do a one-step or just simplified checkout experience.
In the next steps in our journey towards a stable API, we want to finalize the remaining 15% of shop scenarios (or decide that we won’t implement them), provide the possibility to perform checkout in any order, as well as rethink and refactor serialization groups. We are pretty happy with what we have already, but we need to check if all of the serialization groups follow our rule of thumb for its creation. We also need to split read groups into one for details and a list view.
From the technical libraries point of view, there are two main points to discuss: the new Calendar component and changes to the Resource and Grid bundle.
Sylius calendar component is a super simple component that provides just abstraction over
\DateTime object creation. Its main purpose is to provide an easy-to-use faking API and make extract common logic.
Any usage of `new` in the codebase is equal to coupling. One does not easily change all `new` calls in Sylius due to the size of the codebase, BC policy, release cycle, or just because you usually have Sylius in your vendor folder. Extraction of all of these constructions will help in the future if one would need to inject TimeZone into their DateTimes, for example.
What is more, it would make testing easier. From the unit(spec) tests perspective, the usage of collaborator allows us to compare exact objects instead of using loose comparative (or comparing timestamps). From the acceptance/end-to-end tests, we can declare what “now” means in a given moment. This component has a predefined hook for behat tests, so a changed date will only be present for one scenario. Of course, FakeCalendar will solely be injected into the container in the test environment.
Does it mean there are no `new DateTime` calls in the Sylius codebase anymore? Not yet. For now, we are using them in the Catalog Promotion and Shipping component as some business logic. However, we will work on that in the future as well.
With some new blood in the Sylius Core Team, we’ve provided a ton of new goodies into the fundamental Sylius libraries. There are new configuration flavors and improvements to the Developer Experience. But for more details, please wait for the blog post written by one of our new Core Team Members – Loic Fremont. For the impatient ones, all new features are available in the latest beta releases of both bundles. You can find them here and here.
For the last few months, our focus has been solely on providing good, high-quality catalog promotions to our community. Therefore, we’ve been only fixing existing bugs in the Plus version. Also, I would like to announce that Sylius Plus is already supporting the newest Sylius release.
That’s all, folks! As already announced, I will participate in the webinar, where I will also talk about mentioned points. Please join us and don’t hesitate to ask any questions that pop up in your head after reading this article.
The Sylius community has always been important, and this webinar will give us all a shared space for regular conversation, gathering feedback, and sharing our further plans. Sounds interesting? Sign up below and see you around!