ManyToMany Joins & When to Avoid ManyToMany

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

We have the N+1 query problem once again. Click to view those queries. The new queries are mixed in here, but you'll see 7 new queries that select from tag with an INNER JOIN so that it can find all the tags for just one Article. Each time we reference the tags for a new Article, it makes a new query for that article's tags.

This is quite possibly not something you need to worry about, at least, not until you can see a real performance issue on production. But, we should be able to fix it. The first query on this page finds all of the published articles. Could we add a join to that query to select the tag data all at once?

Totally! Open ArticleController and find the homepage() action. Right now, we're using $articles = $repository->findAllPublishedOrderedByNewest():

... lines 1 - 13
class ArticleController extends AbstractController
... lines 16 - 28
public function homepage(ArticleRepository $repository)
$articles = $repository->findAllPublishedOrderedByNewest();
... lines 32 - 35
... lines 37 - 63

Open ArticleRepository to check that out:

... lines 1 - 15
class ArticleRepository extends ServiceEntityRepository
... lines 18 - 22
* @return Article[]
public function findAllPublishedOrderedByNewest()
return $this->addIsPublishedQueryBuilder()
->orderBy('a.publishedAt', 'DESC')
... lines 34 - 56

This custom query finds the Article objects, but does not do any special joins. Let's add one. But.... wait. This is weird. If you think about the database, we're going to need to join twice. We first need a LEFT JOIN from article to article_tag. Then, we need a another JOIN from article_tag to tag so that we can select the tag's data.

This is where Doctrine's ManyToMany relationship really shines. Don't think at all about the join table. Instead, ->leftJoin() on a.tags and use t as the new alias:

... lines 1 - 15
class ArticleRepository extends ServiceEntityRepository
... lines 18 - 22
* @return Article[]
public function findAllPublishedOrderedByNewest()
return $this->addIsPublishedQueryBuilder()
->leftJoin('a.tags', 't')
... lines 30 - 33
... lines 36 - 58

The a.tags refers to the tags property on Article. And because Doctrine knows that this is a ManyToMany relationship, it knows how to join all the way over to tag. To actually fetch the tag data, use ->addSelect('t'):

... lines 1 - 15
class ArticleRepository extends ServiceEntityRepository
... lines 18 - 22
* @return Article[]
public function findAllPublishedOrderedByNewest()
return $this->addIsPublishedQueryBuilder()
->leftJoin('a.tags', 't')
... lines 31 - 33
... lines 36 - 58

That is it. Go back to our browser. The 15 queries are... back down to 8! Open the profiler to check them out. Awesome! The query selects everything from article and all the fields from tag. It can do that because it has both joins! That's nuts!

When a ManyToMany Relationship is Not What You Need

Ok guys, there is one last thing we need to talk about, and, it's a warning about ManyToMany relations.

What if we wanted to start saving the date of when an Article was given a Tag. Well, crap! We can't do that. We could record the date that a Tag was created or the date an Article was created, but we can't record the date when an Article was linked to a Tag. In fact, we can't save any extra data about this relationship.

Why? Because that data would need to live on this article_tag table. For example, we might want a third column called created_at. The problem is, when you use a ManyToMany relationship, you cannot add any more columns to the join table. It's just not possible.

This means that if, in the future, you do need to save extra data about the relationship, well, you're in trouble.

So, here's my advice: before you set up a ManyToMany relationship, you need to think hard and ask yourself a question:

Will I ever need to store additional metadata about this relationship?

If the answer is yes, if there's even one extra piece of data that you want to store, then you should not use a ManyToMany relationship. In fact, you can't use Doctrine at all, and you need to buy a new computer.

I'm kidding. If you need to store extra data on the article_tag table, then, instead, create a new ArticleTag entity for that table! That ArticleTag entity would have a ManyToOne relationship to Article and a ManyToOne relationship to Tag. This would effectively give you the exact same structure in the database. But now, thanks to the new ArticleTag entity, you're free to add whatever other fields you want.

If you generated a ManyToMany relationship by mistake and want to switch, it's not the end of the world. You can still create the new entity class and generate a migration so that you don't lose your existing data. But, if you can configure things in the beginning... well, even better.

Ok guys, you are now Doctrine pros! Your relationship skills strike fear at the heart of your enemies, and your ability to JOIN across tables is legendary among your co-workers.

Yes, there is more to learn, like how to write even more complex queries, and there are a lot of other, cool features - like Doctrine inheritance. But, all of the super important stuff that you need to create a real site? Yea, you got it down. So go out there, SELECT * FROM world, and build something amazing with Doctrine.

Alright guys, seeya next time.

Leave a comment!

  • 2020-03-25 Diego Aguiar

    Yea, you can add another entity for holding those relationships. Like a middle ware between your the order and everything related to the product

  • 2020-03-24 Niki

    Diego Aguiar I need in Order Product to make separate column "ProductModel" so it can be OrderID|Product|ProductModel

  • 2020-03-23 Diego Aguiar

    Ohh, so "ProductModel" is indeed an entity or your business? I thought it was just a DTO (Data transfer object). Hmm, what you can do is to wrap that relationship in another entity, something like ProductOrder and it will hold a reference to Order Product and ProductModel. And, in your Order you will have a collection of those ProductOrder's. Does it makes sense to you?

  • 2020-03-23 Niki

    I'll deserialize the info from the Json and i will query for the data.

    I need to store it because in my case every product has model

  • 2020-03-23 Diego Aguiar

    Hey Niki

    > Is it better option to use json field in orders entity and store data as array in this way [1:['product':'5','productmodel':'10']]?

    I don't think that's a good idea because it's going to be hard to make it work with Doctrine. The question here is why you need to store the ProductModel?

  • 2020-03-20 Niki

    I have a issue with shopping cart options.
    Orders entity has:
    -UserID (ManyToOne relation to User entity)
    -ProductID (ManyToMany relation to Product entity)
    -ProductModelID (ManyToMany relation to ProductModel Entity)

    User entity is standart.
    Product entity has only "ProductName" property
    ProductModel entity has only "ProductModelName" property

    I have two seperated tables which are:
    OrderID: 1, ProductID: 1

    OrderID: 1, ProductModelID: 1

    This is a example of the issue which I think can mess:

    id: 1, UserID: 1

    OrderID: 1, ProductID: 5
    OrderID: 1, ProductID: 6

    OrderID: 1, ProductModelID: 10
    OrderID: 1, ProductModelID: 17

    When a order has more than one product - product 5 must be productmodel 10, but i think it can mess up and display 17 instead, because it's related to order 1. Am I right or it's fine this way?

    Is it better option to use json field in orders entity and store data as array in this way [1:['product':'5','productmodel':'10']]?

  • 2019-09-23 Vladimir Sadicov

    Hey Rob

    IIRC for many to many relations to persist everything correctly is better to use DataTransformers for data linking.

    And once again about you situation, there is one limitation with color fields, sometime it can work unexpected because there is a Color Form type, but without deep investigation, I cannot say it for 100%


  • 2019-09-18 Rob

    I've searched for solutions for why I can't get a many to many relationship to persist using Symfony Forms. The tutorials for using Fixtures and the RandomReferences code works great but can't figure it out using forms.

  • 2019-09-17 Rob

    Hi Vladimir Sadicov , yes I used colors on my form field but something else is causing entity property not to bind. When using colors I get this runtime error: "Neither the property "colors" nor one of the methods "colors()", "getcolors()"/"iscolors()"/"hascolors()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView"."

  • 2019-09-16 Vladimir Sadicov

    Hey Rob

    Everything looks good except your color form field. It should be called colors as entity property you want to bind.


  • 2019-09-14 Rob

    I am setting up a many to many relationship following the Article to Tag entity example in the tutorial. I have the Fixture class setup as described and loading the fixtures sets the relationship as expected. However, I notice the Forms tutorial does not cover persisting the Article to Tag manyToMany relationship using a form; either for creating or editing a Article.

    So I have run into issue with my manyToMany between my Profile entity and Color entity. When I buildForm I get the error :

    "Neither the property "color" nor one of the methods "getColor()", "color()", "isColor()", "hasColor()", "__get()" exist and have public access in class "App\Entity\Profile".

    If I show my code below, perhaps you see where I am going wrong. Thanks in advance!


    class Profile
    * @ORM\ManyToMany(targetEntity="App\Entity\Color", inversedBy="profiles")
    private $colors;

    * @return Collection|Color[]
    public function getColors(): Collection
    return $this->colors;

    public function addColor(Color $color): self
    if (!$this->colors->contains($color)) {
    $this->colors[] = $color;

    return $this;

    public function removeColor(Color $color): self
    if ($this->colors->contains($color)) {

    return $this;


    class Color
    * @ORM\ManyToMany(targetEntity="App\Entity\Profile", mappedBy="colors")
    private $profiles;

    ProfileFormType BELOW

    class ProfileFormType extends AbstractType
    public function buildForm(FormBuilderInterface $builder, array $options)
    ->add('color', EntityType::class, [
    'class' => Color::class,
    'choice_label' => function(Color $color) {
    return sprintf('(%d) %s', $color->getId(), $color->getName());
    'placeholder' => 'Choose a color',
    'choices' => $this->colorRepository->findAllByName(),
    'invalid_message' => 'Symfony is too smart for your hacking!',

    _form.html.twig BELOW
    {{ form_start(profileForm) }}
    {{ form_row(profileForm.title, {
    label: 'Profile Title'
    }) }}
    {{ form_row(profileForm.color) }}
    {{ form_row(profileForm.content) }}
    {{ form_row( }}
    {{ form_end(profileForm) }}

  • 2019-07-09 Diego Aguiar

    Hey Alessandro!

    ​That's a very fair question :)

    ​When you are working with a ManyToMany relationship but you need to add extra fields, then, you can't use Doctrine's ManyToMany relationship anymore. What you need is a third entity which will join the other 2 and will hold the extra data per item. So, let's say you have entity A and B, and we will name the join-entity as "AB", so you will end up with a relationship as follows:
    A OneToMany AB
    B OneToMany AB

    Probably this answer may help you out to understand it a bit more:


  • 2019-07-08 Alessandro

    I have followed the tutorial but I cannot deny I am quite confused, although the tutorial is very well eplained.
    Basically I did manage to successfully create ManyToMany relationship that holds two columns, but I cannot figure out how to create a third one

    Basically I have a "User" table and "Social" table (that holds social media information in the form of id, name).

    Now, each User can have many socials and each social can have many users, but I also need to add an extra column that hold the url of that specific social, so the ManyToMany table would have something like "user_id, social_id, url".

    II tried to manually remove the ManyToMany table and create an entity called UserSocial, where the first property name is "user_Id" set it to ManyToOne relation and second to be "social_id" set to OneToMany with Social Entity, but I don't know if the method suggested by console "$user->getUserSocials()" is the appropriate one. When I created ManyToMany, the method called "$user->getSocials()" felt more appropriate.

    I really need some clarification, because my head is kind of exploding trying to figure out how it works.


  • 2019-07-04 weaverryan

    Hey Josan!

    Hmm, interesting! If you look at the query it generates at around time 2:34 ( ) it's a LEFT JOIN from article to article_tag, then another LEFT JOIN from article_tag to tag. Those two left joins should not change the number of results returned. I just tried this locally - after loading the database fixtures. Both with and without the query, I'm seeing 5 results on the homepage (of course, the exact number of published articles if you load the fixtures will be random).

    Can you take a look again to be sure that it's changing the number of results?


  • 2019-06-30 Josan

    By adding
    ->leftJoin('a.tags', 't')

    to the "findAllPublishedOrderedByNewest" function (in ArticleRepository), the articles returned on index.twig.html were reduced from 10 to 6!

    Is there any fix for this?

  • 2019-04-04 Krzysztof Krakowiak

    Thanks Ryan, I will investigate it tomorrow. I did different solution (works but don't like it), but after your answer I have realized that I need orphanRemoval.

    I did some tests and yes, it works as you explained, I have added these methods and mapped field definition to form.

    My previous solution was done with unmapped field, and then in controllers I had to run extra method to process that field from form.

    I am not sure what is the best solution here.

    I am thinking also about adding sensiolabs-de/rich-model-forms-bundle and do it with custom setter defined in configured in form, so there will be no need to do it in controller.

  • 2019-04-04 weaverryan

    Hey Krzysztof Krakowiak!

    I'm don't have full context, but I may be able to answer this last, direct question. You can do this by making custom getter, adder & remover methods to "fake" a traditional ManyToMany relationship. For example, in User, you could create a getAssets() method, which iterates over assignedAssets and returns the array of actual Asset objects. You would also create an addAsset(Asset $asset), which would create the AssignedAsset() and set it on the assignedAssets property. And finally, you would create a removeAsset(Asset $asset), which would find the correct AssignedAsset based on the Asset argument and remove it (you will probably need some orphanRemoval on the relationship for the AssignedAsset to be deleted correctly.

    If you do all of this and get it working, then, to the form system, it will *appear* like you have a ManyToMany relationship on User to Asset called "assets". It will be able to call getAssets(), addAsset() and removeAsset() just like a normal ManyToMany relationship.

    Let me know if that helps!


  • 2019-04-04 Krzysztof Krakowiak

    Mainly how can I tell Symfony: yes Symfony I have split this ManyToMany relation but please for Form rendering treat it like typical ManyToMany :D

  • 2019-04-04 Krzysztof Krakowiak

    This is all bad... resolving one problem creates another.... have split my Many to Many relation because in joining table i have an extra data and now I do not know how to render this split relation as a many to many relation in my form, relation is between User and Asset, so I have extra entity AssignedAsset, when I render:

    ->add('assignedAssets', null, [
    'multiple' => true,
    'label' => 'Assigned Assets',
    'attr' => [
    'size' => 12,

    I got blank, I do not know how to configure it to display entries form Asset table.

    Tested few things and nothing works...

  • 2019-01-11 Diego Aguiar

    Hey OutspOaken

    I think you are declaring the "LIMIT" clause in the wrong place, it should limit your outter SELECT instead of inner SELECT


  • 2019-01-11 OutspOaken

    Hello, thank you for the awesome course!

    I have a question about adding a LIMIT clause to this new query, how I can limit the number of articles retrieved from the database?

    Something like SELECT AS id_0, [...] t1_.updated_at AS updated_at_14 FROM article a0_ LEFT JOIN article_tag a2_ ON = a2_.article_id LEFT JOIN tag t1_ ON = a2_.tag_id WHERE in (SELECT id FROM article LIMIT 10 ORDER BY published_at DESC)

    Because if I simply add a setMaxResults(10) to the query, it stops retrieving results after 10 Tags, meaning our hydration is not complete since we didn't get our 10 articles.

  • 2018-12-17 Edin

    Another great course. Kudos!

  • 2018-11-01 weaverryan

    Nice find Jennifer Koenig! Thanks for sharing!

  • 2018-10-30 Jennifer Koenig

    It was a Symfony form problem after all: in my GroupFormType, in addition to specifying the entity type of the dropdown field as Group, I was implementing the configureOptions and setting the defaults data_class to Group as well, which Symfony did not like! Once I deleted this method from my GroupFormType and got rid of cascade persist, it worked as expected!

  • 2018-10-29 weaverryan

    Hey Jennifer Koenig!

    Hmm! This is a bit of a mystery! A few things to look into:

    1) You said "Ownership side is roles". So, the owning side os the Group.roles property, right? And in your form, it sounds like you are setting the Role.groups side of the relation (the inverse side). Did you generate the relationship with the make:entity command? That generated code "synchronizes" the owning side when you set the inverse side. Basically, I'm first just making sure that we're setting the owning side, at some point. Though that wouldn't entirely explain your weird behavior.

    2) You mentioned that you're selecting an existing group from a drop-down in a Symfony form. Is this a true, "select one" drop-down (using the EntityType)? If so, that's a slight mismatch (unless you have some additional code that's handling this). I'm assuming that this field in the form is called "groups". And, if you've set it to an EntityType where you just select one, then it will try to call setGroups() but only pass it *one* Group object. The problem is that we have an *array* of groups - not just one. So, in theory, that should be causing some issues as well.

    3) Setting the cascade option should have been an ok solution. But, because it seems to be causing some unexplained issues, I would recommend removing it. Then, in your controller, try persisting the groups manually. Something like:

    // after the form submit handling
    foreach ($role->getGroups() as $group) {

    In theory, that's what the cascade persist was doing anyways, but this could "shed some light" on things.

    Let me know what you find out!


  • 2018-10-29 Jennifer Koenig

    I have a many-to-many relationship between Roles (user roles) and Groups (user groups). Ownership side is roles. When I use the code suggested by the tutorial and try to add an existing group (selected from a dropdown) to a role over a Symfony form, I get the error that

    "A new entity was found through the relationship '...Entity\Role#groups' that was not configured to cascade persist operations for entity: 1. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"})."

    When I put cascade persist on the "groups" definition in "Role", however, the result is that a NEW, empty group is inserted into the group table, and this new id is saved with the selected role in the role_group table. WHY? The existing group disappears somewhere in the flush() operation...

  • 2018-09-25 weaverryan

    Hi there!

    The course download code has since been fixed - if you download the course code from this page, you will now not have any problems. If you ARE still having problems, post your exact error message here and we'll be happy to help.


  • 2018-09-22 Student

    I have similar error, please help to fix.

  • 2018-09-10 Diego Aguiar

    Hey LaserMcBlade

    For that case you can do something like this:

    $result = $qb
    ->leftJoin('a.comments', 'c')


  • 2018-09-09 LaserMcBlade

    I am curious how to get the comment count and reduce this page down to one query, all while using the same repository method - I am not clear on how to do this with the query builder / DQL and this is the type of thing I'd want to do all the time. Can DQL give us merely the count of a relation or do we need to rebuild the query from scratch with count(), join, and group by? We can use ->leftJoin('a.comments', 'c')->addSelect('c') but then we are retrieving all comment rows rather than just a count.

    This has been an amazing course, I learned so much, thank you to the KNP team!

    edit: I see we can do something like this:
    ->leftJoin('a.comments', 'c')
    but then we are returning an array of arrays rather than array of Articles, which seems to introduce more complications...

  • 2018-09-05 weaverryan

    Hey Karsten Krohn!

    Oh yea, *definitely* a bug... made by me :). The class is called ArticleFixtures (notice the s) - I made some changes, and messed that up! It's all better now - thanks for letting us know!


  • 2018-09-01 Karsten Krohn

    Thank for this great tutorial.

    After finishing the course, I downloaded the course-code and compared the "final"-folder with mine (because I had some minor issues with mine).
    In my environment, the "final" seems to be broken, because

    ./bin/console doctrine:fixtures:load

    throws an error:

    Fixture "App\DataFixtures\ArticleFixture" was declared as a dependency, but it should be added in fixture loader first.

    Is it just me, or may there be something wrong in the course-code?

    Thanks, Karsten

  • 2018-07-03 Victor Bocharsky

    Hey Greg,

    Thanks for sharing it! IIRC, by default DataTables load ALL the data and then paginate over the loaded data with JavaScript, i.e. it's not AJAX-based by default. But it can be configured to load data from the server by AJAX requests, so yeah, it may work for Yahya as well.


  • 2018-07-03 Greg is super-cool for JS pagination.

  • 2018-06-27 Diego Aguiar

    Ah man, thanks!

  • 2018-06-27 mouerr

    Victor Bocharsky Am waiting for the translations course, thank you.

  • 2018-06-27 mouerr

    Great Symfony Tutorials i ever found in the web, Thank you, you are the best.

  • 2018-06-26 Victor Bocharsky

    Hey Yahya,

    Thanks! :) Well, we're going to make an entire course about translations, it should be released soon. For other topics, some extensions from StofDoctrineExtensionsBundle we mention in our Symfony tutorials, use our updated search to find ones. About other ideas - would be cool to have screencasts about them too, and we have them in mind for the future, but I have no estimations when it may be released yet.

    > Another topic but is there AJAX based alternative to knp-paginator-bundle?

    I personally do not know any specific bundle, but we do talk about pagination in this course: . You may also check this screencast: . That's an API way to do pagination. But you can check some popular JS libs on GitHub that helps with infinite scroll, etc. Along with KnpPaginatorBundle or PagerfantaBundle you can implement it easy.


  • 2018-06-24 Yahya A. Erturan

    Great tutorials, thank you.

    Can you cover more topics, especially the ones most web developers encounter, navigation sortable trees, saving entities with translatable fields, versioning and logging best practices, and of course uploading media. I saw most of them in Stof Doctrine Extensions. However, you guys making everything easier then it really is :)

    Another topic but is there AJAX based alternative to knp-paginator-bundle?

    Thanks for all your help.

  • 2018-06-22 Victor Bocharsky

    Hey Etienne,

    Thanks for sharing this, good post.


  • 2018-06-22 Etienne Lp

    Hey again !

    Just to share with others, I read this article from @Iltar, that proposes the DTO pattern in order to avoiding entities in forms.

    Cheers !

  • 2018-06-21 Etienne Lp

    Hey weaverryan !

    Cool, I'm reassured now ! I think i will use most of the time this way instead of the Form Component (Unless Form could bring me cool stuff without to many complication for shure ;) )

    Thanks again,
    Love your tutorials !

  • 2018-06-20 weaverryan

    Hey Etienne Lp!

    Good job on the plural stuff :).

    > When you build a javascript front-end instead of form component, is there a trick when you wanna map the data to your entity in order to take advantage of the Validator component ? Or mb you simply hydrate your object by hand and then send it to the validator ?

    Yep, I would hydrate it by hand and send it to the validator. It's pretty easy. The only trick is that the validator returns errors in a "funny" format, so I usually need to loop over the errors and create an array that makes more sense to me. As an example, check out this code block - - expand the entire file, and look for getErrorsFromForm(). This uses the form, so using the validator will be a bit different. But, the idea will be the same: the Valdiator will return an "iterable" object (i.e. something you can loop over). You can loop over this to create a simple array.

    Btw, for the hydration part, you could use the form component or the serializer if your reading it a lot of data. But if you're doing something simple, just keep it simple and hydrate by hand.


  • 2018-06-20 Etienne Lp

    Hello weaverryan !

    Again... Thanks for your help. All works perfectly :)
    I also fixed my singular / plural, was confusing me.

    In your first comment you said :
    > "Btw, at some point, if your form became even more and more complex, it would be better to build a JavaScript front-end instead of using the form component"

    When you build a javascript front-end instead of form component, is there a trick when you wanna map the data to your entity in order to take advantage of the Validator component ? Or mb you simply hydrate your object by hand and then send it to the validator ?

    Cheers !

  • 2018-06-19 weaverryan

    Hey Etienne Lp!

    Bah, this was my fault! The code I gave you was wrong. It should be:

    $builder->add('userIndicators', CollectionType::class, [
    'entry_type' => UserIndicatorsFormType::class

    As you mentioned, userIndicators is an array (well, a collection object, but, for the form, it's the same thing: it is *many* UserIndicators objects, not just one). So, you need to use the CollectionType to render many of these. I totally meant to put this in my original code - sorry!

    > Note : Maybe not very important , but someone tell me that the composite primary keys are no longuer supported in Doctrine, should I instead add an ID autoincrement in `UsersIndicators` Entity ?

    I'm not sure if this is true or not, but I always add a normal primary key (i.e. do not use composite primary keys) because it just makes things simpler. I'm sure there's some minor cool things about having the composite primary keys... but I like making the entity act like all my other entities.


  • 2018-06-19 Etienne Lp

    Hey weaverryan,

    So much tanks for your answer !

    I changed my code in order to have the same as you expeted.
    I think i'm close to win this buuut, i got already the same error exception. I Know why it crashed but i dunno how to fix it.
    In my controller, the `$user` variable is an User Object. In this User Object (Entity), i got the property $userIndicators that map to the `UsersIndicators` Entity. BUT, this is an arrayCollection, and when i passed the $user Object to the Form, Symfony crash with :

    > "The form's view data is expected to be an instance of class App\Entity\UsersIndicators, but is an instance of class Doctrine\ORM\PersistentCollection. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Doctrine\ORM\PersistentCollection to an instance of App\Entity\UsersIndicators."

    Maybe i totally misunderstood something ?

    Note : Maybe not very important , but someone tell me that the composite primary keys are no longuer supported in Doctrine, should I instead add an ID autoincrement in `UsersIndicators` Entity ?

    Thanks again !

    Edit : Just in order to illustrate where I wanna go :

    Indicator 1 : checkbox (for displayed (boolean)) --- color picker (for color (string))
    Indicator 2 : checkbox (for displayed (boolean)) --- color picker (for color (string))
    Indicator 3 : checkbox (for displayed (boolean)) --- color picker (for color (string))

  • 2018-06-18 weaverryan

    Hey Etienne Lp!

    First, nice job setting up the OneToMany / ManyToOne relationships so that you can store your extra fields on the "middle" entity! Second, yep, *forms* are where things typically get really complex. In your case, fortunately, your form and your entities are actually pretty "close". I mean, you are trying to render a form with the same hierarchy and fields as your entities. And so, we should be able to build a form that does this pretty easily. Here is my advice:

    1) Create a form for your UserIndicators entity - e.g. UserIndicatorsFormType (I think you already did this, but just listing it for clarity). Give this two fields: color & displayed. And, set the data_class option to UserIndicators.

    2) Create a form for your User class first. I'm going to assume that the entire purpose of this form is to edit the "indicators", but not edit any other user information. In that case, you could have a EditIndicatorsUserFormType class. Inside, give it just one field (you can put other fields from your User if you want to): userIndicators (or whatever the property name is on User for the relationship). This field should look like this:

    $builder->add('userIndicators', UserIndicatorsFormType::class);

    3) Finally, in your controller, you will actually build the form around your User entity:

    $form = $this->createForm(EditIndicatorsUserFormType::class, $user);

    So, you're *actually* creating a form for your User, inside, we're modifying the userIndicators property.

    Let me know if this helps! Btw, at some point, if your form became even more and more complex, it would be better to build a JavaScript front-end instead of using the form component. But, from what you've told me, the form system should work great here.


  • 2018-06-18 Etienne Lp

    Hey , thanks for those tutorials !

    But got a question for you guys :

    My code :
    I got a relation OneToMany / ManyToOne : Entity User ==> Entity UsersIndicators <== Entity Indicator.
    (Note : I got a composite primary key in UsersIndicators on the properties "$user" and "$indicator" )
    The Entity "UsersIndicators" got extra fields like "$color" and "$displayed".

    My problem :
    I have trouble creating my form.
    I need to create a Form that, for a connected User, a list of his Indicators are displayed and for each indicator, the user could select the color (string), and if if want to display it (boolean). Not to add or delete indicators.

    I try to create a formType for the UsersIndicators Entity, but in my Controller, when i createForm with the FormType, i passed at the second argument the $userIndicator propertie of the User Entity. This is actually an ArrayCollection of UsersIndicators !

    Symfony tells me, in the exception, to add a viewTransformer but i'm a little lost...
    Any idea ?

    Thanks in advance

  • 2018-05-15 Victor Bocharsky

    Hey Matt,

    Not sure about adding more chapters to this course, this one is *almost* the final list, but we may tweak or add something during releasing videos if we'll have some ideas, so it's difficult to say 100% :)

    Yeah, definitely we're going to release new Symfony 4 related courses, we do not talk about Symfony Forms yet, etc. But we're also going to release ReactJS course soon which will be built on Symfony 4 of course.


  • 2018-05-14 Matt Johnson

    Thanks, Victor. You guys are really cranking through them!

    So, will there be more steps added to this course or will the next update to the Symfony4 series be a course after this one?

  • 2018-05-14 Victor Bocharsky

    Hey Matt,

    We're working on this and further chapters right now, as soon as they are ready - we'll release them! And yeah, good question! Actually, I'm working on refactoring these notifications system right now, when this feature is deployed (should be soon) you will have 2 notifications for subscribed courses: one when the 1st chapter is published and another one when the the course is completely released (i.e. all chapters are released).

    We're trying to release new videos each day, so probably email users every day about new videos would be too often and smell spammy :) Thanks for understanding!

    But if you want to get notifications about each chapter, we actually have some kind of them already, you can check our "Course Updates" page: .


  • 2018-05-12 Matt Johnson

    Guess that's the end of the road for now! I saw the "notified when course is completed" option, but will there be a way to get notifications when more of these incomplete sections are added?