Customizing Fixtures¶
What are fixtures?¶
Fixtures are just plain old PHP objects, that change system state during their execution - they can either persist entities in the database, upload files, dispatch events or do anything you think is needed.
sylius_fixtures:
suites:
my_suite_name:
fixtures:
my_fixture: # Fixture name as a key
priority: 0 # The higher priority is, the sooner the fixture will be executed
options: ~ # Fixture options
They implement the Sylius\Bundle\FixturesBundle\Fixture\FixtureInterface
and need to be registered under
the sylius_fixtures.fixture
tag in order to be used in suite configuration.
Note
The former interface extends the ConfigurationInterface
, which is widely known from Configuration
classes
placed under DependencyInjection
directory in Symfony bundles.
Why would you customize fixtures?¶
There are two main use cases for customizing fixture suites, in each of them you can adapt the data of your shop to be realistic, the default fixtures suite of Sylius is selling clothes, if you are selling food you’d probably need your own fixtures to show that:
preparing test data for the development purposes like demo applications prepared for QA
preparing the shop configuration for the production instance
How to modify the existing Sylius fixtures?¶
In Sylius, fixtures are configured in src/Sylius/Bundle/CoreBundle/Resources/config/app/fixtures.yml
.
It includes the default
suite that is partially-configured.
If you are planning to modify the default fixtures applied by the sylius:fixtures:load
command, modify the config\packages\sylius_fixtures.yaml
file.
Modifying the shop configuration (channels, currencies, payment and shipping methods)¶
sylius_fixtures:
suites:
default: # this key is always called whenever the sylius:fixtures:load command is called, below we are extending it with new fixtures
fixtures:
currency:
options:
currencies: ['PLN','HUF']
channel:
options:
custom:
pl_web_store: # creating new channel
name: "PL Web Store"
code: "PL_WEB"
locales:
- "%locale%"
currencies:
- "PLN"
enabled: true
hostname: "localhost"
hun_web_store:
name: "Hun Web Store"
code: "HUN_WEB"
locales:
- "%locale%"
currencies:
- "HUF"
enabled: true
hostname: "localhost"
shipping_method:
options:
custom:
ups_eu: # creating a new shipping_method and adding channel to it
code: "ups_eu"
name: "UPS_eu"
enabled: true
channels:
- "PL_WEB"
- "HUN_WEB"
payment_method:
options:
custom:
cash_on_delivery_pl:
code: "cash_on_delivery_eu"
name: "Cash on delivery_eu"
channels:
- "PL_WEB"
bank_transfer:
code: "bank_transfer_eu"
name: "Bank transfer_eu"
channels:
- "PL_WEB"
- "HUN_WEB"
enabled: true
It is more complicated to create fixtures for products, because they have more dependencies (to Variants, Options etc.). In order to prepare a Product
you have to create not only the product itself but other related entities via their own factories.
Sylius delivers four ready implementations of Product
fixtures, that have their relevant options (like sizes for T-shirts):
BookProductFixture
MugProductFixture
StickerProductFixture
TshirtProductFixture
You can modify their YAML fixture configs, but only within the capabilities delivered by those fixtures classes.
How to customize fixtures for customized models?¶
Tip
The following example is based on other example of extending an entity with a new field. You can browse the full implementation of this example on this GitHub Pull Request.
Let’s suppose you have extended App\Entity\Shipping\ShippingMethod
with a new field deliveryConditions
,
just like in the example mentioned above.
1. To cover that in fixtures, you will need to override the ShippingMethodExampleFactory
and add this field:
<?php
// src/Fixture/Factory/ShippingMethodExampleFactory.php
namespace App\Fixture\Factory;
// ...
use Sylius\Bundle\CoreBundle\Fixture\Factory\ShippingMethodExampleFactory as BaseShippingMethodExampleFactory;
final class ShippingMethodExampleFactory extends BaseShippingMethodExampleFactory
{
//...
public function create(array $options = []): ShippingMethodInterface
{
/** @var ShippingMethod $shippingMethod */
$shippingMethod = parent::create($options);
// Protect object if part of our objects don't have new field
if (!isset($options['deliveryConditions'])) {
return $shippingMethod;
}
foreach ($this->getLocales() as $localeCode) {
$shippingMethod->setCurrentLocale($localeCode);
$shippingMethod->setFallbackLocale($localeCode);
$shippingMethod->setDeliveryConditions($options['deliveryConditions']);
}
return $shippingMethod;
}
protected function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);
$resolver
->setDefault('deliveryConditions', 'some_default_value')
->setAllowedTypes('deliveryConditions', ['null', 'string'])
;
}
private function getLocales(): iterable
{
/** @var LocaleInterface[] $locales */
$locales = $this->localeRepository->findAll();
foreach ($locales as $locale) {
yield $locale->getCode();
}
}
}
2. Extend the Sylius\Bundle\CoreBundle\Fixture\ShippingMethodFixture
in App\Fixture\ShippingMethodFixture
:
<?php
// src/Fixture/ShippingMethodFixture.php
namespace App\Fixture;
use Sylius\Bundle\CoreBundle\Fixture\ShippingMethodFixture as BaseShippingMethodFixture;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
final class ShippingMethodFixture extends BaseShippingMethodFixture
{
protected function configureResourceNode(ArrayNodeDefinition $resourceNode): void
{
parent::configureResourceNode($resourceNode);
$resourceNode
->children()
->scalarNode('deliveryConditions')->end()
;
}
}
3. Configure the services in the config/services.yaml
file:
sylius.fixture.example_factory.shipping_method:
class: App\Fixture\Factory\ShippingMethodExampleFactory
arguments:
- "@sylius.factory.shipping_method"
- "@sylius.repository.zone"
- "@sylius.repository.shipping_category"
- "@sylius.repository.locale"
- "@sylius.repository.channel"
- "@sylius.repository.tax_category"
public: true
sylius.fixture.shipping_method:
class: App\Fixture\ShippingMethodFixture
arguments:
- "@sylius.manager.shipping_method"
- "@sylius.fixture.example_factory.shipping_method"
tags:
- { name: sylius_fixtures.fixture }
Tip
When creating fixtures services manually, remember to turn off autowiring for them:
App\:
resource: '../src/*'
exclude: '../src/{Entity,Fixture,Migrations,Tests,Kernel.php}'
If you leave autowiring on, errors like Fixture with name “your_custom_fixture” is already registered. will most probably appear. Your fixture service will register twice (as app.fixture.bla by you and as AppFixtureBlaFixture by DI autoconfigure).
4. Add new Shipping Methods with delivery conditions in config/packages/fixtures.yaml
:
sylius_fixtures:
suites:
default:
fixtures:
# ...
shipping_method: # our new configuration with the new field
options:
custom:
geis:
code: "geis"
name: "Geis"
enabled: true
channels:
- "PL_WEB"
deliveryConditions: "3-5 days"