DoctrineFixturesBundle
repository·4.3.x·Indexed 25 days ago
https://github.com/doctrine/doctrinefixturesbundleA Symfony bundle that integrates the Doctrine Data Fixtures library, allowing developers to programmatically load sample or test data into the Doctrine ORM. It provides the `doctrine:fixtures:load` CLI command to execute fixtures, with support for database purging, dry runs, fixture grouping, and dependency injection for accessing application services.
What's inside DoctrineFixturesBundle
- DoctrineFixturesBundle allows you to load data fixtures programmatically into the Doctrine ORM within a Symfony application. It acts as a bridge between the Doctrine Data Fixtures library and the Symfony framework.
Share objects between fixtures using object references
4.3.xWhen splitting fixtures into multiple files, you can reuse ORM entities across files using object references.
- In the source fixture, use
$this->addReference('name', $object)to store an entity. - In the dependent fixture, use
$this->getReference('name', EntityClass::class)to retrieve it.
Note: This only works for ORM entities.
// src/DataFixtures/UserFixtures.php class UserFixtures extends Fixture { public const ADMIN_USER_REFERENCE = 'admin-user'; public function load(ObjectManager $manager): void { $userAdmin = new User('admin', 'pass_1234'); $manager->persist($userAdmin); $manager->flush(); $this->addReference(self::ADMIN_USER_REFERENCE, $userAdmin); } } // src/DataFixtures/GroupFixtures.php class GroupFixtures extends Fixture { public function load(ObjectManager $manager): void { $userGroup = new Group('administrators'); // returns the User object created in UserFixtures $userGroup->addUser($this->getReference(UserFixtures::ADMIN_USER_REFERENCE, User::class)); $manager->persist($userGroup); $manager->flush(); } }- In the source fixture, use
Access services in fixtures via dependency injection
4.3.xSince fixture classes are registered as services in Symfony, you can use standard dependency injection to access application services (like password hashers) within your
load()method.// 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): void { $user = new User(); $user->setUsername('admin'); $password = $this->hasher->hashPassword($user, 'pass_1234'); $user->setPassword($password); $manager->persist($user); $manager->flush(); } }Migrate to DoctrineFixturesBundle 3.0
4.3.xWhen upgrading to version 3.0, several architectural changes were introduced regarding fixture registration and dependency management:
Registering Fixtures as Services
Automatic loading of fixtures from a directory (e.g.,
AppBundle\DataFixtures\ORM) has been removed. You must now register fixture classes as services and tag them withdoctrine.fixture.orm.If you are using Symfony 3.3+ with default service configuration, this happens automatically if your fixture classes extend
Doctrine\Bundle\FixturesBundle\Fixtureor implementDoctrine\Bundle\FixturesBundle\ORMFixtureInterface.Dependency Injection in Fixtures
The base
Fixtureclass no longer implementsContainerAwareInterface, meaning the$this->containerproperty is no longer available. It is recommended to use constructor dependency injection instead of manually implementingContainerAwareInterface.Implementing Dependencies
The base
Fixtureclass no longer implementsDependentFixtureInterface. If your fixture requires agetDependencies()method, you must explicitly implementDoctrine\Common\DataFixtures\DependentFixtureInterface.# src/AppBundle/Resources/config/dataFixture.yml services: _defaults: tags: ['doctrine.fixture.orm'] autowire: true # if you need dependency injection, see next bullet point AppBundle\DataFixtures\ORM\: resource: '../../DataFixtures/ORM/*'class MyFixture extends Fixture { + private $someService; + public function __construct(SomeService $someService) + { + $this->someService = $someService; + } public function load(ObjectManager $manager) { - $this->container->get('some_service')->someMethod(); + $this->someService->someMethod(); } }+ use Doctrine\Common\DataFixtures\DependentFixtureInterface; - class MyFixture extends Fixture + class MyFixture extends Fixture implements DependentFixtureInterfaceWrite data fixtures
4.3.xData fixtures are PHP classes where you create and persist objects to the database. To create a fixture, extend the
Doctrine\Bundle\FixturesBundle\Fixtureclass and implement theload(ObjectManager $manager)method. Use the$managertopersist()your entities andflush()to save them to the database.// 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): void { // create 20 products with random prices for ($i = 0; $i < 20; $i++) { $product = new Product(); $product->setName('product '.$i); $product->setPrice(mt_rand(10, 100)); $manager->persist($product); } $manager->flush(); } }Implement and register a custom Purger
4.3.xIf the built-in purging methods are insufficient, you can implement a custom purger and factory.
- Implement
ORMPurgerInterfacefor your purging logic. - Implement
PurgerFactoryto instantiate your purger. - Register the factory in your service container with the tag
doctrine.fixtures.purger_factoryand assign it analias. - Use the
--purgeroption in the CLI to select your custom purger by its alias.
// src/Purger/CustomPurger.php namespace App\Purger; use Doctrine\Common\DataFixtures\Purger\ORMPurgerInterface; use Doctrine\ORM\EntityManagerInterface; class CustomPurger implements ORMPurgerInterface { private EntityManagerInterface $entityManager; public function setEntityManager(EntityManagerInterface $em): void { $this->entityManager = $em; } public function purge(): void { // ... custom logic } } // src/Purger/CustomPurgerFactory.php namespace App\Purger; use Doctrine\Bundle\FixturesBundle\Purger\PurgerFactory; use Doctrine\Common\DataFixtures\Purger\PurgerInterface; use Doctrine\ORM\EntityManagerInterface; class CustomPurgerFactory implements PurgerFactory { public function createForEntityManager(?string $emName, EntityManagerInterface $em, array $excluded = [], bool $purgeWithTruncate = false) : PurgerInterface { return new CustomPurger(); } }- Implement
Migrate to DoctrineFixturesBundle 4.0
4.3.xWhen upgrading to version 4.0, be aware of the following breaking changes:
- Type Declarations: Strict type declarations have been added throughout the bundle. Any custom classes that extend or implement bundle types must be updated to match the new signatures.
- Final Classes: Several classes are now marked as
final. You should use composition instead of inheritance if you previously extended these classes. - Mandatory ManagerRegistry: The constructor for
Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommandnow requires aManagerRegistryinstance.
Run fixtures in Dry Run mode
4.3.xThe--dry-runoption allows you to simulate the execution of your fixtures. It processes the fixtures and handles logging/output as usual, but all persisting operations are skipped and no changes are made to the database. This is useful for safely inspecting fixture behavior.Install DoctrineFixturesBundle
4.3.xTo install the bundle, use Composer. If you are using Symfony Flex, use the aliasorm-fixtures. Otherwise, use the full package name.Configure purging behavior when loading fixtures
4.3.xBy default,
doctrine:fixtures:loadpurges existing data usingDELETE FROM tablestatements. You can customize this behavior using CLI options or by implementing a custom purger.CLI Options
- Truncate instead of Delete: Use
--purge-with-truncateto useTRUNCATE tablestatements. - Exclude tables: Use
--purge-exclusionsto prevent specific tables from being purged (useful for semi-static data). You can pass this flag multiple times to exclude multiple tables.
Custom Purger Implementation
To implement a custom purging strategy, create a class implementing
ORMPurgerInterfaceand a factory implementingPurgerFactory.- Truncate instead of Delete: Use
Load fixtures from a custom directory
4.3.xBy default, fixtures are loaded from
src/DataFixtures. To use a different directory (e.g.,fixtures/):- Update Autoloading: Add a PSR-4 entry for the new directory in your
composer.jsonunderautoload-dev. - Run Composer: Execute
composer dump-autoload. - Configure Dependency Injection: Register the new directory in your Symfony service configuration so that fixtures are properly autowired and autoconfigured.
Note: Changing this directory does not affect the
Symfony MakerBundle(make:fixtures) command, which will continue to use the defaultsrc/DataFixturespath.// composer.json "autoload-dev": { "psr-4": { "DataFixtures\": "fixtures/" } }# config/services.yaml services: DataFixtures\: resource: '../fixtures'// config/services.php namespace Symfony\Component\DependencyInjection\Loader\Configurator; return function(ContainerConfigurator $container): void { $services = $container->services() ->defaults() ->autowire() ->autoconfigure(); $services->load('DataFixtures\\', '../fixtures'); };- Update Autoloading: Add a PSR-4 entry for the new directory in your
Organize and execute specific fixture groups
4.3.xBy default, all fixtures are executed. To run only a subset, you can use groups.
Using FixtureGroupInterface
Implement
Doctrine\Bundle\FixturesBundle\FixtureGroupInterfaceand define the groups in a staticgetGroups()method:class UserFixtures extends Fixture implements FixtureGroupInterface { public static function getGroups(): array { return ['group1', 'group2']; } }Running groups via CLI
Use the
--groupoption to specify which group(s) to load. You can also load a single fixture by its class name, as the loader automatically adds the short class name as a group.# Execute a specific group $ php bin/console doctrine:fixtures:load --group=group1 # Execute multiple groups $ php bin/console doctrine:fixtures:load --group=group1 --group=group2 # Execute a single fixture by its class name $ php bin/console doctrine:fixtures:load --group=UserFixtures