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

Entity Extend Bundle Laravel Package

wucdbm/entity-extend-bundle

Wucdbm EntityExtendBundle is a Symfony bundle for extending Doctrine entities with additional data without modifying their core classes. It helps organize reusable entity extensions, keep domain models clean, and manage custom fields or model add-ons more easily across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony2 bundle, so step one for a Laravel developer is acknowledging the stack gap: there is no service provider, no config/ publish tag, and no Artisan surface. You interact with it entirely through AppKernel, Doctrine's entity manager, and Symfony's DI container.

Minimal integration path:

  1. Install it into a Symfony2/3 app, not a Laravel app. composer require wucdbm/entity-extend-bundle. The package name on Packagist is wucdbm/entity-extend-bundle even though the repo is PjEntityExtendBundle — expect that mismatch to confuse your autoload/debugging searches.
  2. Register the bundle in app/AppKernel.php:
    new Pj\EntityExtendBundle\PjEntityExtendBundle(),
    
  3. Point Doctrine at the bundle's mapping if it isn't auto-registered (older Symfony2 bundles often required an explicit doctrine.orm.mappings entry or relied on the Resources/config/doctrine convention). Check Resources/config/ first — that is where the mapping driver and any DI services live.
  4. Find the base extension entity. The whole point of the bundle is likely a base class (something like EntityExtension) that you subclass, plus a discriminator-style mapping so one join table can hold many "extra attribute" entities for different host entities. Read the Entity/ directory before writing any code.

Where to look first: the Entity/ directory for the base extension class and its Doctrine mapping, then Resources/config/ for services and mapping config, then DependencyInjection/ for extension points. Skim composer.json for the PHP and Symfony version constraints — that single file tells you whether this is salvageable or archival.

First use case: you have a Product entity you don't want to touch (third-party bundle, or a stable core), and you need to attach a handful of optional, sparse attributes (SEO fields, warehouse metadata). Instead of altering the product table, you create a ProductExtension extends EntityExtension with those fields, map it one-to-one back to Product, and read it through the relation. That "extend without touching the original schema" idea is the reason the bundle exists, and it's the fastest way to evaluate whether the abstraction fits your problem.

Implementation Patterns

The mental model maps cleanly onto things Laravel developers already know, which helps when porting or reimplementing:

  • Polymorphic-ish extension table → Doctrine single-table inheritance. The extension table typically carries a type/discriminator column, and each concrete extension entity maps to a row keyed to its host. Think of it as a morphTo relation, but resolved by Doctrine's inheritance map at the entity level rather than by a *_type string column at query time.
  • One-to-one inverse side on the host. The pattern is Product::$extension (inverse, mappedBy) ↔ ProductExtension::$product (inversedBy), with the extension table's FK being the host's PK. This keeps the extension row and host row in lockstep — one extension per host, by construction.
  • Sparse/optional fields. Because the extension is a separate row, you can have a Product with no extension at all. Guard every access: if ($product->getExtension()) { ... }. This is the single most common source of null-fatigue in this pattern, and it's why the bundle is better suited to a fixed set of optional fields than to "anything goes" metadata.
  • Repository-level fetch joins. With a one-to-one, Doctrine will lazy-load the extension on every access, which is a textbook N+1. Write repository methods that ->leftJoin('p.extension', 'e')->addSelect('e') whenever you list products in a grid or API response.
  • Cascade and lifecycle. Persist the extension with the host via cascade: ["persist"] on the inverse side if the bundle's base class doesn't already configure it — check the mapping before you add it, or you'll double-cascade. Use a Doctrine event subscriber (prePersist/preUpdate) to stamp createdAt/updatedAt on the extension if the base class doesn't.
  • Forms. In Symfony2 you would embed the extension as a sub-form ($builder->add('extension', new ProductExtensionType())) and let the entity cascade. In Laravel-speak this is the equivalent of $request->validated() for a nested relation plus $model->extension()->updateOrCreate(...).
  • Admin/CRUD integration. If the app uses Sonata or EasyAdmin (Symfony equivalents), the extension usually needs its own admin class, because the inherited fields don't appear on the host admin automatically. Plan for that surface area; it's often more work than the entity wiring itself.
  • Reuse across hosts. If the bundle truly supports many hosts against one extension table, the intended pattern is a shared base extension entity with a discriminator, and a per-host concrete subclass only when fields differ. Resist adding host-specific columns to a generic base — schema drift there is painful to migrate.

Laravel translation of the pattern: if you're evaluating this for ideas rather than direct use, the modern Laravel analogue is a HasOne extension model with a morphTo, or a JSON metadata column for truly sparse data. The bundle's separate-table approach buys you real columns, indexes, and Doctrine types; a JSON column buys you zero migrations. Choose based on how often you query/filter on the extension fields.

Gotchas and Tips

  • It's Symfony2 / PHP 5-era. Check composer.json constraints before anything else. If it pins symfony/symfony ~2.x and php >=5.5, installing it in anything modern is a fight you will lose. Treat this as a reference implementation to read, not a dependency to ship, unless you're genuinely on Symfony2.
  • Zero stars, zero dependents, no maintenance signal. No releases, no CI, no tests means every bug is yours. Read the mapping files line by line before trusting them, and be prepared to fork. Budget for a fork on day one rather than pretending you'll upstream fixes.
  • Discriminator mapping is the sharp edge. If the base extension uses single-table inheritance, adding a new extension type requires a mapping change (the discriminator map lives in annotations/XML/YAML, not the database). A forgotten discriminator entry fails at hydration time with a confusing Unknown discriminator value error, not at boot.
  • Lazy loading will bite you in list views. One-to-one inverse relations are lazy by default. If a page suddenly makes N+1 queries, suspect the extension join first — this is the single most common performance regression with this kind of bundle.
  • Schema tooling and migrations. doctrine:schema:validate and doctrine:migrations:diff will pick up the extension tables, but if the bundle ships its own mapping in Resources/config/doctrine, you can get duplicate mapping errors or tables you didn't intend to create. Run doctrine:mapping:info early to see exactly what Doctrine thinks exists.
  • Entity inheritance conflicts. You cannot cleanly combine this bundle's extension mechanism with Doctrine's own SINGLE_TABLE/JOINED inheritance on the same entity. Pick one strategy per entity hierarchy.
  • Cascade misconfiguration masquerades as "it doesn't save." If the extension silently isn't persisted, check cascade: ["persist"] on the owning side and whether the base class sets it. This bites everyone once.
  • Debugging tip: dump the SQL Doctrine actually runs (doctrine.dbal.logging: true in dev, or the Symfony profiler's Doctrine panel). Because the abstraction hides a join behind a property accessor, reading the executed SQL is faster than reasoning about the mapping.
  • Extension points to look for: lifecycle event subscribers and any doctrine.event_listener services declared in Resources/config/services.yml are where the bundle hooks into Doctrine. Those are your supported extension points; anything else you override is your own risk.
  • Portability note for Laravel devs: don't try to make this bundle run under Laravel. It's a Doctrine bundle with Symfony DI assumptions. If the pattern interests you, reimplement it in Eloquent with HasOne/morphOne plus a small trait — you'll get the same "extend without touching the base schema" benefit in an afternoon, and you'll own the code.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin