pecserke/yaml-fixtures-bundle
A Symfony bundle for loading Doctrine fixtures from YAML files, making test and development data easier to read, write, and maintain than traditional PHP fixtures.
First, the honest framing: this is a Symfony bundle, not a Laravel package. It hooks into the Symfony kernel, the DI container, and Doctrine's doctrine/data-fixtures command. You cannot composer require it into a Laravel app and get anything working on its own — there is no service provider, no artisan command, and it expects %kernel.*% parameters and a bundle registration. As a Laravel developer you'd only touch this if you're maintaining a legacy Symfony service (or a Symfony app inside a multi-framework shop), or if you're using laravel-doctrine/orm and want to borrow the YAML→entity mapping idea (in which case, copy the loader, don't install the bundle).
Assuming you're in a Symfony project where it does apply, the minimal path:
composer require --dev pecserke/yaml-fixtures-bundle doctrine/data-fixtures
AppKernel::registerBundles() on Symfony 3, config/bundles.php on Symfony 4.config/config.yml (see the config quirk in the gotchas — the docs use a parameter that was removed in Symfony 4):
yaml_fixtures:
directory: "%kernel.project_dir%/fixtures"
@name references for associations:
App\Entity\User:
user_alice:
email: [email protected]
user_bob:
email: [email protected]
App\Entity\Post:
post_one:
title: 'First post'
author: '@user_alice'
Command/ and Resources/config/services.yml for the version you installed — the README and the code have drifted across releases):
bin/console doctrine:fixtures:load --no-interaction
Where to look first: the README for the YAML dialect, then Resources/config/services.yml to see how the loader is wired and what the real config keys are, then the loader class itself. For a 3-star, 2019-era bundle, the source is the documentation.
First use case: seed a small graph — a couple of users and their posts — on a throwaway dev database. That's the sweet spot: static, human-readable reference data. It is not a factory library, and it will not generate randomized or relational data for you.
Organize by aggregate, not by table. One YAML file per bounded context (fixtures/blog.yml, fixtures/accounts.yml) beats one file per entity, because references only resolve across files if the parents load first. Keeping a parent and its children in the same file removes the ordering problem entirely.
Name your fixtures meaningfully and treat names as an API. @user_alice is a handle you'll reference from other files and from tests. Renaming one silently breaks every @ reference to it, so grep before you rename.
Load order is declaration order. The loader resolves @refs as it walks the file, so a child that references a parent must come after it — in the file, and across files if you split them. Flatten association graphs rather than trying to be clever with ordering.
Use it for functional-test fixtures, not just dev seeds. Boot the kernel in setUp(), run the loader programmatically against a test database, and you get fast, diffable fixtures for integration tests. This is where YAML earns its keep: the fixture data is reviewable in a PR in a way that a 200-line PHP fixture class is not.
Set the owning side of associations in YAML. Doctrine only persists the owning side of a relation. If you write the inverse side (posts: ['@post_one'] on User when Post.author owns the FK), nothing gets written and you'll spend an hour debugging "why is the join table empty."
Pair with PHP fixtures for anything dynamic. The bundle has no Faker integration, no expressions, no service calls. The pragmatic split is: YAML for static reference data (roles, countries, categories, a handful of demo users), PHP FixtureInterface classes for volume, randomization, and computed values. Load both in the same run — they're just two fixture groups.
In a Laravel codebase, mirror the pattern rather than the package. A custom artisan command that reads YAML via symfony/yaml and calls Model::create() gets you 90% of the ergonomics with none of the Symfony coupling. If you're on laravel-doctrine/orm, use doctrine/data-fixtures directly and skip the bundle — the bundle's value-add is DI wiring you don't have.
It is effectively unmaintained. Last release October 2019, three stars, zero dependents. It targets the PHP 7.x / Symfony 3.4–4.x era. On PHP 8 you should expect deprecation noise at minimum and fatals if it extends ContainerAwareCommand or similar removed APIs. Before committing, run it against your actual PHP/Symfony matrix — or fork and patch, and budget for that as a real cost.
The documented config parameter no longer exists. %kernel.root_dir% was removed in Symfony 4; if the README tells you to use it, substitute %kernel.project_dir%. This is the single most common install failure and it produces a confusing "parameter not found" at container compile time.
YAML will silently coerce your types. Unquoted yes/no/on/off become booleans, ISO-looking dates become DateTime, null and ~ become null, and long numeric strings become floats. A phone number or a is_active: no flag is the classic footgun. Quote anything that isn't unambiguously a string, and especially quote references: '@user_alice'.
Keys are property names, not column names. A created_at column mapped to a createdAt property needs createdAt in the YAML. Cross-check with bin/console doctrine:mapping:info before you start guessing why a field is ignored.
References don't survive across runs. --append adds rows but does not re-resolve or dedupe references, and reference handles are scoped to a single load. If you need idempotent re-seeding, purge and reload rather than appending.
Debug with verbosity and the parser, not with the database. Run doctrine:fixtures:load -vvv, and when a file misbehaves, parse it standalone with Yaml::parseFile() and var_dump the array — nine times out of ten the problem is a type coercion or an indentation issue, not the loader.
Extension points are thin. There's no documented normalizer/type system to hang custom conversion on. Your realistic options are (a) preprocess the YAML before loading, (b) subclass the loader and register your version as a service, or (c) stop fighting it and write a PHP fixture for the awkward case. Prefer (c); the bundle is small enough that extending it costs more than replacing the one file that's causing trouble.
Don't reach for it on greenfield. If you're starting fresh, nelmio/alice + hautelook/alice-bundle (or doctrine/data-fixtures plus PHP fixtures) is maintained, supports Faker and expressions, and has an actual user base. YamlFixturesBundle's only remaining argument is "it's already in this legacy app and it works."
How can I help you explore Laravel packages today?