doctrine/data-fixtures
Doctrine Data Fixtures provides a simple way to define, manage, and run data fixture loaders for Doctrine ORM/ODM. Use it to seed databases with reusable sample data for development, testing, and demos via an organized fixture execution workflow.
Installation:
composer require doctrine/data-fixtures-bundle
For Laravel, use doctrine/doctrine-bundle (includes fixtures support).
First Fixture:
Create a fixture class in database/fixtures/ (or your preferred location):
// database/fixtures/UserFixtures.php
namespace Database\Fixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use App\Models\User;
class UserFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
$user = new User();
$user->name = 'John Doe';
$user->email = 'john@example.com';
$manager->persist($user);
$manager->flush();
// Reference for later use
$this->addReference('john_doe', $user);
}
}
Run Fixtures:
php artisan doctrine:fixtures:load
Populate a database with test data for development or testing. Example:
php artisan doctrine:fixtures:load --append # Append to existing data
php artisan doctrine:fixtures:load --purge # Clear and reload
Use dependsOn() to define execution order:
class RoleFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
$role = new Role();
$role->name = 'Admin';
$manager->persist($role);
$manager->flush();
$this->addReference('admin_role', $role);
}
}
class UserFixtures extends Fixture
{
public function getDependencies()
{
return [RoleFixtures::class]; // Runs RoleFixtures first
}
public function load(ObjectManager $manager)
{
$user = new User();
$user->name = 'Admin User';
$user->role = $this->getReference('admin_role'); // Uses referenced role
$manager->persist($user);
$manager->flush();
}
}
Reference entities for relationships:
$this->addReference('user_1', $user);
// Later in another fixture:
$user = $this->getReference('user_1');
Use ArrayCollection or loops for efficiency:
$users = [];
for ($i = 0; $i < 100; $i++) {
$user = new User();
$user->name = "User $i";
$users[] = $user;
}
$manager->persist($users);
$manager->flush();
Override default behavior (e.g., dry-run):
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
$executor = new ORMExecutor($container->get('doctrine'), new ORMPurger());
$executor->execute($fixtures, true); // Dry-run mode
Leverage Laravel’s service container:
use Illuminate\Support\Facades\DB;
class DatabaseFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
// Fixture logic
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
}
}
Run fixtures after migrations:
php artisan migrate --seed
Or manually:
php artisan doctrine:fixtures:load
Combine with Laravel factories for dynamic data:
use App\Models\User;
use Faker\Factory as Faker;
class UserFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
$faker = Faker::create();
for ($i = 0; $i < 5; $i++) {
$user = User::factory()->create([
'email' => $faker->unique()->email
]);
$manager->persist($user);
}
$manager->flush();
}
}
Use Laravel’s environment config:
if (app()->environment('testing')) {
// Load test-specific fixtures
}
For large datasets, use doctrine/doctrine-fixtures-bundle's parallel loader:
# config/packages/doctrine_fixtures.yaml
doctrine_fixtures:
parallel: true
UserFixtures won’t be available in ProductFixtures unless explicitly passed via dependencies.dependsOn() to chain fixtures or pass references through constructor injection.--append or chunk data:
$manager->flush(); // Flush after every N entities
A depends on B and B depends on A.ORMPurger deletes all entities of loaded fixtures. Be explicit with purgeMode.Purger::PURGE_MODE_DELETE (default) or Purger::PURGE_MODE_TRUNCATE for faster clears.prePersist). Use EventManager if needed:
$eventManager = $manager->getEventManager();
$eventManager->dispatchEvent(...);
DB::connection()->disableQueryLog();
// Fixture logic
DB::connection()->enableQueryLog();
Test without writing to the database:
php artisan doctrine:fixtures:load --dry-run
Enable verbose output:
php artisan doctrine:fixtures:load -v
Or configure a custom logger:
use Psr\Log\LoggerInterface;
class CustomFixtures extends Fixture
{
public function __construct(private LoggerInterface $logger) {}
public function load(ObjectManager $manager)
{
$this->logger->info('Loading fixtures...');
}
}
Check execution order with:
public function load(ObjectManager $manager)
{
dump('Executing: ' . static::class);
}
Verify references exist:
if (!$this->hasReference('user_1')) {
throw new \RuntimeException('Reference "user_1" not found!');
}
Extend Loader\LoaderInterface for custom logic:
use Doctrine\Common\DataFixtures\Loader\LoaderInterface;
class CustomLoader implements LoaderInterface
{
public function load(ObjectManager $manager)
{
// Custom logic
}
}
Listen to fixture events:
use Doctrine\Common\DataFixtures\Event\FixturesLoadedEvent;
class FixtureSubscriber implements SubscriberInterface
{
public function getSubscribedEvents()
{
return [
FixturesLoadedEvent::class => 'onFixturesLoaded',
];
}
public function onFixturesLoaded(FixturesLoadedEvent $event)
{
// Post-load logic
}
}
Override ExecutorInterface for custom behavior (e.g., parallel loading):
use Doctrine\Common\DataFixtures\Executor\ExecutorInterface;
class ParallelExecutor implements ExecutorInterface
{
public function execute(LoaderInterface $loader, bool $purgeMode)
{
// Parallel logic
}
}
Bind custom fixtures in register():
$this->app->bind(
\Doctrine\Common\DataFixtures\Loader\LoaderInterface::class,
\App\Fixtures\CustomLoader::class
);
Use doctrine/doctrine-migrations-bundle to version-control fixtures:
php artisan doctrine:migrations:execute --fixtures
hasManyThrough):
How can I help you explore Laravel packages today?