Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Bundles
  4. DoctrineFixturesBundle

DoctrineFixturesBundle

Edit this page

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

If you're using Symfony Flex, run this command and you're done:

1
$ composer require --dev orm-fixtures

If you're not using Flex, run this other command instead:

1
$ composer require --dev doctrine/doctrine-fixtures-bundle

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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();
    }
}

Loading Fixtures

Once your fixtures have been written, load them by executing this command:

1
2
# 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:

1
$ 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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// src/DataFixtures/AppFixtures.php
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class AppFixtures extends Fixture
{
    private UserPasswordHasherInterface $hasher;

    public function __construct(UserPasswordHasherInterface $hasher)
    {
        $this->hasher = $hasher;
    }

    // ...
    public function load(ObjectManager $manager)
    {
        $user = new User();
        $user->setUsername('admin');

        $password = $this->hasher->hashPassword($user, 'pass_1234');
        $user->setPassword($password);

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

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.

Note

Adding object references only works for ORM entities or ODM documents.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 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 [
            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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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:

1
2
3
4
$ 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:

1
$ php bin/console doctrine:fixtures:load --group=UserFixtures

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:

1
$ php bin/console doctrine:fixtures:load --purge-exclusions=post_category --purge-exclusions=comment_type

You can also customize purging behavior significantly more and implement a custom purger plus a custom purger factory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 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.

1
2
3
4
5
# config/services.yaml
services:
    App\Purger\CustomPurgerFactory:
        tags:
            - { name: 'doctrine.fixtures.purger_factory', alias: 'my_purger' }
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 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>
1
2
3
4
5
6
7
8
9
10
11
12
// 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.

1
$ php bin/console doctrine:fixtures:load --purger=my_purger

How to load Fixtures from a different Directory

By default, fixtures are loaded from the src/DataFixtures directory. In this example, we are going to load our DataFixtures from a new fixtures directory.

First, add a new PSR-4 autoload-entry in the composer.json with the new fixtures directory:

1
2
3
4
5
6
"autoload-dev": {
    "psr-4": {
        "...": "...",
        "DataFixtures\\": "fixtures/"
    }
},

Note

You need to dump the autoloader with composer dump-autoload

Then, enable Dependency Injection for the fixtures directory:

1
2
3
4
# config/services.yaml
services:
    DataFixtures\:
        resource: '../fixtures'
1
2
3
4
5
6
7
8
9
10
11
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

return function(ContainerConfigurator $container) : void {
    $services = $container->services()
        ->defaults()
            ->autowire()
            ->autoconfigure();

    $services->load('DataFixtures\\', '../fixtures');
};

Caution

This will not override the default src/DataFixtures directory when creating fixtures with the Symfony MakerBundle (make:fixtures).

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    Become certified from home

    Become certified from home

    Make sure your project is risk free

    Make sure your project is risk free

    Version:

    Table of Contents

    • Installation
    • Writing Fixtures
    • Loading Fixtures
    • Accessing Services from the Fixtures
    • Splitting Fixtures into Separate Files
      • Sharing Objects between Fixtures
      • Loading the Fixture Files in Order
    • Fixture Groups: Only Executing Some Fixtures
    • Specifying purging behavior
    • How to load Fixtures from a different Directory

    Symfony footer

    Avatar of Florent Mata, a Symfony contributor

    Thanks Florent Mata (@fmata) for being a Symfony contributor

    18 commits • 576 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony