Supporting Multiple Versions of Symfony Components

This article was published on Wednesday, December 23, 2015; more than 18 months ago. This means the content may be out of date or no longer relevant. You should verify that the technical information in this article is still current before relying upon it for your own purposes.

Symfony recently released version 3.0 of their components and framework. I use these components in a couple of my own packages, along with a bunch of other packages. How do we allow our package to work with multiple versions of the Symfony components?

If your code is compatible in both 2.x and 3.0, you can support both of those in your composer.json file. If not, you will likely want to manage different releases of your library and let the user know which one to use for their version of Symfony.

We can use a pipe operator as an or in composer. For example in my FileLoader package, I use the Config and YAML components and I want to support 2.3 and up. In my composer.json file, I changed these lines.

// Old
"symfony/config": "~2.3",
"symfony/yaml": "~2.3"

// New
"symfony/config": "~2.3|~3.0",
"symfony/yaml": "~2.3|~3.0"

If the project already has an existing version of the Symfony component, it will use that, otherwise it will use the latest allowed, which in this case is 3.0.

Testing

Our package now supports multiple versions, but how do we verify that it works in all those packages? We’re going to look at how to do this in TravisCI. If you’re not using Travis, I would highly recommend it for open source projects. It makes continuous integration a breeze.

Let’s take a look at a basic .travis.yml file for a PHP project.

language: php

php:
  - '5.4'
  - '5.5'
  - '5.6'
  - '7.0'
  - hhvm

sudo: false

before_script:
  - composer install --dev --no-interaction

With this it will only test against the latest version of Symfony components in each PHP version we specify. We can use environment variables to test against multiple versions of Symfony components. Let’s add one for each version we are allowing in our composer.json, in this case 2.3 and above.

env:
  - SYMFONY_VERSION=2.3.*
  - SYMFONY_VERSION=2.4.*
  - SYMFONY_VERSION=2.5.*
  - SYMFONY_VERSION=2.6.*
  - SYMFONY_VERSION=2.7.*
  - SYMFONY_VERSION=2.8.*
  - SYMFONY_VERSION=3.0.*

Then in our before_script section, we’re going to tell composer to require that version of Symfony before we run composer.

before_script:
  - composer self-update
  - if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update; fi;
  - composer update

We also told composer to self-update, as travis is running an old version of composer.

For each one of the env values and PHP version we are testing against, Travis will create a build. This is our build Matrix. Every time we push, it will create our Matrix and look something like this.

Travis builds

Our Matrix can also be customized manually using the matrix option in our Travis config. We are going to do that to tell Travis not to create a build for PHP 5.4 and Symfony 3.0, as Symfony 3.0 requires PHP 5.5 or above.

matrix:
  exclude:
    - php: '5.4'
      env: SYMFONY_VERSION=3.0.*

You can add any number of things to exclude or even include here. Just check out the travis docs.

One final thing we are going to do is cache the global Composer directory. This will allow Composer to use a cached version of the Symfony component, rather than having to fetch it every time.

With all that said and done, our completed .travis.yml file should look like this.

language: php

php:
  - '5.4'
  - '5.5'
  - '5.6'
  - '7.0'
  - hhvm

sudo: false

cache:
  directories:
    - $HOME/.composer

env:
  - SYMFONY_VERSION=2.3.*
  - SYMFONY_VERSION=2.4.*
  - SYMFONY_VERSION=2.5.*
  - SYMFONY_VERSION=2.6.*
  - SYMFONY_VERSION=2.7.*
  - SYMFONY_VERSION=2.8.*
  - SYMFONY_VERSION=3.0.*

matrix:
  exclude:
    - php: '5.4'
      env: SYMFONY_VERSION=3.0.*

before_script:
  - composer self-update
  - if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update; fi;
  - composer update

Commit, push, and verify that your code works with all versions of the Symfony components.

Bonus: Getting Coveralls Working

If you are using php-coveralls and happen to be using the Config Symfony component (like FileLoader is), then you will not be able to test against Symfony 2.3, as php-coveralls requires 2.4 or later. To fix this, I’ve opted to install it globally in composer. You could also download the .phar and use that instead.

after_success:
  - composer global require satooshi/php-coveralls
  - travis_retry php $HOME/.composer/vendor/bin/coveralls -v

Update 12/27/15: As some commenters have pointed out, Symfony 2.4, 2.5, and 2.6 are no longer supported. You can skip these in your Travis builds if you please.