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

Laravel Doctrine Factory Laravel Package

stemble/laravel-doctrine-factory

Use Laravel's modern Eloquent factories with Doctrine entities. Drop-in replacement for the official frozen pre-8.x factory system, adding class-based factories, first-class states, relationship helpers, sequences, recycle, and afterMaking/afterCreating callbacks.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Test-fixture strategy on Doctrine-backed Laravel services. If your domain layer is Doctrine ORM (rather than Eloquent) but your application shell is Laravel, this package directly determines whether your team writes fixtures in Laravel's modern, class-based factory idiom or stays on the legacy closure-based $factory->define() system shipped with laravel-doctrine/orm. That is a developer-experience and hiring decision as much as a technical one: the modern API is what most Laravel engineers already know.
  • Build vs. buy for internal test tooling. The alternative is a thin in-house factory layer over Doctrine's EntityManager. This package is MIT, ~one file of integration surface, and extends Illuminate\...\Factory rather than replacing it — which meaningfully lowers the cost of trying it and the cost of removing it.
  • Test-suite velocity and readability as a roadmap input. Features like for(), has(), magic hasPosts()/forUser(), sequence(), recycle(), and named state methods (->admin()) are what turn 40-line fixture setup blocks into one-liners. If fixture boilerplate is a recurring complaint in retros, this is a concrete, low-risk lever.
  • Onboarding and documentation leverage. Because the Laravel factory docs work as the primary reference, new hires need no Doctrine-factory-specific training. The README's "Differences from Eloquent" section — chiefly that make() calls persist() and bidirectional inverse sides aren't synced in memory — is the entire delta your team must learn.
  • Scoping which testing gaps remain after adoption. The compatibility grid is honest about what is not covered: polymorphic relationships and soft deletes are N/A in Doctrine, hasAttached() (many-to-many with pivot data) requires working through a pivot entity. If your test plan assumed Eloquent parity there, that scope needs re-planning now rather than mid-sprint.

When to Consider This Package

Adopt when all of the following hold:

  • Your entities are Doctrine ORM entities — not Eloquent models — and you are on Laravel.
  • You are currently on laravel-doctrine/orm's official factory system, or writing fixtures by hand, and feel that pain.
  • Your entities have non-trivial constructors. Constructor-aware instantiation (definition keys matched to constructor params, remaining attributes set by reflection) is a genuine differentiator; hand-rolled factory layers usually get this wrong or skip it.
  • Your entities are related in graphs you want to build in one call — including the ability to make() a whole graph and flush() once, with no cascade: ['persist'] annotations needed.

Look elsewhere or hold off when:

  • You're on Eloquent. This package solves a problem you don't have.
  • Vendor-risk tolerance is low. This is the critical caveat: 2 GitHub stars, 0 dependents. No third party has demonstrated it working in production. "Maturity: readme, changelog, releases" means it is documented, not that it is proven. Verify the test suite yourself and read the source before it becomes load-bearing in CI.
  • Your entities' setters carry real logic. Reflection bypasses setters entirely. If validation, domain events, or collection syncing live in setters, the factory will silently produce entities that don't match production construction paths — and your tests will be testing a fiction. Workaround exists (route values through the constructor or call setters in afterMaking()), but it's a correctness hazard, not a convenience gap.
  • Your team is Doctrine-inexperienced. The make()-persists-to-the-identity-map deviation is the kind of thing that produces "why did my test insert rows?" bugs. Mitigable with a lint rule or convention, but it needs a decision, not a default.
  • You need polymorphic fixtures or soft-delete semantics. Not supported; no Doctrine equivalent.
  • A single-maintainer, pre-1.0-ish dependency is unacceptable for your test infrastructure — noting that test infrastructure failing loudly is usually cheaper than production infrastructure failing loudly, which tempers this risk considerably.

How to Pitch It (Stakeholders)

For executives — one paragraph: Our tests for the Doctrine-backed parts of the application currently use a factory system frozen at a Laravel API that was deprecated several major versions ago. This package is a small, MIT-licensed adapter that lets those tests use Laravel's current factory API — the same one our engineers already use everywhere else. It costs essentially nothing to evaluate, is removable without touching application code, and the payoff is faster, more readable test setup and no Doctrine-specific training burden for new hires. The honest risk is that it is a very young package with no external adopters, so I recommend a time-boxed evaluation on one bounded area of the test suite before wider rollout.

For engineering — the substance:

  • Drop-in: add the unmodified HasFactory trait to the entity, extend DoctrineFactory, mirror your entity namespace under database/factories/. No Doctrine-specific trait to import, no changes to Illuminate\...\Factory.
  • You keep states as real methods, plus for()/has()/magic relationship helpers, sequences, recycle(), and afterMaking()/afterCreating().
  • Three behaviors to internalize before you write a line of fixture code:
    1. make() calls EntityManager::persist() — it registers in the identity map. Any later flush() inserts it. This is deliberate and it's what lets you build a graph then flush once, without cascade annotations.
    2. Non-constructor attributes are written by reflection — setters do not fire. If a setter has side effects, pass through the constructor or call it in afterMaking().
    3. Bidirectional inverse sides are not synced in memory. Fix once in configure() via afterMaking(); otherwise $user->getPosts() is empty until flush-and-refresh. This is the biggest trap for anyone arriving from Eloquent.
  • for()/has() take the entity property name, not a column or class name. Magic methods infer it when the property name matches the related class basename.
  • Known non-coverage: polymorphic relations, soft deletes (trashed()), and hasAttached() — M2M with pivot data goes through the pivot entity.

Recommendation: treat this as a spike, not a commitment. Evaluate on one bounded test area, judge it on three things — does the test suite catch the make()/flush() interaction, do our entity setters carry logic that reflection would skip, and does the maintainer respond to issues — and only then decide. The upside is real developer velocity; the downside is bounded because the package sits entirely in test tooling and costs one composer remove to undo.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core