Tag Archives: PHP - Page 2

Software metrics at PHPNW 2011 Conference

PHPNW11I am really excited to be able to speak again in Manchester this October. This time I will be speaking about the ways and tools you can use to assess your code quality and its design. While software metrics help a lot and tell a lot about code, you have to remember they only should be treated as a guidance, not the goal in itself.  So be careful and don’t start coding only to make the metrics look pretty. Here is an excellent video from Alberto Savoia for these who’s gone a bit too far with software metrics.

See you in Manchester!

Spring cleaning? Hell no!


It’s summer time already, but every time I hear about cleaning revolution it reminds me of spring cleaning. And I can tell you I hate spring cleaning! I don’t get the whole idea of one time movements just because you didn’t care enough to keep your things tidy all year long!

The whole thing gets triggered now and again, because another developer gets annoyed with the amount of rubbish in the error log. Through years of not caring “suddenly” it’s hard to spot major issues through the flood of notices, warnings and stricts. So Tech Debt Tuesdays, unit test Thursdays and  clean up Fridays take place. Yada yada yada. Everybody get annoyed trying to fix it and after that all gets to normal. Why?! Have Starbucks Mondays and Orange Wednesdays instead – it’s fun! Do your day to day job and keep your code tidy. Every day. Every hour. Every minute. You spot something, you fix it. Simple. And it doesn’t matter whether it’s your code or not. Whether you are going to change it or not. The fact you have seen it is good enough to make you fix it.

I can only repeat after Uncle Bob Martin:

Cleaning code is just part of the normal everyday job of a programmer. It should not be something special on the schedule.

Teams should gradually fix code quality _outside_ the schedule. The improvements should be long term an on-going. Never schedule them!

Code quality issues should _never_ be in the backlog, or on the schedule. They should never get to that point.

Go team!

Running php linter before pushing changes to a git repository

A problem

Have you ever reviewed code that contained parse errors and wasn’t even proper PHP? I have and that’s why I have finally decided to stop that. Well, I have not decided to stop reviewing code, I have decided to prevent people committing PHP code which contain parse errors. With git hooks it’s fairly easy.

One way with pre-commit hook

One way to do it would be with pre-commit hook. Travis Swicegood explained it very well in his blog post. One problem with that is that every developer would have to deploy that hook locally in every repository. So that was really not an option for us.

Or another with pre-receive hook

What I wanted to do was to prevent people pushing broken code to git repositories stored on our git server (sort of in-house github). So I would deploy a hook on the server and the check would be done in there. pre-receive hook seems to be an ideal place for that. You can find our current version of the hook below:


To get it installed simply copy pre-receive hook into hooks subdirectory of a repository on a git server and make the file executable.


So how does it work? It’s actually pretty simple. If the hook exists with a non zero error code the push will fail, otherwise it will succeed. So all we have to do is to get a list of files changed in a given changeset and run php linter against them.

The hook accepts 3 parameters:

  • old revision id (ie. 325fbce03ba542c37c8529f36bf66998594e8384)
  • new revision id (ie. 58127dc11f4fd0c433cc6485a10925be5b56e1bb)
  • full reference name (ie. refs/heads/master)

Running git diff with –name-only option will give us list of changed files. But we cannot simply run php linter at this point as you have to remember that on git server there is just bare repository, without working directory tree. So we have to fetch the files straight from git context. We can fetch an object contents from index using git cat-file command, but it requires a unique object identifier to return file contents, so first we need to get this first. git ls-tree command is just what we need. Running it with new revision id and file name, we will get all the information we need!

#> git ls-tree 58127dc11f4fd0c433cc6485a10925be5b56e1bb Test/Application/WebTest.test.php
100644 blob 30a5e1914fe075db11c31780454fcc9d1d83aa9d	Test/Application/WebTest.test.php

Now, when we run git cat-file with the object type we got back (blob in case of files) and object id, we will get contents of that file, that we can finally pipe into php linter process. If the process returns any non-zero error code we display an appropriate message and stop script execution with a non-zero code:

smarek@28:~/git/modules/Sandbox (master)$ git push origin master
Counting objects: 14, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 857 bytes, done.
Total 9 (delta 2), reused 0 (delta 0)

Running php linter...
Error parsing file 'Test/Application/WebTest.test.php'

error: hooks/pre-receive exited with error code 255
To git:Sandbox.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'git:Sandbox.git'

otherwise we just stop the script with a zero code!

smarek@28:~/git/modules/Sandbox (master)$ git push origin master
Counting objects: 8, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 658 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)

Running php linter...
No errors detected

To git:Sandbox.git
90f43b9..36582e1  master -> master

No more parse errors! FTW!

February aftermatch

Finally, during the first days of my holiday, I have found a few days to finish this post.

Well, Feb this year has been extremely busy. First hot house at work, a brand new idea for me that worked brilliantly, then PHP Unconference Europe in Manchester, and finally PHPUK 2011 in London. And although that was already March, it’s worth adding PHPNW monthly user group meeting in Manchester as well, where I had a talk about PHPUnit, the next one in “Back to basics” series.

But lets start from the beggining.

The hot house

Brand new idea for me. We got off site for 3 days from the office to prototype and implement a first version of our end to end continuous integration process. And by end-to-end I mean end-to-end – form project initialisation to the final release integration and automated deployment. It’s been 3 very exhausting days, not the usual 9-5 working day you usually have at work, but it was well worth having it. The idea of it is, you get the gather the whole team – developers, project managers, BAs, QA engineers and everybody else that are crucial for the project, in one room, away from any sort of distraction and plan (and most importantly execute) the whole thing. The 3 days have a specific structure, with the 1st day being sort of introduction and planning, 2nd day being entirely focused on execution and 3rd day, the shorter one, being a wrap-up and summary of the whole event with the main goal of raising post event actions that are meant to be executed in the office afterwards.

During this 3 days we achieved something that we couldn’t in the past several months – we have put a concept in place and implemented it proving the the whole thing can work. Now we know that we can automate the process of developing, building and testing single project workstreams and when they are ready put them altogether during a merge into a release, build, deploy and test the whole release. That includes both PHP and Java artifacts, DB changes, internal CMS artifacts and regression selenium packs and functional tests developed and executed during the project. Oh! How I love automation.

PHP Unconference Europe (19-20 Feb 2011)

Official site: http://www.phpuceu.org/phpuceu-2011/
Unconference wiki: http://eu.php-unconference.de/

I was looking forward to it very much. I have never been to an unconference before, and I didn’t quite get the whole idea of an unconference. Well, I knew roughly the idea behind it, just never seen it in action.

So, in general I am a bit disappointed. As a completely community driven event it was an enormous success. A load of people turned up, we had a few interesting proposals upfront, then a few more was added during the event. From the organisation point of view it was brilliant. Everything went smoothly, beer was good, food was good, people were great. The bit that needs improving are the talks itself. And I don’t blame anybody for it. In fact if I could blame somebody I would start from myself. The talks that were proposed upfront and were chosen by the community went quite well. The disussion panels – not so much. They weren’t bad, don’t get me wrong. They just simply could be better. But I already know, that next time I will come better prepared. Always learn on mistakes – that’s my motto.

PHPUK 2011 (25 Feb)

Official site: http://www.phpconference.co.uk/conference/php-uk-conference-2011

Just 5 days after, I attended another big UK event, this time in London. Schedule this year was pretty impressive. I was mainly interested in the two afternoon talks in Auditorium – Sebastian Bergmann’s “Agility and Quality” and Thorsten Rinne’s “Continuous Improvement in PHP Projects”. But before I get to them, let’s rewind and start from the beginning.

The conference had started with Marco Tabini’s “Experience” key note. Marco refereshed the idea od user experience with a few funny anecdotes and targeted it specifically at developers. Nothing really new, but we all need to be reminded from time to time, that we should always be focused and don’t forget about end users and their needs.

After that I had to choose between 3 talks:

  • Martin Beeby’s “HTML5 and CSS3 Today”
  • Ivo Jansch’s “PHP in a Mobile Ecosystem”
  • Ian Barber’s “ZeroMQ Is The Answer”

I didn’t hesitate a second and went straight away to Sidetrack 2 to see what ZeroMQ is all about. And I don’t regret my decision. I think it was the best talk of PHPUK 2011. Ian kept me focused all the time and definitely convinced me to try out ZeroMQ. Great talk, with plenty of usage examples and a demo. Well done!

After a short break it was time for the talk I was waiting for. But again the choice for me wasn’t difficult either. We had:

  • “Xdebug” by Derick Rethans in Sidetrack 1
  • “Agility and Quality” by Sebastian Bergmann in Auditorium
  • “Running on Amazon EC2” by Jonathan Weiss in Sidetrack 2

I had seen Derick’s talk before and I am not really interested in Amazon EC2, not just yet at least. So I went straight away to see Sebastian’s talk. Sebastian is a well known international speaker, practically an expert in QA for PHP topics. And maybe that’s why I was really disappointed. Sebastian seemed to be nervous at the beggining, although it went better as he went along. Still I was expecting something new. Instead of that, the talk brought up some of the well known “agility practices”, how they fit in during project lifecycle and how some of the tools can help to achieve that. Nice WOW theme made it look interesting, but not interesting enough to keep me focused.

I have stayed at the Auditorium to listen to “Continuous Improvement in PHP Projects” by Thorsten Rinne. The other 2 talks that I have missed were:

  • “Large-scale Data Processing with MapReduce and PHP” by David Zülke in Sidetrack 1
  • “The InnoDB Storage Engine for MySQL” by Morgan Tocker in Sidetrack 2

And I must say, that was the worst talk I have heard during the conference. It seemed Thorsten either didn’t prepare very well to do this talk or he had real problems expressing himself. Not that I couldn’t understand him, but he was repeating some phrases all over again. Adding to that, some of the things were pretty much the same things Sebastian has talked about just before. The significant amount of time was spent introducing and explaining how to install some CI tools. And then, during Q&A session, he said some things that I strongly disagree with, like advising to implement CI process (and doing unit tests) without telling that to management. In my opinion that is the worst thing that you can do. I really regret I didn’t go to Sidetrack 2 and didn’t see David Zülke’s talk. I am sure it was much much better.

Next talk I have chosen was “Optimising a Zend Framework Application” by Rob Allen. It was a difficult choice, as I also wanted to see Stuart Herbert with his “Beyond Frameworks” talk in Sidetrack 1. I wasn’t that interested in Lorenzo Alberton’s “NoSQL Databases: What, When and Why”. All I can say, Rob delivered a good talk again. Learnt a few things about Zend Framework, which will definitely help me in my day to day job. I only heard that the other 2 talks were equally good and interesting!

At last I have attended “Advanced OO Patterns” by Tobias Schlitt in Auditorium. The other 2 talks were:

  • “Varnish in Action” by Thijs Feryn in Sidetrack 1
  • “99 Problems, But The Search Ain’t One” in Sidetrack 2

It was a good talk with a bit of humour. Tobias went through some of the design patterns explaining their pros and cons. Nothing really revolutionary, but it is always good to refresh this stuff from time to time. Shame that, at the same time Stuart Herbert and Jeremy Coates where discussing phpfundamentals matters at the lobby. I have left the talk to join them to learn more about that.

In general I must say it was a successful event, very well organised. Good food, free beers at the end and the after conference socials at “Slug And Lettuce” only made it better. I will definitely try to attend the next edition in 2012!

PHPNW montly user group meeting

I try to attend this local community event whenever I can, so I couldn’t miss it this time either. Especially that I was going to to do an introductory talk about PHPUnit. When I have arrived there was only a few people, so we have decided to wait a few more minutes to wait for the late comers. And it appeared to be a good decision as in the next 20 mins or so the room was nearly packed full! I went through some basic features of unit testing based on some live examples. A small accident near the end made me finish the talk without the slides (my MBP battery went out of power), so I had to improvise a bit, but I think, overall, it all went pretty well as we had quite a few questions afterwards and a really nice discussion at the end. You can find the slides from the talk on slideshare.

Autotesting with watchr, growl and PHPUnit

Inspired by a conversation at the office couple of days ago with a slightly bald software developer from the UK and @Stubbs I decided to play a bit with the concept of autotesting. I came across it about a year a go during BTDevCon and I really liked it, but back then I have seen it in action, when one of the developers was using it for a demo in Ruby. I haven’t heard about anything similar for PHP so I didn’t dig in further. Until now.

Let’s get back to the concept of autotesting again for a minute.  The other term for it is continuous testing and in short it is about getting an instant feedback on your code while you’re developing it. In practise, the test suite is being triggered every single time you save a file and the results of the run are displayed on the screen. You don’t have to run the test suite manually, it is done for you.

All you need is watchr, growl and growlnotify (which is available as part of Growl Extras). Watchr is a flexible tool that allows you to watch the filesystem and run an arbitrary command when a change is detected, growl is a notification system for Mac OS X and growlnotify is a command-line tool to post Growl notifications.


To install watchr you can either install it using gem:

#> sudo gem install watchr
Successfully installed watchr-0.7
1 gem installed
Installing ri documentation for watchr-0.7...
Installing RDoc documentation for watchr-0.7...

or clone the latest version from github, generate the gem and install it from your local disk:

#> git clone git://github.com/mynyml/watchr.git
#> cd watchr
#> gem build watchr.gemspec
   Successfully built RubyGem
   Name: watchr
   Version: 0.7
   File: watchr-0.7.gem
#> sudo gem install watchr-0.7.gem
Successfully installed watchr-0.7
1 gem installed
Installing ri documentation for watchr-0.7...
Installing RDoc documentation for watchr-0.7...

Growl and growlnotify

Growl (with included extras) is available from its home page as a standard dmg image. Just follow onscreen installation instructions.

Setup watchr with PHPUnit

To set up watchr with PHPUnit you only need one configuration file. In there, you define which part of the filesystem you want to watch for changes and what do you want to do when the change occurs. In my case all I want is to execute my test suites. So here is the example file, called watchr.rb and stored in the top level directory of my module:

In the first line, I have set up watchr to watch any file with php extension for incoming changes and when it detects the change to execute code_changed() function. code_changed() does nothing else but executes phpunit command in my Test subdirectory and passes the results to growl() function.  And the growl() function basically parses the results, checks whether tests run successfully or not and executes growlnotify with an appropriate message and image.

Let the fun begin!

All you have to do now is run watchr, start changing your code and watch for growl notifications!

#> watchr watchr.rb
Positive notification

Positive notification

Failure notification

Failure notification

You can get both the configuration and images I have used from my github. Happy continuous testing!


Sonar for PHP coming

sonarI have received a lot of positive feedback after my The Journey towards Continuous Integration talk at PHP NW 2010 conference. It seems that a lot of people have found it both interesting and inspiring. I am really glad. After the talk many people asked me about Sonar which I briefly mentioned and were eager to know more about it. With this blog post I will try to fill the gap in my talk.

Solving the mistery

I have heard about Sonar for the first time about a year ago I think. It looked cool! All the fancy graphs, statistics, numbers… But, first I couldn’t understand how would it actually fit into our development process and secondly it had no support for PHP. A lot of things has changed since then though.

With a continuous integration process nearly in place at work, we now need to properly track the progress not only of the build itself, but also how in overall our code quality changes. We want to know whether the code complies to the rules we have set up, whether over time it gets better and at the same time we want to communicate the progress to the business.  What a surprise for me it was, when I have found out that actually all of that we could achieve with Sonar! And imagine the grin on my face when I was told that there are people that have started working on PHP plugin for Sonar!

Installing Sonar

Installing Sonar is very easy. Sonar runs on any operating system that support Java and Maven. For version 2.1 which I am gonna install you will need Java Development Kit v1.5 or later and Maven 2.0.9+, 2.1.+ or 2.2.+.

If you’re using Ubuntu distribution, just can just follow the instructions below.

To install Sun JDK you need to enable partner repositories first. Just edit /etc/apt/sources.list , uncomment the following lines:

# deb http://archive.canonical.com/ubuntu maverick partner
# deb-src http://archive.canonical.com/ubuntu maverick partner

and install the JDK:

#> sudo apt-get update
#> sudo apt-get install sun-java6-jdk

To install maven you can use apt-get as well:

#> sudo apt-get install maven2

With all the things in place it’s time to download Sonar. You can get it from its download page. Remember that not all plugins are compatible with all Sonar versions, so before you make a decision which version to download check Sonar Compatibility matrix. Because I am gonna use 0.2 version of PHP plugin I will download Sonar 2.1.2.

#> wget http://dist.sonar.codehaus.org/sonar-2.1.2.zip

Installation is as easy as just unpacking the archive:

#> mkdir ~/apps
#> cd ~/apps && unzip /home/proofek/Downloads/sonar-2.1.2.zip

Configuring Sonar

By default Sonar runs with an embedded Apache Derby database. If you want just to play with Sonar or test it then you can just skip the next step, but if you plan to use it later on or you want to install it in a production environment then you better switch to more robust database server like MySQL, Oracle, Postgresql or MS SqlServer. Sonar suports them all. I will install it and configure it with MySQL server.

First, let’s install MySQL server. Again apt comes handy:

#> sudo apt-get install mysql-server

The server should automatically be started after that and should accept any incoming connections. Now we have to create empty database and a user that Sonar will use. Let’s name the database and user sonar and use S0n4rU53r as a password. Obviously it’s up to you how you will call them, just make sure you use the same names later on in Sonar configuration file. Also remember this is only a sample configuration and you might want to configure the access to database differently for security reasons.

#> mysql -uroot -p -e "CREATE DATABASE sonar"
#> mysql -uroot -p -e "CREATE USER 'sonar'@'%' IDENTIFIED BY 'S0n4rU53r'"
#> mysql -uroot -p -e "GRANT ALL ON sonar.* TO 'sonar'@'%'"

Next, edit conf/sonar.properties configuration file, uncomment template for MySQL support and comment out the default Derby configuration.

#sonar.jdbc.url: jdbc:derby://localhost:1527/sonar;create=true
#sonar.jdbc.driver: org.apache.derby.jdbc.ClientDriver
#sonar.jdbc.defaultTransactionIsolation: 1
#sonar.jdbc.validationQuery: values(1)
sonar.jdbc.url: jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8
sonar.jdbc.driver: com.mysql.jdbc.Driver
sonar.jdbc.validationQuery: select 1

At the bottom of that file, in Global database settings section, you can change default database username and password.

sonar.jdbc.username:                       sonar
sonar.jdbc.password:                       S0n4rU53r
sonar.jdbc.maxActive:                      10
sonar.jdbc.maxIdle:                        5
sonar.jdbc.minIdle:                        2
sonar.jdbc.maxWait:                        5000
sonar.jdbc.minEvictableIdleTimeMillis:     600000
sonar.jdbc.timeBetweenEvictionRunsMillis:  30000

If you want to run Sonar on different IP address or port you can configure that at the top of this configuration file:

# Listen host/port and context path (for example / or /sonar). Default values are
#sonar.web.port:                           9000
#sonar.web.context:                        /

Now we’re ready to start Sonar for the first time. Start  and stop scripts are located in bin directory.

Execute the following script to start the server :

  • on linux/mac : bin/[YOUR PLATEFORM]/sonar.sh start
  • on windows : bin/windows-x86-32/StartSonar.bat

Note that you can also run as a NT service with bin/windows-x86-32/InstallNTService.bat, then bin/windows-x86-32/StartNTService.bat

For Linux start command will look like this:

#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh start

and you stop Sonar like this:

#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh stop

It gets a while to start it for the first time as the database schema is being set up. Have a look at the log file to see the progress and watch for any issues that might prevent Sonar from starting.

#> tail -f ~/apps/sonar-2.1.2/logs/sonar.log

Message like this indicates that application is ready to use:

2010.11.09 21:55:39 INFO  org.sonar.INFO  Sonar started:

Just browse now to http://localhost:9000/. Sonar is ready to use.

Sonar dashboard

Sonar dashboard (after first run)

Installing PHP plugin

At the moment (mid Nov 2010), only version 0.2 of the plugin has been released, and you can download it from the official plugin site.

It’s split into 5 separate jar files:

  • core PHP plugin
  • PHPUnit plugin
  • PHP_Codesniffer plugin
  • PHP Depend plugin
  • PHP MD plugin
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-plugin/0.2/sonar-php-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-unit-plugin/0.2/sonar-php-unit-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-codesniffer-plugin/0.2/sonar-php-codesniffer-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-depend-plugin/0.2/sonar-php-depend-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-pmd-plugin/0.2/sonar-php-pmd-plugin-0.2.jar

But that’s not all. The plugin actually requires the following tools to be installed on a machine that you are going to analyse your project on (and it actually doesn’t have to be the same machine you install Sonar on):

If you are already using them, you will know how to install/configure them. Only PHP_Codesniffer requires special treatment, so I strongly recommend you follow my installation guide for PHP_Codesniffer below. For those of you, who are not really familiar with these tools yet, here is a quick guide how to set them all up.


Fairly simple installation, especially with apt:

#> sudo apt-get install php5-cli
#> php -v
PHP 5.3.3-1ubuntu9.1 with Suhosin-Patch (cli) (built: Oct 15 2010 14:17:04)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
#> sudo apt-get install php-pear
#> pear list
Installed packages, channel pear.php.net:
Package          Version State
Archive_Tar      1.3.7   stable
Console_Getopt   1.2.3   stable
PEAR             1.9.1   stable
Structures_Graph 1.0.3   stable
XML_Util         1.2.1   stable

PHPUnit + Xdebug

Now lets use PEAR installer to install PHPUnit. This is a standard installation procedure for PHPUnit.

#> sudo pear channel-discover pear.phpunit.de
#> sudo pear channel-discover components.ez.no
#> sudo pear channel-discover pear.symfony-project.com
#> sudo pear install --alldeps phpunit/PHPUnit
#> phpunit --version
PHPUnit 3.5.3 by Sebastian Bergmann.

and pecl installer to install Xdebug. We will need php sources and some development tools as well, because pecl will actually compile Xdebug on the fly before installing it. For systems from Ubuntu/Debian family just use apt to install php5-dev package.

#> sudo apt-get install php5-dev

And after that install Xdebug and enable the extension by creating xdebug.ini file with the following content:

#> sudo pecl install xdebug
#> sudo vim /etc/php5/conf.d/xdebug.ini
xdebug.auto_trace = "Off"
xdebug.collect_params = "On"
xdebug.collect_return = "Off"
xdebug.trace_format = "0"
xdebug.trace_options = "1"
xdebug.trace_output_dir = "/local/tmp/xdebug"
xdebug.trace_output_name = "timestamp"
xdebug.profiler_enable = "0"
xdebug.auto_profile = "1"
xdebug.auto_profile_mode = "6"
xdebug.output_dir = "/local/tmp/xdebug"
xdebug.profiler_output_dir = "/local/tmp/xdebug"
xdebug.profiler_output_name = "timestamp"

Refer to Xdebug documentation for specific configuration options. Let’s just verify now that PHP has Xdebug support.

#> php -v
  PHP 5.3.3-1ubuntu9.1 with Suhosin-Patch (cli) (built: Oct 15 2010 14:17:04)
  Copyright (c) 1997-2009 The PHP Group
  Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
      with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans


With PHP_Codesniffer it’s a little bit different. The stable version 1.2.2 which is available now (mid Nov 2010) doesn’t support rulesets yet (but bear in mind version 1.3 will). So guys at SQLi have come up with a work around.

First of all if you already have PHP_Codesniffer installed with version bigger then 1.2.2 you have to uninstall it first. And that’s because we have to install a modified version 1.2.3 of PHP_CodeSniffer. BUT REMEMBER, this is not an official release. It has been created specifically to work with Sonar. So:

#> sudo pear uninstall PHP_CodeSniffer


#> wget https://www.assembla.com/spaces/sqlics/documents/dSJnowvZqr35SUeJe5cbLr/download/dSJnowvZqr35SUeJe5cbLr -O PHP_CodeSniffer_1.2.3.tgz
#>  sudo pear install ~/Downloads/PHP_CodeSniffer_1.2.3.tgz
#> phpcs --version
PHP_CodeSniffer version 1.2.3 (stable) by Squiz Pty Ltd. (http://www.squiz.net)

Then we have to download and install SQLi Codesniffer which will work like a bridge between Sonar and PHP_Codesniffer.

#> wget https://www.assembla.com/spaces/sqlics/documents/ak6024vZur34RweJe5cbLA/download/ak6024vZur34RweJe5cbLA -O SQLI_CodeSniffer_0.4.0dev1.tgz
#> sudo pear install /home/proofek/Downloads/SQLI_CodeSniffer_0.4.0dev1.tgz
#> sqlics --version
SQLI_CodeSniffer version 0.4.0dev1 (alpha) by SQLI (http://www.sqli.com)

If for any reasons these links or instructions doesn’t work anymore, check the original instructions at SQLi site.

PHP Depend

PHP Depend installation is also a standard one:

#> sudo pear channel-discover pear.pdepend.org
#> sudo pear install pdepend/PHP_Depend-beta
#> pdepend --version
PHP_Depend 0.9.19 by Manuel Pichler


Same with PHP Mess Detector:

#> sudo pear channel-discover pear.phpmd.org
#> sudo pear install --alldeps phpmd/PHP_PMD-alpha
#> phpmd --version
PHPMD 0.2.7 by Manuel Pichler

With all tools in place, just stop Sonar, copy the jar files to Sonar’s plugins directory (~/apps/sonar-2.1.2/extensions/plugins/) and start Sonar again:

#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh stop
#> cp sonar-php-plugin-0.2.jar sonar-php-codesniffer-plugin-0.2.jar sonar-php-depend-plugin-0.2.jar sonar-php-pmd-plugin-0.2.jar sonar-php-unit-plugin-0.2.jar /home/proofek/apps/sonar-2.1.2/extensions/plugins/
#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh start

If you carefully watch logs now you will see the plugins being loaded and set up!

#> tail -f ~/apps/sonar-2.1.2/logs/sonar.log
2010.11.09 22:51:18 INFO  org.sonar.INFO  Load metrics...
2010.11.09 22:51:19 INFO  org.sonar.INFO  cleaning alert thresholds...
2010.11.09 22:51:19 INFO  org.sonar.INFO  Load metrics done: 1118 ms
2010.11.09 22:51:19 INFO  org.sonar.INFO  Load rules...
2010.11.09 22:51:19 INFO  org.sonar.INFO  loading 365 findbugs rules...
2010.11.09 22:51:21 INFO  org.sonar.INFO  loading findbugs extensions...
2010.11.09 22:51:21 INFO  org.sonar.INFO  loading 97 PHP CODESNIFFER rules...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading PHP CODESNIFFER extensions...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading 12 PHP PMD rules...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading PHP PMD extensions...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading 123 checkstyle rules...
2010.11.09 22:51:23 INFO  org.sonar.INFO  loading checkstyle extensions...
2010.11.09 22:51:23 INFO  org.sonar.INFO  loading 216 pmd rules...
2010.11.09 22:51:25 INFO  org.sonar.INFO  loading pmd extensions...
2010.11.09 22:51:25 INFO  org.sonar.INFO  loading 3 squid rules...
2010.11.09 22:51:25 INFO  org.sonar.INFO  loading squid extensions...
2010.11.09 22:51:25 INFO  org.sonar.INFO  Load rules done: 6566 ms
2010.11.09 22:51:25 INFO  org.sonar.INFO  Load profiles...
2010.11.09 22:51:27 INFO  org.sonar.INFO  loading findbugs profiles...
2010.11.09 22:51:27 INFO  org.sonar.INFO  loading the profile Sonar way with Findbugs/java from findbugs
2010.11.09 22:51:34 INFO  org.sonar.INFO  loading PHP CODESNIFFER profiles...
2010.11.09 22:51:34 INFO  org.sonar.INFO  loading the profile Default Php Profile/php from PHP CODESNIFFER
2010.11.09 22:51:37 INFO  org.sonar.INFO  loading PHP PMD profiles...
2010.11.09 22:51:37 INFO  org.sonar.INFO  loading the profile Default Php Profile/php from PHP PMD
2010.11.09 22:51:38 INFO  org.sonar.INFO  loading checkstyle profiles...
2010.11.09 22:51:38 INFO  org.sonar.INFO  loading the profile Sonar way/java from checkstyle
2010.11.09 22:51:39 INFO  org.sonar.INFO  loading the profile Sonar way with Findbugs/java from checkstyle
2010.11.09 22:51:40 INFO  org.sonar.INFO  loading the profile Sun checks/java from checkstyle
2010.11.09 22:51:43 INFO  org.sonar.INFO  loading pmd profiles...
2010.11.09 22:51:43 INFO  org.sonar.INFO  loading the profile Sonar way/java from pmd
2010.11.09 22:51:47 INFO  org.sonar.INFO  loading the profile Sonar way with Findbugs/java from pmd
2010.11.09 22:51:51 INFO  org.sonar.INFO  loading the profile Sun checks/java from pmd
2010.11.09 22:51:51 INFO  org.sonar.INFO  loading squid profiles...
2010.11.09 22:51:51 INFO  org.sonar.INFO  activating php default profile...
2010.11.09 22:51:51 INFO  org.sonar.INFO  activating java default profile...
2010.11.09 22:51:51 INFO  org.sonar.INFO  Load profiles done: 25681 ms
2010.11.09 22:51:51 INFO  org.sonar.INFO  Start sonar done: 37528 ms
2010.11.09 22:52:12 INFO  org.sonar.INFO  Loading web services...
2010.11.09 22:52:13 INFO  org.sonar.INFO  Sonar started:

Preparing for analysis

We’re just about to analyse our first project then. How exciting! There is only a few things left before we can start though.

Sonar uses maven to analyse projects and needs a pom file to perform it. A typical pom file for PHP project looks like this:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsichemaLocation="http://maven.apache.org/POM/4.0.0">

All you have to do, is to replace underscored values with relevant ones. I’ll show you a complete example of it in a minute.

We need to configure maven first, so it knows how to connect to sonar mysql database. There are two locations, where maven keeps its settings.xml file:

  • The Maven install: $M2_HOME/conf/settings.xml
  • A user’s install: ${user.home}/.m2/settings.xml

Refer to your operating system documentation to find out how maven is installed by default. In Ubuntu/Debian family system global configuration file is in /etc/maven2/settings.xml, while in MacOsX it is in /usr/share/maven/conf/settings.xml.

All we have to do now, is to create custom maven profile and activate it. First locate <profiles> section in the xml file. Although there are a few profile examples inside this section already, they are probably all commented out. We will simply add our profile section to it:

    <!-- profile
    Existing profiles definitions (...)

Next activate the new profile in activeProfiles section. Remove the comments around this section and just add bolded section to it:


If there are any profiles activated already there, just simply delete them. They don’t exists anyway and will only cause maven to complain during analysis.

If Sonar has been installed on a separate machine and you want to analyse your project on a different machine, then you will have to adjust sonar.jdbc.url option to point it to the sonar database and at the same time grant relevant permissions to the database itself. Also you have to tell maven how it can access Sonar server by specifying sonar.host.url option in profile section:


The last thing we have to do is to switch on a few options and make some tweaks for the PHP plugin itself. Integration with the PHP tools is pretty basic at the moment, but is enough to perform some simple analysis. So I am gonna run Sonar in so called dynamic analysis mode, run the tools manually to create all xml reports, and then run Sonar maven task to parse them and add the results to Sonar dashboard. The only exception will be PHP_CodeSniffer – I will let Sonar run the SQLi version and produce compatible report. Bear in mind in future plugin releases I expect the integration to get much better and then, if  you would like to you will be able to use Sonar to run the tools.

Let’s add the following lines to the maven settings.xml file then:


Analysing projects with Sonar

I have picked up vfsStream project as an example for analysis. Unfortunately this is the only open source project I have found so far, that requires a minimal effort to get it up and running. I have tried PHPUnit, pdepend, PHP_CodeSniffer, Zend Framework and many many more, but they either fail analysis, they are not compatible with PHPUnit 5.3 yet or they have very custom test suite runners which would need some major changes before we could actually perform analysis.

From my experience so far, Sonar often can not analyse the project because it still has problems parsing coverage report. I expect this to improve in next plugin versions though. Most problems can be solved by stopping using AllTests.php files and properly defining phpunit.xml file with filter whitelist section. I have analysed dosens of projects at work using that approach without a problem.

So let’s get vfsStream sources first:

#> svn checkout http://bovigo.googlecode.com/svn/vfs/trunk/ vfsStream

Let’s make it PHPUnit 3.5 compatible first by removing the following line from src/test/AllTests.php file:


Next let’s create a directory we will use to store xml reports in:

mkdir -p build/logs

and run PHPUnit to generate both junit log file and coverage clover report file:

#> phpunit --coverage-clover build/logs/phpunit.coverage.xml --log-junit build/logs/phpunit.xml src/test/AllTests.php
PHPUnit 3.5.3 by Sebastian Bergmann.

............................................................  60 / 169
............................................................ 120 / 169

Time: 3 seconds, Memory: 13.75Mb

OK (169 tests, 759 assertions)

Writing code coverage data to XML file, this may take a moment.

vfsStream doesn’t have phpunit.xml file, but fortunately  AllTests.php works just fine.

Now let’s run PHP Depend to create pdepend report.

#> pdepend --phpunit-xml=build/logs/pdepend.xml src/main
PHP_Depend 0.9.19 by Manuel Pichler

Parsing source files:
.........                                                        9

Executing CyclomaticComplexity-Analyzer:
.....                                                          119

Executing ClassLevel-Analyzer:
.....                                                          112

Executing CodeRank-Analyzer:

Executing Coupling-Analyzer:
.......                                                        148

Executing Hierarchy-Analyzer:
......                                                         139

Executing Inheritance-Analyzer:
..                                                              57

Executing NPathComplexity-Analyzer:
.....                                                          119

Executing NodeCount-Analyzer:
......                                                         122

Executing NodeLoc-Analyzer:
......                                                         131

Generating pdepend log files, this may take a moment.

Time: 00:01; Memory: 19.25Mb

With all the reports in place

#> ls -ltr build/logs/
total 184
-rw-r--r--  1 smarek  staff  15565 22 Nov 10:18 pdepend.xml
-rw-r--r--  1 smarek  staff  41787 22 Nov 10:18 phpunit.xml
-rw-r--r--  1 smarek  staff  32455 22 Nov 10:18 phpunit.coverage.xml

it’s time to create pom.xml file based on the template mentioned before. Our pom.xml file will look like this:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsichemaLocation="http://maven.apache.org/POM/4.0.0">

Let’s save the file in top level project directory and run analysis command from there:

smarek@14:~/apps/vfsStream$ mvn sonar:sonar
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'sonar'.
[INFO] Ignoring available plugin update: 2.0-beta-1 as it requires Maven version 3.0
[INFO] ------------------------------------------------------------------------
[INFO] Building vfsStream
[INFO]    task-segment: [sonar:sonar] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [sonar:sonar {execution: default-cli}]
[INFO] Sonar host: http://localhost:9000
[INFO] Sonar version: 2.1.2
[INFO] Execute: org.codehaus.sonar.runtime:sonar-core-maven-plugin:20101122103356:internal
[INFO] [sonar-core:internal {execution: default-internal}]
[INFO]  Database dialect class org.sonar.api.database.dialect.MySql
[INFO]  -------------  Analyzing vfsStream
[INFO]  Selected quality profile : Default Php Profile, language=php
[INFO]  Configure maven plugins...
[INFO]  Sensor PhpSourceImporter[getLanguage()=PHP,getClass()=class org.sonar.plugins.php.core.sensors.PhpSourceImporter]...
[INFO]  Importing files from project vfsStream
[INFO]  main
[INFO]  test
[INFO]  Sensor PhpSourceImporter[getLanguage()=PHP,getClass()=class org.sonar.plugins.php.core.sensors.PhpSourceImporter] done: 409 ms
[INFO]  Sensor AsynchronousMeasuresSensor...
[INFO]  Sensor AsynchronousMeasuresSensor done: 20 ms
[INFO]  Sensor PhpCodesnifferSensor...
[INFO]  ExecutePHPCodeSniffer with command 'sqlics --report-file=/Users/smarek/apps/vfsStream/build/logs/codesniffer.xml --report=checkstyle --level=warning --standard=GN --extensions=php,php3,php4,php5,phtml,inc /Users/smarek/apps/vfsStream/src/main'
[INFO]  PHPCodeSniffer ended with returned code '1'.
[INFO]  Analysing project with file:/Users/smarek/apps/vfsStream/build/logs/codesniffer.xml
[INFO]  Sensor PhpCodesnifferSensor done: 4233 ms
[INFO]  Sensor SurefireSensor...
[INFO]  parsing /Users/smarek/apps/vfsStream/build/surefire-reports
[INFO]  Sensor SurefireSensor done: 2 ms
[INFO]  Sensor CpdSensor...
[INFO]  Sensor CpdSensor done: 228 ms
[INFO]  Sensor PhpUnitSensor...
[INFO]  Parsing file :
[INFO]  Parsing file : {0}
[INFO]  Sensor PhpUnitSensor done: 637 ms
[INFO]  Sensor ProfileSensor...
[INFO]  Sensor ProfileSensor done: 13 ms
[INFO]  Sensor ProjectLinksSensor...
[INFO]  Sensor ProjectLinksSensor done: 6 ms
[INFO]  Sensor VersionEventsSensor...
[INFO]  Sensor VersionEventsSensor done: 9 ms
[INFO]  Sensor PHP Depend Sensor...
[INFO]  Collecting measures...
[INFO]  Saving measures...
[INFO]  Sensor PHP Depend Sensor done: 173 ms
[INFO]  Sensor Maven dependencies...
[INFO]  Sensor Maven dependencies done: 7 ms
[INFO]  Execute decorators...
[INFO]  ANALYSIS SUCCESSFUL, you can browse http://localhost:9000
[INFO]  Database optimization...
[INFO]  Database optimization done: 83 ms
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 19 seconds
[INFO] Finished at: Mon Nov 22 10:34:50 GMT 2010
[INFO] Final Memory: 25M/81M
[INFO] ------------------------------------------------------------------------

Let’s get back to the browser now and refresh the dashboard.


Sonar dashboard after running analysis


vfsStream analysis details

Congratulations! You have just analysed your first PHP project with Sonar!

Understanding the measures

I will only briefly tell you about different sections of the dashboard this time. Feel free to explore it and remember – there is quite comprehensive documentation at http://www.sonarsource.org/ including wiki, tutorials and even some screencasts!

At the top of the dashboard you have all the results of static code analysis, including all sort of statistics about your code complexity and size.


Code complexity analysis

On the right side of the dashboard, Sonar reports all rules violations generated by PHP_CodeSniffer. Don’t be surprised with the results you see. Remember we didn’t configure the plugin to use any specific standard. 0.2 version of the plugin uses an included GN standard, just for illustration purposes. That will definitely improve in future plugin versions and complete integration with PHP_CodeSniffer 1.3.


Rules violations based on PHP_CodeSniffer report

And finally at the bottom you have got results of the test suite run:


Unit tests results

phpUnderControl integration

Integration with phpUnderControl is really trivial. All you have to do is to add another task to your ant build file and execute it at the end of the build!

<project default="build" basedir=".">

    All the other targets here

    <target name="sonar">
        <exec dir="${basedir}/Source/" executable="mvn" failonerror="false" >
           <arg line="sonar:sonar" />

    <target name="build" depends="clean,checkout-code,update-branches,generate-configs,php-documentor,php-codesniffer,php-depend,phpunit,sonar" />


What’s next?

Version 0.3 of the plugin is coming soon to your houses soon, and with it comes:
  • better integration with PHP_CodeSniffer 1.3 (SQLi CodeSniffer no longer required)
  • rulesets support – import/export feature
  • Copy/Paste detector support (phpcpd)
  • better code coverage analysis
  • one plugin – one jar – easier installation
It will only get better! Happy analysis!

phpUnderControl 0.6.0 released

I am pleased to announce that new version of phpUnderControl is out.

You can install it through its pear channel:

proofek@home:~$ sudo pear channel-discover pear.phpundercontrol.org
Adding Channel "pear.phpundercontrol.org" succeeded
Discovery of channel "pear.phpundercontrol.org" succeeded
proofek@home:~$ sudo pear install --alldeps phpuc/phpUnderControl-0.6.0
downloading phpUnderControl-0.6.0.tgz ...
Starting to download phpUnderControl-0.6.0.tgz (545,857 bytes)
.............................................................................................................done: 545,857 bytes
install ok: channel://pear.phpundercontrol.org/phpUnderControl-0.6.0

or if you already have a previous version simply upgrade:

proofek@home:~$ sudo pear upgrade --alldeps phpuc/phpUnderControl-0.6.0
downloading phpUnderControl-0.6.0.tgz ...
Starting to download phpUnderControl-0.6.0.tgz (545,857 bytes)
.............................................................................................................done: 545,857 bytes
upgrade ok: channel://pear.phpundercontrol.org/phpUnderControl-0.6.0

Release 0.6.0 brings a few new features as well as a few bug fixes.

New Copy/Paste Detector and Changeset tab

Big thanks to hpbuniat for this contribution.
Changeset tab contains details of modifications in the source code since the last successful build. Copy/Paste Detector tab contains report produced by Copy/Paste Detector (CPD) for PHP.

Copy/Paste Detector (CPD) for PHP



Changeset tab

Integrating CPD with phpUnderControl is dead easy. Just install the tool and define another target in your build file. See an example below.

proofek@home:~$ sudo pear channel-discover pear.phpunit.de
proofek@home:~$ sudo pear channel-discover components.ez.no
proofek@home:~$ sudo pear install phpunit/phpcpd
proofek@home:~$ phpcd --version
phpcpd 1.3.1 by Sebastian Bergmann.
<target name="phpcpd" >
    <exec executable="phpcpd" failonerror="false">
        <arg line="--log-pmd ${basedir}/build/logs/pmd-cpd.xml ${basedir}/source/src" />

With these new features there are also two additional graphs on the metrics tab: Build at Revision Timeline and Duplicated Code

phpUnderControl metrics charts

Metrics tab

More details in PHP-MD and Codesniffer tabs

PHP Mess Detector and Codesniffer tabs got refreshed a little bit and now contain a bit more details.

PHPMD - PHP Mess Detector



Codesniffer tab

Implemented #665: Display limit for build metrics.

As per Manuel post earlier on, now it is also possible to control maximum number of log entries displayed on the graphs. Simply modify your config file that generates graphs and add –max-number option to it.

    <artifactspublisher dir="projects/${project.name}/build/api" dest="artifacts/${project.name}" subdirectory="api"/>
    <artifactspublisher dir="projects/${project.name}/build/coverage" dest="artifacts/${project.name}" subdirectory="coverage"/>
    <execute command="phpcb --log projects/${project.name}/build/logs --source projects/${project.name}/source/src --output projects/${project.name}/build/php-code-browser"/>
    <artifactspublisher dir="projects/${project.name}/build/php-code-browser" dest="artifacts/${project.name}" subdirectory="php-code-browser"/>
    <execute command="/usr/bin/phpuc graph --max-number 10 logs/${project.name} artifacts/${project.name}"/>

Bug fixes

  • Fixed #771:  Invalid character in CodeSniffer output.
  • Fixed #732: Show revision of SVN/CVS on dashboard. Patch supplied by hpbuniat, through phpunit’s issue tracker.
  • Fixed #1003: Force build button in the /cruisecontrol app doesn’t work.
  • Fixed #1011: Custom ant script now set properly when requested
  • Fixed #1044: callServer should return false. Patch supplied by Mekras in phpunit’s issue tracker.

Integrate PHP_Depend with phpUnderControl

The newest version of phpUnderControl has now basic support for PHP_Depend. With PHPUnit deprecating support for metrics, it’s just about the time to switch. And it’s not as complicated as it might sound.

First of all you need to install PHP_Depend. Using pear it’s the easiest and quickest way to do it. If you haven’t registered PHP_Depend pear channel yet, it is time to do it now:

141:~ sebmarek$ sudo pear channel-discover pear.pdepend.org
Adding Channel "pear.pdepend.org" succeeded
Discovery of channel "pear.pdepend.org" succeeded

After that simply use pear to install the latest version of PHP_Depend:

141:~ sebmarek$ sudo pear install pdepend/PHP_Depend-beta
Did not download optional dependencies: pecl/imagick, use --alldeps to download automatically
pdepend/PHP_Depend can optionally use package "pecl/imagick" (version >= 2.2.0b2)
downloading PHP_Depend-0.9.11.tgz ...
Starting to download PHP_Depend-0.9.11.tgz (323,787 bytes)
..................................................................done: 323,787 bytes
install ok: channel://pear.pdepend.org/PHP_Depend-0.9.11

and confirm that PHP_Depend installed successfully:

141:~ sebmarek$ pdepend --version
PHP_Depend 0.9.11 by Manuel Pichler

The next step is to modify your project’s build file. If you don’t use phpunit configuration xml file the change is really simple. Just remove –log-metrics option from your phpunit ant task:

<target name="phpunit">
    <exec dir="/pth/to/your/module" executable="phpunit" failonerror="true">
        <arg line="--log-junit ${basedir}/build/logs/phpunit.xml
                   --log-metrics ${basedir}/build/logs/phpunit.metrics.xml
                   --coverage-xml ${basedir}/build/logs/phpunit.coverage.xml
                   --coverage-html ${basedir}/build/coverage" />

If you use phpunit xml file remove relevant entry from logging section:

    <log type="coverage-html" target="/path/to/build/coverage/" charset="UTF-8" yui="true" highlight="false" lowUpperBound="35" highLowerBound="70"/>
    <log type="coverage-clover" target="/path/to/build/logs/phpunit.coverage.xml"/>
    <log type="junit" target="/path/to/build/logs/phpunit.test.xml" logIncompleteSkipped="true"/>
    <log type="metrics-xml" target="/path/to/build/logs/metrics.xml"/>

Finally just add new ant task in the build file that will run pdepend and generate metrics xml file and additional graphs.

<target name="php-depend">
    <exec executable="pdepend" dir="${basedir}/Source" logerror="on">
        <arg line="--phpunit-xml=${basedir}/build/logs/pdepend.xml
                   . " />

<target name="phpunit">
    <exec dir="${basedir}/Source/Test/" executable="phpunit" failonerror="true" />

<target name="build" depends="clean,checkout-code,php-documentor,php-codesniffer,php-depend,phpunit" />

Now either wait until next build happens or simply trigger the next build manually and navigate to the metrics tab. All the charts should be still there. In addition two additional charts has been added – Package Dependencies and visual summary of the analyzed project source code.

PHP_Depend metrics

Additional charts generated with PHP_Depend

Package dependencies chart is also shown at the top of phpUnderControl Overview tab.

To learn more about software metric and PHP_Depend itself have a look at Documentation section at http://www.pdepend.org/

Fixing metrics in phpUnderControl 0.5.0

I recently upgraded our buildbox to phpUnderControl 0.5.0 being really curious about new CodeBrowser feature. And indeed CodeBrowser addon is really cool (see Manuel Pichler announcement on his site for details), but after the upgrade I found Metrics tab broken. Instead of nice shiny graphs it showed me Java exception like this:

Metrics exception

Metrics exception

It took me a while to figure out what caused this strange behaviour. I have found the answer when I have run graph generation manually:

#> phpuc graph logs/PHPUnit-3.5/ artifacts/PHPUnit-3.5/

It returned pretty instantly the following error:

The value '1' that you were trying to assign to setting 'labelCount' is invalid. Allowed values are: int > 1.

A little bit of googling and I actually found the answer, again on Manuel Pichler site, in the comments for the announcement.

Basically with phpUnderControl 0.5.0 a file has been released called ClassComplexityInput.php. It is not ready yet to generate a graphs (I suspect it’s gonna be a graph representing class complexity), but phpUnderControl goes through all available input processors to generate graphs for the metrics page.

Fix in that case is pretty trivial, just remove the file (it’s in phpUnderControl/Graph/Input/ directory) and voila – your graphs are back!

Metrics fixed

Metrics fixed