xcidar/doctrine-fixtures-generator-bundle
A Symfony bundle that generates Doctrine fixtures from your existing database data. Quickly create realistic, schema-consistent fixture classes for testing and development, reducing manual setup and keeping test data aligned with your current schema. Ideal for bootstrapping test suites and local env...
1. Install (dev only)
composer require --dev xcidar/doctrine-fixtures-generator-bundle
composer require --dev doctrine/doctrine-fixtures-bundle
The generator writes fixtures that extend Doctrine\Common\DataFixtures\FixtureInterface / AbstractFixture, so the fixtures bundle is a hard runtime dependency of the output, not just of the generator.
2. Register the bundle in dev/test only
Old bundles (last release 2019) still use the *Bundle class convention. Look at the actual class inside vendor/xcidar/doctrine-fixtures-generator-bundle/ before editing config/bundles.php — it may be Webonaute\DoctrineFixturesGeneratorBundle\WebonauteDoctrineFixturesGeneratorBundle or a legacy WebonauteDoctrineFixturesGeneratorBundle class. Register it only for ['dev', 'test'] so it never loads in prod.
3. Where to look first
bin/console list — confirm the command is registered (typically webonaute:fixtures:generate or similar; the exact name varies by fork). If it does not appear, the bundle is not loaded in the current env.bin/console <command> --help — this is the authoritative reference for the entity argument format (usually an FQCN like App\Entity\Product) and the IDs syntax.DependencyInjection/Configuration.php / services.yml in vendor/ — this tells you the configurable output directory and namespace, which you must align with your PSR-4 autoloading.4. Minimal config
# config/packages/dev/doctrine_fixtures_generator.yaml
# (key name and node names vary — copy them from the bundle's Configuration.php)
doctrine_fixtures_generator:
destination: '%kernel.project_dir%/src/DataFixtures/Generated'
namespace: 'App\DataFixtures\Generated'
Create the directory and make sure the namespace matches the path, or the generated classes will not autoload.
5. First use case
The canonical workflow: point it at a staging database, pick a small set of primary keys for one entity, and turn real rows into a committable fixture.
bin/console doctrine:fixtures:generate 'App\Entity\Product' 12,45,301
Inspect the generated file, fix the obvious problems (see Gotchas), then verify:
bin/console doctrine:fixtures:load --group=generated -e test
That "generate → read → hand-tune → load" loop is the intended day-to-day usage. Treat the output as a scaffold, not a finished fixture.
Generate per aggregate root, wire relations manually. The generator faithfully reproduces scalar columns but is unreliable for associations. The pattern that scales is: generate the leaf/reference entities first (categories, countries, users), load them, then hand-write the root fixture using $this->addReference('product-12', $product) and $this->getReference(...) for associations. Generated files become the "data half"; you own the "relations half."
Reference-based assembly across generated fixtures. Add $this->addReference('entity-'.$entity->getId(), $entity); immediately after each generated persist(). Then any other fixture can getReference() by the original database ID, which keeps the generated code traceable back to the source row — invaluable when a fixture breaks six months later.
Snapshot-to-fixture pipeline. Scrubbed staging dump → import into a disposable test DB → run the generator for the top 3–5 entities with a curated ID list → commit. Script the ID list in a small shell/Makefile target so regeneration is reproducible instead of ad-hoc.
fixtures:
bin/console doctrine:fixtures:generate 'App\Entity\Category' 1,2,3 --env=dev
bin/console doctrine:fixtures:generate 'App\Entity\Product' $(PRODUCT_IDS) --env=dev
Parametrize rather than duplicate. If the generator emits 50 near-identical blocks for 50 IDs, refactor once into a foreach over an array of field maps with a private createProduct(array $data) helper. You keep the values (the expensive part) and lose the copy-paste noise.
Bridge to Alice / nelmio/alice. If your team prefers YAML fixtures, use the generator purely as a source of realistic field values: run it against staging, copy the literal strings into Alice YAML, delete the generated PHP. This is often the highest-value use of the tool for teams already invested in Alice.
Load ordering and groups. Give generated fixtures a getGroups() returning ['generated'] so CI can run --group=generated in isolation and skip them in a full fixture load where hand-written seed data must win.
Configuration tree changes) and PHP 8.1+ if the code uses deprecated patterns. Before investing, try composer why-not, and check whether the bundle compiles with bin/console cache:warmup -e dev. If it won't boot, a fork or an inline copy of the generator class is usually cheaper than fighting it.NOT NULL foreign keys. Loading in the wrong order produces integrity-constraint errors that look like generator bugs but are fixture-ordering problems — use DependentFixtureInterface or explicit groups.DateTime, DateTimeImmutable, JSON/text arrays, decimals and binary/blob columns are the usual casualties: expect new \DateTime('...') to be missing, JSON to arrive as a plain string, and blobs to be garbled. Grep generated files for set.*(array|json|blob) setters and fix them by hand.setId() (some forks do), you can collide with auto-increment sequences on --append loads. Prefer letting the ORM assign IDs and rely on addReference for linkage.prePersist listeners (Slugifier, Timestampable, password encoders) will mutate your carefully captured values on load. If a generated fixture must preserve production-like timestamps or hashes, be aware they can be overwritten.EntityManager the command uses.Generated/ subdirectory, or commit before regenerating.-vvv and tail var/log/dev.log. "Command not found" is almost always env/bundle registration, not a broken install.How can I help you explore Laravel packages today?