Symfony2 ManytoMany bidirectional relationship - H

2020-06-23 06:12发布

I am working on a form with 2 input fields and a submit button. The first field is a simple dropdown (Category) but the other one is a tags-input field(Tag) where u can enter multiple tags at a time. Both fields accept predefined input options only.

The category option values are hardcoded in javascript:

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

The options for tag are fetched from the tag table in the database. Here is the screenshot of the database tables:

enter image description here

The Category and Tag entities are associated with Doctrine's ManytoMany bidirectional relationship, with category being the owning side.

Note: I am not using Symfony formType to create the form, instead I've used javascript for that.

The javascript works fine and I get the input data in my controller. Problem is that i've never persisted a ManytoMany relation manually. Did read the docs but not sure if I missed anything.

Here is the Tag entity (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;
    }
}

Here is the Category entity (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;
    }

}

Here is the controller(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();
}

The $form_data is an array with the input category and added tags detail. It looks like this:

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

Still it doesn't persist. The var_dump($category); display the selected category object with category id and categoryname, but the associated tags property is empty.

Here is the screenshot of the output:

enter image description here

Any Ideas?

Quick question on the side: Do I need to add cascade={"persist"} to both the sides of relationship definition here?

EDIT: Here, I've hard-coded $form_data instead of using input data as I did above. The 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();
    }

The controller output:

enter image description here

As you can see the tags property of the category object is still empty.

Hope this'll help understand the issue better. Awaiting response...

1条回答
霸刀☆藐视天下
2楼-- · 2020-06-23 06:23

When getting the appropriate tag entity by doing

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

Isn't the value of $tag an array of collections?

So possibly do the following?

    $category->addTag($tag[0]);
查看更多
登录 后发表回答