Tutorial: Using Sonata Admin with magic __call method

I thought I would start off the new year with a tutorial on a tricky process I’ve had to do a few times for various projects using Symfony, Sonata Admin, and PHP’s magic method __call.

If you’re creating a basic project in Symfony 2, the Sonata Admin Generator is a great tool to use. It’s highly configurable, and easy to extend and modify for your own needs, like most Symfony bundles. It does have one flaw for use in my projects, and that is if you are using the __call magic method for getters/setters, the list view will show blank fields, because it relies on method_exists to find a getter method. (It currently checks for get{Property} and is{Name}).

For example, here is a very simple base model with a __call() method to capture get{Property} requests. This is useful if your getter methods are just returning the property with no other logic. I personally prefer not to have all those extra methods as they are basically cruft, when I can accomplish the same thing with magic methods.

The code that uses the method_exists function is in Sonata\AdminBundle\Admin\BaseFieldDescription::getFieldValue. In order to override this one function, we must:

  • Create custom FieldDescription class to override one method
  • Create custom ModelManager in our bundle, to use the new FieldDescription class
  • Make the new ModelManager available as a service
  • Update our admin services to use this ModelManager

Now I will walk you through these steps.

Custom FieldDescription Class

This one is pretty simple. I copied this code directly from the existing FieldDescription::getFieldValue and changed just a few lines. After adding the check to is_callable, I check that the result returned is not null – this is because is_callable will return true if __call exists, so even if you’re not processing that particular function call, it will still be callable.

You can however simplify this if you know you will always rely on get{Property} for your getters.

Custom ModelManager

The custom ModelManager is also easy, just copy the code from the current ModelManager and update the use statement to use your FieldDescription class. You’ll also want to alias the original ModelManager for your extend statement. The function is in fact exactly the same as the original, but since I have added the use statement for my new FieldDescription class before the class, it will use mine now.

ModelManager as Service

Update your services file to create a service for the new ModelManager. I prefer to use yml for my config files, but you can do this in XML or Annotations as well.

Update Admin Services to use ModelManager Service

Last step is to update your admin services to use the new ModelManager’s service. Again, you can use YML, XML or PHP for this.

Result

I hope this will help anyone out there trying to accomplish the same goal!