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
pascal 9:43 AM on 21 June 2011 Permalink |
Thanks for the simple example.. I find doctrine2 doc missing examples/tutorials…
Tobias 12:58 PM on 7 July 2011 Permalink |
Great post. I really like the magic with the php app/console doctrine:generate:entities YourAppYourBundle command
manu 10:28 AM on 13 July 2011 Permalink |
So… the link table is generated by doctrine ? What if I want to add fields in it ?
manu 10:43 AM on 13 July 2011 Permalink |
Oh I see. “Foreign keys as identifiers are currently in master and will be included in Doctrine 2.1″
Luke 4:52 AM on 11 October 2011 Permalink |
Does this generate an additional association class? I also need to add an additional attribute to my join table
Cethy 10:23 AM on 28 October 2011 Permalink |
@Luke & manu : You need to make a one2many2one (1:*:1) relation. As in doctrine1, doctrine2 does not support this kind of stuff yet.
Matteo 6:56 PM on 18 November 2011 Permalink |
Two times I have needed about Symfony2, and two times I have found solution here. Great blog!
Permana Jayanta 11:46 PM on 8 January 2013 Permalink |
And where is the Book Entity? Sorry, I’m a little bit noob here