Symfony2: Assetic Twig Functions

In my post Symfony2: Using Assetic for Image Optimisation I looked at using Assetic for image optimisation. In that I looked at OptiPNG set up like this in the config:

and using a Twig template that looks like this:

In order to optimise a PNG file. It is possible however to achieve this with a much simpler Twig template by setting up a Twig function from the Assetic config. By adding the following config:

The Twig template can be changed to the following:

Note that we are no longer using the apply_to filter and instead explicitly specifying the optipng filter with the function call.

You can specify the output directory in the config in the following way:

The function name maps directly to the filter name so these must be the same for this to work. You can only use this to map using a single filter, so for more complex combining of files and use of multiple filters, as you may want to do for JavaScript and CSS files, this is not an appropriate solution. For images though, where you will usually only want to apply a single filter to a single file this is an excellent way of simplifying your Twig templates.

Symfony2: Moving Away From the Base Controller

When you start learning Symfony2 using the book, you are introduced to the base controller. The base controller has some helpful methods to make common tasks easier. After a while though you may want to move away from extending this controller, in fact, it is the advised best practice for controllers in shared bundles. When you do, you will no longer have access to these useful methods, in this post I am going to look at how to accomplish the same tasks without them.

I have created a simple controller for some basic form interaction with a model which uses the base controllers methods. I am going to go through how to change this to a service which does not extend the base controller. The starting point looks like this:

It uses a form type object LimeThinkingSpringBundleFormTestimonialType for the form which looks like this:

The controller as it stands has actions for displaying, adding and editing testimonials. I have extracted the common tasks, retrieving a testimonial from the database and rendering the form, into their own methods. It is routed to like this:

Removing Helper Methods

To start with I am going to change the helper methods to use services still retrieved using the get() helper method which is a short cut for getting services from the container. After this is complete we can convert to a service and inject the required services instead.

The methods we need to replace are:

  • getDoctrine()
  • generateUrl()
  • render()
  • createForm()
  • redirect()
  • createNotFoundException()
  • get()

Once all these are gone we can stop extending SymfonyBundleFrameworkBundleControllerController. To start we will actually introduce more use of get() as this allows us to access services from the Dependency Injection Container (aka Service Container).

getDoctrine()

The easiest to remove is getDoctrine():

becomes

generateUrl()

Next up generateUrl():

becomes

render()

becomes:

createForm()

becomes:

redirect()

Now for a couple that are slightly different:

becomes:

We also need to add:

to the use statements at the top of the file.

createNotFoundException()

becomes:

with:

added to the use statements.

get()

is just a shortcut for

So we can replace all the get() calls throughout.

Now that all the methods from the base controller have been removed we can change to extending ContainerAware instead. doing so means that the container is available to the controller. So the class now looks like this:

Defining the Controller as a Service

We can also now move to defining our controller as a service. See this cookbook recipe and my post Symfony2: Controller as Service for details on how to do this and how to set up an Dependency Injection extension to load a service definition for a bundle. In this case we would change to routing to the controller like this:

with a services XML config like this:

Note that the container is explicitly injected into the service using the method defined in ContainerAware as this is no longer automatically done.

Injecting Services

Now for the more controversial bit. In my opinion injecting the container in this way is not the correct way to use it. I have written about this in these posts: When Dependency Injection goes Wrong and In Defence of Dependency Injection Containers. This is not the opinion of everyone and not an official best practice, it is just my recommendation.

I have also looked at how to inject dependencies in Symfony2 in these posts: Symfony2: Dependency Injection Types and Symfony2: Injecting Dependencies Step by Step. So I am not going to go over how to do this in detail again this time, the end result of removing the services is that the class looks like this:

and the services XML like this:

Edit: As per Stof’s comment the predefined request service should be used. As this is scoped to request the controller will also need to be scoped to request to avoid scope widening. The services.xml should then look like this:

There are still some objects being created using the new keyword. These are all effectively value objects though rather than services. That is to say that they hold specific values and would not be reusable in other classes in the same way that the other injected services are. The RedirectResponse, for example, is specific to the testimonial not being found and is not something we could inject using the container. There is an argument that this is still a dependency that should be removed. If you are that way inclined then a way to do it would be to instead inject Factory objects to create these objects on demand. The factory could then be mocked for testing or a different factory used if you wanted to change the object returned. If you do want to do this then at the moment you will have to write your own though.

In Defence of Dependency Injection Containers

There has been some criticism recently of the use of Dependency Injection Containers (DICs) with a lot of people saying that DI != DICs. For example see http://till.klampaeckel.de/blog/archives/154-Dependency-Injection-Containers.html and the comments on it. Whilst I agree with that DI !+ DICs, I do not agree with it being turned into DI good, DICs bad. In this post I want to look a bit more at this. Disclaimer: A lot of what follows is just my opinion and is not particularly intended as a direct response to the above article. It is as much a response to me sounding a bit anti Dependency Injection Containers in this post When Dependency Injection goes Wrong.

DICs as Glorified Registries

A lot of the criticism has been focused on how DICs are essentially just a glorified registry and introduce dependencies on the container. I fully agree that using a DIC in this way, that is requesting services from it, is indeed problematic.

The problematic usage I am mean is code that looks like this:

So what are the issues with code like this?

Reduced re-usability

We may have removed the direct dependency on whatever my_service is but we have a dependency on the container now. So this code cannot be used without the container, this reduces the re-usability of the code.

Only Slightly Less Tight Coupling

The tight coupling between this class and myservice has been removed, however we have created a coupling between all code that requests myservice from the container as they will receive the same object from the container. We have not created the ability to configure these classes independently of each other.

What is my_service?

In the example code you cannot tell what class my_service is, or more relevantly for using it, what interface(s) it implements. In order to find out you need to consult the configuration of the DIC. Not only can you not tell but your IDE cannot either, so there will be no auto-completion when you are using the service. (I appreciate there are workarounds to this). Additionally nothing enforces the interface of the service so no checking is being done to make sure it is a suitable service before it is put to use.

Unit Testing Difficulties

To write tests for the above code you cannot just mock my_service directly, you either need to use the service container itself to get the mock in or mock the service container and get the mocked container to hand out the mocked service.

This is indeed not Dependency Injection at all in my opinion, you are not injecting the dependencies if you are doing this, you are requesting services from the container, no injection is taking place. Dependency Injection is injecting a class’s dependencies through means such as the constructor or a setter method. The container itself is not seen in such classes.

Actual Dependency Injection

So how can we remove the dependency on my_service without running into the above issues? By injecting it directly into the class. In this example it is injected into the constructor:

So our code now has no direct dependencies on another object, just a requirement that an object implementing the MyServiceInterface interface is passed into the constructor. So there is no tight coupling between the class and a particular implementation of the interface. We have also avoided any coupling with the container.

Other classes which require an implementation of MyServiceInterface can receive the same or a different implementation now so there is no coupling with them. You and your IDE now know you are working with a MyServiceInterface implementation so you will get auto-completion. To test this class we can now just create a mock implementation of the interface and inject it in directly with no need to involve the container.

A big advantage to using DI in this way throughout your code, is that it fully separates the configuration from the rest of the code. This means that you can wire up the classes differently for different applications easily. None of the code outside of the parts doing the wiring needs to be aware of the particular configuration. There is no need for messy code choosing which version of a class to use. If you need different functionality for a different app then you can just drop in a class with the new functionality without needing to touch the existing code.

There is a learning curve to starting to code in this way, as well as getting used to having to create the DI configuration instead of creating classes directly in the code, but its one that is well worth it.

Where does this leave DICs?

So does this mean that DICs are bad full stop? No quite the opposite. If you do DI properly and use constructor and/or setter injection (and possibly property injection) then in a large application DICs offer many advantages in wiring up the application.

For very small apps and when writing tests it is easy enough to just create the classes and pass them in as dependencies. In a large application with a complicated object graph this becomes a difficult task. This is where a DIC comes into its own. I am mainly going to concentrate on the Symfony2 service container when looking at the advantages of using a DIC for this large scale wiring, as it is the one I am most familiar with.

The first advantage is that the Symfony2 container allows you to configure services using YAML, XML or PHP and then takes care of the actual creation of the objects. This means that you can write much more readable configurations. For examples of configuring Dependency Injection in Symfony2 using XML see my post: Symfony2: Dependency Injection Types

Another advantage is that you do not have to configure everything in one place. In Symfony2 the code is separated into bundles, both the core code and third party code is all in this bundle form. Each bundle contains its own services configuration files so only the DI configuration for the bundles actually being used is read into the DIC. Trying to create such a complex wiring in one place without the help of a DIC would be a mammoth task.

The DIC also carries out other tasks to aid in performance. This is particularly important when doing large scale DI in PHP as these are not long running services as with Java but created on each request. One aspect of this is caching of the confguration once it has been “compiled” from the XML or YAML config files. Another is the use of proxy classes for lazy loading, meaning that the full object graph is not created every time but only when services are actually used. All this happens behind the scenes but is completely separated from the code that is wired together, which itself is unaware of the way in which it is wired up.

Conclusion

So is it true to say that DI != DICs, well yes sort of. More accurate would be to say that DI, possibly using a DIC for configuration != requesting services directly from a DIC being used as a glorified registry. Unfortunately that’s not quite as snappy.

Symfony2: A Few Assetic Notes

Just a quick post with a few notes on Assetic. These are mainly on topics people have been searching for when they have visited this blog.

Loading Filters

If you are using Assetic from Symfony2 then its worth being aware that it does not automatically load up all the available filters. Only the filters you specify in your app’s config will be loaded. So for example to use the yui_css filter you need to specify it like this in the app’s config.yml:

It will then be loaded and available to use. If you do not do this you will get error messages such as:

If the filter you want to use does not need options setting for it then you can make sure it is loaded like this:

Watch for Changes to Dumped Files

Your assets can be dumped to the file systems as static files in order to serve them efficiently. For production you can do this on deploy. For development you can just let Assetic produce them on demand, however you can instead dump them as static files using the watch option like this:

With this the command will not exit and loop constantly checking for changes to the files you are serving using Assetic, if any changes are detected they will be dumped again so you will see the changes. It will also respond to changes in the Twig templates, so if you do something such as include an additional CSS file in the collection of assets to be served as a single file then it will be dumped again including the extra asset.

Avoid Overwriting your Working Files

If you are dumping your files to web/css and web/js etc. then do not keep the working files there, they will get overwritten when you dump the files.

Image Resizing/Manipulation

You can use Assetic for some image processing, see my post Symfony2: Using Assetic for Image Optimisation for more details. However you cannot currently use it for tasks such as resizing and cropping. You can still do these tasks from Twig templates by using the AvalancheImagineBundle, which is a Symfony2 bundle to allow you to use the Imagine library from Twig. Imagine provides a standard Object Oriented interface for image manipulation in PHP and uses extensions such as GD2, Imagick and Gmagick for the processing. The bundle currently only has a built in filter for thumbnailing images but you can create custom filters for your own needs.

Symfony2: Writing a Dependency Injection Extension Configuration

In this post I will look at how to write a more sophisticated Dependency Injection Extension for your Symfony2 bundles.

Bundle Level Config

In my earlier post Symfony2: Controller as Service I looked at creating a very basic extension that would allow us to load an XML file defining the services. The class looked like this:

This loads a single service config XML file. You are not tied to using XML for this, YAML or PHP configuration can also be used and would be loaded as follows:

Doing any of the above will load the relevant service config into the Dependency Injection Container (or Service Container as it is also known). Whilst you can use YAML or PHP config files the best practice recommendation is to use XML for bundle service configuration if the bundle is intended to be released as a third party bundle. Whilst YAML is good for simpler config files the verbosity of XML is actually an advantage when maintaining a more complicated one. Likewise the nature of the PHP config means it is more difficult to decipher, the choice is still your’s though.

You are not limited to loading a single config file, this way you can split up complicated service definitions into manageable files. For any parameters or service definitions that appear in multiple files those loaded later will overwrite these values. You can also then only load the definitions needed for an app rather then everything. For example in the AsseticBundle only the filters specified in the app config will have their service definition loaded.

For more details on how to write the bundle level XML config please read my posts, Symfony2: Dependency Injection Types and Symfony2: Injecting Dependencies Step by Step

App level config

So far I have only looked at loading config kept within the bundle. You can open up parameters to be set from an app’s config file. Any config parameters relating to the bundle from the app’s config will be passed into the load method of our extension as the $configs argument. So if the app’s config.yml file contained the following settings:

then the passed in $configs array will be the following array

It is nested in an array because you can have multiple config files, each will be placed into an array. So if you have also have settings in config_dev.yml:

Then the received configs array would like this:

You can then use these to set parameters in the Container in the following way:

Edit: Accessing the config variables in the above example does not deal with merging the values from different configs, it has effectively ignored the setting in config_dev.yml. Using the Config component as described below will avoid this problem.

Configuration Building

It is not however advisable to just set any values in the config to the DIC’s service definitions. It would be much better to only set the values you want and to do some validation of the values passed in. Fortunately the pain of this is alleviated by using the built in Config component. We can build a configuration using its fluid interface which allows us to build up complex configurations specifying value types and more . Lets start with an example to show how to do this:

We can then use this to process the values passed in from the app’s configs by adding to our Extension’s load method:

The Processor will merge the values from $configs with the Configurtaion we have built checking the values as we go. In the above case we will end up with a a merged config that looks like this:

The Processor merges the values from the config tree with those from the app level config, if there are multiple app level configs then any repeated values are overwritten by those later in the array. The order they are in the array depends on which file imported which with those imported later appearing earlier in the array. Whilst this sounds counter intuitive it is what allows the values in config_dev.yml, which imports config.yml, to overwrite the ones in config.yml.

The Processor will not merge this config into the Service Container’s config automatically but returns it as an array, you still need to choose which values from the config to write to the Service Container.

One thing to note is that when merging a configuration in this way is that an exception will be thrown if any values not specified are included in the app’s config rather than them just being ignored.

Configuration Nodes

So let’s look at the Configuration in some more details and look at some of the node types and their settings. The first thing to note is that the TreeBuilder uses a fluid interface so we can chain method class, each time you add a node you move to calling its methods, a call to the end() method moves you back up to the parent.

In the example above I used three types of node, scalar, boolean and array, so have a look at these and the other node types in a bit more detail:

Variable Node

variableNode() This is the most basic node type and does nothing to enforce the value of the node.

Scalar Node

scalarNode() A scalar node can be used for the following types: booleans, strings, null, integers, floats. Attempting to set something else to it, such as an array, will result in an exception being thrown.

Boolean Node

booleanNode() Whilst you can use a scalar node for boolean values using a boolean node will ensure that only boolean values can be set as an exception will be thrown for any other values.

Array Node

arrayNode() You can use an array node to allow nested config values in the app level configuration. In the above example I then explicitly set the children of the arrays type. Of course we do not always want to specify what every child of the array should be to allow some flexibility in the config. This means there is much more to using Array Nodes, howver I am not going to cover this here but will look at it in a future post. Edit: I have not covered this in a future post but it is not documented in the Symfony2 component documentation

Configuration Settings

Using the correct node type will provide us with some immediate checking of the value to ensure it is the correct type. Additionally further settings for each node can be made to further validate the config. Some of the settings we can use to enforce use are as follows.

Default Value

defaultValue($value) You can use this to set a default value for the node, if the node is then not given a value in the app level config the default value will be used. If no default value is given and the node is not given a value in the app level config then it will not appear in the processed config.

There are short cut methods available for setting the default value to true, false and null, these are respectively defaultTrue(), defaultFalse() and defaultNull()

Required

isRequired() You can specify that a node is required, if it is set and the node has no value set in the app level config an exception is thrown.

Allow Overwrite

cannotBeOverwritten() You can use this to say that the value of a node and its children cannot be overwritten. This does not mean that a default value is used and no value can be set in the app level config but that it can only have its value set in one app level config file.

Treat Like

treatTrueLike($value) This allows you to make your configuration easier for end users, by treating them setting true as something else in the background. For example if you had treatTrueLike('complicatedValue') then if the node is set to true in the user level config then it will be set to complicatedValue in the processed config. As well as treatTrueLike() there is treatFalseLike() and treatNullLike().

These are by no means a full list of the configuration possibilities, whilst there is not much documentation for this available at the moment you can learn a lot by having a look at the Configuration classes in the Bundles included in the standard distribution of Symfony2.