Symfony2: Yet more on that Twig Extension

In my last post I looked at the end at creating a Twig extension that would return the template to extend in order to pull the logic for the decision out of the template. The template names were just stored in class constants to keep the example simple; I mentioned that these could be moved out into configuration. A few people asked for more details on how that would be done so here it is. This is not specific to Twig extension but it does provide us with an example to look at exposing bundle configuration.

So to start with the extension class looks like this:

with this service definition:

As we only have a couple of template names we could inject them individually to the constructor:

and set them as parameters in our services file:

It may be better though to just accept an associative array of template names so that we can increase the number later without increasing the number of constructor arguments:

So far this has just used setting parameters directly, however this does not give us much opportunity to validate the configuration. Currently the parameters are set in our bundle as well. If we decide that this bundle is worth sharing between applications then we would want to be able to set the parameters outside of the bundle in the app level config. We could just leave setting these parameters directly and move to doing that in the app parameters file:

This still does not give us much control over what values get set. If we move to making them part of the config that the bundle exposes to the app level config then we can validate the values. It also makes it easier for someone else or ourselves in the future to see how to configure the bundle by looking at the allowed config.

We can instead make setting the template part of the bundle configuration instead of setting the parameters directly. This is the way the bundles that are part of the framework handle their configuration. The first step is to tell the bundle to expect configuration relating to the templates in the Configuration class that is in the DependencyInjection directory. This is autogenerated if you create your bundles with the generate:bundle console command:

Here we are saying that we want an array of templates, at the moment all we have said is that it must exist and that it must have at least one element. We will now not be able to run the application as we get an exception due to not having met these requirements.

We can now add them to the config.yml file, instead of the parameters section we add them to a section with the top level key which matches out bundle’s name which was set as the root node name in the configuration class above. For the examples this is “acme”:

At this point we can remove the previous setting on these values in the parameters section of the config.

We should now be able to load the application without an exception about the config, however the template values are not yet being set as parameters. For that we also need to take the validated config and directly set the parameters. This is done in the Extension class in the DependencyInjection folder which is again generated automatically. In that we can see the configuration being processed in the first two lines of the load method. This is where the config files such as config.yml and config_dev.yml are merged and validated against the tree in the Configuration class.

We can use the processed configuration array to access the values and set them as parameters:

We are now back where we started and had to make a few changes to get there, so what have we actually gained? Not much so far and our Twig extension is still expecting particular keys to be set in that array, which is going to cause issues if they are missing. We can start to get the benefits of the changes by tightening up the validation settings in Configuration class.

We do not just want an array with some values in this case we want specific keys to be set. So to ensure that the “full” and “partial” keys have values we can change the configuration to:

If we usual use the same name for these templates then we could set default values and use convention to avoid the explicit configuration but still leave open the possibility of overriding these values if we need to:

There is a console command to dump the config, showing the available key and any default values. This is dumped as Yaml so you can copy it as a starting pint for configuring the bundle. You can run it for this demo bundle with app/console config:dump-reference acme.

We can add additional information to this from the configuration tree using the info() and example() methods. Info is printed above the key it is set for as a comment; examples are printed as an inline comment after the value. The example is less useful where we already have default values so let’s go back to version where we didn’t and enhance it with some additional information:

Running the console command now gives us:

So we have made our bundle more robust by validating its configuration and made more information about this configuration available to future uses of it. There are a lot more options available when validating configuration as there are a lot more possible requirements around what config is needed. There is more information on the possibilities when defining configuration in the official documentation.

Symfony2: More on Twig Ajax Templates

This post is a few notes to follow up on some of the responses to my previous post on reusing inner Twig templates for full page responses and ajax responses.

One clarification to make, as I had not made it clear, is that is only relevant to the case where you are sending back HTML fragments is response to Ajax requests (and where that fragment is the same as the full page response minus the common parts of the page). If your Ajax response is XML or JSON then this technique is irrelevant as you will already be using different templates. In that case you can switch template using the _format route parameter or you may want to look at using the FOSRestBundle.

Thomas Rabaix of the Sonata Project pointed out that a further improvement can be made by separating out the names of the templates to be extended into configuration by using Twig globals. This means that the choice of template to extend is no longer hardcoded into the templates at all. In a Symfony2 app it is easy to register globals in config. Our simple intermediate template that decides whether to extend the full or ajax template would now look like this:

with the global parameters set in the app’s main config file:

I also mentioned moving any logic for deciding which template to use to a Twig extension, if it became more complex than our simple ternary operator, so that it could be tested outside of a template. This could return the template to use rather than just a boolean allowing more complex decisions to be made as well.

A simple version of the extension may look like this:

We can now remove the intermediate template altogether and call our twig function from the inner template:

In this example the templates are hardcoded in as class constants to keep the example straightforward, this could be changed to have them injected in to the extension so that they can be kept in configuration instead.

Symfony2: Ajax and Full Page Templates

A quick look at one way to use the same controller action and Twig template (or just template) for displaying a full page and also just the inner content for an Ajax request in a Symfony2 application. This is using the ability to set which template a twig template extends from dynamically (which is shown here in the Twig documentation).

So assuming we have a current inner template that looks like this:

This extends our main layout template that adds the rest of the page, the header, footer etc. Whenever we render it we will get the full page with all the content from the outer template as well. For an Ajax request we only want the content of the body block to be displayed, we do not want any of the outer content that is provided by the the main template and we are not interested in the title block either. We can do this by creating an alternative Ajax outer template to render just the body block that is as simple as:

Then in our inner template we can use the app global to find out if it is an Ajax request:

Note: If you are using Twig outside of Symfony2 then you will need to add an alternative way of identifying whether it is an Ajax request.

It’s a simple as that. However we can add an improvement in order to avoid having to repeat that check in multiple inner templates. By adding an intermediate template that contains just that logic and extending the inner template from it this can be kept in a single template:

Another possible time you may need this sort of solution is where a template should sometimes be rendered as a main request and sometimes as a subrequest. The only real difference here is the logic in checking which template to extend. By passing a parameter when rendering a subrequest you can then check that:

If you needed to combine these and other reasons for making the decision it would be worth moving the logic involved to a function using a Twig extension where it could then be tested outside of the template.

Symfony2: Trimming Fat from Controllers

In this post I am going to look at some techniques for cleaning up Symfony2 controller actions. Some of this by using some of the extras that are part of the standard distribution and some by moving code out to be triggered by events.

So here is a fairly standard update action in a controller:

The controller action starts by checking if the current user has the ROLE_ADMIN role and throws and exception if they don’t. The product entity is retrieved from the database based on the passed id. A form is created and the request retrieved from the container and bound to the form. If the form is valid the entity has its last updated field updated, the entity manager is flushed and an email sent to notify of the changes. If the product changes are not valid then the edit form is redisplayed.

The controller action is quite lengthy now and some of the work being done, in particular the sending of the email, does not really belong in it. Let’s go through some steps we can take to arrive at a much leaner controller.

Starting with a task common to many actions, the rendering of the template and returning a Response object with the results can be made simpler. By adding the Template annotation we can just return the array of parameters to be passed to the template. With the annotation in place, when you return the parameters the template will be automatically rendered and a Response with the result sent. Note that the annotation is namespaced and requires the use statement to be added:

A further annotation, the Secure annotation can be used to replace the permissions checking. By adding this annotation the check for the ROLE_ADMIN role and the exception throwing if necessary, will take place without the need for the code:

We can use Symfony2 resolving of controller action arguments to remove more code from our action. First by having the request automatically injected as a method argument. By type hinting the argument as Request the current request will be passed to the action automatically and we can remove the line requesting it from the controller:

We can do something similar for the Product by using the ParamConverter annotation. So instead of the $id argument we have a $product type hinted as our Product entity. This is automatically retrieved from Doctrine or an exception thrown if it is not found, pretty much as we were doing in the code anyway, allowing us to remove the code for getting the entity from the database altogether:

In fact in this case, where we are not setting any options on the ParamConverter annotation, we can omit it altogether:

If you have are not using Doctrine then you can still get similar results by creating your own ParamConverters.

We have now removed a lot of the boiler plate code that is needed in a lot of actions and we are starting to be able to see what our action is doing better. It looks like it is doing a bit too much around the saving of the product changes. Keeping track of when it was last updated is really a job for the entity itself rather than the controller. Fortunately with a Doctrine entity this can be easily achieved with Doctrine’s lifecycle callbacks. By enabling these with an annotations and then annotating a method that updates the lastUpdated field before the update is persisted:

We can now remove worrying about keeping this up to date from the controller. This time not only have we reduced the controller action we have ensured that the last update field is kept up to date however the entity is updated and not just from our controller action.

The last step is to remove the sending of the email, we can again do this with an event. In this case we need to use the mailer service and we do not want to have to inject it into our entity. We can use a standalone event listener instead and inject the services and parameters we need directly into the constructor:

In the service configuration file we specify the services and parameters to pass into the listener and tag it as an Doctine event listener. The listener will now be called after an entity is updated:

We can now remove the sending of the email from the controller. Again as well as reducing the size of our controller we have introduced flexibility to our application. It is now easy to change or remove the listener without having to touch the controller code. We could even add another listener to send SMS notifications without touching the controller. If you are not using Doctrine then you can still gain these benefits by raising your own events with the event dispatcher.

Our controller is now much shorter than before by removing much of that boiler plate code and it is easier to see what is happening. The decision about what happens when a product is updated have been moved away from the controller and into the model layer.

Note: The example controller extends from the base controller and makes direct use of the service container. I have previously written about moving away from in favour of controllers as services. I do think there are advantages to that but since extending the base controller is more common, I have based my example for this post on that.

Symfony2: Console Usage Notes

There is quite a lot of documentation, blog posts etc out there on writing console commands for Symfony2. Here though I am going to look at the more basic usage of the console with a few notes on getting more out of it.

Listing Commands

You can get a list of the options for running commands as well as the currently registered commands by runnning

you can omit the list and just run

for the same output.

Third party bundles can register new commands so the list can change as you install more bundles into an application.

The commands are namespaced using : as the separator, you can list just the commands in a particular namespace by specifying the namespace with the list commands. For example to just see a list of doctrine commands:

You can be more specific again with:

to just see the Doctrine mapping related commands.

Help

You can just get usage details and options without the list of commands with

You can get help specific to an individual by specifying that command a well, e.g.:

Shell

If you have several commands to run then using the shell option will stop you being returned to the normal command line and allow you to just run Symfony2 commands without the need for specifying app/console:

Shortcut Syntax

You can avoid having to type out the full names of commands by just typing the shortest part needed to make it unambiguous. For example, to clear the cache you can just type:

ca rather than c is needed to avoid ambiguity with config and container.

Different Environments

By default when you run a console command it will run in the dev environment. You can change this by specifying the environment:

For some commands the environment you run in important because it will change the effect of running the command e.g. cache:clear and assetic:dump. For other commands though they will run the same but you will get them to run quicker and use less memory by using the prod environment – remember to clear the production cache if necessary first though.

You can still run commands in the dev environment and get some performance gain for commands which collect a lot of debug information by turning off debug mode. For example, the populate command in the FOQElasticaBundle will, by default, collect a lot of debug information which will cause it to use a lot of memory when indexing a lot of entities, this can be avoided by specifying no debug:

Symfony2: Coding Standards Update

I posted about coding standards in Symfony2 and how to check them a while ago. Since then the standard used has changed as Symfony2 has adopted the PSR 0,1,2 standards. This is just a very quick post to update my earlier post since some of the information in it is now out of date.

Checking these standards will be one of the standards bundled with PHPCodeSniffer although work is still continuing on this at the moment. You can get the work in progress if you get PHPCodeSniffer from github instead of installing it using Pear. Once this is complete there will be no need to install a custom standard in order to check that your Symfony2 project code meets these standards, you can just run /path/to/phpcs --standard=PSR2. Using PSR2 as the standard will automatically check PSR1 and 0 as well as they are subsets of PSR2.

As well as just checking the standards, you can now also use Fabien Potencier’s coding standards fixer, which not just checks but fixes code to meet these standards where possible making fixing it a much less tedious process.

Symfony2: Using Validation Groups

Validation groups are covered in the Symfony2 documentation but are split between the sections of validation and forms. In this post I will look at using them when you have multiple forms for a single entity which is one of the most common use cases.

A Brief Introduction to Validation in Symfony2

In Symfony2 applications validation constraints are applied to the Entity and not to the Form. Strictly speaking any PHP class can be validated, there is nothing special about the class the validation is being applied to. The class does need to extend anything, it is passed to the validation service which performs the validation based on the metadata about the class whether that is stored as XML, YAML, PHP or as annotations in the class file. I’m just going to give examples with annotations here, details of using the others can be found in the official docs.

So let’s say we have a Profile class representing the information about a user on our application. We can set the validation constraints we want on our fields with annotations:

The validator service will let us validate the fields of our Profile class, this can be injected into any of our services that need to validate an object:

Whilst this is very useful, a lot of the time we will want to use a form to allow users to add/edit their profile and then validate the model via the form. So we may have a form class that looks like this:

We can then make use of this form class in a controller action:

It can look from this as though the validation is tied to the form since we ask if the form is valid. This is a very useful shortcut method but slightly misleading. What is actually being validated is the Profile object we created and passed to the createForm method of the controller after it has had the data from the POST request added to it.

The advantage to letting the form interact with the validation service really comes into its own when you have forms with collections and embedded forms as it ensures that all the objects involved are valid for you. This is then a real time saver but it is helpful to remember that the form is actually using the validator service to validate the associated entities.

Multiple Forms with one Entity

One potential disadvantage of associating validation with the entity is that for many applications you do not have a one to one relationship between models and forms. If we discover that asking for a lot of profile information during registration is putting users off signing up, then we might decide to split up asking for this information. We just want to ask for some basic information as part of registration and then ask for the rest of the profile information afterwards. We now have the following forms. The first for pre-registration, where we just ask for their name and email address:

The second contains those fields so they can edit them and also their phone numbers and country:

The problem we now have is that when we validate the pre-registration form it will fail because phoneNumber and country are required fields but the user will not have filled out these fields as they were not in the form. We do not want to just remove the validation relevant to the second form from the Profile class, whilst the first form will then be able to be successfully validated, the second will not have its additional fields validated.

Validation Groups to the Rescue

This is not a reason to change from having the association between the entity and validation and go to associate validation with forms. Conceptually validation belongs with the entity, it is what is being validated, the form is just one means of setting the data on the entity.

This issue can instead be solved using validation groups. The validation groups allow you to specify which validation assertions should be used when you are validating a model. The group is specified in the configuration for the constraint, if no group is specified the constraint will be part of the Default group. In our case we want to set a group for fully validating a profile but by default only validate the pre-registration fields:

We can now choose which group of constraints we are interested in validating against. So when the user first joins up we will not want the second stage constraints to be enforced so it is only the Default group we want to be enforced. This is the group that will be used anyway for the form, so when we check if our pre-registration form is valid only the constraints that do not have a group specified will be checked and our full constraints will be ignored.

For the full form we want to specify that both the default and the full constraints are applied which we can do in the getDefaultOptions method of our form type class:

Edit: In Symfony 2.1 the getDefaultOptions method has been deprecated, you should use setDefaultOptions instead:

Note that we have to specify the Default group as this will not automatically be included if we add a different group to the array. All the fields will now be validated, if we only want to validate the fields in the full group we could have just left out Default from the groups.

You can also use the groups outside of forms by specifying them as the second argument when using the validation service directly:

Multiple Groups

It’s forcing it a bit with our example, but let’s imagine that we want to split our number of forms further into a series of steps then we can use multiple groups, you can even assign multiple groups to a constraint:

These groups can then be combined as you see fit for a form. This is particularly useful if you need to create a wizard type form with a quite a few steps.

Wrapping Up

Using validation groups allows us to make validation much more flexible than it would be otherwise. Without the validation groups we would not be able to selectively validate an entity which would cause some real issues with applications with multiple forms. They can be used to separate an entity’s constraints into separate forms but this is just a way of using them rather than all there is to them. There is still no direct tie introduced between the groups and the forms, so a form can use multiple groups and the groups can also be used outside of the context of forms.

ShefPHP Symfony2 Bootcamp Part 3

Tomorrow is the third part of the ShefPHP Symfony2 bootcamp. As well as last month’s requirements, this month you need to install elasticsearch. For the purposes of the session, it can just be downloaded and run, there is no need to worry about making it into a service (you will you need Java as well to run it). You will also need to have curl support enabled in PHP.

Please also download the start point, as with last month this is different from last month’s end point so please will all attendees download this. Thanks, see you on Wednesday evening.

ShefPHP Symfony2 Bootcamp Part 2

Tonight is the second part of the ShefPHP Symfony2 bootcamp. There is a bit of preparation for attendees. Please could you have mongodb installed, along with the pecl extension. You also need to have the gd or ImageMagick extension installed.

I have put together a starting point for the application, please could you download this in advance. This is not the same as the end point of session one, so please can you do this even if you did attend the first part.

Symfony2: Manipulating Service Parameters and Definitions

In my previous post I looked at Symfony2 Service Container Compiler Passes, in this post I will look at how to manipulate service container parameters and definitions from within a compiler pass.

So the important method of the compiler pass which gets called when the container is being built is the process method which looks like this:

In this method we can work with the passed in container which has been set up with parameters and service definitions from the various configuration files.

Getting and Setting Container Parameters

Working with container parameters is straight forward using the container’s accessor methods for parameters. You can check if a parameter has been defined in the container with

You can retrieve parameters set in the container with:

and set a parameter in the container with:

Getting and Setting Service Definitions

There are also some helpful methods of the passed in container builder for working with the service definitions.

To find out if there is a definition for a service id:

This is useful if you only want to do something if a particular definition exists. In my previous post I looked at an example from the AsseticBundle where a parameter was required only if a particular service has defined so hasDefinition() was used to check for the service definition before checking if the parameter was set. Here it is again:

You can retrieve a definition with

or

which unlike getDefinition() also resolves aliases so if the $serviceId argument is an alias you will get the underlying definition.

The service definitions themselves are objects so if you retrieve a definition with these methods and make changes to it these will be reflected in the container. If, however, you are creating a new definition then you can add it to the container using:

Working with a definition

Creating a new definition

If you need to create a new definition rather than manipulate one retrieved from then container then the definition class is SymfonyComponentDependencyInjectionDefinition.

Class

First up is the class of a definition, this is the class of the object returned when the service is requested from the container.

You may want to change the class used by a definition, if for example there is functionality which can only be used if a service from another bundle exists then you may have a class which make use of that other service and one that does not. The one that does not could be used for the service and then the one with the extra functionality swapped in using a compiler pass if the other service is available.

To find out what class is set for a definition:

and to set a different class:

Constructor Arguments

To get an array of the constructor arguments for a definition you can use

or to get a single argument by its position

You can add a new argument to the end of the arguments array using

The argument can be a string, an array, a service parameter by using '%paramater_name%' or a service id by using

In a similar way you can replace an already set argument by index using:

You can also replace all the arguments (or set some if there are none) with an array of arguments

Method Calls

If the service you are working with uses setter injection then you can manipulate any method calls in the definitions as well.

You can get an array of all the method calls with:

Add a method call with:

Where $method is the method name and $arguments is an array of the arguments to call the method with. The arguments can be strings, arrays, parameters or service ids as with the constructor arguments.

You can also replace any existing method calls with an array of new ones with:

Wrapping Up

The methods available then are the same ones that can be used to configure the container in the first place and which are shown in the Symfony2 documentation along with the XML and YAML ways you may be more familiar with. You would usually want to use config files rather than directly creating the definitions when setting the container up. In compiler passes you need to use these methods for making changes to the service definitions.

I have only looked at the more common methods of the definition object here, you can see some more available methods, by looking at the relevant docs e.g. How to Use a Factory to Create Services and looking at the PHP tab in the examples. Bear in mind the place of compiler passes in the process of building the service container though, for example, if you add a tag to a definition in a compiler pass, but the pass that looks for those tags has already run, then it will have no effect.

If there is one thing to take away from this post, it is that if you dislike writing YAML or XML configs for services then just be glad you can and you do not have to write all the definitions this way 🙂