Как прикрепить 1 entyti ко многим Entities

228
09 июня 2017, 12:23

Задача создать комментарии для страниц, постов, портфолио... пользователей, ответы на сами комментарии. Как правильно оформить? Можно ли targetEntity передавать строчку через запятую?

/**
     * @ORM\ManyToOne(targetEntity="Post", inversedBy="comments")
     * @ORM\JoinColumn(name="object_id", referencedColumnName="id")
     */
    private $object;
Answer 1

Через запятую в targetEntity перечислить несколько сущностей нельзя - не забывайте что Вы ссылаетесь скорее всего на разные таблицы в БД.

Насколько я понял, вы хотите перечислить в targetEntity все сущности, под которыми Вы хотите размещать комментарии. Причем насколько я могу восстановить контекст по отрывку кода, данное поле и аннотация находятся в классе Comment.

Пофантазируем...

Теоритически можно сослаться на несколько разных сущностей, с помощью одного поля с помощью наследования. В Doctrine(ORM, которую использует Symfony) есть различные стратегии хранения иерархии классов, в том числе и такая, в которой всё дерево классов хранится в одной таблице, которая содержит объединение полей (т.е. множество всех полей всех классов) и при выборе элементов одного класса, выбираются только поля объявленные в данном классе и унаследованные от родителей(но не поля соседних классов).

Т.е. есть подобная иерархия классов:

Record  
      |--  Page
      |--  Post
      |--  News
      |--  Review
      |--  etc...

И Вы устанавливаете связь между классом Comment и родительским классом Record. Тогда Ваше поле с аннотацией сможет выглядеть следующим образом:

/**
 * @ORM\ManyToOne(targetEntity="Record", inversedBy="comments")
 * @ORM\JoinColumn(name="record_id", referencedColumnName="id")
 */
private $record;

Стоит отметить, что не стоит городить наследование, в случае где его быть не должно и хранить все сущности в одной таблице - это безумие. И даже если на момент реализации, несколько классов допустимо будет подогнать под одного предка, это не значит что в будущем не появится необходимости прикрутить комментарии к другой сущности, которая не имеет ничего общего с предыдущими. Поэтому данныый вариант, однозначно, отметается.

Возможен и обратный вариант с наследованием:

Comment  
      |--  CommentToPage
      |--  CommentToPost
      |--  CommentToNews
      |--  CommentToReview
      |--  etc...

В данном варианте классы Page, Post, News, Review, etc. не наследуются от единого предка и хранятся в разных таблицах, но разделены классы комментариев, в каждом из которых есть поля содержимого комментария и времени публикации, унаследованных от родительского класса Comment и по одному полю со ссылкой на конкретную сущность у каждого из дочерних классов(CommentToPage,etc.).

В таком случае в каждом классе будет поле со ссылкой:

class CommentToPage extends Comment{
    /**
     * @ORM\ManyToOne(targetEntity="Page", inversedBy="comments")
     * @ORM\JoinColumn(name="page_id", referencedColumnName="id")
     */
    private $page;
}
...
class CommentToPost extends Comment{
    /**
     * @ORM\ManyToOne(targetEntity="Post", inversedBy="comments")
     * @ORM\JoinColumn(name="post_id", referencedColumnName="id")
     */
    private $post;
}

Суровая реальность

На деле же, просмотрев огромное количество проектов убеждаюсь, что практически все считают, что "овчинка выделки не стоит", и не парятся с наследованием и хранением нескольких сущностей в одной таблице. Встречается два варианта:

1.Хранение в классе комментария нескольких ссылок(наиболее частый вариант):

class Comment{
    /**
     * @ORM\ManyToOne(targetEntity="Page", inversedBy="comments")
     * @ORM\JoinColumn(name="page_id", referencedColumnName="id")
     */
    private $page;
    //...
    /**
     * @ORM\ManyToOne(targetEntity="Post", inversedBy="comments")
     * @ORM\JoinColumn(name="post_id", referencedColumnName="id")
     */
    private $post;
}

2.Гораздо реже используют несколько классов комментариев, хранящихся в разных таблицах и естественно дублирующих поля содержимого комментария и времени.

В этом случае много копипасты и откровенно говоря придётся чуть больше постучать палчиками по клавиатуре, поэтому предыдущий вариант наиболее популярен.

Суть

Главное - понимать суть. А суть в том, что за всеми сущностями, классами и аннотациями стоят реальные таблицы в базе данных, поля которых ссылаются на строчки в других таблицах и имеют внешние ключи. Помня это и представляя структуру таблиц в базе данных будет проще создавать Сущности и связи между ними.

Напоследок несколько ссылок:

  • Doctrine: Association mapping
  • Doctrine: Inheritance mapping (Наследование)
READ ALSO
laravel как передать массив post в контроллер?

laravel как передать массив post в контроллер?

Вот что пытаюсь сделать в роутерах:

340
Реализация кроссдоменной авторизации

Реализация кроссдоменной авторизации

Есть сайт servicecom, выступающий в качестве точки авторизации для сайта mydomain

208
Symfony 3, форма из двух Entity классов

Symfony 3, форма из двух Entity классов

Здравствуйте! Есть два класса Entity, которые содержат разные полямне нужно сделать общую форма и потом соответственно записать данные в из формы...

220