Skip to content

Commit

Permalink
Merge pull request #151 from javiereguiluz/patch-2
Browse files Browse the repository at this point in the history
Updated the dcs to follow the recommended Symfony practices
  • Loading branch information
guilhermeblanco committed Nov 4, 2015
2 parents 5947b44 + f244606 commit 0f1a2f9
Showing 1 changed file with 74 additions and 98 deletions.
172 changes: 74 additions & 98 deletions Resources/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,53 @@ DoctrineFixturesBundle

Fixtures are used to load a controlled set of data into a database. This data
can be used for testing or could be the initial data required for the
application to run smoothly. Symfony2 has no built in way to manage fixtures
application to run smoothly. Symfony has no built in way to manage fixtures
but Doctrine2 has a library to help you write fixtures for the Doctrine
:doc:`ORM</book/doctrine>` or :doc:`ODM</bundles/DoctrineMongoDBBundle/index>`.

Setup and Configuration
-----------------------

Doctrine fixtures for Symfony are maintained in the `DoctrineFixturesBundle`_.
The bundle uses external `Doctrine Data Fixtures`_ library.
Doctrine fixtures for Symfony are maintained in the `DoctrineFixturesBundle`_,
which uses external `Doctrine Data Fixtures`_ library.

First, install the bundle with Composer:
Follow these steps to install the bundle in your Symfony applications:

.. code-block:: bash
Step 1: Download the Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~

$ composer require doctrine/doctrine-fixtures-bundle
Open a command console, enter your project directory and execute the
following command to download the latest stable version of this bundle:

If everything worked, the ``DoctrineFixturesBundle`` can now be found
at ``vendor/doctrine/doctrine-fixtures-bundle``.
.. code-block:: bash
.. note::
composer require --dev doctrine/doctrine-fixtures-bundle
``DoctrineFixturesBundle`` installs
`Doctrine Data Fixtures`_ library. The library can be found
at ``vendor/doctrine/data-fixtures``.
This command requires you to have Composer installed globally, as explained
in the `installation chapter`_ of the Composer documentation.

Finally, register the Bundle ``DoctrineFixturesBundle`` in ``app/AppKernel.php``.
Step 2: Enable the Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~

Then, add the following line in the ``app/AppKernel.php`` file to enable this
bundle only for the ``dev`` and ``test`` environments:

.. code-block:: php
// app/AppKernel.php
// ...
public function registerBundles()
{
$bundles = array(
// ...
);
if (...) {
class AppKernel extends Kernel
{
public function registerBundles()
{
// ...
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
};
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
}
return $bundles
}
// ...
}
Expand All @@ -53,31 +58,29 @@ Writing Simple Fixtures
-----------------------

Doctrine2 fixtures are PHP classes where you can create objects and persist
them to the database. Like all classes in Symfony2, fixtures should live inside
them to the database. Like all classes in Symfony, fixtures should live inside
one of your application bundles.

For a bundle located at ``src/Acme/HelloBundle``, the fixture classes
should live inside ``src/Acme/HelloBundle/DataFixtures/ORM`` or
``src/Acme/HelloBundle/DataFixtures/MongoDB`` respectively for the ORM and ODM.
This tutorial assumes that you are using the ORM - but fixtures can be added
just as easily if you're using the ODM.
For a bundle located at ``src/AppBundle``, the fixture classes should live inside
``src/AppBundle/DataFixtures/ORM`` or ``src/AppBundle/DataFixtures/MongoDB``
respectively for the ORM and ODM. This tutorial assumes that you are using the ORM,
but fixtures can be added just as easily if you're using the ODM.

Imagine that you have a ``User`` class, and you'd like to load one ``User``
entry::
entry:

// src/Acme/HelloBundle/DataFixtures/ORM/LoadUserData.php
.. code-block:: php
// src/AppBundle/DataFixtures/ORM/LoadUserData.php
namespace Acme\HelloBundle\DataFixtures\ORM;
namespace AppBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\HelloBundle\Entity\User;
use AppBundle\Entity\User;
class LoadUserData implements FixtureInterface
{
/**
* {@inheritDoc}
*/
public function load(ObjectManager $manager)
{
$userAdmin = new User();
Expand All @@ -93,11 +96,8 @@ In Doctrine2, fixtures are just objects where you load data by interacting
with your entities as you normally do. This allows you to create the exact
fixtures you need for your application.

The most serious limitation is that you cannot share objects between fixtures.
Later, you'll see how to overcome this limitation.

Executing Fixtures
------------------
Loading Fixtures
----------------

Once your fixtures have been written, you can load them via the command
line by using the ``doctrine:fixtures:load`` command:
Expand All @@ -109,26 +109,24 @@ line by using the ``doctrine:fixtures:load`` command:

.. code-block:: bash
$ php app/console doctrine:fixtures:load
php app/console doctrine:fixtures:load
If you're using the ODM, use the ``doctrine:mongodb:fixtures:load`` command instead:

.. code-block:: bash
$ php app/console doctrine:mongodb:fixtures:load
php app/console doctrine:mongodb:fixtures:load
The task will look inside the ``DataFixtures/ORM`` (or ``DataFixtures/MongoDB``
The task will look inside the ``DataFixtures/ORM/`` (or ``DataFixtures/MongoDB/``
for the ODM) directory of each bundle and execute each class that implements
the ``FixtureInterface``.

Both commands come with a few options:

* ``--fixtures=/path/to/fixture`` - Use this option to manually specify the
directory where the fixtures classes should be loaded;

* ``--append`` - Use this flag to append data instead of deleting data before
loading it (deleting first is the default behavior);

* ``--em=manager_name`` - Manually specify the entity manager to use for
loading the data.

Expand All @@ -141,35 +139,32 @@ A full example use might look like this:

.. code-block:: bash
$ php app/console doctrine:fixtures:load --fixtures=/path/to/fixture1 --fixtures=/path/to/fixture2 --append --em=foo_manager
php app/console doctrine:fixtures:load --fixtures=/path/to/fixture1 --fixtures=/path/to/fixture2 --append --em=foo_manager
Sharing Objects between Fixtures
--------------------------------

Writing a basic fixture is simple. But what if you have multiple fixture classes
and want to be able to refer to the data loaded in other fixture classes?
For example, what if you load a ``User`` object in one fixture, and then
want to refer to it in a different fixture in order to assign that
user to a particular group?
For example, what if you load a ``User`` object in one fixture, and then want to
refer to it in a different fixture in order to assign that user to a particular
group?

The Doctrine fixtures library handles this easily by allowing you to specify
the order in which fixtures are loaded.

.. code-block:: php
// src/Acme/HelloBundle/DataFixtures/ORM/LoadUserData.php
namespace Acme\HelloBundle\DataFixtures\ORM;
// src/AppBundle/DataFixtures/ORM/LoadUserData.php
namespace AppBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\HelloBundle\Entity\User;
use AppBundle\Entity\User;
class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
{
/**
* {@inheritDoc}
*/
public function load(ObjectManager $manager)
{
$userAdmin = new User();
Expand All @@ -182,12 +177,11 @@ the order in which fixtures are loaded.
$this->addReference('admin-user', $userAdmin);
}
/**
* {@inheritDoc}
*/
public function getOrder()
{
return 1; // the order in which fixtures will be loaded
// the order in which fixtures will be loaded
// the lower the number, the sooner that this fixture is loaded
return 1;
}
}
Expand All @@ -198,20 +192,16 @@ of 2:

.. code-block:: php
// src/Acme/HelloBundle/DataFixtures/ORM/LoadGroupData.php
namespace Acme\HelloBundle\DataFixtures\ORM;
// src/AppBundle/DataFixtures/ORM/LoadGroupData.php
namespace AppBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\HelloBundle\Entity\Group;
use ApBundle\Entity\Group;
class LoadGroupData extends AbstractFixture implements OrderedFixtureInterface
{
/**
* {@inheritDoc}
*/
public function load(ObjectManager $manager)
{
$groupAdmin = new Group();
Expand All @@ -223,12 +213,11 @@ of 2:
$this->addReference('admin-group', $groupAdmin);
}
/**
* {@inheritDoc}
*/
public function getOrder()
{
return 2; // the order in which fixtures will be loaded
// the order in which fixtures will be loaded
// the lower the number, the sooner that this fixture is loaded
return 2;
}
}
Expand All @@ -240,20 +229,16 @@ references:

.. code-block:: php
// src/Acme/HelloBundle/DataFixtures/ORM/LoadUserGroupData.php
namespace Acme\HelloBundle\DataFixtures\ORM;
// src/AppBundle/DataFixtures/ORM/LoadUserGroupData.php
namespace AppBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\HelloBundle\Entity\UserGroup;
use AppBundle\Entity\UserGroup;
class LoadUserGroupData extends AbstractFixture implements OrderedFixtureInterface
{
/**
* {@inheritDoc}
*/
public function load(ObjectManager $manager)
{
$userGroupAdmin = new UserGroup();
Expand All @@ -264,9 +249,6 @@ references:
$manager->flush();
}
/**
* {@inheritDoc}
*/
public function getOrder()
{
return 3;
Expand All @@ -286,7 +268,7 @@ Using the Container in the Fixtures
-----------------------------------

In some cases you may need to access some services to load the fixtures.
Symfony2 makes it really easy: the container will be injected in all fixture
Symfony makes it really easy: the container will be injected in all fixture
classes implementing :class:`Symfony\\Component\\DependencyInjection\\ContainerAwareInterface`.

Let's rewrite the first fixture to encode the password before it's stored
Expand All @@ -296,15 +278,14 @@ component when checking it:

.. code-block:: php
// src/Acme/HelloBundle/DataFixtures/ORM/LoadUserData.php
namespace Acme\HelloBundle\DataFixtures\ORM;
// src/AppBundle/DataFixtures/ORM/LoadUserData.php
namespace AppBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Acme\HelloBundle\Entity\User;
use AppBundle\Entity\User;
class LoadUserData implements FixtureInterface, ContainerAwareInterface
{
Expand All @@ -313,28 +294,22 @@ component when checking it:
*/
private $container;
/**
* {@inheritDoc}
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* {@inheritDoc}
*/
public function load(ObjectManager $manager)
{
$user = new User();
$user->setUsername('admin');
$user->setSalt(md5(uniqid()));
$encoder = $this->container
->get('security.encoder_factory')
->getEncoder($user)
;
$user->setPassword($encoder->encodePassword('secret', $user->getSalt()));
// the 'security.password_encoder' service requires Symfony 2.6 or higher
$encoder = $this->container->get('security.password_encoder');
$password = $encoder->encodePassword($user, 'secret_password');
$user->setPassword($password);
$manager->persist($user);
$manager->flush();
Expand All @@ -345,13 +320,14 @@ As you can see, all you need to do is add :class:`Symfony\\Component\\Dependency
to the class and then create a new :method:`Symfony\\Component\\DependencyInjection\\ContainerInterface::setContainer`
method that implements that interface. Before the fixture is executed, Symfony
will call the :method:`Symfony\\Component\\DependencyInjection\\ContainerInterface::setContainer`
method automatically. As long as you store the container as a property on the
method automatically. As long as you store the container as a property in the
class (as shown above), you can access it in the ``load()`` method.

.. note::

If you are too lazy to implement the needed method :method:`Symfony\\Component\\DependencyInjection\\ContainerInterface::setContainer`,
If you prefer not to implement the needed method :method:`Symfony\\Component\\DependencyInjection\\ContainerInterface::setContainer`,
you can then extend your class with :class:`Symfony\\Component\\DependencyInjection\\ContainerAware`.

.. _DoctrineFixturesBundle: https://github.com/doctrine/DoctrineFixturesBundle
.. _`Doctrine Data Fixtures`: https://github.com/doctrine/data-fixtures
.. _`installation chapter`: https://getcomposer.org/doc/00-intro.md

0 comments on commit 0f1a2f9

Please sign in to comment.