Пользовательское отношение «многие ко многим» в Doctrine

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

Пользовательское отношение «многие ко многим» в 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;
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
24
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Оказывается, Доктрина напрямую не допускает такого рода отношений.

Лучшее решение, которое я смог придумать, состояло в том, чтобы создать две коллекции в 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;
}

Другие вопросы по теме