Symfony2 & MongoDB ODM: Adding the missing ParamConverter

Posted on by Matthias Noback

Just a quick post...

What seems to be missing from the DoctrineMongoDBBundle is a ParamConverter service which resolves request attributes to controller arguments by fetching a Document using the MongoDB DocumentManager. For entities, this would work:

/**
 * @Route("/blog/{id}
 */
public function showAction(Post $post)
{
    // $post will be the entity Post with the "id" taken from the route pattern
}

This works because of the DoctrineParamConverter, which is registered by default by the SensioFrameworkExtraBundle. But only for Doctrine ORM, and not for Doctrine MongoDB ODM. As Christophe Coevoet mentioned when someone tried to implement this missing feature, it can be added easily by yourself, without writing any PHP code, though it might not be so clear how to accomplish this. Still, the only thing you have to do is add a service to your services.xml file:

<service id="doctrine_mongo_db_param_converter" class="Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\DoctrineParamConverter">
    <argument type="service" id="doctrine_mongodb" />
    <tag name="request.param_converter" converter="doctrine.odm" />
</service>

As you can see, the DoctrineParamConverter is reusable, but it receives the ManagerRegistry for MongoDB ODM instead of the ORM.

So now, when Post is a Document, it will be fetched by its ID, just like if it were an Entity.

Please check out the ParamConverter documentation when you don't use the default Document manager, or when the value of the Document's identifier is not in the request attribute "id".

PHP Symfony2 MongoDB request reuse
Comments
This website uses MailComments: you can send your comments to this post by email. Read more about MailComments, including suggestions for writing your comments (in HTML or Markdown).
Tobalsan

I just tried, and I can confirm that this still works in 2018 with Symfony 4.1.

Matthias Noback

Cool, thanks for letting everyone know :)

Андрей Бобрышев

Thank you very much for this post! Exactly what I was looking for. Works great!
If you are using .yml configuration:
doctrine_mongo_db_param_converter:
class: Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\DoctrineParamConverter
arguments: ["@doctrine_mongodb"]
tags:
- { name: "request.param_converter", converter: "doctrine.odm" }

Marc

Thanks.. It wondering and searching a long time why ParamConverter was not working .. then found your post. Thanks!

spolischook

Not bad. I have some another problem with
$this->getDoctrine()
in common controller. I add
$container->setAlias('doctrine', 'doctrine_mongodb');
to my Extension file and its work fine. Converter also work fine after this. So I create PR
https://github.com/doctrine...
Your vote is welcome.

spolischook

Jeremy closed my PR with good reason. So I add
true === $container->hasAlias('doctrine') ?: $container->setAlias('doctrine', 'doctrine_mongodb');
to my Extension file

Michaël Perrin

Exactly what I was looking for, thanks!

Daniel Ancuta

Works perfectly! Thanks! :)

Seems like the service ID now needs to be sensio_framework_extra.converter.doctrine.orm for this to work using Sensio Bundle 2.3, otherwise it won't override the default converter.

John Taylor

Hey Matthias,

Thanks for that post, it really helps me out. There is one thing I hope you can help me with. How do I enable the ODM param converter on Symfony 2.0? I tried using your example but Symfony couldn't find a service with that name to inject.

Thanks (:

Matthias Noback

Hi John,
I'm not sure why it would not work. Is it the "doctrine_mongodb" service that is missing?
Best regards,

meze

But if we look inside DoctrineParamConverter, we'll see that it uses the 'entity_manager' option. But doctrine odm doesn't have entity managers, how does it work?

Matthias Noback

The "entity_manager" option only tells us that the DoctrineParamConverter was designed with the ORM in mind. The converter works for ORM and ODM, because both implement a ManagerRegistry (Doctrine\Common\Persistence\ManagerRegistry) - they allow for different entity and document managers (reference by name). It also works, because both registries return instances of Doctrine\Common\Persistence\ObjectManager when asked for a specific manager, so querying documents and entities is quite alike.