teamneusta/pimcore-fixture-bundle

Provide basic functionality to enable installing fixtures in Pimcore

1.0.0 2024-04-24 09:19 UTC

This package is auto-updated.

Last update: 2024-04-25 07:46:28 UTC


README

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

  1. Require the bundle

    composer require teamneusta/pimcore-fixture-bundle
  2. Enable the bundle

    Add the Bundle to your config/bundles.php:

    Neusta\Pimcore\FixtureBundle\NeustaPimcoreFixtureBundle::class => ['test' => true],

Usage

Writing Fixtures

Data fixtures are PHP 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;
use Pimcore\Model\DataObject\Product;

final class ProductFixture implements Fixture
{
    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();
        }
    }
}

Loading Fixtures

To use fixtures in tests, a few preparations must be made.

Currently, the FixtureFactory still has to be instantiated manually. The easiest way to do this is with a project-specific kernel base class.

use Neusta\Pimcore\FixtureBundle\Factory\FixtureFactory;
use Neusta\Pimcore\FixtureBundle\Factory\FixtureInstantiator\FixtureInstantiatorForAll;
use Neusta\Pimcore\FixtureBundle\Factory\FixtureInstantiator\FixtureInstantiatorForParametrizedConstructors;
use Neusta\Pimcore\FixtureBundle\Fixture;
use Pimcore\Test\KernelTestCase;

abstract class BaseKernelTestCase extends KernelTestCase
{
    protected FixtureFactory $fixtureFactory;

    /** @param list<class-string<Fixture>> $fixtures */
    protected function importFixtures(array $fixtures): void
    {
        $this->fixtureFactory ??= (new FixtureFactory([
            new FixtureInstantiatorForParametrizedConstructors(static::getContainer()),
            new FixtureInstantiatorForAll(),
        ]));

        $this->fixtureFactory->createFixtures($fixtures);
    }

    protected function tearDown(): void
    {
        unset($this->fixtureFactory);
        \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);
    }
}

Accessing Services from the Fixtures

Sometimes you may need to access your application's services inside a fixture class. You can use normal dependency injection for this:

Important

You need to create your FixtureFactory with the FixtureInstantiatorForParametrizedConstructors for this to work!

final class SomeFixture implements Fixture
{
    public function __construct(
        private Something $something,
    ) {
    }

    public function create(): void
    {
        // ... use $this->something
    }
}

Depending on Other Fixtures

In a fixture, you can depend on other fixtures. Therefore, you have to reference them in your create() method as parameters.

Important

All parameters of the create() method in your fixtures may only reference other fixtures. Everything else is not allowed!

Referencing other fixtures ensures they are created before this one.

This also allows accessing some state of the other fixtures.

final class SomeFixture implements Fixture
{
    public function create(OtherFixture $otherFixture): void
    {
        // do something with $otherFixture->someInformation
    }
}

final class OtherFixture implements Fixture
{
    public string $someInformation;

    public function create(): void
    {
        $this->someInformation = 'some information created in this fixture';
    }
}

The state can also be accessed from the tests:

use Neusta\Pimcore\FixtureBundle\Fixture;
use Pimcore\Model\DataObject\Product;

final class ProductFixture implements Fixture
{
    public int $productId;

    public function create(): void
    {
        $product = new Product();
        $product->setParentId(0);
        $product->setPublished(true);
        $product->setKey("Product Fixture");
        // ...

        $product->save();

        $this->productId = $product->getId();
    }
}
use Pimcore\Model\DataObject;

final class MyCustomTest extends BaseKernelTestCase
{
    /** @test */
    public function some_product_test(): void
    {
        $this->importFixtures([
            ProductFixture::class,
        ]);

        $productFixture = $this->fixtureFactory->getFixture(ProductFixture::class);
        $product = DataObject::getById($productFixture->productId);

        self::assertNotNull($product);
    }
}

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