Symfony2: Obtaining the Request Object

In this quick post I am looking at how to obtain the Request object in a Symfony2 controller as a service. This is actually covered in the docs but in one of the earlier introductory pieces and so is easily missed or forgotten about by the time you actually need to know it. I know I missed this and have previously not shown the correct way to do this.

If you are extending the base controller then its getRequest() method will retrieve the Request object from the container. If you are making your controllers services then you will generally inject in the services, you would have requested from the container, to the constructor or via a setter method. This is not the correct way to work with the Request object as it has a narrower scope than the controller. This basically means that the controller can be used for multiple requests whereas a Request object should only be used for the single request it represents. This means that a fresh request object should be injected each time an action of the controller is called rather than just when the controller is created.

The base controller uses its injected container to get a new Request object each time the action is called, so one way would be to inject the controller itself into the service. There are many reasons not do this which I have covered elsewhere. Fortunately there is a simple way to avoid having to do this, thanks to a cool feature of the framework; Symfony2 will automatically inject the Request object into your actions each time they are called, if you ask for it in the following way:

The key here is the type hint of SymfonyComponentHttpFoundationRequest, as long as this is in place the Request object will be injected in as a method argument. This avoids any scope issues without having to inject the container. This will work for controllers whether they are services or not and regardless of whether there are any other method arguments. So, for example, you can still combine this with annotated parameter conversion:

Symfony2: Routing to Controller as Service with Annotations

A very quick post as I couldn’t find anything documenting this yet (I will submit this to the docs also). If you want to use the combination of annotations for routing and also make your controllers into services then you can by specifying the service id in the class route:

Whether you should make controllers services is a while different matter and I am going to stay away from that can of worms (at least for today).

Symfony2: Doctrine Migrations and ACL tables

Edit: This is an issue with Symfony 2.0.x and looks to have been resolved for 2.1, please see Denderello’s comment below for more details

If you use Doctrine migrations in a Symfony2 app then one difficulty you may run into is with database tables that do not relate to your entities. The doctine:migration:diff command will make sure that the current database schema is updated to match the schema generated from the entities in an app. Whilst this is an excellent way of managing database versions across multiple instances of the app, I have run into a problem with this. If you are also using the ACL feature of Symfony2 security then this uses database tables that do not have corresponding entities. This means that whenever you generate diffs they will include the SQL to remove the ACL tables.

I have tried various solutions to this. The easiest would be if there was a way to specify that certain tables should be ignored when running the diff command. As far as I can see there is no way to do this at the time of writing, someone please correct me if I am wrong.

I tried creating entities for the ACL tables by creating these using the init:acl command in a fresh version of the database and the following the procedure to generate entities for the tables. Unfortunately there were some differences between then entities and the tables so that running doctine:migration:diff still created SQL relating to these tables. It may not have been significant but I do not know enough about how the ACL part of the security component works to want to run these. Additionally it felt like a very hacky workaround anyway.

The successful attempt was just to move these tables to a different database which turned out to be a pretty simple procedure. So here is how to move the ACL tables to a different database:

You need to set up an additional connection in config.yml with the details of the second database:

The only differences between the connections is the database name in this case. The new database name parameter acldatabasename needs adding to parameters.ini. You also need to specify the new connection is to be used for ACL in security.yml:

Then setting up the ACL tables with the usual command will add them to the new database:

Now if you run the doctine:migration:diff command it will just look in the default connection’s database and ignore the other connection’s database.

This all assumes you are still at a development stage where you can just start over with a fresh database. If not then you will need to actually move the existing tables to the new database.