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

Object Reference Bundle Laravel Package

arthem/object-reference-bundle

Doctrine ORM bundle that stores references to any entity as a type and ID pair, using the ObjectReference attribute and lazy closures so relations stay lightweight and framework-agnostic.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Polymorphic Relationships: The bundle enables polymorphic object references (e.g., storing either an Actor or another type in a single column via closures), which aligns with Laravel/Lumen’s Doctrine ORM use cases where dynamic entity relationships are needed (e.g., audit logs, event sourcing, or generic "owner" fields).
  • Closure-Based Lazy Loading: The design leverages PHP closures for deferred hydration, reducing immediate DB queries. This is valuable for performance-critical paths but introduces complexity in debugging and caching.
  • Reflection-Driven Configuration (1.1.1): As of 1.1.1, ObjectReference mapping is derived from the PHP property signature via reflection rather than an explicit custom mapping key. This reduces boilerplate and eliminates a class of misconfiguration bugs (mismatched key lengths/types), but shifts failure modes to reflection time (e.g., union-typed properties, untyped properties, or attributes on non-serializable types).
  • Doctrine ORM Dependency: Tight coupling to Doctrine ORM (v2.5+) may limit flexibility in Laravel’s native Eloquent ecosystems unless hybrid ORM setups are adopted.

Integration Feasibility

  • Laravel Compatibility: Requires Symfony Framework Bundle (v6.3/7.x) and Doctrine ORM, which are non-native to Laravel. Integration would necessitate:
    • A Symfony-compatible Laravel kernel (e.g., via symfony/flex or manual bootstrapping).
    • Doctrine ORM setup alongside Eloquent (potential conflicts in service containers).
  • Attribute-Based Mapping: Uses PHP 8+ attributes (#[ObjectReference]). With 1.1.1’s reflection-derived configuration, developers no longer supply explicit keyLength/type arguments in most cases, lowering the barrier to entry. Still requires config/doctrine.php and compiler-pass verification that the attribute is discovered.
  • Closure Serialization: Storing closures in DB columns (Types::STRING) risks serialization/deserialization edge cases (e.g., class autoloading, closure scope). Reflection-derived config increases reliance on runtime introspection but does not change the serialization risk profile.

Technical Risk

  • Maturity: Multi-release history now exists (1.0.0 → 1.1.0 → 1.1.1), with an active maintainer merging PRs. Risk of abandoned-package scenarios is marginally lower, but still no dependents or community support (0 stars as of last assessment).
  • Reflection-Based Config Risk (New in 1.1.1): Deriving configuration from reflection means errors surface at hydration/persist time rather than at boot. Union types, \Closure|User annotations, and nullable properties must be explicitly understood by the developer — failure modes are less obvious than an explicit misconfigured key.
  • Performance Overhead: Closure-based lazy loading adds runtime reflection costs (now compounded slightly by per-attribute reflection in 1.1.1). Benchmarking is critical for high-throughput systems.
  • Doctrine vs. Eloquent: Potential for ORM conflicts (e.g., event listeners, hydration strategies) if both are active.
  • Migration Complexity: Backfilling existing tables with polymorphic references may require custom scripts.

Key Questions

  1. Use Case Justification:
    • Why not use Eloquent’s built-in polymorphic relationships (morphTo) or a dedicated library like spatie/laravel-morph-many-to-many?
    • Is the closure-based approach necessary, or would a simpler UUID/foreign key pattern suffice?
  2. Stack Alignment:
    • Can the bundle coexist with Laravel’s service container (e.g., binding Doctrine entities as Laravel services)?
    • How will route/model binding interact with Doctrine’s routing?
  3. Failure Modes:
    • What happens if the referenced class is autoloaded after the closure is stored?
    • How are transactions handled across Doctrine and Eloquent?
    • New: Does the reflection-based configuration (1.1.1) correctly resolve union types, readonly properties, and promoted constructor properties used by modern Laravel entities?
  4. Testing:
    • Are there unit/integration tests for edge cases (e.g., circular references, missing classes)?
    • How does the bundle handle schema migrations and reflection changes between PHP minor versions?

Integration Approach

Stack Fit

  • Hybrid ORM Setup:
    • Install via Composer: composer require arthem/object-reference-bundle.
    • Configure Doctrine ORM alongside Eloquent (e.g., via doctrine/orm package with custom EntityManager).
    • Use Symfony’s FrameworkBundle as a dependency (may require Laravel’s symfony/console bridge).
  • Attribute Configuration (simplified in 1.1.1):
    • Replace Eloquent’s belongsTo/morphTo with #[ObjectReference] on entities. Configuration is now derived by reflection, so keyLength can be omitted unless overriding defaults:
      #[ORM\Entity]
      class Post {
          #[ObjectReference]
          private \Closure|User $author;
          private $authorId; // Required by bundle
          private $authorType;
      }
      
  • Service Provider:
    • Register Doctrine’s EntityManager in Laravel’s container:
      public function register(): void {
          $this->app->singleton(EntityManagerInterface::class, function ($app) {
              return DoctrineORMModule::configureEntityManager($app['config']['doctrine']);
          });
      }
      

Migration Path

  1. Pilot Phase:
    • Start with a single entity (e.g., Story) to test Doctrine + Eloquent coexistence.
    • Use a feature guard to toggle between Eloquent and Doctrine for the polymorphic field.
  2. Schema Changes:
    • Add actor_id (string) and actor_type (string) columns to existing tables.
    • Backfill data via a migration:
      Schema::table('stories', function (Blueprint $table) {
          $table->string('actor_id')->nullable()->after('id');
          $table->string('actor_type')->nullable()->after('actor_id');
      });
      
  3. Hybrid Queries:
    • Use Doctrine’s QueryBuilder for ObjectReference fields, Eloquent for others.
    • Example:
      $stories = $entityManager->getRepository(Story::class)
          ->createQueryBuilder('s')
          ->where('s.actorType = :type')
          ->setParameter('type', 'Actor')
          ->getQuery()
          ->getResult();
      
  4. Reflection Upgrade Note: When moving from 1.0.0 to 1.1.x, remove any custom keyLength/type configuration that now conflicts with reflection-derived defaults. Validate on a shadow schema first.

Compatibility

  • Doctrine vs. Eloquent:
    • Avoid mixing ORMs in the same query (e.g., no DB::table() calls for Doctrine entities).
    • Use repository patterns to abstract differences:
      interface StoryRepository {
          public function findByActorType(string $type);
      }
      
  • Event Listeners:
    • Doctrine events (e.g., prePersist) may conflict with Eloquent observers. Use priority flags or disable one system per entity.
  • Caching:
    • Closure-based lazy loading bypasses Laravel’s cache drivers. Cache resolved objects manually.

Sequencing

  1. Phase 1: Prove concept with a non-critical entity (e.g., LogEntry) on 1.1.1 to confirm reflection behavior.
  2. Phase 2: Integrate Doctrine’s EntityManager into Laravel’s container.
  3. Phase 3: Replace Eloquent polymorphic relationships with ObjectReference.
  4. Phase 4: Optimize queries and test edge cases (class autoloading, transactions, union-typed properties).

Operational Impact

Maintenance

  • Dependency Management:
    • Doctrine ORM updates may require manual testing (e.g., Symfony 7.x compatibility).
    • Closure serialization logic is fragile; monitor for PHP version-specific bugs.
    • Reflection drift: reflection-based configuration can silently change behavior across PHP minor versions (e.g., nullability, readonly). Pin php in composer.json and add CI matrix coverage for supported versions.
  • Debugging:
    • Stack traces for lazy-loaded closures will be opaque. Add custom logging:
      #[ObjectReference]
      private \Closure|User $author;
      private $authorId;
      
      public function getAuthor(): ?User {
          try {
              $this->author = $this->author->call($this);
              return $this->author;
          } catch (\Throwable $e) {
              Log::error("Failed to load author for ID {$this->authorId}", ['exception' => $e]);
              return null;
          }
      }
      
  • Documentation:
    • Internal docs must cover:
      • When to use ObjectReference vs. Eloquent’s morphTo.
      • Closure scope pitfalls (e.g., $this binding).
      • How reflection infers reference metadata and when explicit overrides are still required.

Support

  • Troubleshooting:
    • Common issues:
      • "Class not found" errors during closure execution (fix: ensure autoloading).
      • Doctrine/Eloquent hydration conflicts (fix: use separate EntityManager instances).
      • New: Reflection errors on unsupported property shapes (e.g., intersection types).
    • Support teams must understand both ORMs and the bundle’s reflection semantics.
  • Vendor Risk:
    • Small but growing release history reduces (but does not eliminate) fork/patch risk. Maintain a fork-and-patch playbook.

Scaling

  • Performance:
    • Pros: Lazy loading reduces initial queries.
    • Cons: Closure execution adds per-access overhead (~1–5ms per call). Reflection-derived config adds marginal boot/hydration cost versus explicit mapping.
    • Mitigation: Cache resolved objects in a WeakMap or Redis; warm reflection metadata in long-running workers.
  • Database:
    • String-based actor_id/type columns may bloat indexes. Consider UUIDs for consistency.
    • Add indexes for polymorphic queries:
      #[ORM\Index(name: 'idx_actor_type', columns: ['actor_type'])]
      class Story {}
      
  • Horizontal Scaling:
    • Closure serialization is stateless; ensure all app servers have identical class autoloading and reflection caching.

Failure Modes

Scenario Impact Mitigation
Closure execution fails Silent null returns Add try-catch with logging
Referenced class is deleted Broken closures Soft deletes or validation hooks
Doctrine/Eloquent conflict Query corruption Isolate entities by ORM
PHP version mismatch Closure serialization fails Pin PHP version in composer.json
Reflection cannot infer config Attribute ignored / runtime error Test union/readonly/promoted types; fall back to explicit mapping
High traffic Closure overhead spikes Cache resolved objects

Ramp-Up

  • Developer Onboarding:
    • 1–2 hours: Understand ObjectReference vs. Eloquent’s morphTo and the reflection-based config model.
    • 4–8 hours: Set up Doctrine in Laravel (kernel, config, service provider).
    • 1 day: Implement and test a pilot entity, verifying reflection against the target entity shapes.
  • Training Topics:
    • Closure scope and $this binding.
    • Doctrine event listeners vs. Eloquent observers.
    • Reflection pitfalls: union types, readonly properties, promoted constructors.
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.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc