Environment specific data fixtures with Symfony+Do

2020-05-18 07:36发布

With Smyfony2 and Doctrin2, data fixtures can be created using the following example: http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html

What I would like is to be able to use this concept for testing so that setup/teardown can create a pure test data environment for functional testing. How might I go about having a specific set of test-only fixtures run during functional tests and how do I separate these fixtures from my standard fixtures so that the console command ignores them?

It seems that the way to do it would be to replicate the functionality of the doctrine:fixtures console command and store the test fixtures elsewhere. Does anyone have a better solution?

2条回答
冷血范
2楼-- · 2020-05-18 08:04

An alternative to breaking out fixtures by directory is to use a custom fixture class. Your fixture classes would then extend this class and specify the environments it will actually be loaded in.

<?php

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\KernelInterface;

/**
 * Provides support for environment specific fixtures.
 *
 * This container aware, abstract data fixture is used to only allow loading in
 * specific environments. The environments the data fixture will be loaded in is
 * determined by the list of environment names returned by `getEnvironments()`.
 *
 * > The fixture will still be shown as having been loaded by the Doctrine
 * > command, `doctrine:fixtures:load`, despite not having been actually
 * > loaded.
 *
 * @author Kevin Herrera <kevin@herrera.io>
 */
abstract class AbstractDataFixture implements ContainerAwareInterface, FixtureInterface
{
    /**
     * The dependency injection container.
     *
     * @var ContainerInterface
     */
    protected $container;

    /**
     * {@inheritDoc}
     */
    public function load(ObjectManager $manager)
    {
        /** @var KernelInterface $kernel */
        $kernel = $this->container->get('kernel');

        if (in_array($kernel->getEnvironment(), $this->getEnvironments())) {
            $this->doLoad($manager);
        }
    }

    /**
     * {@inheritDoc}
     */
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    /**
     * Performs the actual fixtures loading.
     *
     * @see \Doctrine\Common\DataFixtures\FixtureInterface::load()
     *
     * @param ObjectManager $manager The object manager.
     */
    abstract protected function doLoad(ObjectManager $manager);

    /**
     * Returns the environments the fixtures may be loaded in.
     *
     * @return array The name of the environments.
     */
    abstract protected function getEnvironments();
}

Your fixtures would end up looking like this:

<?php

namespace Vendor\Bundle\ExampleBundle\DataFixtures\ORM;

use AbstractDataFixture;
use Doctrine\Common\Persistence\ObjectManager;

/**
 * Loads data only on "prod".
 */
class ExampleData extends AbstractDataFixture
{
    /**
     * @override
     */
    protected function doLoad(ObjectManager $manager)
    {
        // ... snip ...
    }

    /**
     * @override
     */
    protected function getEnvironments()
    {
        return array('prod');
    }
}

I believe that this should work with both ORM an ODM data fixtures.

查看更多
三岁会撩人
3楼-- · 2020-05-18 08:21

The easiest way is to put your fixtures into different folders and then load them with the php app/console doctrine:fixtures:load --fixtures=../src/Acme/TestBundle/DataFixtures/ORM/test command. The fixtures option must point to the relative path from where you app folder!

You can then split up your data into initial, test and so on or create dev, test, staging, prod fixtures, just as you like.

If you want to mix them up, I don't know any better solution than what I did: I createt a "templates" folder where all fixtures reside in. In my dev folder, I create one class which extends the proper fixture class from template and adjusts what is needed to adjust (like overriding the getOrder method). It's not perfect and I guess one could think about extending the fixtures:load command to take multiple paths, but it works for me.

查看更多
登录 后发表回答