ufo-tech/doctrine-behaviors
Add reusable Doctrine entity behaviors to your Laravel app: timestamps, slugs, soft deletes, tree structures, and more. Drop-in traits keep entities consistent and cut boilerplate, so you write less mapping code and ship features faster. Great for teams standardizing entity logic.
Architecture fit — poor, and the framing needs correcting up front. ufo-tech/doctrine-behaviors is not a Laravel package. It is a Symfony bundle wrapping Doctrine ORM event subscribers (Timestampable, Blameable, Sluggable, SoftDeletable, Translatable, Loggable, Tree, Uuidable, Filterable). Laravel's default persistence layer is Eloquent; Doctrine is an opt-in third-party integration via laravel-doctrine/orm. So the package can only be leveraged in a Laravel codebase that has already committed to Doctrine ORM as its primary mapper, and even then it must be wired by hand because the Symfony bundle auto-configuration does not exist in Laravel. For a greenfield Laravel service, this package is the wrong tool: SoftDeletes, timestamps, spatie/laravel-sluggable, spatie/laravel-translatable, and model observers cover the same ground with zero new dependencies. Value only appears where Doctrine is a hard constraint — a migrated Symfony app, a shared domain model between Symfony and Laravel services, or a legacy schema-bound module.
Integration feasibility — technically possible, operationally awkward. The behaviors are implemented as Doctrine EventSubscriber/EventListener classes plus attribute-driven mapping. In Laravel you would register them directly on Doctrine's EventManager ($em->getEventManager()->addEventSubscriber(...)) and skip the bundle entirely, which means you own the mapping of "which entity gets which behavior" (upstream relies on marker interfaces/traits and bundle config). Two concrete blockers to validate in a spike: (1) Blameable almost certainly resolves the current user through Symfony's security.token_storage; Laravel has no Security component token, so you need a custom user resolver bound to Auth::id(), or Blameable silently writes null. (2) Translatable may assume Symfony locale/request context. Both are fixable with an adapter class, but they are not configuration-free.
Technical risk — high, dominated by supply-chain and provenance, not by code quality. The package describes itself as "a fork of a fork," has 8 stars and 0 dependents. That combination means no downstream battle-testing, no CVE triage path, no guarantee of a tagged release when doctrine/orm 3.x or Symfony 8 lands, and a single-maintainer bus factor. Pinning to a commit SHA is mandatory; pinning to a version range is not acceptable. Secondary risks: namespace collision with the upstream knplabs/doctrine-behaviors if anything else pulls it in (Composer will not always catch this cleanly), and behavioral divergence from upstream that is undocumented.
Key questions to put to the maintainer (or answer ourselves by reading the source):
doctrine/orm and PHP version constraints, and is ORM 3.x on the roadmap?symfony/framework-bundle and symfony/security-bundle as hard dependencies? Can the subscribers be used standalone?Stack fit. Viable targets: Laravel 10/11 with PHP 8.2+, laravel-doctrine/orm v2.x, doctrine/orm 2.15–2.19. Assume no ORM 3.x support until proven otherwise — the fork's stated purpose is Symfony 7 compatibility, not ORM modernization. If the application is on Eloquent, stop here and use native equivalents; the cost/benefit does not clear the bar.
Migration path. Treat this as a strangler integration, not an install-and-go:
EventManager, confirm attributes are honored and no Symfony container is required.composer.json, or fork into a private VCS repo we control. Given 0 dependents and 8 stars, a private fork is the defensible default.DoctrineBehaviorsServiceProvider) so the dependency is replaceable in one file if the fork dies.BlameableUserResolver (and any locale resolver) as our own classes bound into the container; never patch vendor code.Compatibility. Verify against our actual matrix before committing: PHP minor version, doctrine/orm constraint, laravel-doctrine/orm constraint, and whether doctrine/dbal 4 is in play (a common breaking point for older listeners). Check that Symfony component transitive dependencies don't collide with packages already present (notably symfony/console, symfony/http-foundation via other Laravel packages).
Sequencing. Do this after Doctrine is already the established mapper and the team has shipped at least one Doctrine-backed feature. Introducing Doctrine and a fork-of-a-fork behavior library in the same release couples two risky changes and makes rollback ambiguous.
Maintenance. The realistic assumption is that we become the de facto maintainer. Budget: a quarterly review of upstream/Doctrine releases, plus ad-hoc patching when doctrine/orm or PHP bumps break a listener. If the team cannot absorb that, do not adopt. A vendored copy with a PATCHES.md is cheaper to reason about than a floating Packagist dependency.
Support. No vendor SLA, no security advisory subscription, no issue-triage guarantee. Escalation path is "read the source." That is acceptable for internal tooling with a named owner and unacceptable for anything on a compliance or revenue path without that owner.
Scaling. The behaviors are event-subscriber based and execute inside Doctrine's Unit of Work, so cost scales with flush size, not request count — same profile as any Doctrine listener. Watch two hotspots: Sluggable doing per-flush existence checks (unique-index churn under bulk insert), and Translatable generating additional queries per locale hydration. Neither is a blocker at typical scale; both need a load test before a bulk-import feature ships. SoftDeletable interacts with query filters and lazy loading — verify that reporting/analytics queries bypass it deliberately rather than accidentally.
Failure modes, ranked by likelihood:
Auth. Detectable only by data audit; add a non-null constraint in staging.doctrine/orm upgrade breaks a listener at runtime, not at install. Mitigate with a lockfile, a smoke test in CI, and no auto-merge on Composer updates touching doctrine/*.knplabs/doctrine-behaviors — duplicate class definitions or confusingly similar FQCNs during code review.Ramp-up. Two distinct costs. Doctrine fluency (Unit of Work, proxies, DQL, migrations) is the larger one — 1–2 weeks for a Laravel-only engineer to be productive, and this package is not the place to learn it. The package-specific cost is small: roughly half a day to read the listeners and understand the registration model, once Doctrine is already in place. Overall estimate: 1–2 day spike, 1–3 weeks to harden and land the first behaviors in production, then ~2–5% of one engineer per quarter in upkeep.
Recommendation. Low score (0.04) is directionally correct. Adopt only under three conditions, all of which must hold: the codebase already runs Doctrine ORM as its primary mapper; we can pin to a commit SHA or private fork; and a named engineer owns quarterly maintenance. Absent any one of those, implement the four or five behaviors we actually need as in-house Doctrine subscribers (a few hundred lines) or use Eloquent equivalents — both are cheaper than inheriting a two-hop fork with no downstream users.
How can I help you explore Laravel packages today?