Symfony 2: alternativa para usar heranças com UniqueEntity

Português
, ,

Olá,

Hoje eu me deparei com um bug conhecido do Symfony2 ao usar UniqueEntity e herança com entidades. Na discussão, @gentisaliu recomendou usar um repositório customizado, então estou documentando a solução abaixo:

Entidades:

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. O método findByName deve explicitamente fazer a busca na entidade pai, caso contrário ele verificará se é único apenas naquele tipo, e não globalmente (name = ? AND type = ?)
  2. A propriedade repositoryMethod define qual método do repositório vai ser utilizado para determinar se uma entidade é única ou não. O método deve retornar um objeto contável, array funciona, mas eu prefiro retornar o resultado da query.
  3. A propriedade repositoryClass precisa ser a mesma para todas as entidades ou, caso você não possa usar o mesmo repositório, implemente o método repositoryMethod em todos os repositórios. Neste caso, tenha o cuidado do efetuar a query pela entidade pai, conforme item 1.

Até mais.