Symfony2 ManytoMany двунаправленное отношение – как сохранить вручную

Я работаю над формой с двумя полями ввода и кнопкой отправки. Первое поле – это простое раскрывающееся меню (категория), а другое – поле ввода тегов (тег), в котором вы можете одновременно вводить несколько тегов. Оба поля принимают только предопределенные параметры ввода.

Значения параметров категории жестко закодированы в javascript:

categories = [ {"id": 1, "categoryname": "standard"}, {"id": 2, "categoryname": "premium"}, {"id": 3, "categoryname": "gold"} ]; 

Параметры тега извлекаются из таблицы tag в базе данных. Вот скриншот таблиц базы данных:

введите описание изображения здесь

Объекты Category и Tag связаны с двунаправленным отношением Dootrine ManytoMany, причем категория является стороной, владеющей.

Примечание . Я не использую Symfony formType для создания формы, вместо этого я использовал javascript для этого.

Javascript отлично работает, и я получаю входные данные в своем контроллере. Проблема в том, что я никогда не сохранял отношения ManytoMany вручную. Прочитал документы, но не уверен, что я что-то пропустил.

Вот объект Tag ( Tag.php ):

 <?php namespace AppBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use AppBundle\Entity\Category; /** * Tag * * @ORM\Table(name="tag") * @ORM\Entity(repositoryClass="AppBundle\Repository\TagRepository") */ class Tag { /** * @var int * * @ORM\Column(name="Id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * * @var string * * @ORM\Column(name="TagName", type="string") */ protected $tagname; /** * @ORM\ManyToMany(targetEntity="Category", mappedBy="tags") */ protected $categories; /** * @return ArrayCollection */ public function __construct() { $this->categories = new ArrayCollection(); } /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set id * * @return Tag */ public function setId($id) { return $this->id = $id; } /** * Set tagname * * @param string $tagname * @return Tag */ public function setTagname($tagname) { $this->tagname = $tagname; return $this; } /** * Get tagname * * @return string */ public function getTagname() { return $this->tagname; } /** * Add categories * * @param \AppBundle\Entity\Category $categories * @return Tag */ public function addCategory(\AppBundle\Entity\Category $categories) { $this->categories[] = $categories; return $this; } /** * Remove categories * * @param \AppBundle\Entity\Category $categories */ public function removeCategory(\AppBundle\Entity\Category $categories) { $this->categories->removeElement($categories); } /** * Get categories * * @return \Doctrine\Common\Collections\Collection */ public function getCategories() { return $this->categories; } } - <?php namespace AppBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use AppBundle\Entity\Category; /** * Tag * * @ORM\Table(name="tag") * @ORM\Entity(repositoryClass="AppBundle\Repository\TagRepository") */ class Tag { /** * @var int * * @ORM\Column(name="Id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * * @var string * * @ORM\Column(name="TagName", type="string") */ protected $tagname; /** * @ORM\ManyToMany(targetEntity="Category", mappedBy="tags") */ protected $categories; /** * @return ArrayCollection */ public function __construct() { $this->categories = new ArrayCollection(); } /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set id * * @return Tag */ public function setId($id) { return $this->id = $id; } /** * Set tagname * * @param string $tagname * @return Tag */ public function setTagname($tagname) { $this->tagname = $tagname; return $this; } /** * Get tagname * * @return string */ public function getTagname() { return $this->tagname; } /** * Add categories * * @param \AppBundle\Entity\Category $categories * @return Tag */ public function addCategory(\AppBundle\Entity\Category $categories) { $this->categories[] = $categories; return $this; } /** * Remove categories * * @param \AppBundle\Entity\Category $categories */ public function removeCategory(\AppBundle\Entity\Category $categories) { $this->categories->removeElement($categories); } /** * Get categories * * @return \Doctrine\Common\Collections\Collection */ public function getCategories() { return $this->categories; } } 

Вот объект Category.php ( Category.php ):

 <?php namespace AppBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use AppBundle\Entity\Tag; /** * Category * * @ORM\Table(name="category") * @ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository") */ class Category { /** * @var int * * @ORM\Column(name="Id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * * @var string * * @ORM\Column(name="CategoryName", type="string") */ protected $categoryname; /** * * @var string * * @ORM\Column(name="Description", type="string") */ protected $description; /** * @ORM\ManyToMany(targetEntity="Tag", cascade={"persist"}, inversedBy="categories") */ protected $tags; /** * @return ArrayCollection */ public function __construct() { $this->tags = new ArrayCollection(); } /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set id * * @return Category */ public function setId($id) { return $this->id = $id; } /** * Set categoryname * * @param string $categoryname * @return Category */ public function setCategoryname($categoryname) { $this->categoryname = $categoryname; return $this; } /** * Get categoryname * * @return string */ public function getCategoryname() { return $this->categoryname; } /** * Set description * * @param string $description * @return Category */ public function setDescription($description) { $this->description = $description; return $this; } /** * Get description * * @return string */ public function getDescription() { return $this->description; } /** * Add tags * * @param \AppBundle\Entity\Tag $tags * @return Category */ public function addTag(\AppBundle\Entity\Tag $tags) { $this->tags[] = $tags; return $this; } /** * Remove tags * * @param \AppBundle\Entity\Tag $tags */ public function removeTag(\AppBundle\Entity\Tag $tags) { $this->tags->removeElement($tags); } /** * Get tags * * @return \Doctrine\Common\Collections\Collection */ public function getTags() { return $this->tags; } } - <?php namespace AppBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use AppBundle\Entity\Tag; /** * Category * * @ORM\Table(name="category") * @ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository") */ class Category { /** * @var int * * @ORM\Column(name="Id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * * @var string * * @ORM\Column(name="CategoryName", type="string") */ protected $categoryname; /** * * @var string * * @ORM\Column(name="Description", type="string") */ protected $description; /** * @ORM\ManyToMany(targetEntity="Tag", cascade={"persist"}, inversedBy="categories") */ protected $tags; /** * @return ArrayCollection */ public function __construct() { $this->tags = new ArrayCollection(); } /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set id * * @return Category */ public function setId($id) { return $this->id = $id; } /** * Set categoryname * * @param string $categoryname * @return Category */ public function setCategoryname($categoryname) { $this->categoryname = $categoryname; return $this; } /** * Get categoryname * * @return string */ public function getCategoryname() { return $this->categoryname; } /** * Set description * * @param string $description * @return Category */ public function setDescription($description) { $this->description = $description; return $this; } /** * Get description * * @return string */ public function getDescription() { return $this->description; } /** * Add tags * * @param \AppBundle\Entity\Tag $tags * @return Category */ public function addTag(\AppBundle\Entity\Tag $tags) { $this->tags[] = $tags; return $this; } /** * Remove tags * * @param \AppBundle\Entity\Tag $tags */ public function removeTag(\AppBundle\Entity\Tag $tags) { $this->tags->removeElement($tags); } /** * Get tags * * @return \Doctrine\Common\Collections\Collection */ public function getTags() { return $this->tags; } } 

Вот контроллер ( DefaultController.php ):

 /** * @Route("/formsubmit", options={"expose"=true}, name="my_route_to_submit") */ public function submitAction(Request $request) { $jsonString = file_get_contents('php://input'); $form_data = json_decode($jsonString, true); $em = $this->getDoctrine()->getManager(); // set category details $categoryId = $form_data[0]['id']; $category = $em->getRepository('AppBundle:Category')->findOneById($categoryId); // set tags $len = count($form_data[1]); for ($i = 0; $i < $len; $i++) { $tagId = $form_data[1][$i]['id']; $tag = $em->getRepository('AppBundle:Tag')->findOneById($tagId); $category->addTag($tag); } // persist/save in database $em->persist($category); $em->flush(); } 

$form_data – это массив с категорией ввода и добавлением тегов. Это выглядит так:

 $form_data = [ ['id' => 3, 'categoryname' => 'gold'], [ ['id' => 1, 'tagname' => 'wifi'], ['id' => 4, 'tagname' => 'geyser'], ['id' => 2, 'tagname' => 'cable'] ] ]; 

Тем не менее это не сохраняется. var_dump($category); отобразите выбранный объект категории с id категории и id categoryname , но свойство связанных tags пусто.

Вот снимок экрана:

введите описание изображения здесь

Есть идеи?

Быстрый вопрос на стороне : мне нужно добавить cascade={"persist"} в обе стороны определения отношения здесь?

EDIT: Здесь я жестко закодировал $form_data вместо использования входных данных, как я сделал выше. DefaultController.php :

  /** * @Route("/formsubmit", options={"expose"=true}, name="my_route_to_submit") */ public function submitAction(Request $request) { $form_data = [ ['id' => 3, 'categoryname' => 'gold'], [ ['id' => 1, 'tagname' => 'wifi'], ['id' => 4, 'tagname' => 'geyser'], ['id' => 2, 'tagname' => 'cable'] ] ]; $em = $this->getDoctrine()->getManager(); // set category details $categoryId = $form_data[0]['id']; $category = $em->getRepository('AppBundle:Category')->findOneById($categoryId); // set tags $len = count($form_data[1]); for ($i = 0; $i < $len; $i++) { $tagId = $form_data[1][$i]['id']; $tag = $em->getRepository('AppBundle:Tag')->findOneById($tagId); // $tag->addCategory($category); $category->addTag($tag); } var_dump($category); exit; // persist/save in database $em->persist($category); $em->flush(); } 

Выход контроллера:

введите описание изображения здесь

Как вы видите, свойство tags объекта категории по-прежнему пуст.

Надеюсь, это поможет лучше понять проблему. В ожидании ответа…

При получении соответствующего объекта тега путем выполнения

  $tag = $em->getRepository('AppBundle:Tag')->findOneById($tagId); 

Разве значение $ tag не является массивом коллекций?

Так что, возможно, выполните следующее?

  $category->addTag($tag[0]);