Mastering Doctrine Relations!


What you'll be learning

In the part 1 of the Doctrine Tutorial we created a freakin' awesome setup: with Doctrine: entities, queries, migrations and fixtures.

But, we're missing a big, giant, huge, important piece! Database relations! And once you've mastered these, you'll be unstoppable! But... a lot of information out there make Doctrine relations look over-complicated. And actually, they're simple and beautiful, especially with some recent changes in Symfony 4:

  • Generating a ManyToOne relationship (association)
  • The annotations for a relation
  • The OneToMany inverse side of a relation
  • Referencing objects across fixture classes
  • The owning versus inverse sides of a relation
  • Doing magic with the ArrayCollection (Criteria)
  • Querying with Joins
  • ManyToMany Relations
  • Pagination!

Help us bring "The Space Bar" app to the galaxy, with, (inter) stellar database relations. Yep, that's the level of humor you can expect!

Your Guides

Ryan Weaver

Buy Access

Questions? Conversation?

  • 2019-11-19 Lydie

    Many thanks for this great explanation !!! That was important for me to understand the reason to continue to improve my knowledge on symfony.

  • 2019-11-18 weaverryan

    Hey Lydie !

    Bahhh, sorry about my slow reply! I was *just* finally working through some things - it's SymfonyCon week, so we're a little extra busy. Anyways, I'm super happy you got it sorted! (And sorry about the SPAM issue - that's lame).

    Let me give you a bit of context on "why" this was all happening... in case it's useful :). When you store the Cart object in the session (which is a totally legal thing to do!) something funny happens the next time you "fetch" it out of the cart. Here is the flow:

    A) Request 1: you create a Cart object and insert it into the database. It gets id 1!
    B) Request 1: you then put that Cart in the session
    // 2 minutes go by, user adds another Product to their Cart
    C) Request 2: you fetch the Cart out of the session. It is (of course) id 1.

    This is enough to describe the issue. When you are on that "second" request (step C), Doctrine has not queried for the Cart object *on that request*. Doctrine keeps track of all the objects it has saved or queried for during a request (so that if you query for the same object twice, it skips making a 2nd query and just gives you back the same object). But this is NOT the same request as steps (A) and (B). And so, when you persist/flush the Cart object, Doctrine "thinks" it's a *new* object and *inserts* it. The key to understand why is this: when Doctrine tries to determine whether an object should be updated in the database versus inserted, it does *not* simply check to see if the object (e.g. Cart) has an "id" or not. Nope, it checks its "identity map" - which is a fancy way of saying - it asks itself: "Have I queried for or saved this object on this request?". If it has, then it knows about it and updates it. If it has not, then it tries to insert it (also, in this situation, it requires you to call persist() - which is the reason for the original error).

    Phew! So actually, one solution is to store the Cart id in the session, not the entire object. We do something similar here on SfCasts - we only store the cart "id". We have a CartManager service, however, that helps us get the object. Basically, we all $cartManager->getCart() and IT takes care to read the cart "id" from the session, query for it, and return it. So we avoid the problem and still get a really nice user experience where we don't need to worry about querying for the Cart in the controller.

    I hope this helps - even if it wasn't as timely as I would have liked!


  • 2019-11-18 Lydie

    I have finally changed my way of doing things. Before adding a product in the cart, I get it again from the db (to get the latest information in case for ex the price has changed) and then add it to the cart:

    So my code becomes:

    $items = $this->session->get( 'shoppingCart/items' );
    foreach ( $items as $item ) {
    $cartProduct = new CartProduct();
    // get the latest information about the product saved in database
    $product = $product_repository->findOneBy([
    'id' => $item['product'],
    'isDeleted' => 0,
    'isEnabled' => 1
    if (!empty($product)) {
    $cartProduct->setProduct( $product );
    $cartProduct->setQuantity( $item['qty'] );
    $cart->addProducts( $cartProduct );

    $em->persist( $cart );


  • 2019-11-18 Lydie

    weaverryan ,

    No idea of what could be the issue here?
    Thx !

  • 2019-11-14 Lydie

    Huh my comments were removed because they were detected as spams. Maybe because of the stack trace. Let me post the message without :)

    The Cart class:

    * @ORM\OneToMany(
    * targetEntity="App\Entity\CartProduct",
    * mappedBy="cart",
    * )
    private $products;

    The cart object is created and saved to database based on products saved in session. Below the way I used to save products in session:

    $items[$product->getId()] = [
    'product' => $product,
    'qty' => $request->request->get('add_item_to_cart')['quantity']
    $this->session->set('shoppingCart/items', $items);

    The CartProduct class:

    * @ORM\ManyToOne(targetEntity="App\Entity\Cart", inversedBy="products")
    * @ORM\JoinColumn(nullable=false)
    private $cart;

    * @ORM\ManyToOne(targetEntity="App\Entity\Product")
    * @ORM\JoinColumn(
    * nullable=false
    * )
    private $product;

    In the cart controller:

    $items = $this->session->get( 'shoppingCart/items' );
    foreach ( $items as $item ) {
    $product = new CartProduct();
    $product->setProduct( $item['product'] );
    $product->setQuantity( $item['qty'] );
    $em->persist( $product );
    $cart->addProducts( $product );

    $em->persist( $cart );

    The $item['product'] is a Product object.

    Hope this helps :)

  • 2019-11-13 Lydie

    Hi weaverryan !

    Thx for helping! To answer to your questions:

    1) No, nothing special in my code.
    2) Let me try to explain what I am trying to do. The user add products to a cart. This is kept in session:

    // add the new item in cart
    $items[$product->getId()] = [
    'product' => $product,
    'qty' => $request->request->get('add_item_to_cart')['quantity']
    $this->session->set('shoppingCart/items', $items);

    When the user starts the payment process, this cart is saved to database:

    $cart = new Cart();
    $cart->setUser( $user );
    $items = $this->session->get( 'shoppingCart/items' );
    foreach ( $items as $item ) {
    $product = new CartProduct();
    $product->setProduct( $item['product'] );
    $product->setQuantity( $item['qty'] );
    $em->persist( $product );
    $cart->addProducts( $product );

    $em->persist( $cart );

    The Cart class:

    * @ORM\OneToMany(
    * targetEntity="App\Entity\CartProduct",
    * mappedBy="cart",
    * )
    private $products;

    The CartProduct class:

    * @ORM\ManyToOne(targetEntity="App\Entity\Cart", inversedBy="products")
    * @ORM\JoinColumn(nullable=false)
    private $cart;

    * @ORM\ManyToOne(targetEntity="App\Entity\Product")
    * @ORM\JoinColumn(
    * nullable=false
    * )
    private $product;

    The full stack trace (the original one):

    Multiple non-persisted new entities were found through the given association graph:

    * A new entity was found through the relationship 'App\Entity\CartProduct#product' that was not configured to cascade persist operations for entity: App\Entity\Product@000000001057f61a000000007afc015d. 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"}). If you cannot find out which entity causes the problem implement 'App\Entity\Product#__toString()' to get a clue.
    * A new entity was found through the relationship 'App\Entity\CartProduct#product' that was not configured to cascade persist operations for entity: App\Entity\Product@000000001057f7e8000000007afc015d. 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"}). If you cannot find out which entity causes the problem implement 'App\Entity\Product#__toString()' to get a clue.

    at vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php:105
    at Doctrine\ORM\ORMInvalidArgumentException::newEntitiesFoundThroughRelationships(array(array(array('fieldName' => 'product', 'joinColumns' => array(array('name' => 'product_id', 'unique' => false, 'nullable' => false, 'onDelete' => null, 'columnDefinition' => null, 'referencedColumnName' => 'id')), 'cascade' => array(), 'inversedBy' => null, 'targetEntity' => 'App\\Entity\\Product', 'fetch' => 2, 'type' => 2, 'mappedBy' => null, 'isOwningSide' => true, 'sourceEntity' => 'App\\Entity\\CartProduct', 'isCascadeRemove' => false, 'isCascadePersist' => false, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false, 'sourceToTargetKeyColumns' => array('product_id' => 'id'), 'joinColumnFieldNames' => array('product_id' => 'product_id'), 'targetToSourceKeyColumns' => array('id' => 'product_id'), 'orphanRemoval' => false), object(Product)), array(array('fieldName' => 'product', 'joinColumns' => array(array('name' => 'product_id', 'unique' => false, 'nullable' => false, 'onDelete' => null, 'columnDefinition' => null, 'referencedColumnName' => 'id')), 'cascade' => array(), 'inversedBy' => null, 'targetEntity' => 'App\\Entity\\Product', 'fetch' => 2, 'type' => 2, 'mappedBy' => null, 'isOwningSide' => true, 'sourceEntity' => 'App\\Entity\\CartProduct', 'isCascadeRemove' => false, 'isCascadePersist' => false, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false, 'sourceToTargetKeyColumns' => array('product_id' => 'id'), 'joinColumnFieldNames' => array('product_id' => 'product_id'), 'targetToSourceKeyColumns' => array('id' => 'product_id'), 'orphanRemoval' => false), object(Product))))
    at Doctrine\ORM\UnitOfWork->assertThatThereAreNoUnintentionallyNonPersistedAssociations()
    at Doctrine\ORM\UnitOfWork->commit(null)
    at Doctrine\ORM\EntityManager->flush()
    at App\Controller\CartController->cart(object(CartRepository), object(UserAddressRepository), object(Request), object(EntityManager))
    at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
    at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
    at Symfony\Component\HttpKernel\Kernel->handle(object(Request))

    Hope this help!

  • 2019-11-12 weaverryan

    Hey Lydie !

    Sorry for my slow reply! And woh! Something is *very* strange here! This simply... shouldn't happen. So, if you're still with me, we need to dig further! A few things:

    1) Are you doing anything strange like $entityManager->clear() in your app... or are you doing this work in a test? Or, $entityManager->detach(). Everything makes it *feel* like you queried for CartProduct object... but then Doctrine... sorta "forgets" that it knows about it. Specifically, the UnitOfWork keeps track of every entity that it has queried for or saved during a request. The error we're seeing (I believe) is that you've queried for this CartProduct... then when everything saves... it's as if it's forgotten that it queried for this object.

    2) Can you post a screenshot of the full stack trace? And maybe, if you can, the code you have for doing all the saving and the annotations for the relationships :).

    It definitely smells to me like some very subtle thing is causing lots of weirdness. Things aren't behaving correctly!


  • 2019-11-07 Lydie

    A little bit more details:

    Uncaught PHP Exception ErrorException: "Notice: Undefined index: 000000002e4d2d6e0000000027619249" at /vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php line 2997

    this is about these lines:

    public function getEntityIdentifier($entity)
    return $this->entityIdentifiers[spl_object_hash($entity)];

    Hope this help!

  • 2019-11-07 Lydie

    Hey weaverryan ,

    I have done what you suggested and I got another error (quite strange btw):

    Notice: Undefined index: 000000002e4d2d6e0000000027619249

    Not really helpful, isn't it ? ;)

  • 2019-11-07 weaverryan

    Hey Lydie!

    It sounds like you are definitely understanding the "problem" correctly :).

    > The problem is when I save the cart to database, even if the product already exists, it does not recognize it.

    Yea... this looks "weird" to me also. If you already have a Product saved into the database, and then you create a new CartProduct and set that Product onto it, you should *not* need to explicitly call persist on that Product (or cascade={"persist"}, which is just the same thing as manually persisting). So, I agree, you should not need to have that second persist - I think something weird is going on.

    Here's what I would do to debug:

    Add the cascade=persist to the product field on CartProduct... *just* to see what happens. Does it all save normally? Or does this (crazily) create a NEW Product in the database? This will give us a hint about what's going on. According to the error, it sort of seems like Doctrine thinks (for some reason) that this is a NEW Product it should insert.

    Based on what this, we can keep debugging :).


  • 2019-11-06 Lydie

    Got a question about error "A new entity was found through relationship YY that was not configured to cascade persist operations for entity XX".
    I have a Cart (fields: cartProduct entity, ...), cartProduct (fields: product entity, ...) and Product entities. Between cart and cartProduct, I have a OneToMany relationship and between cartProduct and product, a ManytoOne. I got "cascade={"persist"}" set for the first relationship but not for the second one. I can not have product in my cart that did not exist before. The problem is when I save the cart to database, even if the product already exists, it does not recognize it. Did I miss something?


  • 2019-02-13 Diego Aguiar

    Hey bartek1234321

    Nope, it doesn't mean it's a bad practice. I usually use "cascade on persist" when I work with collections, so then I don't need to persist new items added to a collection.
    You can find more info about cascade operations here: https://www.doctrine-projec...


  • 2019-02-13 bartek1234321

    I cann't find any information about cascade operation in symfony 4 doctrine tutorial, doest it mean do not use it beacuse it's bad practise or what ? ;)

  • 2018-11-05 Alex

    Hi Ryan. You are doing a great job. Thank you.
    I am looking for advice: How to store gallery images of possibly a lot of users?
    In Database or FS?
    Usually the users upload large images and in different formats. How to deal with all this?
    Thank you again.

  • 2018-05-30 Knayz

    Angular and RxJs Observables are so sweet! Redux and ngRx will be nice too.

  • 2018-05-30 Alexander Enlund

    okay... Thanks for the fast reply and the recommendations!

  • 2018-05-29 weaverryan

    To add more info, we will definitely do something with API's, and relatively soon. I'd like to do a tutorial about APIPlatform, which is AWESOME. But, we may also do something that sticks a bit more to normal Symfony features.

    About Angular specifically, we do have a React tutorial planned, and may do some Vue stuff in the future. But, Angular is not currently on my radar. However, fortunately, there's nothing really special about using Symfony & any of the front-end frameworks. For authentication, the easiest thing to do is use normal "form login" authentication, then allow your AJAX requests to use the session cookie. Then, it's all just normal API/AJAX requests.

    If you have any other questions, let us know!


  • 2018-05-28 Diego Aguiar

    Hey Alexander Enlund

    I can't give you a release date yet, but we already have a tutorial about forms, it's made on Symfony3, but nothing serious has changed

    And, if you want to learn more about how to customize your form's rendering, then you may also like to watch this tutorial:


  • 2018-05-28 Diego Aguiar

    Hey bob

    At the moment we do not have that course in our plans, but we *do* hear all our customer's suggestions, so, thanks for letting us know what would you like to learn!
    You can check our upcoming tutorials here:

    Have a nice day :)

  • 2018-05-28 Alexander Enlund

    When are forms going to appear?

  • 2018-05-27 bob

    Will there be symfony 4 tutorial on api's and how to use that with angular 5 or 6 ?

  • 2018-05-15 Tech Nomad

    Ok, great! Thanx for the quick reply!

  • 2018-05-15 Victor Bocharsky

    Hey Alexander,

    Very rough approximation - it will be started releasing after "Doctrine & the Database" course, probably on the next week. We also want to start releasing ReactJS course very soon, so these two courses on the way to be released.


  • 2018-05-15 Tech Nomad

    Hey, could you tell something about approximate publishing date? Would be great! Thanx in advance!

  • 2017-11-06 Diego Aguiar

    Hey @disqus_GFPv27keNL

    Yeah, ManyToMay relationships are not used very often, but when you have a solid use case (like in your case), you just go for it :)

    Have you watched our tutorial about doctrine collections? I believe you will find it useful


  • 2017-11-06 Dennis

    I've got a question, you say that a manyToMany is almost never the case. But all the relations I'm creating are ManyToMany in my eyes. Here are a few examples:

    User can have many addresses and an address can have many users (Husband, Wife and Kids)
    Product can have multiple categories but a category can have multiple products as well

    How am I suppose to see these relationships? Do you have an extra video that explains it more with examples?

  • 2017-10-04 Stonehenge Webdev

    Thank you Diego! I was so focused on solving this on the backend, I forgot about js.

  • 2017-09-27 Diego Aguiar

    Hey @stonehengewebdev

    We are happy to hear you are liking our tutorials!

    Nice question. Is it allow to us JS for this? Because if the embedded form is empty, you could delete it before submitting, and let the backend do the rest


  • 2017-09-26 Stonehenge Webdev

    Hi Ryan,

    Thanks a lot for the nice tutorials, I really learn a lot by going through the many available courses on your website.
    Right now I have some difficulties preventing empty embedded forms (coupled to an entity) to be saved in the database.

    I actually want to provide the user the embedded form to fill in, but if every field is blank for that embedded form, I want:
    the validation to pass (I can write a callback function to handle this,
    if some some fields are filled in than some other fields are required.
    Or some other logic)
    - the embedded entity to not be saved in the database.

    After searching a long time on the internet I could not get a clear approach
    for this situation. I was thinking about a writing method to check the
    entity is empty, but I think there must be another better way to do

    How would you solve this problem?

  • 2017-06-27 Diego Aguiar

    Hey @deskema!

    We are glad to hear you are liking our tutorials :)
    Services are easy once you know how to properly wire them up


  • 2017-06-27 deskema

    Love those tutorials!
    I left services for last because I believe Doctrine, Forms and Authentication are already a super huge bunch of information to create a nice complete application. :)

  • 2017-06-13 Diego Aguiar

    That's an excellent idea!

  • 2017-06-13 Simon Carr

    I have already started on the api series and am planning to restrict all updates to go through an api.

  • 2017-06-13 Diego Aguiar

    Hmmm, that's interesting, in that case it will be a lot better, and safer, to go with your second approach, just be sure to find all the scenarios where those values get updated


  • 2017-06-12 Simon Carr

    Thanks Diego. I did try that already but have found the results inconsistent. I have a number of tables that relate to my part number table and while it worked with some it would not with others. As I fixed one problem I would find another.

    It also required some manual intervention in the migration files to ensure the indexes were created on the correct fields to allow the foreign key to be applied.

    In the end I decided to just go with standard relationships and do update else insert sql queries when the data is refreshed.

  • 2017-06-12 Diego Aguiar

    Hey @disqus_auUoVCL4Lo

    You can change the association field by using the "JoinColumn" option, but I believe it only works with primary/foreign keys

    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\YourEntity")
    * @ORM\JoinColumn(name="field_name", referencedColumnName="your_custom_field_name")
    private $fieldToAssociate;


  • 2017-06-11 Simon Carr

    I am struggling with my use case.

    I have a table of part numbers that is refreshed from a ERP system on a regular basis. I don't want to relate my other tables to the ID column because that will change when the part number table is refreshed.

    Is it possible to join my tables via partNumber rather than id?


  • 2017-05-08 Diego Aguiar

    Hey Fatih!

    Excellent question, I think we all have been through this :)

    What works for me is "put in practice what I've learned", if you have a project where you can use your new skills, perfect, do it!
    If you don't, you can start building something small, just to practice a little bit more, or some times I just take notes of the hardest things, so when the time comes I can remember it easily.

    I hope it helps you, have a nice day :)

  • 2017-05-07 Fatih

    Guys, i just finished Mastering Doctrine Relationships in Symfony and it looks like getting harder to me. So i need your recommendations, what should i do for next step? Should i go for next tutorial or make my own project using what i learnt and get everything done?

  • 2017-02-20 Victor Bocharsky

    Hey Hermen,

    Do you have any errors with it? Or you just curious about it?

    You can look over this article of Doctrine docs with a few simple examples: http://docs.doctrine-projec... , searching for self-referencing. So you need to choose the relation type of it: is it a OneToOne, OneToMany or ManyToMany, because it depends on you. Also take a look at StofDoctrineExtensionsBundle: . It already has Blameable behavior which could help you a lot with your case I think: .

    I hope this links help you. If you have more questions - just ask here.


  • 2017-02-17 Hermen

    Hey guys and gal, anything to be aware of when setting up a recursive relation? Entity User has fields 'createdBy' and 'updatedBy' which should relate to the User entity...

  • 2016-11-13 Shairyar Baig

    Many thanks Ryan, this drove me crazy for hours. I ended up changing the method name but it makes sense and i now renamed the property. As always many thanks for the explanation. I will check out the tutorial as well.

  • 2016-11-13 weaverryan

    Hey Shairyar!

    Short answer: we're covering this in *depth* right now on the new collections tutorial:

    Longer answer: This is a problem with pluralization. Let me give you a different example: imagine the OneToMany was on a property called products. Then, you would also have a products field on your form. With this setup, the form system will try to call addProduct() and removeProduct() when you submit your form. If you have the right setup, this all ends up being really cool (that's what we cover in the new tutorial).

    But in your case, your field is "user_address", and this property holds an array of "Address" objects. This should *really* be called "user_addresses" - since it holds *many* addresses. Since your property name is singular, the form system is confused - it thinks that the actual word is "user_addres" and that you are making it plural with "user_address" (with 2 s). So, it tries to call addUserAddres and removeUserAddres, instead of addUserAddress() and removeUserAddress().

    To fix it, do one of the following:
    1) Rename your property from user_address to user_addresses
    2) Rename your add/remover to addUserAddres and removeUserAddres (which is kinda crazy)

    Let me know if this helps! The error is telling you which methods it's trying to call.


  • 2016-11-12 Shairyar Baig

    Hi Ryan,

    I cant seem to understand oneToMany add and remove function names that get generated when you create the relationship

    I have an entity `User` and `Address` and they share a oneToMany relationship

    targetEntity: AppBundle\Entity\Address
    mappedBy: address_user
    cascade: ["persist"]

    targetEntity: AppBundle\Entity\User
    inversedBy: user_address

    When I ran the command `doctrine:generate:entities` it created the add and remove function in User Entity

    I then created a FormType as following

     public function buildForm(FormBuilderInterface $builder, array $options)
    ->add('user_address', CollectionType::class, array(
    'entry_type' => AddressType::class,
    'allow_add' => true,
    'by_reference' => false,
    'error_bubbling' => false,

    On submitting this form I kept on getting the following error

    `Neither the property "user_address" nor one of the methods "addUserAddres()"/"removeUserAddres()", "setUserAddress()", "userAddress()", "__set()" or "__call()" exist and have public access in class "AppBundle\Entity\User".`

    I dont understand why is it looking for a method name addUserAddres() instead of addUserAddress()

    Note: generating entity seems to be adding single word in `Addres` rather than `Address` for the add and remove method in User entity. I added another 's' in these method names and things started working fine.

    Whats going on here?

  • 2016-10-11 Victor Bocharsky

    Hey Robert,

    I think there're a lot of ways to do that, but probably cache the whole rendered template is more appropriate here. We have a chapter about it: check out the Fragments, ESI and Caching . But keep in mind, that the cached template with ESI - is another request (sub-request) to your application. It covered in that chapter.


  • 2016-10-11 Steptach

    Well now i got another question :P

    I want to cache a result or even better a part of the template. The thing is if i cache the entity i can't access the getCategory (reference to antoher entity) if i load it from the cache. I want to prevent the database queries. And idk how to use the esi in this case.

    My goal is to display 6 different entitys which changes every 15 minutes.
    The most viewed, the 'featuered' and so on

    Thanks in advance

  • 2016-10-10 weaverryan

    Sweet! Keep killing it!

  • 2016-10-09 Steptach

    Hello Ryan,

    Thanks it worked.

    This site is still the best resource to learn symfony

  • 2016-10-08 weaverryan

    Hey Robert!

    Do you happen to have two circular relationships between the two tables in question? I mean, like a ManyToOne from Game to Category and also some other relationship (e.g. ManyToOne or OneToOne) from Category to Game? Alice actually *should* delete things in the correct order: it calculates that by looking at the relationships. But, if you have 2 tables that both relate to each other, there's no "right" order that would make things work. In that case, you need to add some onDelete="" (e.g. CASCADE, or SET NULL) behavior to the ORM\JoinColumn annotation to one of the relationships so that the records can be deleted in the database without the db throwing a constraint.

    Let me know if that describes your situation!


  • 2016-10-07 Steptach

    SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreig
    n key constraint fails (`root`.`game`, CONSTRAINT `FK_232B318C12469DE2` FOREIGN KEY (`category
    _id`) REFERENCES `category` (`id`))

    How should I deal with this?
    It happens when i try to load the fixtures from alices. Alice deletes the tables in the wrong order. Is there a way to control this behaivor?

  • 2016-09-20 weaverryan

    I just started on the tutorial today :). But, that still means that it's anywhere from 3-6 weeks away from the release schedule. So, not too long now :)

  • 2016-09-20 Hermen

    Getting anxcious...

  • 2016-09-01 Hermen


  • 2016-08-23 weaverryan

    Haha, you're going to make it very easy to make sure we hit all the right topics for the tutorial :). Thanks for the continued input!

  • 2016-08-23 Hermen

    I had thought it would be something along those lines. Thanks for your feedback and also the tip about the bundle. I'll definitely look into it.

  • 2016-08-22 Victor Bocharsky

    Hey Hermen,

    For nice URLs, you simple should add a new *unique* string column in your DB table, i.e. "slug" or "alias" which will contain this pretty nice part of URL. And since it is unique, you could query entity by this slug instead of ID. And of course, in your route use "/news/{slug}" where you'll pass an entity slug to generate a valid route instead of "/news/{id}". The only problem - you should use only valid characters in your slugs and avoid such as "?", "#", etc. Thanks to the bundles, there're already a couple of third-party libs which help with generating a slug for Doctrine entities. Probably, the most popular is the "StofDoctrineExtensionsBundle" which has a lot of DoctrineExtensions's features includes a Sluggable one. So check it out.


  • 2016-08-20 Hermen

    And how to put all this information, from the Many, the One and the other Many, on the screen in a single page...

  • 2016-08-20 Hermen

    And, but you probably have this on the role already, when using a ManyToOne with separate joining entity (so, not a real ManyToMany, but a ManyToOne/OneToMany/ManyToOne), how to update that. You even might have ment that in your last sentence, but English is not my first language and neither is Symfony...

  • 2016-08-20 Hermen

    And while your at it, but this may be completely off (this) topic, nice URL's and getting stuff from the database. Example: When following the tutorials, a route is created, e.g. \news\watch-our-great-tutorial-about-manytomany. But, if I want to fetch that article from a database, I probably need to use something like \news\2345 where 2345 is the id of that news item. Or is there something out there that lets me fetch that article and show the nice URL?

  • 2016-08-16 weaverryan

    Yes, you bring up a valid point :). I rarely use ManyToMany because of this: I almost always use ManyToOne with an extra entity because it gives me the extra flexibility immediately. And yes, if you want fields like dateCreated, then you would need the extra entity even for these fields. That's why I don't often use ManyToMany. But, we'll still do a tutorial on it, and more about the really hard parts of OneToMany/ManyToOne - things like the owning/inverse side that you were asking about.


  • 2016-08-16 Hermen

    Ah, yes. I forgot, I read that somewhere. Maybe you could go into why not always use that solution even of there are no extra fields. By the way, the extra fields, does that include the 'record meta data' like "dateCreated" and "dateModified"?

  • 2016-08-15 weaverryan

    Thanks Hermen! The topic about updating from both sides is very important - this will probably be the most important part of the tutorial :). About the "extra data", I will also mention this, because it's really important. But, the answer is simple: if your join table needs even *one* extra field, then you should no longer use a ManyToMany relationship. Instead, you should build a new entity that will join the other two. For example, suppose you have a ManyToMany between Product and Category. If you need some extra field on the join table, then you need to create a new ProductCategory entity, which will have a ManyToOne to Product and a ManyToOne to Category. A true ManyToMany only works if there are *no* extra fields.

    And thanks again for the details!

  • 2016-08-12 Hermen

    How to go about it (how to set it up) one way and both ways (like OneToMany and ManyToOne), how to update a page with both sides ('main form' and 'sub form'), how to go about a many to many with extra data in the joining table. Like: I want to catalog my DVD's with movie title, synopsis, year released and rating (like Motion picture rating system which in my country holds more ratings, see so this is ManyToMany) and the main actors with their role in the movie (ManyToMany with extra data).

    Hope you can make anything out of this.

  • 2016-08-11 weaverryan

    Sorry about that - it obviously got pushed back beyond July. But, we'll be starting this tutorial very soon (like, next on my list). So, while I have you - is there anything specifically that's confusing? I'll be putting together the list of things to cover - want to make sure I hit everything important!


  • 2016-08-11 Maciek


    Any news according to "ManyToMany" relationship?

  • 2016-06-15 weaverryan

    Hey Hermen!

    I've added it to the schedule for July, but as an "extra" - we will do a few other casts in July before it. So, I can't promise July, but we'll do our best!


  • 2016-06-15 Hermen

    Anything on the schedule yet *wishfull thinking*?

  • 2016-06-10 Shairyar Baig

    yes thats what i ended up doing writing a custom query :)

  • 2016-06-08 weaverryan

    Hi Baig!

    Hmm, I'm not sure - I don't fully understand the data model. If there is a Request and I accept it, then I understand that this creates a ManyToMany between my User and the Request. But *before* I accept this Request, how is the Request linked to the User? I'm not sure about this part.

    But in general, when you have complex queries like this where ultimately you just need a "count" of something, I often write the query in SQL first (and test it in phpmyadmin or something similar). Then, I write that same query in DQL / the query builder.


  • 2016-06-07 Shairyar Baig

    Hi Ryan,

    I have a question. Suppose I have 2 entities `User` and `Request` and they are linked with each other in `manyToMany`

    Now the scenario is that I can also accept the request and you can also accept the same request and accepting the request creates the `manyToMany`

    So now lets suppose there are total of 3 requests out of which I have accepted 2 and you have accepted 3

    How on front end can we display the user the "Total number of requests" and "Total number of request accepted" and "total number of request that are pending to be accepted".

    Suppose in controller I have this

    $em = $this->getDoctrine()->getManager();

    //get all dinners to be listed as upcoming dinners in view
    $allRequests = $em->getRepository('AppBundle:Requests')->findAll();

    return $this->render('AppBundle::requests.html.twig', array(
    'allRequests' => $allRequests,

    And inside twig i have

    Here I would like to display the counts "Total Received", "Total Accepted" and "Total Pending"
    {% for requests in allRequests %}



    {% endfor %}

    How can this be achieved.


  • 2016-04-19 weaverryan

    It's not currently on the schedule, so it will likely *not* come out in the next 3-6 months. However, if we have more people ask for it, that might change :).

  • 2016-04-18 Maciek

    When should we expect "ManyToMany" course?

  • 2016-03-23 Hermen

    I'll be waiting for it!

  • 2016-03-20 weaverryan

    Ah, a power user - very nice find :D

  • 2016-03-20 weaverryan

    Hey Hermen! We decided to save ManyToMany for its own small tutorial - it's got some special aspects we can cover, like removing items and form collections. I want to get that all *just* right - because they can be a real joy to work with :)

  • 2016-03-20 Jonathan Keen

    You guys certainly know how to make addicts want more... ;) I can't tell you how often I come here to look for new tutorials to absorb. I'm even guilty of browsing to see when you sometimes publish the notes before the videos...which is what I was just doing.

  • 2016-03-20 Hermen

    Looking forward to these. Will you be dealing with ManyToMany also?