1

I have the following entity graph:

#[ORM\Entity]
class Professional
{
    #[ORM\Id]
    #[ORM\Column(type: 'professional_id')]
    #[ORM\GeneratedValue(strategy: 'NONE')]
    private ProfessionalId $id;

    #[ORM\OneToOne(targetEntity: ProfessionalCatchmentArea::class, mappedBy: 'professional', cascade: ['all'])]
    private ?ProfessionalCatchmentArea $catchmentArea = null;
}
#[ORM\Entity]
class ProfessionalCatchmentArea
{
    #[ORM\Id]
    #[ORM\OneToOne(targetEntity: Professional::class, inversedBy: 'catchmentArea')]
    #[ORM\JoinColumn(nullable: false)]
    private Professional $professional;

    #[ORM\OneToMany(targetEntity: ProfessionalCatchmentAreaZone::class, mappedBy: 'catchmentArea', orphanRemoval: true, cascade: ['all'])]
    private Collection $zones;
}
#[ORM\Entity]
class ProfessionalCatchmentAreaZone
{
    #[ORM\Id]
    #[ORM\Column(type: 'uuid')]
    #[ORM\GeneratedValue(strategy: 'NONE')]
    private Uuid $id;

    #[ORM\ManyToOne(targetEntity: ProfessionalCatchmentArea::class, inversedBy: 'zones')]
    #[ORM\JoinColumn(name: 'professional_id', referencedColumnName: 'professional_id', nullable: false)]
    private ProfessionalCatchmentArea $catchmentArea;
}

Note: ProfessionalId is a custom ID class containing a UUID.

As you can see, Professional has a one-to-one relationship with ProfessionalCatchmentArea, which in turn has a one-to-many relationship with ProfessionalCatchmentAreaZone.

Due to the one-to-one, ProfessionalCatchmentArea shares its primary key with Professional.

Therefore, the JoinColumn for the many-to-one relationship from ProfessionalCatchmentAreaZone to ProfessionalCatchmentArea is based on the professional_id column.

For some reason, even though Doctrine does not complain with this mapping (bin/console doctrine:schema:validate is OK), and even though traversal from Professional to $catchmentArea to $zones works fine, attempting to load the ProfessionalCatchmentAreaZone entities directly from the EntityRepository fails:

$entityManager->getRepository(ProfessionalCatchmentAreaZone::class)->findAll();

Cannot assign App\Entity\ProfessionalId to property App\Entity\ProfessionalCatchmentArea::$professional of type App\Entity\Professional

Any idea why?

Is this mapping one-to-one => one-to-many, while sharing the primary key in the one-to-one relationship, not supported? Is this a Doctrine bug?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
  • Shouldn't you declare the Id of `ProfessionalCatchmentArea` as `ProfessionalId $id`, exactly like you did for the `Professional` entity? – Olivier Jan 19 '22 at 17:06
  • @Olivier Before checking if that would work for me, one question: is there a way to enforce a foreign key on `ProfessionalCatchmentArea.professionalId` if it's declared as a `ProfessionalId` and not as a `OneToOne` to `Professional`? Does Doctrine allow declaring a foreign key if it's not an association? – BenMorel Jan 20 '22 at 00:26
  • Unfortunately I'm not familiar with Doctrine so I can't answer those questions. – Olivier Jan 20 '22 at 08:59
  • 2
    Show the `ProfessionalId` type source. – cetver Jan 20 '22 at 22:59
  • 1
    In order to replicate your issue it would be helpful to get info about: PHP version, Packages version (or composer.lock), Database vendor and version, Example code to populate database with some dummy data. – Jimmix Jan 22 '22 at 18:26
  • 1
    I spent some time on this, even built tables based on your example. One thing I was not able to reproduce were those `uuid` and `professional_id` types of columns. The rest, with int column types does work OK. So I would not look into relation configuration any more. – yergo Jan 22 '22 at 21:56

1 Answers1

1

I've got a few ideas:

  1. Based on the information provided, I'm inclined to believe this is an issue with the object inheritance and the mapped type for the data type of Professional->$id.

    Given that ProfessionalId extends the UUID, the only valid class datatype for ProfessionalId is the class ProfessionalId.

    If the data type was UUID then the values that are compatible with UUID would be an instance of UUID or ProfessionalId (because it INHERITS UUID).

  2. Check that the Datatype is registered for that name:

    <?php
    
    // In your bootstrap file
    
    \Doctrine\DBAL\Types\Type::addType('professional_id', ProfessionalId::class);
    
    ?>
    
  3. Ensure that the ProfessionalId type inherits the annotations from the UUID type as seen here:

    https://stackoverflow.com/a/40442063/5779200

Noah
  • 859
  • 7
  • 17