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

Seed Bundle Laravel Package

evotodi/seed-bundle

Symfony/Doctrine bundle for loading and unloading seed data before your initial production push. Define seed commands with ordering to populate tables like states or initial admin users, unlike DoctrineFixturesBundle, which targets development.

View on GitHub
Deep Wiki
Context7

Getting Started

The honest first step is a stack check. This is a Symfony 6+/Doctrine bundle, not a Laravel package — it has no artisan integration, no service provider, no Laravel container wiring. If you are a Laravel developer, php artisan db:seed, DatabaseSeeder, and model factories already cover the entire job this bundle does, and pulling this in would drag Symfony Console + DI assumptions into your app for zero gain. Read the rest of this section as "what to do if you're standing in a Symfony codebase" or as "what to steal conceptually for your Laravel seeder."

Minimal Symfony setup:

  1. composer require evotodi/seed-bundle (requires PHP 8+, Symfony 6+; 7.x targets Symfony 7/8).
  2. Create src/DataSeeds/ and register it as a service namespace in config/services.yaml:
    services:
        Evotodi\SeedBundle\DataSeeds\:
            resource: '../DataSeeds/*'
    
  3. Write your first seed — a class extending Evotodi\SeedBundle\Command\Seed with a static seedName(), an optional getOrder(), and load() / unload() return-int methods.
  4. bin/console seed:load (all seeds, ordered) or bin/console seed:user load (one seed).

Where to look first: the README's UserSeed example is the entire mental model — seedName() defines the command name (seed:user), load() persists via $this->manager, unload() clears the table. There is no config file (dropped in v6).

First use case to ship: the initial admin user + role/status lookup tables. That's the canonical "must exist before first production traffic" dataset, and it's the case this bundle was explicitly built for.

If you're porting the idea to Laravel (which is the sane move), the mapping is direct:

  • Seed class → database/seeders/UserSeeder.php extending Illuminate\Database\Seeder
  • seedName() ordering → $this->call([...]) order in DatabaseSeeder
  • seed:load user → php artisan db:seed --class=UserSeeder
  • load() / unload() → run() + a truncate() in a down/rollback method
  • --skip / glob filtering → not built-in; add a flag in your own command

Implementation Patterns

Reference-data seeds (the primary pattern). One seed class per logical dataset — country, state, currency, role — each returning a stable getOrder(). Keep data in an array or a small fixture file in the seed class; the seed should be readable in a PR diff. This is the pattern that actually pays off day-to-day: onboarding an environment becomes bin/console seed:load, not "restore this dump."

Initial-admin seed — make it idempotent even though the bundle doesn't. load() is not idempotent by design; it assumes a clean database. Guard with a lookup before persist:

if (!$this->manager->getRepository(User::class)->findOneBy(['email' => $admin])) {
    // persist
}
$this->manager->flush();
$this->manager->clear();

This is what lets the same command run again in staging without exploding on a unique constraint.

Environment-partitioned seeds via glob. The bundle's genuinely nice idea is naming seeds like prod:users:us, dev:prices and filtering with webmozarts/glob (prod/users/*, prod/**/*, dev:prices prod:users:*). Colons and slashes are interchangeable. Use this to carve a production corpus apart from a demo/dev corpus without a second tool — that's the one feature Laravel's db:seed doesn't natively give you.

Ordering as a dependency graph (a weak one). getOrder() ascending is your cross-seed dependency mechanism: roles before users, countries before states. Because ties are semi-random, encode real dependencies as strictly increasing integers with gaps (0, 10, 20) — that leaves room to slot a seed in later without renumbering and without creating accidental ties.

Operator-invoked, not migration-attached. The bundle's design intent is that seeding is a deliberate operator step in the deploy runbook, not a side effect of doctrine:migrations:migrate. Wire it as a release step: seed:load --break --debug in the deploy script (the --debug output is your audit trail of what ran in what order). Note there's no transaction wrapping and no idempotency guarantee, so --break matters.

unload() is a rollback button — treat it as armed. It's typically a raw DELETE FROM/TRUNCATE. That's fine on a fresh bootstrap database and dangerous anywhere else. If you expose seed:unload in a runbook at all, gate it behind an environment check in your wrapper script; don't let it near a database with customer data.

Laravel-side integration tip if you're bridging both worlds: don't install this bundle. Reuse the conventions — one seeder per reference dataset, an explicit ordering array in DatabaseSeeder, and an environment filter using --class or a custom --group option on a small Artisan command. You get 95% of the value in code you already own.

Gotchas and Tips

Equal getOrder() values load semi-randomly — this is the #1 footgun. The README calls it out twice. It becomes a real bug when combined with --from: seed:load --from seed-c may or may not run seed-b/seed-d if they share an order. Always run seed:load --debug in staging before trusting a production run, and prefer unique, spaced order values over ties.

Seeds not appearing under seed: in the command list = clear the cache. Console command registration is cached; bin/console cache:clear is the standard first move.

Naming is load-bearing. seedName() must follow Symfony's colon-separated console convention, and the class must extend Seed — the bundle discovers commands, it doesn't scan for an interface.

Return codes are enforced. load()/unload() must return 0 or Command::SUCCESS; anything else is a failed seed and (with --break) halts the run. A missing return gives you null, which is not success — silent failure.

Call disableDoctrineLogging() at the top of load(). The README warns Doctrine logging eats a lot of memory; large seed inserts will balloon RSS otherwise. Also flush() then clear() per batch to keep the identity map from accumulating entities.

The admin-user example uses passwordEncoder->encodePassword(), which is deprecated in modern Symfony — use UserPasswordHasherInterface::hashPassword(). Copy-pasting the README verbatim onto Symfony 7/8 will surface this.

Version floor is real. v6.0 was a rewrite (config file dropped, seedName() static, no *Seed suffix requirement, PHP 8/Symfony 6 minimum). Any tutorial or Stack Overflow answer predating that is wrong. Releases land roughly annually — treat 7.x/8.x support as "someone checked the deprecations," not "actively developed."

Supply-chain sanity check before adopting: ~14 stars, zero dependents, effectively single-maintainer, last substantive release early 2024. It's MIT and small enough to vendor and read in an afternoon — that's the mitigation. If it must never break, fork it into your monorepo and pin; the surface area (one base command class + two global commands) is small enough that owning it is a weekend, not a quarter.

Debugging a failed seed: run the per-seed command directly (bin/console seed:user load) to isolate it from ordering/glob concerns, then seed:load --debug user to confirm it's in the registry and where it sorts. If ordering looks wrong, that's almost always a tie, not a glob problem.

Extension points worth knowing: you can skip the src/DataSeeds/ service convention entirely and register seeds like any other command service; the glob filter accepts full webmozarts/glob syntax, so ** recursive patterns are available for grouping by environment or feature area.

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