aurelienC
aurelienC

Reputation: 1183

Doctrine mapping to unknow entity

is it possible to create a relation to a generic table/class whith Doctrine?

Here is some code to make it easier to understand:

// class Log...

// TODO:
// It could be useful to have a reference to
// the element mentioned by the log, the issue is
// we don't know what kind of entity it is.

/**
 * @ORM\ManyToOne(targetEntity="???")
 */
private $elementId

Maybe instead of using targetEntity I could just use an int that is the id of the element located in the unknow table.

Upvotes: 2

Views: 114

Answers (2)

Alsatian
Alsatian

Reputation: 3135

There is no built-in possibility now.

Let me propose a work around using Doctrine Lifecycle Events :

  • Create 3 properties :

    /*
     * @ORM\Column(name="element_class", type="string")
     */
    private $elementClass
    
    /*
     * @ORM\Column(name="element_id", type="integer")
     */
    private $elementId
    
    // Not mapped
    private $element
    
    public function setElement($element)
    {
        $this->element = $element;
        $this->elementClass = get_class($element);
        $this->elementId = $element->getId();
    }
    
    public function getElement()
    {
        return $this->element;
    }
    
    // You need these for the PostLoad event listener :
    
    public function hydrateElementPostLoad($element)
    {
        $this->element = $element;
    }
    
    public function getElementClass()
    {
        return $this->elementClass;
    }
    
    public function getElementId()
    {
        return $this->elementId;
    }
    
  • Then create a PostLoadListener able to hydrate the element property :

    namespace AppBundle\EventListener;
    
    use Doctrine\ORM\Event\LifecycleEventArgs;
    
    use AppBundle\Entity\Log;
    
    class PostLoadListener
    {
        public function postLoad(LifecycleEventArgs $args)
        {
            $entity = $args->getEntity();
    
            if($entity instanceOf Log){
                $em = $args->getEntityManager();
                $entity->hydrateElementPostLoad(
                    $this->em->getRepository($entity->getElementClass())->findOneById($entity->getElementId())
                );
            }
        }
    }
    
  • And register this event in your services.yml :

    services:
        places.listener:
            class: AppBundle\EventListener\PostLoadListener
            tags:
                - { name: doctrine.event_listener, event: postLoad } 
    

That's also how the most famous Bundle for logging works (The Gedmo DoctrineExtensions Logger)

  • To retrieve all logs for an entity, create a repository method for your Log entity :

    getLogs($entity)
    {
        return $this->_em->findBy(array(
            'element_id'=>$entity->getId(),
            'element_class'=>get_class($entity)
        ));
    }
    

Upvotes: 2

Anas EL KORCHI
Anas EL KORCHI

Reputation: 2048

You are trying to manage some abstraction of one or more of your entities in the database level which is a headache,

Doctrine already has proposed Somme solutions to manage this kind of abstractions by using Inheritance Mapping

A mapped superclass is an abstract or concrete class that provides persistent entity state and mapping information for its subclasses, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.

For more information check this

Upvotes: 2

Related Questions