Search code examples
formssymfonycheckboxinsertmany-to-many

Symfony 2.8 many-to-many insert into db multiple checkboxes


I have two entities - Book and Genre (many to many relationship). Book entity:

/**
* @ORM\ManyToMany(targetEntity="Genre", mappedBy="books")
*/
private $genres;

Genre entity:

/**
* @ORM\ManyToMany(targetEntity="Book", inversedBy="genres")
* @ORM\JoinTable(name="genres_books")
*/
private $books;

In my BookType form I want to assign the book to many genres (particular book can be crime and thriller or biography and history or whatever). BookType:

    ->add('genres', EntityType::class, array(
        'label' => 'Genres',
        'class' => 'MyBundle:Genre',
        'choice_label' => 'name',
        'expanded' => true,
        'multiple' => true,
        'required' => false           
    ));

Setters/getters:

Book

/**
 * Add genres
 *
 * @param \MyBundle\Entity\Genre $genres
 * @return Book
 */
public function addGenre(\MyBundle\Entity\Genre $genres)
{
    $this->genres[] = $genres;

    return $this;
}

/**
 * Remove genres
 *
 * @param \MyBundle\Entity\Genre $genres
 */
public function removeGenre(\MyBundle\Entity\Genre $genres)
{
    $this->genres->removeElement($genres);
}

/**
 * Get genres
 *
 * @return \Doctrine\Common\Collections\Collection 
 */
public function getGenres()
{
    return $this->genres;
}

Genre

/**
 * Add books
 *
 * @param \MyBundle\Entity\Book $books
 * @return Genre
 */
public function addBook(\MyBundle\Entity\Book $books)
{
    $this->books[] = $books;

    return $this;
}

/**
 * Remove books
 *
 * @param \MyBundle\Entity\Book $books
 */
public function removeBook(\MyBundle\Entity\Book $books)
{
    $this->books->removeElement($books);
}

/**
 * Get books
 *
 * @return \Doctrine\Common\Collections\Collection 
 */
public function getBooks()
{
    return $this->books;
}

The form is submitted without any errors (new book is added with all the values except the genre(s)) but I can't establish the relationship - table genres_books is empty after the form is submitted. What's wrong? Thanks in advance.

Edit - BookController:

/**
 * Creates a new book entity.
 *
 * @Route("/new", name="book_new")
 * @Method({"GET", "POST"})
 */
public function newAction(Request $request)
{
    $book = new Book();
    $form = $this->createForm('MyBundle\Form\BookType', $book);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {           
        $this->getDoctrine()->getManager()->persist($book);
        $this->getDoctrine()->getManager()->flush($book);

        return $this->redirectToRoute('book_show', array('id' => $book->getId()));
    }

    return $this->render('book/new.html.twig', array(
        'book' => $book,
        'form' => $form->createView(),
    ));
}

Solution

  • To be able to persist genres in this setup you have to change owning side of relation.

    Book entity:

    /**
     * @ORM\ManyToMany(targetEntity="Genre", inversedBy="books")
     * @ORM\JoinTable(name="genres_books")
     */
    private $genres;
    

    Genre entity:

    /**
     * @ORM\ManyToMany(targetEntity="Book", mappedBy="genres")
     */
    private $books;
    

    Tested on Symfony 3.2.6