Weave Code
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

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require arthem/object-reference-bundle
    

    Add the bundle to config/bundles.php:

    return [
        // ...
        Arthem\ObjectReferenceBundle\ArthemObjectReferenceBundle::class => ['all' => true],
    ];
    
  2. First Use Case: Define an entity with a polymorphic reference using the #[ObjectReference] attribute. Example:

    use Arthem\ObjectReferenceBundle\Mapping\Attribute\ObjectReference;
    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity]
    class Post
    {
        #[ORM\Column(type: 'string', length: 36, nullable: true)]
        #[ObjectReference(keyLength: 15)]
        private \Closure|Comment $comment;
    
        private $commentId; // Required field
        private $commentType; // Required field
    
        // Getter/setter logic (see README)
    }
    
  3. Database Schema: Run migrations to ensure the *Id and *Type columns are created:

    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    

Implementation Patterns

Common Workflows

  1. Polymorphic References: Use #[ObjectReference] for entities that can reference multiple types (e.g., User, Group, or Service).

    #[ObjectReference(keyLength: 20)]
    private \Closure|(User|Group) $owner;
    
  2. Lazy Loading: Implement closures in getters to defer object hydration until needed:

    public function getOwner(): ?(User|Group)
    {
        if ($this->owner instanceof \Closure) {
            $this->owner = $this->owner->call($this);
        }
        return $this->owner;
    }
    
  3. Type Safety: Leverage PHP 8+ union types (User|Group) in method signatures for IDE autocompletion and runtime checks.

  4. Repository Integration: Query polymorphic references using Doctrine’s SingleTableInheritance or ClassTableInheritance strategies:

    $posts = $entityManager->createQueryBuilder()
        ->select('p')
        ->from(Post::class, 'p')
        ->where('p.commentType = :type')
        ->setParameter('type', Comment::class)
        ->getQuery()
        ->getResult();
    
  5. Form Handling: Use Symfony’s DataTransformer or ChoiceType with custom query builders to handle polymorphic selections:

    $builder->add('owner', EntityType::class, [
        'class' => [User::class, Group::class],
        'query_builder' => function (EntityRepository $er) {
            return $er->createQueryBuilder('u')
                ->where('u.id = :id')
                ->orWhere('u.type = :type');
        },
    ]);
    

Gotchas and Tips

Pitfalls

  1. Missing Fields: Forgetting to declare $*Id and $*Type fields will cause Doctrine to fail during schema validation. Always include them, even if unused.

  2. Closure Serialization: Closures are not serializable by default. Ensure your entity’s __serialize()/__unserialize() methods handle them:

    public function __serialize(): array
    {
        return [
            'actor' => $this->actor instanceof \Closure ? null : $this->actor,
            'actorId' => $this->actorId,
            'actorType' => $this->actorType,
        ];
    }
    
  3. Key Length Mismatch: The keyLength in #[ObjectReference] must match the actual length of the referenced entity’s ID column (e.g., uuid = 36, integer = 10).

  4. Circular References: Avoid bidirectional references with closures to prevent infinite loops in getters/setters.

Debugging Tips

  1. Query Logs: Enable Doctrine debug mode to inspect generated SQL for polymorphic queries:

    $entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
    
  2. Type Validation: Use instanceof checks in getters to handle cases where the referenced object is not yet loaded:

    if ($this->owner === null && $this->ownerId !== null) {
        $this->owner = $entityManager->find($this->ownerType, $this->ownerId);
    }
    
  3. Event Listeners: Attach lifecycle listeners to populate closures during postLoad:

    $entityManager->getEventManager()->addEventListener(
        \Doctrine\ORM\Events::postLoad,
        function ($event) {
            $entity = $event->getObject();
            if (method_exists($entity, 'initializeClosures')) {
                $entity->initializeClosures($event->getEntityManager());
            }
        }
    );
    

Extension Points

  1. Custom Reference Strategies: Override the bundle’s ObjectReferenceType to support non-standard ID formats (e.g., custom UUIDs):

    use Arthem\ObjectReferenceBundle\DBAL\Types\ObjectReferenceType;
    
    class CustomObjectReferenceType extends ObjectReferenceType
    {
        public function convertToDatabaseValue($value, AbstractPlatform $platform)
        {
            // Custom logic here
        }
    }
    
  2. Validation Constraints: Add Symfony Validator constraints to enforce reference integrity:

    use Symfony\Component\Validator\Constraints as Assert;
    
    #[ORM\Column(type: 'string', length: 36)]
    #[ObjectReference(keyLength: 15)]
    #[Assert\Type(type: 'object', message: 'Invalid reference type')]
    private \Closure|Actor $actor;
    
  3. API Serialization: Use Symfony Serializer’s @Groups to control exposure of polymorphic references:

    #[Groups(['api'])]
    public function getActor(): ?Actor
    {
        // ...
    }
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui