Symfony 2: Inheritance and UniqueEntity workaround

English
, ,

Hi folks,

Today I struggled over an already known bug on Symfony2 when using UniqueEntity and Entity Inheritance. In the bug discussion, @gentisaliu recommended using a custom repository, and how do this I’m documenting here.

Entities:

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * @ORM\Table(name="parent")
 * @ORM\Entity(repositoryClass="Repository\Parent")
 * @UniqueEntity(fields={"name"}, repositoryMethod="findByName", message="Name already used.")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="type", type="string")
 * @ORM\DiscriminatorMap({
 *      "a" = "ChildA",
 *      "b" = "ChildB"
 * })
 */
class Parent { }
1
2
3
4
5
/**
 * @ORM\Entity(repositoryClass="Repository\Parent")
 * @ORM\Table(name="child_a")
 */
class ChildA extends Parent { }
1
2
3
4
5
/**
 * @ORM\Entity(repositoryClass="Repository\Parent")
 * @ORM\Table(name="child_b")
 */
class ChildB extends Parent { }

repositoryMethod:

1
2
3
4
5
6
7
8
9
public function findByName($criteria)
{
    return $this
            ->getEntityManager()
            ->createQuery("SELECT e FROM Parent e WHERE e.name = :name")
            ->setParameters($criteria)
            ->getResult()
    ;
}
  1. The findByName method must explicitly query the main entity, otherwise you will check a the uniqueness only for that type (name = ? AND type = ?)
  2. The repositoryMethod defines which method in the repository will be used for determine if an entity is unique or not. You have to return an Countable object, array allowed, but I rather use a query result.
  3. The repositoryClass must be the same of all entities, or if you can’t use the same repository, implement your “repositoryMethod” in all repositories. In such case you have to be cautious to do the query the base entity, not the child one.

That’s all.