A new feature request for PHP_CodeSniffer alerted me to the effort of a couple of Zend Framework developers to create a PHP_CodeSniffer standard that can be used by all Zend Framework developers. The feature request mentioned that the name they had chosen (Zend) conflicts with the existing standard that is distributed with PHP_CodeSniffer.
I immediately thought this was a bit strange because I've already had someone from Zend contribute some code for the Zend Framework coding standard, and I've written a fair few sniffs for it myself.
I took a look at the code and noticed that almost all of the sniffs that have been committed to the Zend Framework SVN repository are just copies of the sniffs I have written for the existing PHP_CodeSniffer standards. The troubling part is that all the copyright notices and author tags have been switched to indicate that the code was written by and copyright Zend. Worse still, the licence had been changed to the Zend Framework's New BSD licence.
This is a pretty clear violation of the BSD licence under which PHP_CodeSniffer is distributed, so I've left a comment on the Coding Standard RC page in the Zend Framework wiki. I tried locating an email address, submitting an issue and even commenting on an existing issue, but it appears the Zend Framework doesn't have any scope for non-approved developer comments besides the wiki.
I did get a little angry when I saw this, but I also see this as an opportunity to complete the PHP_CodeSniffer Zend standard and get PHP_CodeSniffer our there to a new developer community. The Zend Framework obviously has a couple of developers dedicated to automating their coding standard checks using PHP_CodeSniffer, so I've provided them with an invitation to contact me and work together. I will hopefully be taken up on that offer.
Update: Thought it might be easier to see the problem if you can focus on one file. Take a look at Zend's FunctionDeclarationArgumentSpacingSniff (from the ZF SVN repo) and Squiz's FunctionDeclarationArgumentSpacingSniff (from the PEAR CVS repo). Only very minor changes have been made. Even with these changes, it would be best to extend the Squiz sniff and do some minor refactoring rather than copy/paste, which I'm happy to help with.
Update: Thomas Weidner has contacted me to let me know the files have been removed from the Zend Framework SVN repo.
Saturday, 26 April 2008
PHP_CodeSniffer code taken and rebadged as Zend Framework code
Posted by
Greg Sherwood
at
9:23 am
Tags: Licencing, PHP_CodeSniffer, Zend, Zend Framework
Monday, 21 April 2008
PHP_CodeSniffer 1.1.0a1 released
I've just uploaded PHP_CodeSniffer version 1.1.0a1, which contains 8 bug fixes and adds a load of new features including support for sniffing JavaScript files, an SVN pre-commit hook, integration with JSL and a new collection of sniffs that implement part of the PMD.
Thanks to everyone who has submitted bug reports and special thanks to Jack Bates for the pre-commit hook, Jan Miczaika for a new sniff and Manuel Pichler for bug fixes and the PMD sniffs.
You can view the full changelog, and download the release, on the package download page.
Posted by
Greg Sherwood
at
11:52 am
Tags: JavaScript Lint, PHP_CodeSniffer, PMD
Monday, 31 March 2008
PHP_CodeSniffer and JavaScript Lint
The new JavaScript tokenizer in PHP_CodeSniffer allows you to write your own custom JS sniffs, but JavaScript Lint already has a set of generic tests that can be applied to your code. Thanks to the JavaScript Lint command line tool, jsl, you can now include JavaScript Lint warnings and errors in your coding standards.
I've just committed the JavaScriptLint sniff into the Squiz standard under a new Debug category. The sniff requires you to have jsl installed on the same machine as PHP_CodeSniffer and you need to tell PHP_CodeSniffer where to find it.
$ phpcs --config-set jsl_path /path/to/jslJavaScript Lint checks for a number of common errors, including missing semi-colons and unused code. Like the Zend CodeAnalyzer sniff, not all errors and warnings need fixing, so all messages reported by jsl are warnings within PHP_CodeSniffer and can be hidden easily.
$ phpcs --standard=squiz /path/to/file.js
Posted by
Greg Sherwood
at
9:11 pm
Tags: JavaScript Lint, PHP_CodeSniffer
Thursday, 20 March 2008
Obscure software bugs always come in pairs
Well, for me anyway, and in MySource Matrix in particular. I don't know what it is, but obscure bugs get reported to me and shortly after I have a fix, I will be fixing the bug on one or two other systems. Yet this bug may have been in the software for years and may be extremely hard to replicate. This has been happening more and more; I think it has been three or four times in the past 12 months, which is just strange.
The strangest case is a bug in a trigger condition that was caused by the way PHP converts strings to numbers. I was so surprised we had never previously encountered the problem that I wrote a blog post on the issue. The night I wrote that post I also committed a fix to MySource Matrix. The very next day I was asked to diagnose a strange problem on another client's system with triggers. The fix I committed the night before also fixed this client's problem.
The latest case reared its head again just today. About a month ago we diagnosed and fixed a strange problem that was caused by IP addresses changing and logging a user out of MySource Matrix during the multiple requests made on the frontend (HMTL, CSS, JS etc). The session is destroyed if you get logged out, but the code that loaded a serialized class didn't first include the class file. We fixed that bug. The next week I diagnosed the same bug on another client's system. Last week I received a support ticket for the same issue. And just today I diagnosed the same problem on a system undergoing implementation. The strange thing is that we have always had systems where users have their IP changing and yet we've never seen this error.
I don't get this so much with PHP_CodeSniffer, although I do tend to fix bugs in CVS only to have someone report it via the PEAR bug tracker. They are not as common or obscure though. Perhaps the size of the project directly relates to the incidence of these sort of bugs.
I think everyone hears that these sort of things happen, and not just with software bugs, but it is still amazing to see how often it occurs.
Posted by
Greg Sherwood
at
4:37 pm
Tags: MySource Matrix, Testing
Monday, 10 March 2008
Rating content and calculating average ratings in MySource Matrix
A new feature was released in version 3.16.6 of MySource Matrix that allows you to calculate an average rating for content based on the comments and ratings users have made. The average rating is calculated as comments are created (or approved, it's up to you) and then stored in a metadata field. This field can then be used to sort pages based on their average rating.
Adding this feature to an existing comment system is fairly easy, but I'll just run through the basics of building a comment system first.
I've built a basic site with two standard pages. Both pages have a paint layout applied that nests in an asset builder and an asset listing that are used to create new comments and list existing ones. The general idea here is that every page will have a form that users can use to create new comments and apply a rating. Under the form will be a listing that prints the current comments and the ratings users applied to them.
Asset Builder
The asset builder is configured to create comment assets. In my case, I have made them Live by default, but you could choose to create them as Under Construction so you can moderate comments. On the Create Locations screen, I have configured an Additional Create Location to create the comment asset under the current asset. I've made the links TYPE_2 so they are not shown in menus.
The create form for comments has been customised (bottom of the asset builder's Details screen) so that the rating can be added when the comment is created. I've also renamed Title to Subject.

Asset Listing
The asset listing is configured to list comment assets. The root node is set as the site asset, but this will be replaced dynamically by the current asset. Direct links only is set to Yes and there is a dynamic parameter set to replace the root node with the current asset's ID.I've customised the No Results bodycopy to print a message encouraging users to post a comment and I've printed the rating as both a percentage and as a star rating in the default type format.

Paint Layout
I've nested the asset builder and the asset listing in the default type format. Be sure to nest the asset builder first otherwise new comments will not appear until the next page refresh. This is obviously not a problem if you are moderating comments as they will not appear until they are approved.
Adding Comments
Once the paint layout is applied, users are presented with the following form:

Calculating Average Ratings
Now that we have our standard commenting system created, we can implement the new average rating functionality. All we do is apply a metadata schema to the assets that are rated and ensure there is a Text field in the schema in which to store the average rating. Then we create a trigger that sets the average rating when a new comment is added.The metadata schema I have created is shown below.

Make sure you set a default value (e.g., zero) so that unrated content gets a default rating.
The trigger I have created is shown below. Remember to enable triggers on the Trigger Manager Details screen.

Once this trigger is enabled, I added a new comment to the page to force the trigger to run. I now have three comments with three different ratings; 20%, 40% and 80%. Once the trigger has fired, the value 46 has been entered into the Rating metadata field for my page. Note that the rating has been rounded down so that an asset with a rating of 99.6% is not rated at 100%.

Now I can configure an asset listing to show the most popular pages in my site. This asset listing is configured to list standard pages under my site and is sorted by the value of the Average metadata field. The Default type format is configured to print the asset's name and the average rating and I've limited it to 10 assets per page.

The rating is just a percentage, but you could get tricky with JavaScript and use the values to prints stars and other graphical elements. Just remember to put a textual value in there somewhere to ensure it is accessible.
And that's it. You can use this average rating anywhere you normally use metadata, including sorting search results. And of course, this is MySource Matrix so you can configure all the frontend interfaces shown here in any way you want.
Posted by
Greg Sherwood
at
4:02 pm
Tags: MySource Matrix, Tutorials
Using PHP_CodeSniffer in an SVN pre-commit hook
I've just commit a new script to PHP_CodeSniffer called phpcs-svn-pre-commit. It sits in the scripts dir with phpcs and phpcs.bat. This script was contributed by Jake Bates, who has also volunteered to maintain the Debian package, and will be available in the 1.1.0 release.
Using the script is pretty easy, but you'll need to modify it slightly.
Edit /path/to/PHP_CodeSniffer/scripts/phpcs-svn-pre-commit and replace @php_bin@ in the first line with the path to the PHP CLI. For example,
#!@php_bin@becomes
#!/usr/bin/php
Then, ensure the path to svnlook is correct by modifying the line:
define('PHP_CODESNIFFER_SVNLOOK', '/usr/bin/svnlook');
Now, add the following line to your pre-commit file in the SVN hooks directory:
/.../phpcs-svn-pre-commit "$REPOS" -t "$TXN" >&2 || exit 1
This will cause the SVN commit to fail if PHP_CodeSniffer finds any errors. The error report will be displayed to the user so they can fix errors before attempting the commit again.
You can also use all the standard phpcs command line options to do things like set the standard to use, the tab width and the error report format:
/.../phpcs-svn-pre-commit --standard=Squiz --tab-width=4 ...
And some example output:
$ svn commit -m "Test" temp.php
Sending temp.php
Transmitting file data .svn: Commit failed (details follow):
svn: 'pre-commit' hook failed with error output:
FILE: temp.php
---------------------------------------------------------------
FOUND 1 ERROR(S) AND 0 WARNING(S) AFFECTING 1 LINE(S)
---------------------------------------------------------------
2 | ERROR | Missing file doc comment
---------------------------------------------------------------
Posted by
Greg Sherwood
at
1:42 pm
Tags: PHP_CodeSniffer, svn
Friday, 7 March 2008
Creating an SVN repostiory on OS X
I've been playing around with an SVN pre-commit hook for PHP_CodeSniffer that was submitted by Jack Bates. Part of that process required me to create a SVN repository for testing. While it was fairly easy overall, there were a few error messages that I got stuck on.
Firstly, creating the repository was dead simple:
$ create --fs-type fsfs /Users/Greg/TestSvnRepo
But then I couldn't checkout my repository. I'd get errors like:
$ svn co file:///Users/Greg/TestSvnRepo
Unable to open an ra_local session to URL
...
Expected version '3' of repository; found version '5'
Common suggestions on mailing lists point to svn not being compiled with ra_local support, which was not the problem in my case:
$ svn --version
svn, version 1.1.4 (r13838) compiled Jul 23 2006, 14:53:55
...
The following repository access (RA) modules are available:
* ra_dav : Module for accessing a repository via WebDAV (DeltaV) protocol.
- handles 'http' schema
- handles 'https' schema
* ra_local : Module for accessing a repository on local disk.
- handles 'file' schema
* ra_svn : Module for accessing a repository using the svn network protocol.
- handles 'svn' schema
I did find one useful article though. It mentions that different versions of svn software can cause problems. I believe this is more common when moving repositories between versions, or when connecting to a remote server, but in my case the problem was my version of svnadmin:
$ svnadmin --version
svnadmin, version 1.4.4 (r25188) compiled Sep 23 2007, 22:32:34
So my svnadmin utility is version 1.4.4 but the svn utility itself is 1.1.4. Adding the pre-1.4 command line argument suggested in the article worked a treat:
$ svnadmin create --fs-type fsfs --pre-1.4-compatible /Users/Greg/TestSvnRepo
$ svn co file:///Users/Greg/TestSvnRepo