2
votes

I have problem with relation Many to One to MappedSuperclass in Symfony 5. I have entities Employee, Employer which extends MappedSuperclass abstract class Person. And I want create raports entity which will be in relation with Person (both Employee and Employer) like below:

    /**
     * @ORM\ManyToOne(targetEntity=Person::class)
     */
    private $person;

But when i try to push migrations I get following error message:

Column name id referenced for relation from App\Entity\Raport towards App\Entity\Person does not exist.

but I have id properties in these classes:

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    protected $id;

I found on the Symfony page example with creating interface to do it but it doesn't work for me too. Maybe someone had that problem before and know how to resolve it. Thanks a lot for any reply.

EDIT My Person class:

**
 * Abstract base class to be extended by my entity classes with same fields
 *
 * @MappedSuperclass
 */
abstract class Person
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    protected $id; //This property exist in Employee and Employer too (like doctrine documentation said)

Now when I change it from superclass to 'JOINED' inheritance when I try create now Employee or Employer I get following error:

An exception occurred while executing 'INSERT INTO person (discr) VALUES  
   (?)' with params ["Employee"]:                                                  

  SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error i  
  n your SQL syntax; check the manual that corresponds to your MySQL server v  
  ersion for the right syntax to use near 'person (discr) VALUES ('Employee')'  
   at line 1        

There isn't any other way to just make relation in one property to few entities whose implements one interface or extends class?? Sometimes I hate doctrine... And my person entity maybe it helps configure what is wrong:

* @ORM\Entity(repositoryClass=PersonRepository::class)
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"person" = "Person", "employee" = "Employee", "employer" = "Employer"})
 */
class Person
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    protected $id;

    public function getId(): ?int
    {
        return $this->id;
    }

}
3
You need a annotation (@MappedSuperclass). See doctrine-project.org/projects/doctrine-orm/en/2.7/reference/…André
I had already that annotation in Person class. Sorry for that I not clarify that before :(kris016
Remove the abstract. I do not have a MappedSuperclass as a relation. I have set the MappedSuperclass is abstract for a class in a project and I get an error. Abstract class seems not to be allowed.André

3 Answers

4
votes

It's possible to have relations into MappedSuperClass (in Symfony). What you want is dynamic mapping, which is not well documented. You have to use Doctrine Event loadClassMetadata. The doc example is very (very) simple, but you can do such more.

In your case, you must check if the entity is the one you want and is not a MappedSuperClass :

<?php

namespace App\Doctrine;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Events;

class LoadClassMetadataListener implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return [
            Events::loadClassMetadata,
        ];
    }

    public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)
    {
        $metadata = $eventArgs->getClassMetadata();
        $class = new \ReflectionClass($metadata->getName());

        if ($class->implementsInterface('Your\Interface') && !$metadata->isMappedSuperclass) {
            $metadata->mapManyToOne(array(
                'targetEntity'  => Person::class,
                'fieldName'     => 'person',
                'inversedBy'    => 'whatYouWant',
                'joinColumns'   => [[
                    'name'                 => 'xxx_id',
                    'referencedColumnName' => 'id',
                    'nullable'             => false,
                ]]
            ));
        }
    }
}
services:
    App\Doctrine\LoadClassMetadataListener
        tags:
            - { name: doctrine.event_subscriber }

$metadata gives access to all mapping possibilities and all mapping options, like with annotations, yaml or XML.

3
votes

You can't have a relation target a MappedSuperClass, since it's NOT an entity itself. It only can itself define an owning one-to-one relationship (or very limited many-to-many):

A mapped superclass cannot be an entity, it is not query-able and persistent relationships defined by a mapped superclass must be unidirectional (with an owning side only). This means that One-To-Many associations are not possible on a mapped superclass at all. Furthermore Many-To-Many associations are only possible if the mapped superclass is only used in exactly one entity at the moment. For further support of inheritance, the single or joined table inheritance features have to be used.

source: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/inheritance-mapping.html#mapped-superclasses

What you might want is a single table inheritance or a class table inheritance (see link above, it shows those as well). It can get quite annoying though. You've been warned.

-1
votes

Try to remove the abstract. I do not have a MappedSuperclass as a relation. I have set the MappedSuperclass is abstract for a class in a project and I get an error. Abstract class seems not to be allowed. It also makes sense because it is not an abstract class in that sense.