Upgrading from Symfony vPR5 to bleeding edge
Some background
We are working on a new Symfony2 project (by new I mean I have been working on it for 2 months now), but it is slowly coming to fruition.
I began in December and cloned the Symfony 2 vPR4 branch from the main Symfony
GIT repository at github.com/symfony/symfony. About a month ago I upgraded from
vPR4 to vPR5 and spent about 4-5 hours making everything work, and a month later,
I thought it was a good time to upgrade to vPR6, but then had a better idea and
decided to upgrade to the bleeding edge repository at github.com/fabpot/symfony.
- This repository always has the latest changes
- I dont have to worry about it unexpectedly breaking things, as GIT uses a detached head_, and
I will not automatically get the latest changes when I
git pull. - Updating the rapidly evolving framework is easier as I can upgrade frequently instead of waiting for the next release. (and hope that most changes are not reverted :) )
Upgrading the repositories
First I updated the Symfony 2 submodule::
# cd to the Symfony submodule dir, in my case ...
cd src/vendor/Symfony
git checkout origin/master
you should get a message like the following::
HEAD is now at 9b15b69... [AsseticBundle] Sort Twig assets by name before loading for filesystem-independent results
So great, we now have Symfony up-to-date. But Symfony is not the only third-party code that we use, so I had to up date the following submodules also::
cd src/Bundle/FOS/UserBundle
git checkout origin/master
cd src/Bundle/DoctrineExtensionsBundle
git checkout origin/master
Perfect. Now everything is up-to-date except our code base!
Upgrading the code base
OK, the last part was easy. The next chunk of my day was spent blindly adapting the code integration to work with the latest version of Symfony and the other third-party libs. I say blindly as really I had no idea how long this would take and where the changes were made. In hindsight checking the GIT commit history should have given me a good idea. So as is usual for me in infomatics, what I thought would take an evening took over 10 hours in total :)
About 3 hours in I had the idea of writing this blog post and so started keeping note of the changes I was making.
Naming convention change for templates
Following a prolonged debate on the symfony-devs mailing list it was finally decided
to change the mytemplate.format.engine (e.g. mytemplate.html.twig, or mytemplate.json.php)
back to mytemplate.engine.format (as was the case in vPR4.
Fortuneatly this is actually pretty easy using the Linux BASH shell::
for i in `find . -type f -name "*twig.html*"`; do git mv $i `echo $i | sed 's/twig.html/html.twig/g'`; done;
The above, in one line, iterates over all the filenames that are output by the find command, and performs
a git mv operation on each moving (renaming) it using a combination of echo and sed.
Then we just need to rename all the references inside the files, for this I used the rpl tool, because its easier then anything else::
rpl '.twig.html' '.html.twig' ./ -R
All done.
Resources in routing files now prefixed with @
So in our case::
crm:
resource: CrmBundle/Resources/config/navigation.xml
type: navigation
Became::
crm:
resource: @CrmBundle/Resources/config/navigation.xml
type: navigation
DIC - Configuration Loading
Dependency injection has become somewhat sexier since vPR5, and during the upgrade process I managed to improve our use of the DIC (Dependency Injection Container), which I will talk about later.
The first thing I noticed is that the syntax no longer has the mybundle.config:
format, where the previous example would cause the execution of function loadConfig
and the following, mybundle.foo would cause the execution of function loadFoo. Now
there is just mybundle: and all configuration given thereafter is passed to a single
load method.
DIC - Kernel Listener Tag
The kernel.listener tag used to cause the referenced class's register method to
be called with the EventDispatcher so that it could register itself to the event dispatcher
and so do stuff with events, this event has now changed to be more explict and eliminates
the need for the register method::
$container->register('some.service', 'Vendor/SomeBundle/SomeClass')
->addTag('kernel.listener', array('event' => 'someevent', 'method' => 'foo'));
So the new syntax explicitly passes the specified event to the specified method, which is cool, unfortunately we used this listener for another purpose, so it no longer worked for us.
We originally used this listener to kick-start our CMS's extension system by allowing
extensions to tune-in to the kernel,listener event and register themselves with
the CMS's extension_manager. Fortunately I found a better way to do this using a compiler pass.
DIC - Implementing compiler pass
So basically, a compiler pass is a way to modify the DIC after it has been initialized,
which enables us to add our CMS extensions directly in the DIC by explicitly adding
extensions to the extension_manager Definition. Or another way to put it would be that
the DIC creates a template class configuration and we can add the extensions directly
to this template::
// src/Vendor/SomeBundle/DependencyInjection/Compiler
class RegisterCoreExtensionsPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$extensionManager = $this->container->getDefinition('yprox.extension_manager');
$serviceIds = $this->container->findTaggedServiceIds('yprox.extension');
foreach ($serviceIds as $serviceId => $attributes) {
$extensionManager->addMethodCall('addExtension', array(new Reference($serviceId)));
}
}
}
So you can see we instruct the DIC builder to add a method addExtension for each
service definition tagged with yprox.extension. Now, when we call the extension.manager
service from within the application it will automatically add all these extensions.
I like it.
Forms -- Lots of changes
The form framework has undergone some significant API changes, which I like also.
Forms -- Factory Method and Form Context
The way to instantiate forms has changed from::
$form = new MyForm('myform_name', $data, $this->get('validator'), array('option1' => 'foo', etc...));
to::
$form = MyForm::create($this->get('form.context'), 'myform_name', array('option1' => 'foo'));
So, firstly it should be noted that everything is an option now, even the validator. So with this
in mind the first argument of the factory method is a reference to a service which provides default
options, including the validation service and the csrf stuff. The options in the third argument
are merged with these contextual options.
Secondly, you might have noticed that the $data argument is missing, this has been moved (as standard)
to the bind method, which is now more funky::
$form->bind($this->get('request'), $data);
By passing the request object directly the age-old Symfony form practice of if ('POST' === $request->getMethodName()) { // bind form, validate, etc ... } is no longer needed and we can simply call isValid inline::
// my controller
$myentity = $this->getMyEntity();
$form = MyForm::create($this->get('form.context', 'myform_name'));
$form->bind($this->get('request'), $myentity);
if ($form->isValid()) {
$this->get('session')->flash('message', 'Entity is Valid.');
}
Forms - Removal of Doctrine value transformers
The value transformers for doctrine, EntityToIDTransformer, CollectionToChoiceTransformer and another which I forget the name of were removed from the source code because they were buggy, unfortunately they are used quite heavily in our project so I had to reimport them, I could only get them working by modifying the Core library, which is far from ideal, but I hear that they will be reimplemented properly soon ...
Security is now in its own bundle!
Whilst the Security component rests in the core the framework integration has been moved
from the FrameworkBundle to SecurityBundle.
At last
It took a while and I have not covered many things, but there are many changes for the better
from vPR5 to latest, and it has, I think, been a real community effort. I have been following
the symfony-devs mailing list closely and it has been really good to see progress in action.
I think Symfony 2 will arrive!
.. _head: http://sitaramc.github.com/concepts/detached-head.html
Comments
Post new comment
Tags
- DropBox
- XMPP
- android
- apache
- archos
- audacious
- awesome
- bash
- bootstrap
- bristol
- diagramming
- doctrine
- doctrine2
- git
- gloucester
- graphs
- gt540
- jack
- javascript
- manchester
- mapdroyd
- markdown
- mongodb
- paris
- php
- profiling
- projectm
- running
- scripting
- sed
- software design
- ssh
- symfony
- symfony2
- thonon-les-bains
- trainer
- travel
- twig
- ubnutu
- vim
- weymouth
- workflow
- xdebug
- xml
- ylly
- yprox
10 Latest Items
-
08
Maytrainer [Velo] paris - compiègne 153.00km / 05:48:32 / 00:02:16mpkm Fois.
-
06
Maytrainer [Velo] Vincennes Hippodrome 1hr 34.34km / 01:00:00 / 00:01:44mpkm Solo effort. Did interfals (sprinting from zebra crossing to hairpin turn).
-
05
Maytrainer [Run] Diderot > Pnt. Alx III > Rue de Charonne 13.96km / 01:08:40 / 00:04:55mpkm Good to run in the rain. Lots of traffic.
-
04
Maytrainer [Velo] Vincennes Hippodrome 1hr 32.20km / 01:00:00 / 00:01:51mpkm Rode apace a peloton, but tried not to get in the draft. Sprinted for a few minutes on every lap.
-
03
Maytrainer [Run] Dumas > P. Auguste > Belleville > Prc. de Villette > Pt. de Lilas > Pt. Vincennces 14.48km / 01:07:00 / 00:04:37mpkm Kept up a reasonably good pace. No problems from calf muscle as was the case yesterday.
-
02
Maytrainer [Run] Dumas > Diderot > Trocadero > Basitlle 14.48km / 01:10:00 / 00:04:49mpkm Experienced pain in the back of my calf and stopped a few times towards the end.
-
01
Maytrainer [Velo] Dumas > Rambouillet 123.31km / 05:06:00 / 00:02:28mpkm Paris Rambouillet. Sunny day. Ate a bakery pizza, tarte au pomme and drank a cola then lay down on a bench in the châte...
-
29
Aprtrainer [Run] 14 - 15 miles 23.34km / 01:50:00 / 00:04:42mpkm Run down the Rue Charonne, down Boulevard Henri IV, round le Ile St-Louis, along the Seine, crossing the Pont d'lén...
-
28
Aprtrainer [Velo] Vincennes Hippodrome 1hr 34.12km / 01:00:00 / 00:01:45mpkm Actually 45 minutes. Rain stopped play. Also boredom. "Sprinted" up the second half of the upside at each circ...
-
27
Aprtrainer [Run] 54 minutes 11.50km / 00:54:00 / 00:04:41mpkm Ran down and around.
