Managing Tags in ManyToMany association with Symfony

Symfony: v3.1.3
Doctrine: v2.5.4

One of the things I found challenging when first working with Symfony was form collections. The Symfony documentation on how to embed a collection of forms as well as how to work with Doctrine associations / relations is a great place to get started. However, checking out other use cases people shared online really helped as well, so I’m going to share another example here which I hope might help others.

For the following example, I will be setting up a Product entity, and a Tag entity. One Product can have multiple Tags, and one Tag can have multiple Products (Many To Many). Here’s how I want it to work:

  • New Tags can be added when adding/editing a Product.
  • No duplicate Tags should be added to the tag table.
  • If this Product is deleted later, any Tag which was added with it should remain in the database.
  • Use the jQuery Tag-it plugin to add the tags to our form for submission.

Ok, let’s get started with our Product entity:

Then, the Tag entity:

A quick note about this line in my Product.php file:

@ORM\ManyToMany(targetEntity="Tag", inversedBy="products", cascade={"persist"})

I decided to pick Product as the owning side in this association, as Tags will only be created when a Product is added or edited. As you can see in the Doctrine documentation you can choose the owning side in a ManyToMany association. You do so by setting “inversedBy” to it, while setting “mappedBy” to the inverse side.

targetEntity  is the class which is your target: Tag

inversedBy  is the property used in the Tag entity for Products (line 27 in Tag.php): products

cascade={"persist"}  will automatically persist any Tags associated to this Product.

As far as the Tag.php file goes, you set  Product  as its targetEntity , and since Tag will be the inverse side in this association, you set  mappedBy  to the property in the Product entity used for Tags (line 27 in Product.php): tags

With that setup, you can run this to generate your getters and setters:

$ php bin/console doctrine:generate:entities AppBundle

The final result of both entities should look like this:

Product.php

Tag.php

Note that both the $tags  and $products  properties need to be set as an ArrayCollection in the constructor. This is explained in the Symfony documentation linked to in the beginning of this article on form collections.

Last but not least, we need to update our database by running:

$ php bin/console doctrine:schema:update –force

If all goes well, then you should see a friendly little message like this afterwards:

Doctrine schema update

You should now have 3 tables added to your database:

phpMyAdmin screenshot

We will setup our forms in the next article: Setting up Form Collection for Tags in Symfony