Pimcore Fixture Bundle
General Tools
Project Summary
Readme
Pimcore Fixture Bundle
Provides a way to manage and execute the loading of data fixtures in Pimcore.
It can be useful for testing purposes, or for seeding a database with initial data.
Installation
-
Require the bundle
composer require teamneusta/pimcore-fixture-bundle
-
Enable the bundle
Add the Bundle to your
config/bundles.php
:Neusta\Pimcore\FixtureBundle\NeustaPimcoreFixtureBundle::class => ['test' => true],
-
Register your Fixtures Folder for Service autoconfiguration
Depending on where you want to create your Fixtures or if they should only be accessible during test execution.
when@test: services: App\Tests\Fixture\: autoconfigure: true resource: '../tests/Fixture/'
Upgrading from earlier Version
Fixtures are now considered actual services and are loaded through Dependency Injection (DI).
To align with this approach,
you'll need to update your Fixture classes by moving service dependencies from the create
method to the constructor.
If your Fixture relies on other Fixtures, implement the HasDependencies
interface.
Here are the key changes:
-
Fixture Interface Update
The old fixture interfaceNeusta\Pimcore\FixtureBundle\Fixture
has been replaced withNeusta\Pimcore\FixtureBundle\Fixture\Fixture
. You can also extend fromNeusta\Pimcore\FixtureBundle\Fixture\AbstractFixture
to implement your Fixtures. -
Change in
create
Method
The signature of thecreate
method has been modified. It no longer takes any arguments, meaning all service dependencies must be specified via Dependency Injection. This is typically done through the constructor. -
Fixtures as Services
Fixtures must be made available in the Dependency Injection container to be discovered. To do this, tag them withneusta_pimcore_fixture.fixture
, or use autoconfiguration for automatic tagging. -
Specifying Inter-Fixture Dependencies
If your Fixture depends on others, use theHasDependencies
interface to specify these dependencies. Additional guidance is available in the section "Referencing Fixtures and Depending on Other Fixtures".
Make sure to update your Fixture classes according to these changes to ensure proper functionality and compatibility with this Bundle.
Usage
Writing Fixtures
Data fixtures are PHP service classes where you create objects and persist them to the database.
Imagine that you want to add some Product
objects to your database.
To do this, create a fixture class and start adding products:
use Neusta\Pimcore\FixtureBundle\Fixture\AbstractFixture;
use Pimcore\Model\DataObject\Product;
final class ProductFixture extends AbstractFixture
{
public function create(): void
{
for ($i = 1; $i <= 20; $i++) {
$product = new Product();
$product->setParentId(0);
$product->setPublished(true);
$product->setKey("Product {$i}");
// ...
$product->save();
}
}
}
Referencing Fixtures and Depending on Other Fixtures
Suppose you want to link a Product
fixture to a Group
fixture. To do this, you need to create a Group
fixture first and keep a reference to it. Later, you can use this reference when creating the Product
fixture.
This process requires the Group
fixture to exist before the Product
fixture. You can achieve this ordering by implementing the HasDependencies
interface.
use Neusta\Pimcore\FixtureBundle\Fixture\AbstractFixture;
use Pimcore\Model\DataObject\ProductGroup;
final class ProductGroupFixture extends AbstractFixture
{
public function create(): void
{
$productGroup = new ProductGroup();
$productGroup->setParentId(0);
$productGroup->setPublished(true);
$productGroup->setKey('My Product Group');
$productGroup->save();
$this->addReference('my-product-group', $productGroup);
}
}
use Neusta\Pimcore\FixtureBundle\Fixture\AbstractFixture;
use Neusta\Pimcore\FixtureBundle\Fixture\HasDependencies;
use Pimcore\Model\DataObject\Product;
use Pimcore\Model\DataObject\ProductGroup;
final class ProductFixture extends AbstractFixture implements HasDependencies
{
public function create(): void
{
$productGroup = $this->getReference('my-product-group', ProductGroup::class);
$product = new Product();
$product->setParentId(0);
$product->setPublished(true);
$product->setKey('My grouped Product');
$product->setProductGroup($productGroup);
$product->save();
}
public function getDependencies(): array
{
return [
ProductGroupFixture::class,
];
}
}
Loading Fixtures
To load fixtures in Tests, we offer the SelectiveFixtureLoader
. To streamline your test setup, we recommend creating a base class with a method to load fixtures via the SelectiveFixtureLoader
. Here's an example demonstrating how to implement this.
use Neusta\Pimcore\FixtureBundle\Fixture;
use Pimcore\Test\KernelTestCase;
abstract class BaseKernelTestCase extends KernelTestCase
{
/**
* @param list<class-string<Fixture>> $fixtures
*/
protected function importFixtures(array $fixtures): void
{
/** @var SelectiveFixtureLoader $fixtureLoader */
$fixtureLoader = static::getContainer()->get(SelectiveFixtureLoader::class);
$fixtureLoader->setFixturesToLoad($fixtures)->loadFixtures();
}
protected function tearDown(): void
{
\Pimcore\Cache::clearAll();
\Pimcore::collectGarbage();
parent::tearDown();
}
}
Use the base class as follows:
use Pimcore\Model\DataObject;
final class MyCustomTest extends BaseKernelTestCase
{
/** @test */
public function import_fixtures(): void
{
$this->importFixtures([
ProductFixture::class,
]);
$productFixture = DataObject::getByPath('/product-1');
self::assertNotNull($productFixture);
}
}
To load fixtures in your local environment or as part of a deployment two commands are provided:
neusta:pimcore-fixture:load
(Loads a defined fixture class.)neusta:pimcore-fixtures:load
(Loads all defined fixture classes.)
Beware that loading a large amount of objects may lead to a high consumption of memory.
Should you encounter memory issues when running the commands in dev
environments you may want to try
setting the environment to prod
. Disabling the debug mode also seems to be beneficial in terms of memory consumption.
For example provide these options when using the symfony console:
bin/console --env=prod --no-debug neusta:pimcore-fixtures:load
Accessing Services from the Fixtures
As the Fixtures are just normal PHP Services you can use all DI features like constructor, setter or property injection as usual.
Extension and customization through Events
The Bundle provides the following events to facilitate extensions and customization:
-
BeforeLoadFixtures
This event is triggered before any fixture is executed. It contains all the fixtures that are scheduled for execution, accessible via$event->getFixtures()
. You can alter the list of fixtures to be loaded by using$event->setFixtures(...)
. -
AfterLoadFixtures
This event occurs after all relevant fixtures have been executed. It carries the fixtures that have been successfully loaded, which can be accessed through$event->loadedFixtures
. -
BeforeExecuteFixture
This event is triggered just before a fixture is executed. Using this event, you can prevent the execution of a specific fixture by setting$event->setPreventExecution(true)
. -
AfterExecuteFixture
This event occurs after a fixture has been executed.
Contribution
Feel free to open issues for any bug, feature request, or other ideas.
Please remember to create an issue before creating large pull requests.
Local Development
To develop on a local machine, the vendor dependencies are required.
bin/composer install
We use composer scripts for our main quality tools. They can be executed via the bin/composer
file as well.
bin/composer cs:fix
bin/composer phpstan
bin/composer tests