123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- DoctrineFixturesBundle
- ======================
- Fixtures are used to load a "fake" set of data into a database that can then
- be used for testing or to help give you some interesting data while you're
- developing your application.
- This bundle is compatible with any database supported by `Doctrine ORM`_
- (MySQL, PostgreSQL, SQLite, etc.). If you are using MongoDB, you must use
- `DoctrineMongoDBBundle`_ instead.
- Installation
- ------------
- In Symfony 4 or higher applications that use `Symfony Flex`_, open a command
- console, enter your project directory and run the following command:
- .. code-block:: terminal
- $ composer require --dev orm-fixtures
- Starting from Symfony 4.0, Flex should be used by default and register the
- bundle for you, and in that case you can skip to the next section and start
- writing fixtures.
- In Symfony 3 applications (or when not using Symfony Flex), run this other
- command instead:
- .. code-block:: terminal
- $ composer require --dev doctrine/doctrine-fixtures-bundle
- You will also need to enable the bundle. In Symfony 3 and earlier applications,
- update the ``AppKernel`` class::
- // app/AppKernel.php
- // ...
- // registerBundles()
- if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
- // ...
- $bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
- }
- 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. No problem!
- Create a fixtures class and start adding products::
- // src/DataFixtures/AppFixtures.php
- namespace App\DataFixtures;
- use App\Entity\Product;
- use Doctrine\Bundle\FixturesBundle\Fixture;
- use Doctrine\Persistence\ObjectManager;
- class AppFixtures extends Fixture
- {
- public function load(ObjectManager $manager)
- {
- // create 20 products! Bam!
- for ($i = 0; $i < 20; $i++) {
- $product = new Product();
- $product->setName('product '.$i);
- $product->setPrice(mt_rand(10, 100));
- $manager->persist($product);
- }
- $manager->flush();
- }
- }
- .. tip::
- You can also create multiple fixtures classes. See :ref:`multiple-files`.
- Loading Fixtures
- ----------------
- Once your fixtures have been written, load them by executing this command:
- .. code-block:: terminal
- # when using the ORM
- $ php bin/console doctrine:fixtures:load
- .. caution::
- By default the ``load`` command **purges the database**, removing all data
- from every table. To append your fixtures' data add the ``--append`` option.
- This command looks for all services tagged with ``doctrine.fixture.orm``. If you're
- using the `default service configuration`_, any class that implements ``ORMFixtureInterface``
- (for example, those extending from ``Fixture``) will automatically be registered
- with this tag.
- To see other options for the command, run:
- .. code-block:: terminal
- $ php bin/console doctrine:fixtures:load --help
- Accessing Services from the Fixtures
- ------------------------------------
- In some cases you may need to access your application's services inside a fixtures
- class. No problem! Your fixtures class is a service, so you can use normal dependency
- injection::
- // src/DataFixtures/AppFixtures.php
- use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
- class AppFixtures extends Fixture
- {
- private $encoder;
- public function __construct(UserPasswordEncoderInterface $encoder)
- {
- $this->encoder = $encoder;
- }
- // ...
- public function load(ObjectManager $manager)
- {
- $user = new User();
- $user->setUsername('admin');
- $password = $this->encoder->encodePassword($user, 'pass_1234');
- $user->setPassword($password);
- $manager->persist($user);
- $manager->flush();
- }
- }
- .. _multiple-files:
- Splitting Fixtures into Separate Files
- --------------------------------------
- In most applications, creating all your fixtures in just one class is fine.
- This class may end up being a bit long, but it's worth it because having one
- file helps keeping things simple.
- If you do decide to split your fixtures into separate files, Symfony helps you
- solve the two most common issues: sharing objects between fixtures and loading
- the fixtures in order.
- Sharing Objects between Fixtures
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- When using multiple fixtures files, you can reuse PHP objects across different
- files thanks to the **object references**. Use the ``addReference()`` method to
- give a name to any object and then, use the ``getReference()`` method to get the
- exact same object via its name::
- // src/DataFixtures/UserFixtures.php
- // ...
- class UserFixtures extends Fixture
- {
- public const ADMIN_USER_REFERENCE = 'admin-user';
- public function load(ObjectManager $manager)
- {
- $userAdmin = new User('admin', 'pass_1234');
- $manager->persist($userAdmin);
- $manager->flush();
- // other fixtures can get this object using the UserFixtures::ADMIN_USER_REFERENCE constant
- $this->addReference(self::ADMIN_USER_REFERENCE, $userAdmin);
- }
- }
- // src/DataFixtures/GroupFixtures.php
- // ...
- class GroupFixtures extends Fixture
- {
- public function load(ObjectManager $manager)
- {
- $userGroup = new Group('administrators');
- // this reference returns the User object created in UserFixtures
- $userGroup->addUser($this->getReference(UserFixtures::ADMIN_USER_REFERENCE));
- $manager->persist($userGroup);
- $manager->flush();
- }
- }
- The only caveat of using references is that fixtures need to be loaded in a
- certain order (in this example, if the ``Group`` fixtures are load before the
- ``User`` fixtures, you'll see an error). By default Doctrine loads the fixture
- files in alphabetical order, but you can control their order as explained in the
- next section.
- Loading the Fixture Files in Order
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Instead of defining the exact order in which all fixture files must be loaded,
- Doctrine uses a smarter approach to ensure that some fixtures are loaded before
- others. Implement the ``DependentFixtureInterface`` and add a new
- ``getDependencies()`` method to your fixtures class. This will return
- an array of the fixture classes that must be loaded before this one::
- // src/DataFixtures/UserFixtures.php
- namespace App\DataFixtures;
- // ...
- class UserFixtures extends Fixture
- {
- public function load(ObjectManager $manager)
- {
- // ...
- }
- }
- // src/DataFixtures/GroupFixtures.php
- namespace App\DataFixtures;
- // ...
- use App\DataFixtures\UserFixtures;
- use Doctrine\Common\DataFixtures\DependentFixtureInterface;
- class GroupFixtures extends Fixture implements DependentFixtureInterface
- {
- public function load(ObjectManager $manager)
- {
- // ...
- }
- public function getDependencies()
- {
- return array(
- UserFixtures::class,
- );
- }
- }
- Fixture Groups: Only Executing Some Fixtures
- --------------------------------------------
- By default, *all* of your fixture classes are executed. If you only want
- to execute *some* of your fixture classes, you can organize them into
- groups.
- The simplest way to organize a fixture class into a group is to
- make your fixture implement ``FixtureGroupInterface``:
- .. code-block:: diff
- // src/DataFixtures/UserFixtures.php
- + use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
- - class UserFixtures extends Fixture
- + class UserFixtures extends Fixture implements FixtureGroupInterface
- {
- // ...
- + public static function getGroups(): array
- + {
- + return ['group1', 'group2'];
- + }
- }
- To execute all of your fixtures for a given group, pass the ``--group``
- option:
- .. code-block:: terminal
- $ php bin/console doctrine:fixtures:load --group=group1
- # or to execute multiple groups
- $ php bin/console doctrine:fixtures:load --group=group1 --group=group2
- Alternatively, instead of implementing the ``FixtureGroupInterface``,
- you can also tag your service with ``doctrine.fixture.orm`` and add
- an extra ``group`` option set to a group your fixture should belong to.
- Regardless of groups defined in the fixture or the service definition, the
- fixture loader always adds the short name of the class as a separate group so
- you can load a single fixture at a time. In the example above, you can load the
- fixture using the ``UserFixtures`` group:
- .. code-block:: terminal
- $ php bin/console doctrine:fixtures:load --group=UserFixtures
- .. _`ORM`: https://symfony.com/doc/current/doctrine.html
- .. _`installation chapter`: https://getcomposer.org/doc/00-intro.md
- .. _`Symfony Flex`: https://symfony.com/doc/current/setup/flex.html
- .. _`default service configuration`: https://symfony.com/doc/current/service_container.html#service-container-services-load-example
- Specifying purging behavior
- ---------------------------
- By default all previously existing data is purged using ``DELETE FROM table`` statements. If you prefer to use
- ``TRUNCATE table`` statements for purging, use ``--purge-with-truncate``.
- If you want to exclude a set of tables from being purged, e.g. because your schema comes with pre-populated,
- semi-static data, pass the option ``--purge-exclusions``. Specify ``--purge-exclusions`` multiple times to exclude
- multiple tables.
- You can also customize purging behavior significantly more and implement a custom purger plus a custom purger factory::
- // src/Purger/CustomPurger.php
- namespace App\Purger;
- use Doctrine\Common\DataFixtures\Purger\PurgerInterface;
- // ...
- class CustomPurger implements PurgerInterface
- {
- public function purge() : void
- {
- // ...
- }
- }
- // src/Purger/CustomPurgerFactory.php
- namespace App\Purger;
- // ...
- use Doctrine\Bundle\FixturesBundle\Purger\PurgerFactory;
- class CustomPurgerFactory implements PurgerFactory
- {
- public function createForEntityManager(?string $emName, EntityManagerInterface $em, array $excluded = [], bool $purgeWithTruncate = false) : PurgerInterface;
- {
- return new CustomPurger($em);
- }
- }
- The next step is to register our custom purger factory and specify its alias.
- .. configuration-block::
- .. code-block:: yaml
- # config/services.yaml
- services:
- App\Purger\CustomPurgerFactory:
- tags:
- - { name: 'doctrine.fixtures.purger_factory', alias: 'my_purger' }
- .. code-block:: xml
- <!-- config/services.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <services>
- <service id="App\Purger\CustomPurgerFactory">
- <tag name="doctrine.fixtures.purger_factory" alias="my_purger"/>
- </service>
- </services>
- </container>
- .. code-block:: php
- // config/services.php
- namespace Symfony\Component\DependencyInjection\Loader\Configurator;
- use App\Purger\CustomerPurgerFactory;
- return function(ContainerConfigurator $configurator) : void {
- $services = $configurator->services();
- $services->set(CustomerPurgerFactory::class)
- ->tag('doctrine.fixtures.purger_factory', ['alias' => 'my_purger'])
- ;
- };
- With the ``--purger`` option we can now specify to use ``my_purger`` instead of the ``default`` purger.
- .. code-block:: terminal
- $ php bin/console doctrine:fixtures:load --purger=my_purger
- .. _`Doctrine ORM`: https://symfony.com/doc/current/doctrine.html
- .. _`DoctrineMongoDBBundle`: https://github.com/doctrine/DoctrineMongoDBBundle
|