Допустим, я хочу реализовать в Doctrine следующие сущности:

Thing представляет собой все, что может выполнять действие над другим Thing. Relation может содержать две сущности и описание действия, а его кортеж уникален.
Вот несколько примеров того, чего я пытаюсь достичь:
Как видите, порядок имеет значение (это не то же самое, что «Боб любит яблоки» и «Яблоки любят Боб»).
Несмотря на все мои усилия, я не могу найти правильный способ реализовать это.
Я попытался создать поле с именем $relations в Thing, помеченное как «Один ко многим», а затем отметить $left и $right в Relation как «Многие к одному». Проблема в том, что у меня не может быть двух перевернутых сторон для одной и той же стороны (по крайней мере, AFAIK).
Эта текущая реализация также не позволяет получить все отношения для конкретного Thing в поле $relations, поскольку я могу указать только одну обратную сторону.
Вот что я придумал до сих пор:
/** @ORM\Entity */
class Thing {
/**
* @ORM\Id
* @ORM\Column(type = "integer", options = {"unsigned":true})
* @ORM\GeneratedValue
*/
protected $id;
/** @ORM\Column(type = "string") */
protected $name;
/**
* @ORM\OneToMany(targetEntity = "Relation", mappedBy = "right")
*/
protected $relations;
}
/** @ORM\Entity */
class Relation {
/** @ORM\Id @ORM\Column(type = "string") */
protected $action;
/** @ORM\Id @ORM\ManyToOne(targetEntity = "Thing") */
private $left;
/** @ORM\Id @ORM\ManyToOne(targetEntity = "Thing", inversedBy = "relations") */
private $right;
}






Оказывается, Доктрина напрямую не допускает такого рода отношений.
Лучшее решение, которое я смог придумать, состояло в том, чтобы создать две коллекции в Thing для отношений вместо одной, а затем определить метод, который выводит обе:
/** @ORM\Entity */
class Thing {
// [...]
/** @ORM\OneToMany(targetEntity = "Relation", mappedBy = "left") */
protected $relationsLeft;
/** @ORM\OneToMany(targetEntity = "Relation", mappedBy = "right") */
protected $relationsRight;
public function getRelations() {
return new ArrayCollection(array_merge(
$this->relationsLeft->toArray(),
$this->relationsRight->toArray()
));
}
}
/** @ORM\Entity */
class Relation {
// [...]
/** @ORM\Id @ORM\ManyToOne(targetEntity = "Thing", inversedBy = "relationsLeft") */
private $left;
/** @ORM\Id @ORM\ManyToOne(targetEntity = "Thing", inversedBy = "relationsRight") */
private $right;
}