Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Dump Fixtures Bundle Laravel Package

jupeter/doctrine-dump-fixtures-bundle

Symfony bundle for exporting Doctrine database contents as reusable fixture classes. Generate fixtures from existing data via a console command, simplifying test data setup and development seeding.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it is a Symfony 2 bundle, not a Laravel package. There is no Illuminate\Support\ServiceProvider, no extra.laravel auto-discovery block, no config/*.php merge path, and no Artisan command base class. composer require into a Laravel app is not a supported path — you either have a legacy Symfony 2.x host app, or you treat this repository as a reference implementation of a command you write yourself. Day-to-day leverage for a Laravel developer is almost entirely in the second mode.

What the package actually does, stripped of Symfony plumbing: reads Doctrine metadata for the entity/table list, selects rows from the connection, and serializes them into fixture files that doctrine/data-fixtures can later load. That is table introspection plus serialization — a few hundred lines of real logic.

Where to look first (in the repo):

  • Command/ — the console command class. This is your spec: it defines the input signature (entity/table selection, output directory, format), the flow, and the exit codes.
  • DependencyInjection/Configuration.php — bundle config keys: output path, connection name, possibly excluded tables.
  • Resources/config/services.xml — shows which parts are services and therefore decoratable/replaceable.
  • The generator/serializer service itself — the part worth porting.

Minimal setup, if and only if you have a Symfony 2/3 host app:

  1. composer require --dev jupeter/doctrine-dump-fixtures-bundle (expect to pin period-correct Doctrine DBAL/ORM; on a modern PHP this may not resolve at all).
  2. Register in app/AppKernel.php, gated to non-prod:
    if (in_array($this->getEnvironment(), ['dev', 'test'])) {
        $bundles[] = new Jupeter\DoctrineDumpFixturesBundle\DoctrineDumpFixturesBundle();
    }
    
  3. Make sure doctrine/doctrine-fixtures-bundle is installed — this bundle only produces fixtures, it does not load them.
  4. app/console list and inspect the doctrine namespace for the dump command and its options.

First use case — a reference table, not users. Pick something small, stable, and dependency-free: countries, languages, currencies, permissions. Dump that one table, load the resulting fixture with doctrine:fixtures:load in a scratch database, and confirm the round-trip. This isolates serialization problems from foreign-key ordering problems, which are the two distinct failure modes you will hit. If you are doing the Laravel port, the emitted fixture file from this exercise is your required output format — reproduce it byte-for-byte before writing anything else.

Implementation Patterns

One fixture per table, never one giant dump. A monolithic dump of the whole schema is un-reviewable in a diff, un-regenerable partially, and fails atomically on a single bad column. Per-table files let you regenerate only what drifted and lets you exclude users/audit_log from regeneration entirely.

Order tables by foreign key, not by name. The single most important behaviour to replicate: build a dependency graph from the metadata and topologically sort before emitting. A dump that is correct but loaded in the wrong order fails on insert. The pragmatic escape hatch in Laravel is Schema::disableForeignKeyConstraints() around the load — use it, but keep the ordering correct anyway so the fixtures remain usable by other tooling.

The Laravel port, concretely. One Artisan command, roughly:

php artisan db:dump-fixtures
    --connection=mysql
    --tables=countries,currencies,regions
    --exclude=users,sessions,password_resets
    --format=php        # or yaml/json
    --output=database/seeders/fixtures
    --chunk=1000

Implementation shape: Schema::getTableListing() / DB::select('SHOW TABLES') for the table list, Schema::getColumns($table) for types, DB::table($table)->orderBy($pk)->cursor() for chunked reads, then a serializer that emits return [ ... ]; PHP arrays (diff-friendly, preserves types, no YAML quoting surprises) or DB::table()->insert() calls in a seeder. Keep the serializer behind a small interface so --format is a strategy swap rather than an if/else ladder.

Chunk the reads. ->cursor() or chunkById() against a real table will otherwise hit memory_limit on anything with more than a few hundred thousand rows. Chunking also gives you a natural place to apply the anonymization transform per row rather than loading everything and mapping in memory.

Layer anonymization as a transform, not a post-process. Config a map of column => faker method | closure | null, applied inside the row loop before serialization. Anything not explicitly allowed should be a hard error, not a silent passthrough — an allowlist beats a denylist when the cost of a miss is real PII in Git history.

Wire into the existing seeder flow. Generated fixtures should be consumable by DatabaseSeeder or iseed-produced seeder classes, not a parallel universe. If you already use orangehill/iseed, check whether it covers the use case before building — it reverse-seeds an existing DB into seeders and is Eloquent-native and maintained. spatie/laravel-db-snapshots covers the "refresh my local env from a snapshot" case more directly. Reach for a custom command when you specifically need Doctrine-style fixtures, FK-ordered cross-table dumps, or column-level scrubbing that neither provides.

Regenerate, don't hand-edit. Fixtures are generated artifacts. Add a scheduled or on-demand regeneration and a cheap CI check that the committed fixtures still match the current schema column set — otherwise they go stale silently after migrations and the failure surfaces as NOT NULL constraint violation in an unrelated test.

Gate on environment. Refuse to run when app()->environment('production') or when the connection is a production DSN. This is a one-line guard that prevents the worst outcome in the whole tool.

Gotchas and Tips

  • It will not install on a modern Laravel stack, and that is the expected outcome. Symfony 2 (2.8 LTS) is end-of-life, targets PHP versions well below 8.x, and brings a second framework's container into your process to solve a dev-tooling problem. Expect Composer to either refuse resolution or resolve a stale subtree that trips SCA scanning.
  • No bus factor. 8 stars, 0 dependents, effectively a single maintainer. Any fork becomes your owned artifact permanently — budget a few hours per Laravel major upgrade, forever.
  • Binary and wide columns are the classic blow-up. Blobs, LONGTEXT, JSON columns, and tables with hundreds of columns produce unusable fixture files and spike memory. Exclude them by default and require an explicit opt-in per column.
  • Type coercion is where fidelity dies. Watch NULL vs empty string, booleans stored as tinyint, datetime formats and timezones, JSON columns that need json_encode at emit and json_decode at load, and enums. Doctrine's DBAL type system handles some of this in the original; your port has to do it explicitly.
  • Foreign key cycles and self-references. Topological sort fails on circular FKs (users.created_by_id -> users.id). Detect the cycle, defer those rows to a second pass after the first insert, or fall back to disabling FK checks.
  • PII is the highest-severity risk here, above any technical concern. This tool copies whatever is in the tables into files that people commit. Anonymization has to be a hard gate with a default-deny column policy, not a code-review note. Treat the scrub config as reviewed code.
  • Debugging the port: when a generated fixture loads wrong, compare three things side by side — the source row via DB::table(), the emitted file, and the row after fixture load. The divergence is almost always a type cast or a NULL/empty-string conversion, and this comparison finds it in minutes.
  • Extension points in the Symfony original are the generator and serializer services in services.xml — you can decorate them to change output format or add scrubbing without touching the command. Preserve that seam in your port: command does argument parsing and orchestration, serializer is injectable, transform is a separate class.
  • Deterministic output matters more than it seems. Order by primary key, strip volatile columns (timestamps, auto-increment IDs you intend to re-resolve), and sort map keys consistently — otherwise every regeneration produces a diff and the fixtures become noise nobody reviews.
  • Do not sequence this behind anything. Confirm Eloquent vs Doctrine in the target stack, then either spike the port against one representative table with an FK in under a day, or drop it. It is a small internal tooling ticket, not a procurement decision.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource