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 Discriminator Bundle Laravel Package

levelab/doctrine-discriminator-bundle

A Symfony bundle that simplifies Doctrine discriminator mapping for entity inheritance, reducing boilerplate when configuring discriminator maps. Useful for single-table inheritance setups and cleaner Doctrine configuration in Symfony applications.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Verdict: reject as a dependency, adopt as a design reference. The artifact is a Symfony bundle, not a Laravel package; it intercepts Doctrine ORM metadata to decentralize the discriminatorMap, and it has had no release since 2016-03-03 with 12 stars and zero dependents. The valuable asset is the ~200-line mechanism, not the distributable.

Architecture fit. The problem it solves is real and Doctrine-idiomatic. Single-table inheritance requires the root entity to declare one discriminatorMap array naming every subclass, which makes the base class a shared registry that every team adding a subtype must edit. The bundle inverts that: each subclass declares its own discriminator value, and a loadClassMetadata subscriber plus a Symfony compiler pass synthesizes the map at metadata-build time. Decoupling the root entity from its descendants is still the correct architectural intent in modern Doctrine. The packaging is the problem — the reusable core is a small fraction of the repo, welded to Symfony\Component\HttpKernel\Bundle\Bundle and a DI extension that has no meaning outside a Symfony kernel.

Integration feasibility — low, and not on the named stack. Three blockers stack:

Dimension State Consequence
Framework Symfony 2.x/3.x bundle registration No service provider, no package discovery; does not boot in Laravel
PHP ~5.5–7.0 era signatures PHP 8.x deprecations and probable fatals in subscriber/compiler pass
Doctrine ORM 2.5-era APIs, doctrine/annotations reader ClassMetadata listener surface has shifted; PHP 8 attributes unsupported
Ecosystem 1 release, 0 dependents, no tests, no CI No compatibility matrix, no triage, no security process

Additionally, Laravel applications typically use doctrine/dbal for the query builder, not Doctrine ORM; where ORM is present it arrives via laravel-doctrine/orm, which consumes neither Symfony bundles nor this listener shape. This is not a configuration problem — it is a dependency-resolution dead end before any code executes.

Technical risk. High and asymmetric, concentrated in the worst possible layer. The cheap failure mode is a clean install error. The expensive one is a partial install on a legacy PHP 7.4 service where the subscriber intermittently fails to populate the map, surfacing as ClassNotFound or hydration errors only for subclasses loaded after the metadata cache warms — i.e., data-integrity bugs, not stack traces. There are no tests to establish behavioral guarantees, and metadata interception is the highest-blast-radius place to inherit unmaintained code.

Key questions for the requesting engineer.

  1. Is the goal to remove coupling from a base entity (a style preference), or to let external packages register subtypes without editing core (a legitimate product requirement)? Only the second justifies investment.
  2. What are the target Doctrine and PHP versions? On PHP 8.1+/Doctrine 3.x the answer is reimplement, not integrate.
  3. Do we already run STI in production? If not, this is speculative capability — defer.
  4. How many subclasses exist today, and how many distinct teams edited the root entity this quarter? Under ~5 subclasses or one team, the explicit map is cheaper and clearer.
  5. Will a named engineer own the code? No owner, no adoption.

Integration Approach

Stack fit — poor as shipped, viable as a pattern. There is no supported installation path into Laravel, and forcing it with --ignore-platform-reqs against a symfony/http-kernel shim drags a parallel framework kernel in for no benefit. The defensible move is a clean-room reimplementation of the mechanism, scoped at 150–250 lines and 4–7 engineering days.

  1. Subscriber, not bundle. Implement Doctrine\Common\EventSubscriber on loadClassMetadata. On the root entity, discover subclasses carrying a #[DiscriminatorValue('foo')] attribute from a declared namespace or cached class list, then assign $metadata->discriminatorMap and $metadata->subClasses. No kernel coupling.
  2. Attribute, not annotation. Drop doctrine/annotations entirely. This removes the deprecated reader and the Symfony DI dependency in one step, and is the single highest-value deviation from the original.
  3. Registration. Bind the subscriber to Doctrine\ORM\Events::loadClassMetadata on the EntityManager event manager in a service provider, or via the laravel-doctrine subscribers config key.
  4. Caching discipline. Discovery scanning is expensive. Cache the resolved map under a key derived from the entity namespace plus a deploy-stamped build ID, and warm it in a post-deploy artisan command. Never scan at request time.
  5. Compatibility guard. Two tests: the resolved map is identical to an explicit discriminatorMap on a fixture hierarchy, and a subclass added in a separate package is picked up without touching the root entity.

Sequencing.

  • Phase 0 (1–2 days): Confirm the requirement, the Doctrine ORM and PHP baseline, and the subclass/team counts. If Doctrine ORM is not already in the stack, stop — introducing an ORM to obtain a mapping convenience is not a justified trade.
  • Phase 1 (3–5 days): Build the attribute plus subscriber spike against a representative hierarchy; validate with metadata cache both cold and warm.
  • Phase 2 (2–3 days): Cache warming, deploy hook, fixture tests, and documentation pinning two invariants — the root entity stays abstract, the discriminator column stays stable.
  • Phase 3: If Phase 1 shows the explicit map was already adequate, retire the requirement. Treat that as a successful outcome, not a failed project.

Do not vendor the repository as a path or VCS dependency. Modernizing a 2016 Symfony bundle costs more than the rewrite and leaves the kernel baggage behind.

Operational Impact

Maintenance. As-shipped, maintenance cost is effectively total and unquantifiable: every PHP or Doctrine upgrade becomes an unscheduled fork-modernization task, and no upstream fix will ever arrive. As-reimplemented, it is 150–250 lines of first-party code with a parity test suite, owned by a named engineer and sized to be understood in an afternoon. This is the entire argument for the rewrite — it converts an unbounded external dependency into a bounded internal utility.

Support. With the package, there is no support channel: no issue triage, no CVE monitoring, no release cadence, a single small maintainer org last active in 2016. With the internal version, support routes through normal team on-call and code review. The cost is a small addition to the owning team's surface area; the benefit is that failures page someone who can actually fix them.

Scaling. The pattern scales along the axis that matters — team count. Adding an entity subtype becomes a one-new-file change with zero merge conflict on a shared base class, which is the coordination-tax reduction that justifies the work. Two caveats to plan for: discovery scanning cost grows with the number of entity classes (mitigated by cache warming at deploy, not request), and decentralized maps reduce discoverability, so ship a build-time assertion that enumerates every resolved subtype so there remains exactly one place to read the full map even though no one must edit it.

Failure modes. Ranked by expected pain: silent metadata divergence where a subclass is not discovered and hydration fails only on cold-cache paths (mitigated by the resolved-map parity test and a deploy-time map dump); discriminator column drift from a careless migration (mitigated by documenting the column as a schema invariant); and fork drift if the internal implementation later diverges from Doctrine's own metadata semantics across a major upgrade (mitigated by pinning Doctrine and re-running the parity fixture on upgrade). None of these are exotic; all are cheap to test for and expensive to discover in production.

Ramp-up. Low for anyone who already knows Doctrine inheritance — the concepts are standard STI plus a metadata subscriber, roughly a half-day to read and a day to extend. Non-trivial for a team that has never run Doctrine ORM at all, which is the common Laravel case; that team is better served by keeping the explicit discriminatorMap until subclass count and cross-team edit frequency make the conflict cost concrete and measurable. Budget the investment in engineering days under developer-experience tooling, not against a product roadmap line; the payoff is reduced coordination friction as the entity model grows, not any user-facing capability.

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib