Сохранение отношения Many to Many к базе данных в Symfony2
В моем проекте Symfony2 у меня есть два связанных объекта: "Пользователи" и "Избранное". У них есть отношения "многие-ко-многим".
Мое приложение работает следующим образом:
На моей Twig-странице у меня есть несколько элементов с кнопкой "Добавить в избранное". Когда вы нажимаете кнопку, мой контроллер сохраняет item_id в столбце "Избранное". Но потом я хочу сэкономить
пользователь, который добавил элемент в избранное, и здесь мое приложение не работает.
Пользователь и избранное существуют, но joincolumn между Users и Favorites остается пустым.
Я также не получаю никаких ошибок.
Вот мой код:
Entity Users
class Users implements AdvancedUserInterface
{
/**
* @var \Doctrine\Common\Collections\ArrayCollection
*
* @ORM\ManyToMany(targetEntity="Favorites", inversedBy="user", cascade={"persist"})
* @ORM\JoinTable(name="user_has_favorite",
* joinColumns={
* @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="favorite_id", referencedColumnName="favorite_id")
* }
* )
*/
private $favorite;
public function __construct()
{
$this->favorite = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addFavorite(\Geo\CityTroopersBundle\Entity\Favorites $favorite)
{
$this->favorite[] = $favorite;
return $this;
}
...
Избранное объектов
class Favorites
{
/**
* @var \Doctrine\Common\Collections\ArrayCollection
*
* @ORM\ManyToMany(targetEntity="Users", mappedBy="favorite", cascade={"persist"})
*/
private $user;
public function __construct()
{
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addUser(\Geo\CityTroopersBundle\Entity\Users $user)
{
$this->user[] = $user;
return $this;
}
Мой контроллер
public function showNewsAction()
{
$request = $this->get('request');
$itemId=$request->request->get('itemId');
if($itemId != NULL)
{
//MAKE NEW FAVORITE AND ADD TO DATABASE LINKED WITH ITEM
$favorite = new Favorites();
$favorite->setItemId($itemId);
//LINK FAVORITE ID WITH USER ID IN JOINCOLUMN
$userId = 6;
$em = $this->getDoctrine()->getEntityManager();
$user = $em->getRepository('GeoCityTroopersBundle:Users')->find($userId);
$favorite->addUser($user);
$em->persist($favorite);
//I TRIED THIS TOO, BUT IT FAILED
/*$user->addFavorite($favorite);
$em->persist($user);*/
$em->flush();
Ответы
Ответ 1
Ты был рядом. Для отношений доктрины "многие-ко-многим" вам нужно вызвать оба метода добавления
$favorite->addUser($user);
$user->addFavorite($favorite);
$em->persist($favorite);
$em->persist($user);
$em->flush();
Это должно сделать трюк. В docs они делают это, но не упоминайте об этом слишком явно. Не уверен, почему либо потому, что многие люди сталкиваются с этим (включая меня).
Ответ 2
Как объясняется здесь, ответственность за управление соединением несет только собственная сторона:
http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html#owning-and-inverse-side-on-a-manytomany-association
Так что только
$user->addFavorite($favorite);
должен сохраняться, а не
$favorite->addUser($user);
Ответ 3
Как указано Седриком, добавление записи для отношения многих ко многим осуществляется только в одном направлении, и это зависит от того, как вы определили отношение: добавление может выполняться только родительским объектом отношения, поэтому в вашем случае вы должны использовать:
$user->addFavorite($favorite);
Ответ 4
В вашей строке:
@ORM\JoinColumn(name="favorite_id", referencedColumnName="favorite_id")
name="favorite_id"
Часть относится к столбцам в таблице соединений, тогда как
referencedColumnName="favorite_id"
ссылается на идентификатор в любимой таблице, который обычно является просто "id". Вы должны попробовать:
/**
* @var \Doctrine\Common\Collections\ArrayCollection
*
* @ORM\ManyToMany(targetEntity="Favorites", inversedBy="user", cascade={"persist"})
* @ORM\JoinTable(name="user_has_favorite",
* joinColumns={
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="favorite_id", referencedColumnName="id")
* }
* )
*/
private $favorite;