We extensively use the Symfony framework and its components in our projects. A few years ago, we released an open source CMS built on Symfony and a whole host of community bundles. Every time a new release of Symfony is made, we follow as soon as possible with a compatible version of the content management system. Recently a major new version of Symfony was released: version 3.0. This upgrade drops all backwards compatibility code that was added since 2.0 was released in 2011. In this article we share our insights and methodology for going about such a huge upgrade based on our experiences in doing so with the Kunstmaan Bundles CMS.

In most cases, updating a Symfony application to a new minor release (eg 2.4 → 2.5) has gone pretty smoothly because of Symfony’s backwards compatibility promise. Symfony guarantees that any Symfony version in the 2.x range (>=2.3) must be backwards compatible with 2.3 and backwards compatibiltiy breaks are only allowed in new major versions like 3.0. Migrating to such a new major version is a little bit more time-consuming. 

What’s new in Symfony 3.0? Well nothing really… All new features were already included in version 2.8, but all deprecated code was removed and a new directory structure was introduced. Version 3.0 is not even a Long Term Supported (LTS) version as you can see in the roadmap below.

So why spend time on this upgrade? If we want to be able to benefit from new features in the future, we need to be able to upgrade to 3.x releases in the coming year and a half. 

The process we follow to upgrade the core CMS and our own projects is as follows:

  1. Upgrade to Symfony 2.8
  2. Make our code and the used community bundles deprecation free
  3. Update to the new directory structure
  4. Upgrade to Symfony 3.0

1. Upgrade to Symfony 2.8

Upgrading your project to Symfony 2.8 is fairly easy. Just update the required Symfony version in your composer.json file to “~2.8” and run 

composer update symfony/symfony --with-dependencies

This will download version 2.8 and update any other libraries that Symfony depends on.

In this new version you’ll see the redesigned web profiler toolbar, that clearly indicates how many deprecation messages were triggered on the current page. This profiler will come in handy in the next paragraphs.

2. Make your code and the used community bundles deprecation free

All deprecated features and functionality were removed in Symfony 3. This means that you should update your own codebase to make it deprecation free as well. In most applications you also depend on third party libraries, so you should also update them to a version that does not trigger any deprecation warnings.

Luckily, there are some useful tools that can help us with this process… And for the remaining deprecations, just fix them manually by following the Symfony upgrade instructions.

Tools that can help you with fixing the deprecation warnings

When you take a look at the list of deprecation warnings in your application, you’ll see that the same warnings occur multiple times (on multiple locations). For large codebases, this upgrade process can be very time-consuming. Fortunately, there are some command line tools that can help you with updating your codebase and fixing the trivial deprecation warnings.

1) Symfony Upgrade Fixer

This open source tool, written by Saša Stamenković, tries to find deprecated code and fixes it for you. You can find the list of fixes it can do on Github. After the installation you can just run

symfony-upgrade-fixer fix .

in your project path, and it will automatically make the changes in your code. With a simple "git diff" you can inspect the changes, and commit them. Note that it also alphabetically orders the use statements in your PHP classes, so you might end up with lots of changed files even if there were no deprecation fixes.

2) Symfony Deprecation Detector

The SensioLabs Deprecation Detector runs a static code analysis against your project’s source code to find usages of deprecated methods, classes and interfaces. After the installation, just run 

/path/to/deprecation-detector/bin/deprecation-detector

in your project directory. This tool does not automatically update your code, but it will tell you where you need to make changes to remove some deprecations.

These 2 tools are the only ones we found useful, but be aware that they will not spot all the deprecations. You will still have to debug and fix the remaining deprecation messages manually.

Deprecations in PHPUnit

When you run your tests using PHPUnit, no deprecation warnings are shown by default. To help you, Symfony provides a PHPUnit bridge. This bridge will show you a nice summary of all deprecation notices at the end of the test report. To enable this bridge, just run:

composer require --dev symfony/phpunit-bridge

From now on, the deprecation messages are shown in your terminal when you run PHPUnit.

Tip: When you are running your unit tests in Travis (via the Symfony bridge), you can set the allowed number of deprecation warnings that will not trigger a build failure. This prevents any new unit tests to trigger extra deprecations, without needing to update your existing tests instantly.

env:
  global:
    - SYMFONY_DEPRECATIONS_HELPER=5 #5 deprecation warnings allowed

3. Update to the new directory structure

Symfony 3.0 has adopted a new directory structure. But… you can already use this new directory structure in your SF 2.8 application to make the upgrade process easier later on. 

Introducing the var directory

The most noticeable change is the new var directory which holds all generated files: logs & cache. To update your application, you need to override a couple of methods of the AppKernel class. Just copy and paste them from the latest Symfony version, and create an empty var directory:

mkdir var
git mv app/cache var/
git mv app/logs var/

Move the console to the bin directory

The app/console command was moved to the "bin" directory in Symfony 3. To adopt this change in SF 2.8, just move the file and update the path to the autoloader after the move:

mv app/console bin/console

and in the file itself replace the

require_once __DIR__.'/bootstrap.php.cache';

with

require __DIR__.'/../app/autoload.php';

Update paths in composer.json

The last thing you need to do is update your composer file with the new directory locations. You need to add the correct directory paths in the extra block of your composer.json file:

"extra": {
    "symfony-app-dir": "app",
    "symfony-web-dir": "web",
    "symfony-var-dir": "var",
    "symfony-bin-dir": "bin"
}

4. Upgrade to Symfony 3

We are almost there… Now it’s time to update Symfony to version 3.0 by changing the required SF version in your composer.json file to "~3.0" and run 

composer update symfony/symfony --with-dependencies

After all the preparations you did, this last step should go without any problems. Enjoy!

Written by

Kristof Jochmans

Senior Software Architect

Follow @jockri