Symfony/Doctrine class table inheritance and foreign key as primary key

1.4k Views Asked by At

I am currently designing a web application with Symfony 2.5 (and Doctrine 2.4.2) that has to be flexible to easily plug in new modules/bundles.

So I have an entity (let say A) that has two one-to-one associations with abstract classes (B and C). The future modules will implement one of the two abstract classes. Since the associations are one-to-one, I made them the ID of the abstract classes to ease the access to them when we know the ID of an instance of A

So here is what the code looks like:

class A:

<?php

namespace Me\TestBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table()
 * @ORM\Entity
 */
class A
{
  /**
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;

  /**
   * @ORM\OneToOne(targetEntity="B", cascade={"all"}, mappedBy="a")
   * @ORM\JoinColumn(name="id", referencedColumnName="a_id")
   */
  private $b;

  /**
   * @ORM\OneToOne(targetEntity="C", cascade={"all"}, mappedBy="a")
   * @ORM\JoinColumn(name="id", referencedColumnName="a_id")
   */
  private $c;
}

class B:

<?php

namespace Me\TestBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table()
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 */
abstract class B
{
  /**
   * @ORM\Id
   * @ORM\OneToOne(targetEntity="A", inversedBy="b")
   * @ORM\JoinColumn(name="a_id", referencedColumnName="id")
   */
  private $a;
}

I will not post the code of the class C since it is the same as class B.

In my point of view, it seems all good. Even for the mapping verification command. Indeed, when I execute php app/console doctrine:schema:validate, it tells me my schema is valid. However, this command then try to compare my schema to the schema in the database and it just fails at that point. php app/console doctrine:schema:update --dump-sql fails in the exact same way. So it is pretty embarrassing since it tells me my schema is valid but it cannot use it properly.

The error:

[ErrorException]
Warning: array_keys() expects parameter 1 to be array, null given in /vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php line 95

The error appears as soon as I add the InheritanceType and DiscriminatorColumn annotation to the classes B and C. Thing is that it tells me my schema is valid.

So does anyone have any clue if I am doing something wrong? Or is it definitely a bug in Doctrine? Do you have any other idea that would bring at least as much flexibility as my current solution?

Elioty

EDIT: I changed the owning side to be the abstract classes B and C since, accordingly to the doc, the owning side is the one with the foreign key and must use inversedBy attribute. Even with these changes, my schema is still valid and the same error still occurs.

EDIT2: If I create another field in B (and C) to hold the identity of the entity instead of the one-to-one association, the error disappears but it is no more like my valid schema.

EDIT3: I had a chat with a member of Doctrine's development team and (s)he told me it definitely looks like a bug. Bug report here.

1

There are 1 best solutions below

0
On

First of all, the command php app/console doctrine:schema:validate checks the validity of the current schema. The current schema is the one generated by your last called to the command php app/console doctrine:schema:update --force

On the other hand the command php app/console doctrine:schema:update --dump-sql does not execute an actual update to the schema, though it may find some errors some others will not be come up...

I dont understand class B. The identity of this (abstract) class is a OneToOne relationship? Anyway, the thing is that Doctine will ignore the @ORD\Id if you don't add inheritanceType definitions. When you add this inheritanceType definition Doctrine will make attribute 'a' the primary key of B. Also it will create another attribute named 'a_id' which will serve as a foreign key for future subclasses (extends of B). But...relationships are not inherited.

Hope this helps...