fsi/doctrine-extensions
Doctrine extensions for Laravel that add common ORM behaviors such as soft deletes, timestamps, sluggable, tree, and sortable mappings, helping you reuse familiar persistence patterns with Doctrine entities.
What it is. fsi/doctrine-extensions is a small library of Doctrine ORM behavioral extensions — entity listeners/subscribers plus traits and interfaces that inject cross-cutting behavior (timestamping, blame/audit, soft-delete, and similar concerns) into Doctrine entities. Functionally it sits in the same problem space as gedmo/doctrine-extensions, which is the de facto standard, has a large contributor base, and is actively released.
Architecture fit — poor. Two layers of impedance:
laravel-doctrine bridge (itself thinly maintained), a second persistence model, and a team that understands the Unit of Work, identity map, and DQL. Doctrine is a viable choice for rich-domain codebases, but it must be an existing architectural decision — not something this package justifies.gedmo. Choosing a 3-star, 0-dependent package over the category leader is very hard to defend in a design review.The package is also invasive by nature: adopting it means editing entity mappings and implementing its interfaces, which couples domain classes to a third-party library's contracts. That is structural, not incidental, coupling.
Integration feasibility — mechanically easy, strategically expensive. Composer install is trivial and the MIT license is permissive. The real cost is the migration-shaped work: mapping changes, schema/migration diffs, and the listener registration wiring (doctrine config, EventManager, service provider). The library surface is small enough that a spike is cheap; the adoption cost is in entity churn and test coverage, not in the install.
Technical risk — high. Concrete indicators:
doctrine/orm ^2.x. Verify with composer why-not against our current constraint set.error_reporting(E_ALL) in CI.Key questions to answer before any decision
gedmo already cover each one? (Almost certainly yes for timestamp/blame/soft-delete/loggable.)doctrine/orm and doctrine/dbal, and does it resolve against our lockfile?onFlush UoW traversal or lighter preUpdate/postPersist hooks?Recommendation: do not adopt as a dependency. If a behavior is required and unserved by gedmo, vendor a fork.
Stack fit. Only pursue if the platform already runs Doctrine on Laravel via laravel-doctrine, and even then prefer gedmo unless this package covers a behavior gedmo does not.
Decision gate. Run a bounded spike (≤ 2 dev-days) against one non-critical module. Acceptance criteria: installs on our PHP/Doctrine versions, no deprecations in CI, behaviors verified by an integration test that asserts the emitted SQL, and a written diff of the mapping changes required.
Compatibility path. Pin doctrine/orm to the major the package supports (likely ^2.x) in an isolated branch. Do not attempt to force ORM 3 compatibility — that would mean owning a port, which converts a dependency into an internal product. Validate with composer why-not doctrine/orm, then run doctrine:schema:validate and a full migrations:diff to catch mapping drift before anything reaches a shared environment.
Migration path. If the codebase already uses gedmo for any of these behaviors, do not migrate — the churn buys nothing and risks double-applied listeners (two subscribers writing the same timestamp column is a real class of bug). If we are greenfield, gedmo is the default; this package is the fallback only for a specific gap.
Sequencing (if we proceed)
gedmo and against "own it in ~150 lines."phpunit, PHPStan at a high level, and a CI matrix covering our PHP versions. This is non-negotiable; we are adopting a library with no upstream test signal.Alternative with better ROI: write the one or two listeners we actually need in-house (~1 dev-week including tests). For a package this small, owning the code is cheaper than owning the supply chain.
Maintenance. Adopting this means we become the de facto maintainers. Budget roughly 2–5 engineer-days per quarter for dependency bumps, Doctrine upgrade porting, and issue triage — and a larger unbudgeted hit the next time Doctrine ships a major, since upstream will not have done the work. This should be recorded as an owned component in the service catalog, not as a routine third-party dependency.
Support. No vendor, no SLA, no security-response process. A CVE in a transitive dependency will not be patched here; we would be patching it ourselves under time pressure. Contrast with gedmo, where the community absorbs that work.
Scaling. Behavioral listeners execute inside the flush cycle. The dominant risk is onFlush-style listeners that traverse the entire Unit of Work — cost scales with batch size, so bulk imports and queue consumers that flush large collections will degrade non-linearly. Instrument before rollout: count queries per flush, measure flush wall-time at 1×, 10×, and 100× batch sizes, and confirm listeners do not issue additional queries per entity (classic N+1 hidden inside a lifecycle hook).
Failure modes to watch
EventManager (a real hazard with multiple entity managers) — behavior just stops, no error, data drifts.Ramp-up. Doctrine's event system, Unit of Work, and DQL are not skills a typical Laravel team carries — Eloquent hides all of it. Expect 2–3 weeks before an engineer can debug a misbehaving listener confidently, on top of the package's own (undocumented-in-repo) conventions. That onboarding cost is paid by every new hire, permanently, for a library that saves perhaps a week of initial implementation.
Net position. Score 1.27 with zero dependents and a 2021 release is the correct read: this is not a component to build on. The opportunity cost is low only if we walk away. If a behavior is genuinely needed, fork it under MIT with tests, wrap it behind our own interfaces, and cap the blast radius — or spend the same week writing the listener ourselves and skip the supply chain entirely.
How can I help you explore Laravel packages today?