Symfony2 & Doctrine2: ManyToMany Association


Quick ref: Let’s say you have 2 Entities, one is called Author and the other Book, one author can have many books, and one book can have many Authors, you will need a ManyToMany association. So in your Author Entity class you put this annotation:

–The Annotation:

#Inside the Author.php class

    /**
     * @orm:ManyToMany(targetEntity="Book", cascade={"persist"})
     */
    private $book; //this will contain a Collection of many Book objects

— Database Creation & Stub Methods auto-generation

That’s it, now, according to the default behaviour, after executing this (which creates the tables):

php app/console doctrine:schema:create

Your database will now have (in this example) 3 tables, one named author, book and one called author_book. This last table is the one that will store the relation between author and book. Now you need to auto-generate the stub methods:

php app/console doctrine:generate:entities YourAppYourBundle

After that, you will have a method called  addBook and getBook, and if you look at the source code, you will see that the book property is a collection of Book entities. This will also rename your original classes and prefix them with a ~ sign. You can delete this fiels after creation of the final classes, if not, you will get a “cant redeclare class” bullshit when calling generate entities again.


–Example

Now, if you can (this code you can test it inside a controller’s action):

       $em = $this->get("doctrine.orm.entity_manager");

    	$book1= new Book();
    	$book1->setName("The Naked Sun");

    	$book2 = new Book();
    	$book2->setName("The Robots of Dawn");

    	$author = new Author();
    	$author->setName("Isaac Asimov");

    	$author->addBook($book1);
    	$author->addBook($book2);

// Saving the author ( this will also save the Books, because of the "cascade={'persist'}" attribute on the annotation)
    	$em->persist(author); //<- Note how we only save the author! Doctrine then makes all the dirty work for us!
    	$em->flush();

Now, when retrieving the author a property called ->getBook() will give you a Collection of Book objects:

        $issac_asimov = $em->find('YourAppYourBundle:User', 1);
        $issac_asimov->getBook(); //this will have all the books from this author.

PS: the $em->find method internally calls the default EntityRepository for the entity if no custom was defined on the annotations, which in turn returns an User entity based on the id: 1

Advertisements