Multi-to-one, self-regulation with inheritance mapping

I have some concepts with common relationships and attributes. So, I want to simplify my scheme using inheritance matching.

I created the base class BaseData mappedsuperclass and make my other objects extend it. This BaseData class has a common relationship that I need in every entity.

He works with many relationships, such as

/** * @ORM\MappedSuperclass */ class BaseData { /** * @ORM\ManyToOne(targetEntity="Service") * @ORM\JoinColumn(name="service_id", referencedColumnName="id") */ protected $service; 

But it gets a little more complicated with self-regulation.

For example, since I want to create a parent link, I tried the following:

 /** * @ORM\MappedSuperclass */ class BaseData { /** * @ORM\ManyToOne(targetEntity="BaseData") * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true) */ protected $parent; 

Obviously, this throws a TableNotFoundException when I try to query this object: QLSTATE[42S02]: Base table or view not found: 1146 Table 'project.base_data' doesn't exist .

So, I tried AssociationOverrides, but it doesn't seem to allow changing the target entity.

So, is there a way to create some self-esteem in MappedSuperclass? And by the way, does that even make sense?

Thank you very much in advance!

Update

Here is anwser:

I defined protected $parent and protected $children in my BaseData mappedSuperClass, as planned. I added them with other information that I need. eg:

 /** * @ORM\MappedSuperclass */ class BaseData { /** * @Datagrid\Column(field="parent.id", title="datagrid.parent_id", visible=false, safe=false) * @Serializer\Expose * @Serializer\Groups({"foo"}) */ protected $parent; /** * @Serializer\Expose * @Serializer\Groups({"elastica"}) */ protected $children; 

Then I add the ORM relation to the loadClassMetadata event.

 /** * @param LoadClassMetadataEventArgs $eventArgs */ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) { // the $metadata is all the mapping info for this class $classMetadata = $eventArgs->getClassMetadata(); $reflObj = new \ReflectionClass($classMetadata->name); if($reflObj) { if ($reflObj->isSubclassOf('CoreBundle\Entity\BaseData')) { $fieldMapping = array( 'targetEntity' => $classMetadata->name, 'fieldName' => 'parent', 'inversedBy' => 'children', 'JoinColumn' => array( 'name' => 'parent_id', 'referencedColumnName' => 'id', 'nullable' => true, 'onDelete' => 'SET NULL', ), ); $classMetadata->mapManyToOne($fieldMapping); $fieldMapping = array( 'fieldName' => 'children', 'targetEntity' => $classMetadata->name, 'mappedBy' => 'parent', ); $classMetadata->mapOneToMany($fieldMapping); } } } 

Register an event and it.

Now every class that extends SuperClass BaseData gets a relation. For example, php app/console doctrine:generate:entities MyBundle generates the following code inside a SubClass entity:

 /** * Set parent * * @param \MyBundle\Entity\Subclass $parent * * @return Subclass */ public function setParent(\MyBundle\Entity\Subclass $parent = null) { $this->parent = $parent; return $this; } /** * Get parent * * @return \MyBundle\Entity\Subclass */ public function getParent() { return $this->parent; } /** * Add child * * @param \MyBundle\Entity\Subclass $child * * @return Subclass */ public function addChild(\MyBundle\Entity\Subclass $child) { $this->children[] = $child; return $this; } /** * Remove child * * @param \MyBundle\Entity\Subclass $child */ public function removeChild(\MyBundle\Entity\Subclass $child) { $this->children->removeElement($child); } /** * Get children * * @return \Doctrine\Common\Collections\Collection */ public function getChildren() { return $this->children; } 
+5
source share
1 answer

You can remove the @ORM\ManyToOne(targetEntity="BaseData") and create an event listener in the event loadClassMetadata. (I have not tested the following code, this is just a starting point). Something like that:

 class TestEvent { public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs) { $classMetadata = $eventArgs->getClassMetadata(); $class = $classMetadata->getName(); $fieldMapping = array( 'fieldName' => 'parent', 'targetEntity' => $class, ); $classMetadata->mapManyToOne($fieldMapping); } } 

It is important to note that the listener will listen to all entities in your application.

See Doctrine Docs on Events And How to Register an Event Listener in symfony2

+2
source

Source: https://habr.com/ru/post/1237095/


All Articles