Composer.json and Travis-ci for our Symfony2 Bundles

Travis-CI and Packagist / composer.json are the new toys in the PHP community and specially amongst the Symfony2 developers crew.

I like Travis-CI because you can easily setup Continous Integration to some degree without having to setup a full working Jenkins (or whatever suite) environment and code can be tested with different PHP versions. This can be really useful to ensure that our code is ready for the incoming PHP5.4. Of course, it will never be a substitute for a professionally configured Jenkins instance but can be a quite good complement to that.

And composer aims to remove dependency problems when our project needs other libraries to work.

In the good (well not so good) old PHP4 times old these good practices were more or less out of the table.
Most web pages were still quite small, there was not a big amount of open-source libraries used amongst projects, most PHP code was written from scratch and unit testing was not really needed (and not even possible, sometimes). But in the last years this has all changed (hopefully for good) and good practices are needed.

So, how can we do all this?

To illustrate this, I will use a small bundle I’ve been working on lately.
This bundle aims to complement out-of-the-box Symfony2 validator with some other validations that are quite common in web development. At the moment of writing this, only major CreditCard validations are included but more validations will be included in the following weeks.

You can see the source code in GitHub.

Composer.json

 1{
 2    "name": "pixelavengers/extra-validator-bundle",
 3    "description": "This bundle provides some useful extra validators",
 4    "keywords": ["validators"],
 5    "type": "symfony-bundle",
 6    "license": "MIT",
 7    "authors": [
 8        {
 9            "name": "Ricard Clau",
10            "email": "ricard.clau@gmail.com"
11        }
12    ],
13    "require": {
14        "php": ">=5.3.2",
15        "symfony/symfony": "2.0.*"
16    },
17    "autoload": {
18        "psr-0": { "Pixelavengers\\Bundle\\ExtraValidatorBundle": "" }
19    },
20    "target-dir": "Pixelavengers/Bundle/ExtraValidatorBundle"
21}

This is the composer.json file content. I think it is pretty self-explanatory and inspired in other big bundle composer files. In the require section, I must admit that requiring all symfony framework to just extend validations is not necessary, and would be better to just require symfony/validator. Anyway I think that it is ok to this example but please take into account that dependencies should only be what is really needed.

It is important to have a look also at the CLI unit-testing bootstrap.php file as I had to add some lines to make it work:

 1<?php
 2$vendorDir = __DIR__ . '/../vendor';
 3
 4if (!@include($vendorDir . '/.composer/autoload.php')) {
 5    die("You must set up the project dependencies, run the following commands:
 6wget http://getcomposer.org/composer.phar
 7php composer.phar install
 8");
 9}
10
11spl_autoload_register(function($class) {
12    if (0 === (strpos($class, 'Pixelavengers\\Bundle\\ExtraValidatorBundle\\'))) {
13        $path = __DIR__.'/../'.implode('/', array_slice(explode('\\', $class), 3)).'.php';
14
15        if (!stream_resolve_include_path($path)) {
16            return false;
17        }
18        require_once $path;
19        return true;
20    }
21});

As you can see, CLI bootstraping first checks that composer is properly installed, otherwise it outputs an error. Composer has its own psr-0 autoload but I couldn’t make it work without this spl_autoload_register snippet.

PSR-0 spec expects each namespace part to be a folder. We code our bundle to fit Symfony2 specs so that it will work as any other bundle but in this kind of projects our root directory is what would be a 4th level directory in a Symfony2 environment. For instance file Amex.php is in namespace Pixelavengers\Bundle\ExtraValidatorBundle\Validator\Constraints but inside the project it is in Validator/Constraints folder. So, first 3 namespace levels have to be “removed” in autoload. (This is harder to explain with words than actually seeing it).

And that’s it, to publish our bundle to packagist we just have to create a new account in Packagist website, and submit our package supplying Github public link. And here you can see this little bundle inside Packagist.

Travis-CI Integration

To integrate our tests with Travis-CI, a .travis.yml file must be created in the root of our project similar to this.

 1language: php
 2
 3php:
 4  - 5.3.2
 5  - 5.3
 6  - 5.4
 7
 8before_script:
 9  - wget http://getcomposer.org/composer.phar
10  - php composer.phar install
11  - phpunit

As you can see, we setup our project to be executed with 3 different PHP versions: 5.3.2 (still minimal SF2 requirements), 5.3 (which will use latest in Travis environments, right now it is 5.3.10) and 5.4.

And finally, before_script key is an array of commands to be executed before starting tests. In our case, we just have to download composer, install it and launch phpunit.

And to link our Github repository to Travis-CI, we just have to login to Travis-CI website with our Github account, and tell Travis which repositories are to be included.
What this does in the background is actually setup a service hook from Github to Travis-CI, and of course can also be setup manually in the Github side quite easily.

And that’s it, any new push to our repository will automatically launch Unit Tests in travis-ci.

Credits for Travis-CI part go to my friend Christian Soronellas we set up Symfony Barcelona project Travis-CI integration and introduced me to all this stuff!

Hope you liked this little explanation! Stay tuned!