Fixtures. DoctrineFixturesBundle

Fixtures (Eng. fixtures) - a very useful development tool. Essentially, it is just a set of test data used in dev mode. They are typically not used in prod mode (for production, Data Migrations are usually used).

There are several convenient bundles for working with fixtures in Symfony. The first one is the basic DoctrineFixturesBundle, which is dedicated to this article.

Installation: 

composer require "doctrine/doctrine-fixtures-bundle:2.2.0"

(The latest stable version at the time of writing this article is specified)

Register the bundle in app/AppKernel.php

if (in_array($this->getEnvironment(), array('dev', 'test'))) {
...
    $bundles[] = new DoctrineBundleFixturesBundleDoctrineFixturesBundle();
..
}

Usage (taken from the Symfony documentation) with an example of creating a test user:

// src/Acme/HelloBundle/DataFixtures/ORM/LoadUserData.php

namespace AcmeHelloBundleDataFixturesORM;

use DoctrineCommonDataFixturesFixtureInterface; use DoctrineCommonPersistenceObjectManager; use AcmeHelloBundleEntityUser;

class LoadUserData implements FixtureInterface { /** * {@inheritDoc} */ public function load(ObjectManager $manager) { $userAdmin = new User(); $userAdmin->setUsername('admin'); $userAdmin->setPassword('test');

$manager->persist($userAdmin); $manager->flush(); } }

An interesting feature is the ability to use references. This is necessary for cases where there is a relationship between the loaded entities. To do this, the fixture uses the addReference('reference', $entity) method, which registers a reference to the entity. Then in the dependent entity, you can use getReference('reference') - and that value will be assigned to the entity's setter. At the same time, you need to control the order of fixture loading (to ensure that the reference is added before attempting to use it). Modify the example above (following the Symfony documentation again, but with some changes):

First, add the Group entity:

// src/Acme/HelloBundle/DataFixtures/ORM/LoadGroupData.php

namespace AcmeHelloBundleDataFixturesORM;

use DoctrineCommonDataFixturesAbstractFixture; use DoctrineCommonDataFixturesOrderedFixtureInterface; use DoctrineCommonPersistenceObjectManager; use AcmeHelloBundleEntityGroup;

class LoadGroupData extends AbstractFixture implements OrderedFixtureInterface { /** * {@inheritDoc} */ public function load(ObjectManager $manager) { $groupAdmin = new Group(); $groupAdmin->setGroupName('admin'); $this->addReference('admin-group', $groupAdmin);

$manager->persist($groupAdmin); $manager->flush(); }

/** * {@inheritDoc} */ public function getOrder() { return 1; // the order in which fixtures will be loaded } }

Now that we have loaded the group (and specified that it should be loaded first), we can proceed to load the user:

// src/Acme/HelloBundle/DataFixtures/ORM/LoadUserData.php
namespace AcmeHelloBundleDataFixturesORM;

use DoctrineCommonDataFixturesAbstractFixture; use DoctrineCommonDataFixturesOrderedFixtureInterface; use DoctrineCommonPersistenceObjectManager; use AcmeHelloBundleEntityUser;

class LoadUserData extends AbstractFixture implements OrderedFixtureInterface { /** * {@inheritDoc} */ public function load(ObjectManager $manager) { $userAdmin = new User(); $userAdmin->setUsername('admin'); $userAdmin->setPassword('test'); $userAdmin->setGroup($this->getReference('admin-group')); $manager->persist($userAdmin); $manager->flush(); }

/** * {@inheritDoc} */ public function getOrder() { return 2; // the order in which fixtures will be loaded } }

We obtained the group by reference.

For a simple example, that's enough. But what if, for example, we need to assign multiple groups to a user? We can write something like this:

$userAdmin->setGroup(array(
    $this->getReference('admin-group'),
    $this->getReference('other-group'),
    $this->getReference('one-more-other-group'),
));

For this to work, the 'other-group' and 'one-more-other-group' should be loaded earlier and references should be created. But it is probably more convenient to implement a method like this:

/**
* @param array $references
* @return ArrayCollection
*/
public function getArrayReference(array $references = array(), $prefix = null)
{
    $outputReferences = new ArrayCollection();

foreach ($references as $reference) { $outputReferences->add($this->getReference($prefix . $reference)); }

return $outputReferences; }

Then we can use it like this:

app/console doctrine:fixtures:load
$userAdmin->setGroup($this->getArrayReferences(array(
   'admin-group',
   'other-group',
   'one-more-other-group'
));

Finally, to load the fixtures, use: