My First Assignment: Creating an Elastica Adapter for the Sonata Admin list view
Just like every marmelab recruit, my first weeks are spent working on various new technologies (Node.js, ElasticSearch, MongoDb, etc) with real use cases.
I've created a bundle, it can be found on GitHub.
Here's the README intro:
The Sonata Admin Bundle provides a web UI to many types of persistence (RDBMS, MongoDB, PHPCR), some of which have limited query capabilities. If you already have an ElasticSearch index for a given model, this bundle allows you to use this index instead of the native repository query system. This may provide a great performance boost, depending on your data structure and indexes.
Sonata Admin with no DB query
First Start: Bad Direction
It was clear that the configuration should be in the entity admin service's definition.
At first, I tried to add a new
manager_type=elastica in the
sonata.admintag. I wanted to override each class used by the admin bundle and/or elastica. I thought I must get rid of any little dependency on doctrine or propel.
That was a mistake.
First, because there was so many classes to override, that I almost wanted to give up.
Second, because my goal was to display a list view in the admin bundle with no query in database. I wanted to be able to filter, sort and paginate the elements, using the ElasticSearch index. But I did not want to override the detail view, the batch actions, ... So, depending on the action, I needed to keep the 'normal' behaviour.
Second Start: Better Understanding
For the second version, the idea was to keep the default
manager_type attribute and to add new parameters in the
sonata.admin tag. Just override what needs to be overridden, KISS as they said.
The goal was simple: to use the elastica index, just add two parameters in the tag:
I needed to use proxy classes that do the job when we need it, and let the ORM do the rest.
I had to create services for each entity to display from the ElasticSearch index. As I didn't want the potential user of the bundle to have to write a bunch of services for each admin class, I have created my first CompilerPass.
I defined an
ElasticaModelManager that is used over the orm
ModelManager. This proxy has a
baseManager attribute that corresponds to the orm
ModelManager. It’s linked to the admin class thanks to the CompilerPass:
$adminService->addMethodCall('setModelManager', array(new Reference($proxyManagerServiceId)));
Most of the time it returns what the ORM does, except for the
createQuery method, where it creates a new
This class implements the
ProxyQueryInterface, and stores an instance of
ElasticaProxyRepository, which is used to query the ElasticSearch index.
This is a real shortcut to explain the link between the admin class and the index, but if anyone is interested in more details, the code is open :)
Though I've already worked a little with Symfony and Sonata, I did only use them to do pretty basic stuff. Working on this bundle helped me to better understand some concepts such as the DIC, or to use the
debug_batcktrace() function !
I've also discovered the CompilerPass, a very powerful tool to override and create on demand services. But with great power comes... sometimes a bad headache.
It was also my first contribution to an open source project. I think it's just awesome. When I had a problem on a Sonata bundle, my PR has been merged in a few hours. And I had feedbacks on this bundle immediately after the repo is public!
I know that it is far for complete and/or finished (and/or totally functional?) but I had fun working on it and I hope it will be improved, used and helpful!