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.
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).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).symfony/flex or manual bootstrapping).#[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.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.\Closure|User annotations, and nullable properties must be explicitly understood by the developer — failure modes are less obvious than an explicit misconfigured key.morphTo) or a dedicated library like spatie/laravel-morph-many-to-many?composer require arthem/object-reference-bundle.doctrine/orm package with custom EntityManager).FrameworkBundle as a dependency (may require Laravel’s symfony/console bridge).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;
}
EntityManager in Laravel’s container:
public function register(): void {
$this->app->singleton(EntityManagerInterface::class, function ($app) {
return DoctrineORMModule::configureEntityManager($app['config']['doctrine']);
});
}
Story) to test Doctrine + Eloquent coexistence.actor_id (string) and actor_type (string) columns to existing tables.Schema::table('stories', function (Blueprint $table) {
$table->string('actor_id')->nullable()->after('id');
$table->string('actor_type')->nullable()->after('actor_id');
});
QueryBuilder for ObjectReference fields, Eloquent for others.$stories = $entityManager->getRepository(Story::class)
->createQueryBuilder('s')
->where('s.actorType = :type')
->setParameter('type', 'Actor')
->getQuery()
->getResult();
keyLength/type configuration that now conflicts with reflection-derived defaults. Validate on a shadow schema first.DB::table() calls for Doctrine entities).interface StoryRepository {
public function findByActorType(string $type);
}
prePersist) may conflict with Eloquent observers. Use priority flags or disable one system per entity.LogEntry) on 1.1.1 to confirm reflection behavior.EntityManager into Laravel’s container.ObjectReference.php in composer.json and add CI matrix coverage for supported versions.#[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;
}
}
ObjectReference vs. Eloquent’s morphTo.$this binding).EntityManager instances).WeakMap or Redis; warm reflection metadata in long-running workers.actor_id/type columns may bloat indexes. Consider UUIDs for consistency.#[ORM\Index(name: 'idx_actor_type', columns: ['actor_type'])]
class Story {}
| 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 |
ObjectReference vs. Eloquent’s morphTo and the reflection-based config model.$this binding.How can I help you explore Laravel packages today?