Collecting CodeCoverage from symfony lime Tests


Since i use PHPUnit to test my symfony Applications and doing all automated stuff with Jenkins, i lost control over my lime test (e.g. in my plugins).
My Plugins stay in some kind of blackbox (lime isnt very useful with CI tools like Jenkins)

I love the Coverage Reports from PHPUnit (which is using PHP_CodeCoverage for that), which outputs me HTML or Clover, just as i need them.

To achieve the same with all my lime tests, i wrote a simple symfony plugin which, replaces the defaults “test:” tasks of symfony with my own modifed tasks.
Internally i extended the LimeHarness to use PHP_CodeCoverage for its reports:

Here is the Plugin

simply clone it or install it via pear or use svn.



PEAR: symfony plugins:install rsPHPUnitLimePlugin

After that you can use the tasks the same way (they have i slightly other name and some more options)


unit test coverage

  • symfony test:phpunit-unit –coverage-clover=log/clover-unit.xml
  • symfony test:phpunit-unit –coverage-html=log/coverage-unit
  • symfony test:phpunit-unit –coverage-folder=lib/
  • symfony test:phpunit-unit –xml=log/junit-unit.xml

functional test coverage

  • symfony test:phpunit-functional –coverage-clover=log/clover-functional.xml frontend
  • symfony test:phpunit-functional –coverage-html=log/coverage-functional frontend
  • symfony test:phpunit-functional –coverage-folder=apps/ frontend
  • symfony test:phpunit-functional –xml=log/junit-functional.xml frontend

plugin test coverage

  • symfony test:phpunit-plugin –coverage-clover=log/clover-functional.xml sfGuardPlugin
  • symfony test:phpunit-plugin –coverage-html=log/coverage-functional sfGuardPlugin
  • symfony test:phpunit-plugin –coverage-folder=plugin/sfGuardPlugin sfGuardPlugin
  • symfony test:phpunit-plugin –xml=log/junit-functional.xml sfGuardPlugin

all test coverage

  • symfony test:phpunit-all –coverage-clover=log/clover-functional.xml
  • symfony test:phpunit-all –coverage-html=log/coverage-functional sfGuardPlugin
  • symfony test:phpunit-all –coverage-folder=./
  • symfony test:phpunit-all –xml=log/junit-functional.xml

They work the same way as before, but they use PHP_CodeCoverage. You get nice HTML Reports and or Clover Reports.

To connect all your Plugin Tests with your default lime tests, simply modify your ProjectConfiguration:


   * reconfigure plugins
  public function setupPlugins()
    if(sfConfig::get('env') == 'prod')

    $plugins = sfFinder::type('directory')->name('*Plugin*')->maxdepth(0)->in(dirname(__FILE__).'/../plugins');
    $blackList = array('swFunctionalTestGenerationPlugin');

    foreach($plugins as $plugin)
      $plugin = substr($plugin, strripos($plugin, DIRECTORY_SEPARATOR)+1);

      if(isset($this->pluginConfigurations[$plugin]) && !in_array($plugin,$blackList))
        //connect the tests

To integrate this tests into your Jenkins Jobs simply use following build-step (as allways) :

export SYMFONY=$WORKSPACE/lib/vendor/symfony/lib

./symfony test:phpunit-unit --xml=log/junit-results-plugin.xml --coverage-html=doc/coverage-plugin/ --coverage-clover=log/clover-report-plugin.xml --coverage-folder=plugins/

This will test all your unit tests, and writes the coverage to html and clover
in your post-build-actions simply publish your coverage data

Voila, now you can monitor your oldskool lime tests, or your plugins. It works with unit,functional and all test tasks

my first symfony2 Bundle “ProjectUtilitiesBundle”

Provides some more RAD symfony2 utilities


  • Bootstrapper run commands defined in a yaml file to bootstrap an application
  • BundleLoader configure your Bundles in a yaml file
  • Configurator configures your application with private variables ie. database credentials 


Add ProjectUtilitiesBundle to your src/ dir

$ git submodule add git:// src/rs/ProjectUtilitiesBundle
$ git submodule init

Add the rs namespace to your autoloader

// app/autoload.php

    'rs' => __DIR__.'/../src',
    // your other namespaces

Add ProjectUtilitiesBundle to your application kernel

 // app/AppKernel.php

 public function registerBundles()
     return array(
         // ...
         new rs\ProjectUtilitiesBundle\ProjectUtilitiesBundle(),
         // ...

//or use the BundleLoader (see below)

Using DependencyInjection

$this->get('bootstrap');    //returns the bootstrapper
$this->get('configurator'); //returns the configurator
$this->get('bundleloader'); //returns the bundleloader

    class: Bootstrapper
    file: app/config/bootstrap.yml

    class: Bundleloader
    file: app/config/bundles.yml

    class: Configurator
    setup: app/config/configuration.yml
    dist: .dist #the file extension for placeholder files
    config: /home/YOU/.[KERNEL.NAME]_[KERNEL.ENVIRONMENT].ini #private vars


  • more tests
  • more sophisticated dic


the bootstrapper builds an app with console and commands

configure your commands:

# app/config/project_bootstrap.yml

  - 'doctrine:generate:entities FooBundle'
  - 'doctrine:schema:update'
  - 'help'

  - 'ls'

run the command

# with the default config
$ app/console project:bootstrap

# with a custom config
$ app/console project:bootstrap --config=~/foo.yml

# stop if a command fails
$ app/console project:bootstrap --stop


the BundleLoader manages your bundle config in an yaml file

use the BundleLoader in your Application Kernel

// app/AppKernel.php
use rs\ProjectUtilitiesBundle\Project\BundleLoader;

class AppKernel extends Kernel

    public function registerBundles()
        $file = $this->getRootDir().'/config/bundles.yml';
        return BundleLoader::loadFromFile($file,$this->getEnvironment());

environment configurations

# app/config/bundles.yml
  - Symfony\Bundle\FrameworkBundle\FrameworkBundle
  - Symfony\Bundle\TwigBundle\TwigBundle
  - Symfony\Bundle\ZendBundle\ZendBundle
  - Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle
  - rs\ProjectUtilitiesBundle\ProjectUtilitiesBundle

  - Symfony\Bundle\DoctrineBundle\DoctrineBundle



the configurator stores your private variables in a file
it replaces placeholders within your files with those variables

define the configuration

# app/config/configuration.yml
  - config
  - views

  - bootstrap_%%KERNEL.ENViRONMENT%%.php

    desc: database name
    default: symfony_%%KERNEL.ENVIRONMENT%%
    desc: database password
    default: symfony
    desc: database user
    default: symfony
    desc: database host
    default: localhost

use the following placeholder format (file format doesnt matter):

   dbname:   %%DB_NAME%%
   user:     %%DB_USER%%
   password: %%DB_PWD%%

all files with extension .dist will be parsed and replaced with tokens!

these .dist files can be stored in your vcs

dont check in password or private configurations

(when the configurator runs it creates placeholder replaced copies without the .dist extension)

run the command

# with the default config (/home/YOU/.[KERNEL.NAME]_[KERNEL.ENVIRONMENT].ini)
$ app/console project:configure

# list current config variables
$ app/console project:configure --list

# lists current setup
$ app/console project:configure --setup

symfony Plugin for managing git repositories


manage symfony plugins hosted on git
(or any other git repository you need in your project)



git clone git://


svn co


symfony plugin:install rsGitExternalsPlugin

activate plugin


create files named .gitexternals in your symfony project:


rsGitExternalsPlugin git://
fooPlugin            git://


pull or clone

symfony plugin:git-externals pull


symfony plugin:git-externals push


symfony plugin:git-externals status


  • more advanced git handling if needed, this plugin should only be used for simple git commands

symfony i18n Plugin written in ExtJs

This symfony plugin is a simple rewrite from the excellent mgI18nPlugin written with jQuery.

As i dont think jQuery is the best solution for nifty RIAs, i forked it and rewrote the interface with ExtJs.

Here is the Fork: .

A Screenshot will explain nearly everything:


  • symfony 1.3
  • Propel or Doctrine
  • pdo_mysql (not tested with others databases)
  • ExtJs


  • edit your factories.yml
       # ...
         class: mgI18N
           source:               mgMySQL
           database:             doctrine  # or propel or any names defined in the databases.yml files
           debug:                false
           learning_mode:        true        # if 'on' all translations are automatically added to the database
           global_application:  'frontend' # Optional ; use the same translations catalogues for all applications
           untranslated_prefix:  "[T]"
           untranslated_suffix:  "[/T]"
             class: sfFileCache
               automatic_cleaning_factor: 0
               cache_dir:                 %SF_I18N_CACHE_DIR%
               lifetime:                  86400
               prefix:                    %SF_APP_DIR%
  • you can change the default doctrine connection’s name by editing your app.yml file
       # ...
         connection: doctrine
           fr: Fran├žais
           en: English

    you can use 2 databases : a project database and a translation database. Separating
    databases help you to manage different staging.

  • (optional) edit the databases.yml file to add the mg_i18n_plugin connection.
       class: sfDoctrineDatabase
         dsn: 'mysql:host=;dbname=project_database_i18n;charset=utf-8'
         username: username
         password: password
  • install the table
    symfony i18n:mg-create-table frontend
  • Install ExtJS
    • update the view.yml
          - ext-all.js
          - /js/resources/ext-all.css
  • publish plugin asset
    symfony plugin:publish-assets
  • install plugin translation for each application
    symfony i18n:mg-xliff-import frontend plugins/mgI18nPlugin/i18n/*
  • add the filter, edit the filters.yml (the filter add current page translation messages)
       class: mgI18nFilter
     common:    ~ # before the common filter
  • clear cache
    symfony cc
  • click the Translations Button in your WebDebug Toolbar

Registering Event

In some edge cases, the plugin might not find the translation. The current fallback
is to register to an event, and add the translation into an array.

  • connect to the event
     class ProjectConfiguration extends sfProjectConfiguration
       public function setup()
         // [...]
         $this->dispatcher->connect('mgI18nPlugin.assign_ajax_values', array('mgI18nAjaxTranslation', 'listenToEvent'));
  • Create a class mgI18nAjaxTranslation
  • Now these messages will appear on the AJAX tabs

Of course you can connect many different objects to the mgI18nPlugin.assign_ajax_values event, from modules to plugins.


By default the translation panel appears only if the current user is a sfGuard’s super admin. This behavior is controlled by the mgI18nUser class. Copy-and-paste this class into the project|application lib folder and customize the logic depends on the specification.

 class mgI18nAjaxTranslation extends mgI18nMessageHelper

   public static function listenToEvent(sfEvent $event, $i18n_messages)

     $messages = array(
       'your-catalogue' => array(
         array('your_message', array('name_param1', 'name_param2'),

     return self::appendMessages($i18n_messages, $messages);


You can import xliff catalogue with the command :
symfony i18n:mg-xliff-import frontend YOUR_CATALOGUE

move your Javascripts to Pagebottom with ease in symfony

Currently i am doing some page speed improvements to my site, and wanted to move all my javascripts to the page bottom.

My first approach was simply moving the script helper to the page bottom:

<?php include_javascripts() ?>

But that wont worked as expected.
Some Widget or Subsites may write some inline scripts, that uses included class from the top of the page.

For example (original):

<script type="text/javascript" src="jquery.js" >

<script type="text/javascript">

would result in (moved helper to the bottom):

<script type="text/javascript">

<script type="text/javascript" src="jquery.js" ></script>

that leads to nasty javascript errors!

Here is the solution for that:
Its a simple symfony Filter which greps all script tags and moves them in correct order the bottom of the page!

activate the filter after your rendering filter in your filters.yml

rendering: ~

  class: DomScriptFilter

Here is the Filter:

 * this filter moves all script tags to the bottom of the dom
 * @author robert
 * @package lib.filter
class DomScriptFilter extends sfFilter
   * @var EXPRESSION finds all script tags and moves them to the bottom

  const EXPRESSION = "/<script [^>]*>([\d\D\w\W\s\S]*?)<\/script>/";

   * executes this filter
   * @param sfFilterChain $filterChain
  public function execute($filterChain)

    $content = $this->getContext()->getResponse()->getContent();

    preg_match_all(self::EXPRESSION, $content, $scripts);
    preg_replace(self::EXPRESSION, '', $content);

    $content = str_replace('', join('',$scripts[0]).'', $content);


and voila it works as expected (with filter):

<script type="text/javascript" src="jquery.js" >
<script type="text/javascript">

Now the page feels much faster, since we dont have to wait for javascripts to load to render the page…