Whitewashing.de http://www.whitewashing.de Whitewashing is the blog of Benjamin Eberlei and covers topics in computer science, databases and web-development. en-en All contents are copyright 2007-2010 by their respective authors. 2010-03-10 Resources for a PHP and Hudson CI Integration Yesterday I finally had the time to setup my first continuous integration environment. Possible solutions for CI are phpUnderControl, Hudson or Arbit. Although phpUnderControl is the most wide-spread, but from I heard complex to setup/maintain, solution supposedly a hack and Arbit just in an early Alpha I decided to give Hudson a shoot. Another reason for this decision, I heard it has a simple plugin architecture and is easy to install and use. Additionally Hudson is easily integrated into Netbeans and Redmine, and I use both tools regularly in development.

My motivation to dive into CI is easily explained. I just never felt it was necessary to add a continuous integration enviroment to my projects, since I had one or two simple bash scripts that did the job. In general this is rather annoying, because they mostly only run PHPUnit and have to be done using a cronjob or manually, without any real process of notification. Additionally you have no way to navigate the test-results, code-coverage and no history of the last builds. For projects like Doctrine 2 we have the additional requirement to support 4 different database platforms, i.e. 4 different PHPUnit configurations. Currently that is solved by me using a Bash script that iterates over the configuration file names and invokes PHPUnit.

There are already some awesome sources how to get Hudson and PHP working. I'll list them here:

All those guides are already awesome and I would recommend choosing one of those to install Hudson, I think i can't add anything new to those. I have used Sebastians Howto, however i also like the third one. David Luhmans guide adds lots of details that are important to get the different parts of a build process to work.

Now what these tutorials all do is that they use a bash command to execute the build process or specifiy an Ant Build file. However there is also a Phing Build process plugin for Hudson that allows to specify the build.xml targets to execute in the process. From the "Available Plugins" list you can choose the "Phing plugin".

After installation you have to configure the Phing install. The Phing Plugin Wiki Page shows how to do this. You have to go to "Manage Hudson" => "Configure System" and look for Phing. There you find the dialog to configure your phing installations.

In the context of choosing a build script for your project you can now choose "Phing" instead of Ant:

You can enter the targets to build, for example on my local Hudson instance I only execute "test" for Doctrine 2, since I am not interested in the building and deployment onto the PEAR channel at this development stage.

From inside Netbeans you can then start builds by pointing to the Hudson instance. See this tutorial by one of the Hudson + Netbeans Developers. You can then start all the builds from inside Netbeans and be notified of the success or failure.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 126 http://www.whitewashing.de/blog/articles/126 2010-02-07 12:25:28
Application Lifecycle Management and Deployment with PEAR and PHAR (revisited) *UPDATE* Some weeks ago I posted an article on using PEAR and PHAR for application lifecycle management and deployment. Since then I have gotten some feedback through comments, but also discussed the topic with collegues. I have also optimized the approach quite considerably and even made an open-source project out of parts of it and I want to share all that is new with you. First of all, yes the presented solution was somewhat complex, partly because it is still a proposed idea and definately up for optimizations. However I am still very convinced of my approach, something I should discuss in more detail.

The only other two languages I have ever programmed something in with more than 50 lines of code are Java and C#. In both languages you can explicitly import different dependencies like libraries and frameworks by adding them to your application, i.e. in java you would add for example Spring as an MVC Web layer, Hibernate as an ORM and several other things to your project and directly bundle them in your executable. This is very easy to configure and maintain in IDEs like Netbeans or Eclipse (C# has the same with allowing you to attach DDLs of libraries to your project). It also makes for a much more straightforward deployment.

In the PHP world this siutation was quite different (up to PHP 5.3) for several reasons:

  • You could not package a library into a single distributable file.
  • The PEAR installer as the only tool for updating and managing dependencies of your application by default installs into a system/global directory. This means dependencies your application uses are located in a completly different location than your application code.
  • You can't manage multiple versions of the same package with PEAR in this system directory, making it very hard to control servers with different applications.
  • The global directory with your application dependencies is most often not under version control, which makes deployment of applications with PEAR dependencies somewhat difficult.

There are some solutions to this problems:

  • Don't use PEAR, but put all dependencies in your version control system.
  • Don't use PEAR, and bundle dependencies to your code in the build/deployment process.
  • Use PEAR like in the article described, on a per project basis.

The solutions that don't use PEAR suffer from the disadvantage that you need to keep track of all the library and framework dependencies yourself and upgrade them yourself. This might not be such a huge problem from a first glance, but in my opinion many PHP applications and projects suffer from using either no framework/library or just exactly one. There is no real cherry-picking going on the PHP world, for example I would really like to use Zend Framework for the general application layout, but still use Doctrine for the Modelling and HTML Purifier for the Output Escaping. Certain tasks might then only be solvable with the help of eZ Components, all of which are then to some extend dependencies of my application. With PEARHUB and PEARFARM on the horizon (Read Padraic on this topic) even more PHP code will be distributed using PEAR channels in the near future. My immutable DateTime code for example makes for a great little open source library that could be distribued via PEAR, aswell as Yadif - a dependency injection container I am using extensivly.

Question: Are you really going to manage all these dependencies correctly manually? Is everything up to date all the time, and upgradeable with ease?

The PEAR driven solution then begins to look very desirable in this light, however it has a considerable disadvantage: The PEAR installer itself works on a system-wide/user-centric basis, making it impossible to manage dependencies of several applications using only one linux user. My little Pearanha to the rescue: I have taken the PEAR installer code (which is distributed with all PHP installations across all systems) and put a new CLI tool on top of it. Its a very simple code-generator that allows to generate a re-configured PEAR installer script which only manages a single application in a given directory. This approach is also used by the symfony plugin mechanism, which internally uses the PEAR installer (did you know?).

Lets revisit my blog application example from my previous PEAR post, first install from Github and make the "pearanha" file executable and put it in your PATH (A PEAR Server Channel will follow any time soon).

Now we need to have an existing application directory somewhere, for example /var/www/blog and then we can put Pearanha on top of it with:

benny@desktop: pearanha generate-project 

You then need to specifiy the project base dir and then the project style (for example Zend Framework or Manual) which prompts your for the directory that should be used for as the vendor/library directory that PEAR will install all the code in. You will also be prompted for a binary/scripts directory which will then hold a new PHP file for you, the file my_phpiranha.

Pro Argument: Switching to Pearanha can be done at any point in your application lifecycle. Just define an additional vendor directory for all the dependencies to go in and generate the applications pear installer and you are good to go.

The generated script is your new application specific PEAR installer and you can begin to install all the required dependencies of your application:

benny@desktop:~$ cd /var/www/blog
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover pear.zfcampus.org
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install zfcampus/zf-alpha
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover htmlpurifier.org
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install hp/HTMLPurifier
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover pear.phpdoctrine.org
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install pear.phpdoctrine.org/DoctrineORM-2.0.0
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover components.ez.no
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install ezc/ezcGraph

All this stuff is now located in /var/www/blog/vendor. Again you can use PEARs complete upgrade, remove and install functionality for your application, now without the hazzle of having to create a linux user for each project you want to manage this way, which in my opinion is a considerable simplification. The complete application (including its dependencies) can then be put under version control and be readily packaged as a single executable PHAR file by your build process.

As a side node, I did try Pyrus instead of PEAR for the same discussed purpose, however most of the current PEAR channels don't validate against Pyrus strict standards for the package.xml file. In the future this might change and a Pyrus based application installer will then be integrated into Pearanha.

UPDATE: I renamed PHPiranha to Pearanha as its more appropriate. Also after apinsteins comment on "pear config-create" I rewrote the generate-project parts to use the config-create functionality internally, which allowed me to throw away half of the self-written code. Thanks!

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 125 http://www.whitewashing.de/blog/articles/125 2010-01-10 23:59:23
Immutable DateTime Objects One serious drawback of PHPs DateTime extension is the mutability of its instances. It can lead to serious bugs if a DateTime instance is passed between different functions and is modified at unexpected places. Additionally this possibly rules out several optimizations for scripts that make very heavy use of dates and could share references to equal timestamps.

Warning: All the code assumes that you work with one timezone only!

The following code is an immutable version of PHP's DateTime. All setter methods throw an exception and add(),sub() and modify() clone the current instance, apply the operation and return the new instance.

namespace Whitewashing\DateTime;

class DateTime extends \DateTime
{
    /**
     * To prevent infinite recursions
     *
     * @var bool
     */
    private static $_immutable = true;

    public function add($interval)
    {
        if (self::$_immutable) {
            self::$_immutable = false;
            $newDate = clone $this;
            $newDate->add($interval);
            self::$_immutable = true;
            return $newDate;
        } else {
            return parent::add($interval);
        }
    }

    public function modify($modify)
    {
        if (self::$_immutable) {
            self::$_immutable = false;
            $newDate = clone $this;
            $newDate->modify($modify);
            self::$_immutable = true;
            return $newDate;
        } else {
            return parent::modify($modify);
        }
    }

    public function sub($interval)
    {
        if (self::$_immutable) {
            self::$_immutable = false;
            $newDate = clone $this;
            $newDate->sub($interval);
            self::$_immutable = true;
            return $newDate;
        } else {
            return parent::sub($interval);
        }
    }

    public function setDate($year, $month, $day) {
        throw new ImmutableException();
    }
    public function setISODate($year, $week, $day=null) {
        throw new ImmutableException();
    }
    public function setTime($hour, $minute, $second=null) {
        throw new ImmutableException();
    }
    public function setTimestamp($timestamp) {
        throw new ImmutableException();
    }
    public function setTimezone($timezone) {
        throw new ImmutableException();
    }
}
class ImmutableException extends \Exception
{
    public function __construct()
    {
        parent::__construct("Cannot modify Whitewashing\DateTime\DateTime instance, its immutable!");
    }
}

Its not the prettiest code, but it works.

A next optimization would be a DateFactory that manages DateTime instances by returning already existing instances for specific dates. This is not a perfect solution, since you won't be able to enforce a single instance when you are using the relative descriptive dates or when calculating with dates using add(), sub() and modify(), however for lots of dates created from a database or other external source it might be quite a powerful optimization depending on your use-case:

namespace Whitewashing\DateTime;

class DateFactory
{
    static private $_dates = array();

    static public function create($hour, $minute, $second, $month, $day, $year)
    {
        $ts = mktime($hour, $minute, $second, $month, $day, $year);
        if (!isset(self::$_dates[$ts])) {
            self::$_dates[$ts] = new DateTime('@'.$ts);
        }
        return self::$_dates[$ts];
    }

    static public function createFromMysqlDate($mysqlDate)
    {
        list($date, $time) = explode(" ", $mysqlDate);
        if($time == null) {
            $hour = $minute = $second = 0;
        } else {
            list($hour, $minute, $second) = explode(":", $time);
        }
        list($year, $month, $day) = explode("-", $mysqlDate);
        return self::create($hour, $minute, $second, $month, $day, $year);
    }
}

This includes some date time calculations and date creation with mktime() and DateTimes unix timestamp capabilities to be able to work. Otherwise the sharing of instances could not be implemented. If you need to create shareable instances from other formats you could just create another creation method for it and convert the format for create() to be used.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 124 http://www.whitewashing.de/blog/articles/124 2010-01-08 09:48:26
Trying a Two Step PEAR/PHAR approach to develop and deploy With PHP 5.3 the PHAR extension is a pretty powerful concept for all your deployment needs, however it does not tell the complete story. Frameworks, Libraries and many different of them are used throughout applications and in recent times people even began to chery-pick the best components from each of the frameworks and package them together. With Pirum being a simple PEAR channel server there is also momentum for projects to distribute their code via PEAR.

However PEAR is mostly used in the server-wide configuration use-case, which is not very useful if you plan to distribute your complete application in one PHAR file. I just recently had the idea for this scenario, so please bear with me and add all the feedback and comments you can come up with. I tested this with the ongoing rewrite of my blog software.

First we'll add a new user that we develop our application with:

sudo useradd -m -g www-data whitewashing
sudo passwd whitewashing
su - whitewashing

Now there is the possibility that with this user PHP and PEAR is not in your $PATH enviroment, so you might have to add it. In my case on Ubuntu i also had to switch the console from /bin/sh to /bin/bash for this user. Then we need to setup our application, I am going to use the Zend Framework project style here but with a little twist. We will add a distinction between vendor and project libraries by adding a vendor directory into the main folder.

But first we create a folder for our application, and create a Zend Framework project in the subfolder "trunk", which will be the focus of our development.

whitewashing@desktop:~$ mkdir whitewashing
whitewashing@desktop:~$ zf create project whitewashing/trunk
Creating project at /home/whitewashing/whitewashing/trunk
whitewashing@desktop:~$ mkdir whitewashing/trunk/vendor

Now we can configure an Apache virtual host to point to our /home/whitewashing/whitewashing/public directory, i call this "whitewashing-dev" add it to my /etc/hosts and can visit the dummy project page.

We then configure our PEAR installation for the specific application user and re-configure the bin and php library paths:

whitewashing@desktop:~$ pear create-config /home/whitewashing/ .pearrc
whitewashing@desktop:~$ pear config-set php_dir /home/whitewashing/whitewashing/trunk/vendor
whitewashing@desktop:~$ pear config-set bin_dir /home/whitewashing/whitewashing/trunk/bin

This configuration assumes that we will install all our stuff into our development trunk. From there also the PEAR installed libraries might be copied into branches or tags. PEAR Project tests, configuration and web-files will still be put by default under $HOME/pear/*. We don't need them for our applications.

Now we install all the dependencies our project needs, in this case Zend Framework, Doctrine 2, HTML Purifier:

whitewashing@desktop:~$ pear channel-discover pear.zfcampus.org
whitewashing@desktop:~$ pear install zfcampus/zf-alpha
whitewashing@desktop:~$ pear channel-discover htmlpurifier.org
whitewashing@desktop:~$ pear install hp/HTMLPurifier
whitewashing@desktop:~$ pear channel-discover pear.phpdoctrine.org
whitewashing@desktop:~$ pear install pear.phpdoctrine.org/DoctrineORM-2.0.0

Now we have all three of the packages installed in our project folder whitewashing/trunk/vendor, see:

whitewashing@desktop:~$ ls -aFl whitewashing/trunk/vendor/
total 680
drwxr-xr-x  7 whitewashing www-data   4096 2009-12-13 14:45 ./
drwxr-xr-x  8 whitewashing www-data   4096 2009-12-13 14:36 ../
drwxr-xr-x  3 whitewashing www-data   4096 2009-12-13 14:43 .channels/
-rw-r--r--  1 whitewashing www-data     57 2009-12-13 14:45 .depdb
-rw-r--r--  1 whitewashing www-data      0 2009-12-13 14:45 .depdblock
drwxr-xr-x  5 whitewashing www-data   4096 2009-12-13 14:45 Doctrine/
-rw-r--r--  1 whitewashing www-data 582208 2009-12-13 14:45 .filemap
drwxr-xr-x 20 whitewashing www-data   4096 2009-12-13 14:39 HTMLPurifier/
-rw-r--r--  1 whitewashing www-data    629 2009-12-13 14:39 HTMLPurifier.autoload.php
-rw-r--r--  1 whitewashing www-data    274 2009-12-13 14:39 HTMLPurifier.auto.php
-rw-r--r--  1 whitewashing www-data    545 2009-12-13 14:39 HTMLPurifier.func.php
-rw-r--r--  1 whitewashing www-data   9299 2009-12-13 14:39 HTMLPurifier.includes.php
-rw-r--r--  1 whitewashing www-data    955 2009-12-13 14:39 HTMLPurifier.kses.php
-rw-r--r--  1 whitewashing www-data   8831 2009-12-13 14:39 HTMLPurifier.php
-rw-r--r--  1 whitewashing www-data  11901 2009-12-13 14:39 HTMLPurifier.safe-includes.php
-rw-r--r--  1 whitewashing www-data      0 2009-12-13 14:45 .lock
drwxr-xr-x  8 whitewashing www-data   4096 2009-12-13 14:43 .registry/
drwxr-xr-x 59 whitewashing www-data   4096 2009-12-13 14:36 Zend/
-rw-r--r--  1 whitewashing www-data  19537 2009-12-13 14:36 zf.php

And both Doctrine and ZF registered their binary CLi tools inside the whitewashing/trunk/bin/folder:

whitewashing@desktop:~$ ls -aFl bin/
total 20
drwxr-xr-x 2 whitewashing www-data 4096 2009-12-13 14:45 ./
drwxr-xr-x 8 whitewashing www-data 4096 2009-12-13 14:36 ../
-rwxr-xr-x 1 whitewashing www-data   50 2009-12-13 14:45 doctrine*
-rwxr-xr-x 1 whitewashing www-data  169 2009-12-13 14:45 doctrine.php*
-rwxr-xr-x 1 whitewashing www-data 1511 2009-12-13 14:36 zf*

We now have the full control over the versions of our dependencies, we can call "pear upgrade " whenever we want to update one of the ZF, Doctrine or HtmlPurifier libraries inside our application.

Now some magic is gonna happen, we start to develop our application and such which is all not really interesting for this topic. At some point we want to package it all up into a PHAR file and distribute it. We want to package our application in one big phar file. We also want to make sure that the configuration files in whitewashing/trunk/application/configs/ are not distributed, but have to be created on the server and are kept that way. We could write an installer script for this configuration management.

The reference for PHAR files is the PHP Manual for the Basics and Cal Evans' two posts (1, 2) on this topic, aswell as a post on Geekmonkey. Contrary to most other PHP extensions, PHAR has an extensive documentation, however its not organized terribly well. Also there are no real use-cases and scenarios discussed, methods are only looked at in isolation. Cals posts are very good on understanding how to package up different libraries, but there is no word on distributing web applications. That is where the Geekmonkey post comes in to wire it all together.

For a Zend Framework application that should have both a web and a cli (cronjobs) entry point into the application we need a specific stub file for the PHAR bootstrapping. A stub is a little PHP script that is executed whenever your PHAR file is included into your php script. It is essentially a front-controller for your PHAR application. It also has mount capabilities that allow to import files or directories from outside into the PHAR context. This is a powerful feature that is required to distribute configurable applications like our blog.

This screenshot shows how the application is currently structued in development mode. In production its structure should look like:

whitewashing
|--application
|  |--configs
|     |-- my application config files are all here...
|--bin
|  |--whitewashing.php
|--public
|  |--index.php
|  |--.htaccess
|--whitewashing.phar

The whitewashing.php and index.php files are the application entry points that only include the phar file and trigger the application bootstrapping that will be included in the Stub file. They both look like:

<?php
define('EXTERNAL_APPLICATION_ROOT', __DIR__."/../");
include EXTERNAL_APPLICATION_ROOT."/whitewashing.phar";

Including a PHAR file essentially has two conesequences:

  • The PHAR path will be added to your include path.
  • The stub file will be executed.

Our application stub looks like this:

<?php

if(defined('EXTERNAL_APPLICATION_ROOT')) {
    // Mount the external application/configs directory as config if it exists.
    if (file_exists(EXTERNAL_APPLICATION_ROOT."/application/configs")) {
        Phar::mount("application/configs", EXTERNAL_APPLICATION_ROOT."/application/configs");
    }
}

/** Zend_Loader_Autoloader */
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();

if (php_sapi_name() == "cli") {
    require_once 'bin/whitewashing.php';
} else {
    require_once 'public/index.php';
}

__HALT_COMPILER();

The first bit of the stub mounts the external application configs directory into the stub and hides possible directories that are present at this location in the PHAR file. This allows us to distribute our application with a default configuration, but allows any user to replace the configuration files to fit the application to his need.

The second bit loads Zend Framework Autoloader that is required by the bootstrapping mechanism. The third bit decides wheater this request is executed from the CLI- or the Web-Entry point of the application. The fourth bit, __HALT_COMPILER(); is a technically required call inside your stub-file.

Now that we have a stub-file for our application, we can package it and distribute it. I am using a modified version of Cal Evans example for this. I have extracted his directory traversal to find all the relevant into a re-usable FilterIterator implementation. I pasted my package.php a Gist on Github. Now this should probably be put into the build context of your application, possibly as a phing or ant task or something alike.

Now what this build process does not manage is the creation of the application entry point php and .htaccess files, but since they won't ever change its easy to add them to the build directory for now. An even more sophisiticated version of the build script would lead to the creation of an additional tar.gz of the complete application folder. Our deployment process would then be as easy as:

  • If the application is not installed yet, unpack the tarball into its location.
  • If the application should be updated, just replace the PHAR file.

If you need the ability to go back to any version of your application you could make use of symlinks.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 123 http://www.whitewashing.de/blog/articles/123 2009-12-19 18:03:48
Netbeans PHP CodeSniffer Plugin: Now with Options Dialog Just two days before the International PHP Conference 09 will start I got an email from alexandrehaguiar that he forked my Netbeans PHP CodeSniffer plugin and added the long awaited Options screen. This is just awesome! This way I don't have to ask the Netbeans guys at IPC all the questions about how to implement it. I merged the changes back into my branch and released a new version which also fixed another small bug. For me it works with both Netbeans 6.7.1 and 6.8 Beta. I want to thank alexandre very much for this awesome contribution.

What you can do now is chose the Coding Standard you want to use in an Options Dialog under the "Miscallenous" button. You can choose from a list of pre-defined standards, or even enter your own if you use one. Additionally you can disable that warning are shown, so that with any given coding standard you only see the errors.

You can download the new version from the Github Project Downloads page.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 122 http://www.whitewashing.de/blog/articles/122 2009-11-14 22:56:31
PHP CodeSniffer for Netbeans v0.2 I finally found some time to spend some time on the PHP CodeSniffer for Netbeans plugin. Previously the plugin used an unnecessary API which restricted the use to Netbeans 6.7.0 only. This API was removed so that the plugin should now work with all Netbeans Versions >= 6.7.0.

Additionally when working the previous version would scan every PHP script on a file per file basis when the all projects or main projects filters were activated. This rendered made the plugin almost useless. In the current version scans of filters that contain more than one file are blocked. That means you will only see Coding Violations when you enable the "Current File" filter. Using any other filter will just do nothing and won't put your Netbeans in permanent hibernation mode (aka useless mode).

There is also some preference "phpcs.codingStandard" using the NbPreferences API which allows to configure the coding standard. However this feature was contributed by Manuel Piechler and I don't yet understand how I can manipulate it. Maybe someone knows how (*Looking in Mapis general direction*)? By default the Zend Coding Standard is used.

Update: Coding Standard can be changed by hacking into the config file .netbeans/6.7/config/Preferences.properties setting "phpcs.CodingStandard=". Additionally I fixed several bugs with the inline highlighting that did not refresh when lines in the file changed.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 121 http://www.whitewashing.de/blog/articles/121 2009-10-05 21:03:16
Enums in PHP A colleague of mine complained about the missing support for Enums in PHP and how one often wants to have a variable that is constant and has one of several specific values. We came up with an elegant solution that we want to share, maybe its even helpful to you.

If you want to implement Enum behaviour with a simple string or int value you end up with having to validate the values at several different locations in the code rather than being able to strictly enforce the Enum structure by using typehints.

We discussed several approaches to this problem that all seemed a bit ugly in one or another way. For example the SplEnum class is a step in the right direction, however you can only use a type hint for "SplEnum" or add another inheritance layer. Also you have to implement different classes for each enum type, which requires you to implement a factory method for your enum to help with creation of the different types.

We came up with a very simple Enum concept. It uses reflection in the constructor to check if the given value is a valid Enum value by checking it against all the defined constants of the implementing class and throws an Exception if it is not. The __toString() magic method is implemented to allow for simple checks of the enums value. Strict type-checks are not possible with this construct, however in our opinion it is a very elegant solution to enforce a limited set of specific values throughout your code-base.

Here is the code plus a small example:

abstract class MyEnum
{
    final public function __construct($value)
    {
        $c = new ReflectionClass($this);
        if(!in_array($value, $c->getConstants())) {
            throw IllegalArgumentException();
        }
        $this->value = $value;
    }

    final public function __toString()
    {
        return $this->value;
    }
}

class Foo extends MyEnum
{
    const FOO = "foo";
    const BAR = "bar";
}

$a = new Foo(Foo::FOO);
$b = new Foo(Foo::BAR);
$c = new Foo(Foo::BAR);

if($a == Foo::FOO) {
    echo "My value is Foo::FOO\n";
} else {
    echo "I dont match!\n";
}

if($a == $b) {
    echo "a value equals b value!\n";
}
if($b == $c) {
    echo "b value equals c value!\n";
}

Now you could nice things such as:

function doStuff(Foo $foo) {
    switch($foo) {
        case Foo::FOO:
            echo "do more here!\n";
            break;
        case Foo::BAR;
            echo "evil stop!\n";
            break;
    }
}

doStuff($a);

What are your thoughts?

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 120 http://www.whitewashing.de/blog/articles/120 2009-08-31 20:10:37
PHP CodeSniffer Support for Netbeans I dived into the code of my new favorite IDE Netbeans these last days and came up with an extension module, which adds PHP CodeSniffer Support on a per file basis to make my life much easier. It shows warnings and errors as annotations to the Editor and marks the affected lines in yellow and red.

My Java skills being very bad, it will only work on Linux currently, since the PHP Code Sniffer "binary" is hardcoded into the Java Source code. You have to create a "/usr/bin/phpcs2" executable, which is a wrapper that looks like:

With Manuals extensions (see the comments) the module now works without the wrapper script. It might even work under Windows now. Yet now the Zend Coding standard is enforced though. I am working on making that one configurable next.

You can install the NBM module install file from the GitHub repository into Netbeans and it "should" work then.

I hope to get more familiar with Netbeans in the future to add some more PHP tools and enhance Code Sniffer support.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 119 http://www.whitewashing.de/blog/articles/119 2009-07-30 21:07:13
Using Symfony Dependency Injection with Zend_Application As a follow-up to my recent post on Dependency Injection containers and Zend_Application I was eager to find out if its possible to integrate the new Symfony Dependency Injection Container into the Zend Framework. To my suprise its possible without having to make any changes to one of the two components. An example use-case would look like:

$container = new sfServiceContainerBuilder();
 
$loader = new sfServiceContainerLoaderFileXml($container);
$loader->load(APPLICATION_PATH.'/config/objects.xml');

$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/config/application.xml'
);
$application->getBootstrap()->setContainer($container);
$application->bootstrap()
            ->run();

Resources instantiated by Zend_Application are then injected into the container by the name of the resource and are given the resource instance. Any object from the Symfony container can then use these dependencies in their object setup. The only drawback of the integration is the fact that the Symfony Container is case-sensitive in regards to the service names but Zend_Application lower-cases all service before injecting them into the container. The following code is a restatement of my previous example of a MyModel class which requires a Zend_Db and Zend_Cache constructor argument.

$container->register('myModel', 'MyModel')
          ->addArgument(new sfServiceReference('db'))
          ->addArgument(new sfServiceReference('cache'));

Access to a MyModel instance with its dependencies is then granted through the call $container->myModel throughout the application. Make sure to call this after running Zend_Application::bootstrap, so that the Resource dependencies are injected first.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 118 http://www.whitewashing.de/blog/articles/118 2009-07-04 09:28:32
Using a Dependency Injection Container with Zend_Application Much has been written on Dependency Injection lately, mostly by Padraic Brady (1, 2) and Fabien Potencier (1, 2, 3, 4, 5). My subjective feeling tells me there are now more PHP DI containers out there than CMS or ORMs implemented in PHP, including two written by myself (an overengineered and a useful one). Its an awesome pattern if used on a larger scale and can (re-) wire a complex business application according to a clients needs without having to change much of the domain code. It aims at a complete seperation of object instantiation and dependency tracking from the business logic.

Beginning with version 1.8 Zend Framework is able to integrate any of these DI containers into its Zend_Application component easily. The Application component intializes a set of common resources and pushes them into the MVC stack as additional Front Controller parameters. Technically a Zend_Registry instance holds all these resources with their respective resource names as keys. The resources are accessible inside the Front Controller and the Action Controller classes. Assume the resource 'Db' is initialized in your application, you can access it with:

$front = Zend_Controller_Front::getInstance();
$container = $front->getParam('bootstrap')->getContainer();
$db = $container->db;

// or:
class FooController extends Zend_Controller_Action {
    public function barAction()
    {
        $container = $this->getInvokeArg('bootstrap')->getContainer();
        $db = $container->db;
    }
}

This is pretty much dependency injection already, but the default registry approach suffers from two serious problem: New instances can only be added to the Container by implementing new Zend_Application resources and these instances cannot be lazy loaded. All resources used by Zend_Application are always loaded on every request. But the application container implementation was developed with Dependency Injection in mind and is not tied to the use of Zend_Registry. Only three magic methods are required by any container that wants to be Zend_Application compliant: __get(), __set() and __isset(). Each instantiated resource is pushed via __set() into the container. If required by another resource, __isset() is used to check wheater a resource with the given name exists inside the container and __get() is used to retrieve the instances from the container.

Some month ago I extended Yadif, a lightweight PicoContainer-like DI container for PHP written by Thomas McKelvey, with several features that make it a very powerful DI container in my opinion. It has a detailed documentation and examples on the GitHub Page if you want to check it out. I extended Yadif to be Zend_Application compliant in a way that the application-wide Zend_Application resources can be used as dependencies for objects that are lazy-loaded from the container. Skipping the tech-talk, here is an example. First we have to replace the default Container with Yadif:

$objects = new Zend_Config_Xml(APPLICATION_PATH."/config/objects.xml");
$container = new Yadif_Container($objects);

$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/config/application.xml'
);
// Set Yadif as Container
$application->getBootstrap()->setContainer($container);
$application->bootstrap()
            ->run();

Assume you run Zend_Application with a "Db" and a "Cache" resource. These resources are loaded on every request. The objects configured in Yadif however are not instantiated until they are requested for the first time from the container. We can merge these two worlds and make use of the Application resources inside the Yadif Configuration "objects.xml", which looks like:

<?xml version="1.0" ?>
<objects>
    <myModel>
        <class>MyModel</class>
        <arguments arg1="db" arg2="cache" />
    </myModel>
</objects>

Instantiating a myModel class inside the Action Controller uses the the Database and Cache resources as constructor arguments:

class FooController extends Zend_Controller_Action {
    public function barAction()
    {
        $container = $this->getInvokeArg('bootstrap')->getContainer();
        $myModel = $container->myModel;
    }
}

Given the possibilites by the Yadif_Container you are now empowered to use Dependency Injection for all your application objects and make use of Zend_Applications resource system. Furthermore any other dependency injection container, simple or complex, can also be integrated easily.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 117 http://www.whitewashing.de/blog/articles/117 2009-06-16 21:48:15
Explicit Code requires no comments - Only bad code does Following the recent discussion on commenting source code by Brandon Savage and Marco Tabini, I wanted to add upon Marcos code example to show that it not even needs any inline comments and can be greatly enhanced in readability with taking 2-5 minutes of time and refactoring the code. The original code sample was:

function __construct(array $pathInfo) {
    $section = $pathInfo[0];
    $file = $pathInfo[1];

    // Assume that the location of this file is inside the main trunk, and that pathInfo has already been filtered.

    $path = dirname(__FILE__) . '/../../' . $section . '/xml/static/' . $file . '.xml';

    if (!file_exists($path)) {
        Controller::singleton()->doError(404);
    }

    parent::__construct('main/xsl/template.xsl', $path);
}

This sample is somehow related to the response and view rendering of an application and its pretty understandable. For me there are some squirks though that would make me have to scroll to other classes to see how they interact. For example the path information falls from heaven. Why is it an array of 2 values and are these sections set the same all the time? And what exactly happens when the front controller does the 404 error? Is there a die() or exit in the doError()

The Agile movement postulates the phase of refactoring for a finished piece of code. Rebuilding the hacked solutions that did it to make them more understandable. I applied this to Marcos code snippet. The refactoring produces about double the code, but its done entirely by using NetBeans nice Rename variable and copy paste on extracting methods, which takes not more than 5 minutes.

class StaticXmlXsltRendererImpl extends AbstractXsltView
{
    function render(array $filteredPathInfo) {
        $templateValuesXmlPath = $this->getTemplateValuesXmlFile($filteredPathInfo);

        if(!$this->templateExists($templateValuesXmlPath)) {
            Controller::singleton()->doError(404);
        } else {
            parent::render('main/xsl/template.xsl', $templateValuesXmlPath);
        }
    }

    private function getTemplateValuesXmlFile($filteredPathInfo) {
        $section = $this->getSection($filteredPathInfo);
        $file = $this->getFile($filteredPathInfo);

        // Assume that the location of this file is inside the main trunk
        return dirname(__FILE__) . '/../../' . $section . '/xml/static/' . $file . '.xml';
    }


    private function getSection($pathInfo) {
        return $pathInfo[0];
    }

    private function getFile($pathInfo) {
        return $pathInfo[1];
    }

    private function templateExists($path) {
        return file_exists($path);
    }
}

In this code snippet the class name, variable names and methods clearly communicate what is done, which wasn't the case in the previous example. The only change for the clients is the change of using the constructor to using the render() method, which communicates the intend more. Also the render method now clearly communicates that either the error or the parent rendering is executed and leaves no doubt about it.

The getTemplateValuesXmlFile() method still uses the comment to show the assumption about relative pathes, but this is only the case because application configuration is made implicit into the code. This has to be extracted to be an explicit configuration constant and the comment can go.

    private function getTemplateValuesXmlFile($filteredPathInfo) {
        $section = $this->getSection($filteredPathInfo);
        $file = $this->getFile($filteredPathInfo);

        return APPLICATION_ROOT . '/' . $section . '/xml/static/' . $file . '.xml';
    }

In my opinion commenting code is necessary only for non-refactored code that has been hacked into existence and is hard to understand. Either the programmer has to get it done and has no chance to clearly communicate the intend. Or what is even worse the to be changed legacy code is hard to understand but you can't take the chances to refactor it because its also already in production and has no tests. Now from the second point it is obvious that upon ugly code you put only more and more ugly code to fix the problems. This is what leads to the legacy maintenance problems that pretty much every programmer faces. And then commenting comes into play: You have to add a new feature X and it has to be done fast. You don't really understand the code or how it works together but you know you can put the new code for the feature into existence but its really unintuitive. So you begin to comment it excessively, because its the only way to clearly show its intend.

There are two mindestting factors that help to write code that is understandable without having to excessivly comment it:

  • From the beginning, do not write code for the computer but for developers. Changing this attitude really helps to write understandable code like the one above.
  • Only leave code better than it was before, never worse.

There are five technical practices that - when followed - allow to write clearly communicating code from the beginning:

  1. Giving classes, variables and methods good names. This is a no-brainer but few people seem to follow it anyways.
  2. Following the object-oriented Single Responsibility Principle by never giving a class more than one responsibility. Macros example seems to follow this one.
  3. Methods should never switch in the level of detail. Micro-work at the datastructure level should never be mixed with macro level delegation to executing large chunks of code. Macros code violates this by mixing the path building micro-level work with the macro-level work of rendering the XSLT template. The path building code can be hidden behind a method to communicate intend more clearly.
  4. Exchange if conditions with private methods that explain the condition being checked for. In Marcos example this is not really necessary, because file_exists already is quite a good description to the condition. But in cases of logical combinations of conditions the method extracting is a superior way to explain the conditions intend without having to write a comment.
  5. Seperate Query and Command: A method never should do a query which returns the state of an object and a command which executes a set of rules on the state.

These practices sum up to one guideline: Make code explicit. This obviously requires less commenting since a comment of explicit code would be duplication and duplication is bad. What if you have a project that does not follow this guidelines? Then of course comments should be used to explain code, but in the long run this should be refactored to self-explaining code. Additionally every new feature should be programmed explicitly to follow the "leave code better than before" principle.

In my opinion two refactoring tools are missing that would greatly help PHP programmers write nice to read code: Extract method and Replace magic value with constant. Can someone integrate them into NetBeans please?

Update: Fixed a creepy copy-paste code bug, thanks to azeroth for pointing out. Moved methods around a bit to be more reading friendly.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 116 http://www.whitewashing.de/blog/articles/116 2009-05-01 08:16:13
Test your Legacy PHP Application with Function Mocks! Much talking is going on about Unittesting, Mocks and TDD in the PHP world. For the most this discussions surround object-oriented PHP code, frameworks and applications.

Yet I would assert that the reality for PHP developers (me included) is dealing with PHP 4, PHP 5 migrated, or non-object oriented legacy applications which are near to impossible to bring under test. Still this code works, is in production and needs maintenance and possibly extension for new features.

For example many applications may still use mysql_* functions at length inside their model or have multiple nested function levels (Example: Wordpress). Runkit to the rescue: A PECL extension that can hack your running PHP code, such that method or functions are repointed to execute new implementations. Using this extension you can actually mock out internal PHP functions, which is great to bring legacy code under test.

Consider this following proof of concept, using the Runkit extension build by Padraic Brady (the one from pecl.php.net does not compile on PHP 5.2), which replaces the functionality of mysql_query(). You have to set the following option in your php.ini: runkit.internal_override = On for this to work. By default only user-defined functions may be overwritten by Runkit.

class FunctionMocker
{
    protected $_mockedFuncBehaviourMap = array();

    public function mock($funcName, $return=null)
    {
        $newFuncCode = 'return "'.$return.'";';
    
        $renamedName = "__".$funcName."_mockOriginalCopy";
        runkit_function_copy($funcName, $renamedName);
        runkit_function_redefine($funcName, '', $newFuncCode);
        
        $this->_mockedFuncBehaviourMap[$funcName] = $renamedName;
    }
    
    public function reset()
    {
        foreach($this->_mockedFuncBehaviourMap AS $funcName => $renamedName) {
            runkit_function_remove($funcName);
            runkit_function_copy($renamedName, $funcName);
            runkit_function_remove($renamedName);
        }
        $this->_mockedFuncBehaviourMap = array();
    }
}

$mocker = new FunctionMocker();
$mocker->mock('mysql_query', 'hello world!');

echo mysql_query(); // hello world

$mocker->reset();

mysql_query(); // error

This example, only allows for string return values of the mock and has no support for replacing the arguments of the mocked function. Also chaining of different return values based on input or call number might be interesting. Some kind of Code Generator Tool would have to be implemented to support this functionality. Additionally Assertions and Verifying should be implemented for the function arguments. All in all this would allow to mock functions as you would mock interfaces/classes, which would be a great addition for all those legacy applications that use procedural PHP.

Additionally what the real killer for runkit would be: The possibility to insert PHP callbacks instead of real PHP code into the runkit_function_redefine.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 115 http://www.whitewashing.de/blog/articles/115 2009-03-27 16:02:35
Using Zend_Soap Server and Autodiscover in a Controller I am in a dilemma. I have condemned the usage of Zend_Soap_Server (or any other webservice server handler) inside a Model-View-Controller application before. Still I get questions about my old Zend_Soap_Server and Zend_Soap_AutoDiscover example not working in the MVC scenario. The following example provides you with a working Soap server inside a Zend_Controller_Action, although I discourage the use of it and would suggest using a dedicated script outside the dispatching process to gain multitudes of performance, which webservices often require.

require_once "/path/to/HelloWorldService.php";

class MyDiscouragedSoapServerController extends Zend_Controller_Action
{
    public function serverAction()
    {
        $server = new Zend_Soap_Server("http://example.com/pathto/wsdl");
        $server->setClass('HelloWorldService');
        $server->handle();
    }

    public function wsdlAction()
    {
        $wsdl = new Zend_Soap_AutoDiscover();
        $wsdl->setUri('http://example.com/pathto/server');
        $wsdl->setClass('HelloWorldService');
        $wsdl->handle();
    }
}

Now all you have to do is create two routes, one that makes http://example.com/pathto/server point to MyDiscouragedSoapServerController::serverAction and the other route that makes http://example.com/pathto/wsdl point to MyDiscouragedSoapServerController::wsdlAction. The wrong version (Version Mismatch) error comes from sending a request for the WSDL file to the actual Soap Server, which he doesn't like.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 114 http://www.whitewashing.de/blog/articles/114 2009-03-11 23:42:35
Speaking about Framework Quality on the IPC Spring 09 Just a short notice, my thesis is taking its last breath, I will be speaking on the IPC Spring 09 conference in Berlin end of may this year on Framework Quality and Unittests:

Framework Quality: Unit-Tests as silent witness

Unit-Tests are often overlooked in framework discussions that focus on features, performance, tools or database abstraction. However they are a silent witness on how poor or well frameworks are designed. In this presentation we will look at the testsuites of the big players in the PHP framework business - Zend Framework, ezComponents, Symfony and CakePHP - and reveal their hidden secrets.

This talk will make heavy use of the PHP Unittest and Metrics Aggregator tool, which i haven written on several times. For both CakePHP and Symfony extensions for their testtools may have to be written.

I am really excited for my first time being speaker on a conference and looking forward to see you at IPC.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 113 http://www.whitewashing.de/blog/articles/113 2009-03-10 12:43:53
Git is great: Helping out with MutateMe These last days I had fun with Padraic Bradys MutateMe project. It dynamically changes your code (using PECL Runkit extension) and checks weather your test cases fetch the errors occurring from changing the source code. This is a great addition to having a test suite, because it finds all the problematic test cases, that try to do too much and fail to cover the code correctly.

I have also contributed to the MutateMe project already and this was only possible due to Git and GitHub, which makes contributing to any project easy like writing a hello world example in a random programing language. As such I have to agree with Padraic: I love Git, too! He already integrated my and Sebastians changes back into the master and we didn't have to focus on merging, communication and integration alot.

My PUMA project is also hosted on GitHub (although nobody has looked into that yet), but I am beginning to write a complete Runner now that calls all three components PHPUnit, PDepend and CodeSniffer at once and directly processes the results. When this is done, I will pack it all up as a PEAR package for anyone to test out.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 112 http://www.whitewashing.de/blog/articles/112 2009-02-25 23:06:48
Update on Unittest and Metrics Tool Some days ago i posted about the PHP Unittest and Metrics Aggregator tool that i have written on (and which I have dubbed PUMA). Discussing it with people I came to the conclusion that the approach using ezcMvcTools is quite problematic that it forces to use this application, although the reporting and the application are quite separate. This is not against ezcMvcTools: I love it, its just the wrong type of support.

I began to split up the aggregator into some sort of importing-exporting tool. You can specify library-, test- and output-directory of your application and it will use the tools at hand (PHPUnit, PDepend and CodeSniffer currently) to generate their XML formatted reports. It then parses those XML outputted files and combines their result to give a consistent view on your application.

The Import-To-Output generator uses a three-step approach. An importer emits signals to report observers, which will then hand over their collected data to specific html pages that are then generated to the disc. This is a very flexible approach that allows anyone to extend and re-use the tool to generate project metrics, unittest overview and other interesting details on your application.

Have a look at the tool on Github and play with it. I would really like to hear your thoughts.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 111 http://www.whitewashing.de/blog/articles/111 2009-02-13 00:02:28
Unittest and Metrics Aggregator Tool for PHP Both PHPUnit and PDepend offer export functionality in XML or in a Test-database that is not quite readable for any user from the start. Over the last month I have gradually written a nice webbased tool, that aggregates this data and (todo in the future) relates them to help me with my open source projects.

PHPUnit can be used with a --test-db-dsn command, which saves all information about tests into a Database and PDepend has a strong Package centric source parser for all sorts of project metrics.

What I needed for my Zend Framework related work (and other projects) was a tool that does a run of the complete test-suite for me and saves the information, so that I can see where problems occur (and if they are due to my changes or other peoples). Since PHPUnit will stopped calculating additional metrics, I have also integrated the fabulous PDepend Tool into this aggregator. It shows me, what classes and functions need refactoring due to complexity issues and draws some nice graphs that summarize all sorts of project related information on a per package basis.

You can download or clone the an alpha version at Github. Its written with ezcMvcTools, so you need this to work too. A list of some screenshots is at the Github Wiki page.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 110 http://www.whitewashing.de/blog/articles/110 2009-02-08 23:06:42
Zend_Form and the Model: Yet another perspective using a Mediator Matthew Weier O'Phinney of the Zend Framework Devteam wrote a controversial post on integrating Zend_Form and the Model last month. He separated concerns of view and model that communicate via a Form, by calling just thee validation functions on the Form inside the mode. On request you could retrieve the model to the controller and view layers. I already wrote into his comments that I didn't like the solution because it relys on implicit rules for the developers to use the Form component correctly in all layers. Additionally the building of the form using this approach would be performed inside the model, although strictly speaking this is responsibility of the View Layer. Another negative point is duplication of input filtering code that has to be performed to use certain variables inside the controller or when different forms talk with the same model.

Jani took it up and proposed writing validators for forms and attaching them to the Form as sort of a mediator. I am not a fan of this approach either, because the validator would have to include domain logic but is not really a part of the domain logic anymore but just a validator. Developers might forget using the validator inside the model for all their actions or there would be duplication of code in some places. In a perfect world, only functions of the models public interface should be called for validation.

My personal favorite for Form and Model integration is a mediator object between the two layers. Your model will have to include an additional interface with one function acceptFormRequest($values); which accepts an array of validated Zend Form field values. It then tries to apply the validated data into a record. Additional required validations of the model can take place in this function, which separates the concerns of Form validation and Model data validation. Still the mediator merges those differences together: You can throw an Exception and it will be attached as a custom error message to the Form. The following very short code will show the required interface and the mediator code. This code is very simple and might produce maintenance overhead fast, but I propose some refactoring enhancements later in the discussion.

interface WW_Model_AcceptFormRequest
{
    /**
     * Acceept a form request
     * @param array $values
     * @return WW_Record_Interface
     */
    public function acceptFormRequest($values);
}
class WW_Model_FormMediator
{
    /**
     * Try to push the form request to the model
     * 
     * @param Zend_Form $form
     * @param WW_Model_AcceptFormRequest $model
     * @return WW_Record_Interface
     */
    public function pushFormToModel(Zend_Form $form, WW_Model_AcceptFormRequest $model)
    {
        if(!$form->isValid()) {
            throw new Exception("Form not valid!");
        } else {
            $values = $form->getValues();
            try {
                $record = $model->acceptFormRequest($values);
            } catch(Exception $e) {
                // This exception message comes from the model, because validation failed
                $form->addErrorMessage($e->getMessage());
                throw new Exception("Form request not accepted by model!");
            }
        }
        return $record;
    }
}

You can see the mediator has two different stages where errors can occour: When the form is not valid or the model is not valid. Both exits can be catched inside the controller and are the indicator that the form has to be displayed again for further input corrections. When successful the model returns a valid record that applies to the form and model requirements and can be displayed. If this record should be persistent this would have been done inside the acceptFormRequest function already. An example using a very simple Model using the a BankAccount example. We have a form that validates all the incoming request data for a withdrawel of money, though does not validate it against the models internal state. Our BankAccountModel implements the WW_Model_AcceptFormRequest interface and returns a valid BankAccount. If found the given amount is withdrawn.

class BankAccountModel implements WW_Model_AcceptFormRequest {
    public function acceptFormRequest($values)
    {
        $bankAccount = $this->getBankAccountBy($values['bankAccountNumber'], $values['pin']);
        if($values['action'] == "withdraw") {
            $bankAccount->withdraw($values['amount']);
            $this->save($bankAccount);
        } else {
            // unknown action...
        }
    }
    public function getBankAccountBy($key, $password) {
        // Find by Primary Key returning 'BankAccount' instance or exception if not found.
    }
    public function save(BankAccount $ba) {
        // Sql for saving the Bank Account
    }
}

class BankAccount
{
    public function withdraw($amount)
    {
        if( ($this->getBalance()-$amount) < 0 ) {
            throw new Exception("You cannot withdraw more money than your bank account holds!");
        }
        $this->balance -= $amount;
    }
}

Two exceptions might be thrown in this case: The Bank Account number does not exist or the password is wrong. Or you are not allowed to withdraw the given amount of money. If any of those exceptions is thrown the Model does not accept the form data and the form will have to be displayed again for the client showing the new error message that was returned from the model. The controller handling this process would lool like this:

class BankAccountController extends Zend_Controller_Action {
    public function performWithdrawlAction() {
        $form = new BankAccountWithdrawlForm(); // extends Zend_Form and builds the form

        if($this->getRequest()->isPost()) {
            $mediator         = new WW_Model_FormMediator();
            $bankAccountModel = new BankAccountModel();
            try {
                $bankAccount = $mediator->pushFormToModel($form, $bankAccountModel);

                $this->view->assign('bankAccount', $bankAccount); // Show new balance in view!
            } catch(Exception $e) {
                $this->view->assign('withdrawlForm', $form);
                $this->_redirect('showWithdrawl');
            }
        } else {
            $this->view->assign('withdrawlForm', $form);
            $this->_redirect('showWithdrawl');
        }
    }
}

You can see the mediator tightly integrates Form and Model without both components knowing too much of each other. Still you can add error messages recieved from the model into the Form and redisplay it. One negative point of this approach is the fact that you only have one method for accepting form data, which could result in variable checking and redispatching in the case of many different operations that can be performed on the same model. For this case you might want to either:

  1. Rewrite the mediator to accept a specific model class (not the interface) and call the required custom method that matches the forms request. (Best approach for separation concerns)
  2. Rewrite the mediator to also pass the get_class($form); value to the model for decision making (Faster approach)

There is still some overhead on using the mediator. Since its generic you could build an Action Helper for it and use the direct call mechanism to save some lines of code.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 109 http://www.whitewashing.de/blog/articles/109 2009-01-23 10:33:29
Finally: Zend_Mail charset and/or long lines header encoding bug fixed There was this lurking bug in Zend_Mail which destroyed every Mail-Header (and corresponding Mail) with non US-ASCII Chars and more than an encoded length of 74 chars. This is quite a huge subset of mails, but it seems a nice solution was not so easy, at least nobody tried to fixed it for quite some time.

Where many hackish solutions we're offered, Ota Mares aka Littlex spent incredible time to hunt the original problem down and with his help I tag-teamed the bug to death today. Saturo Yoshida of Zend Fame added some further spice regarding an alternative solution with Base64 Encoding instead of Quoted Printable Mime Header encoding.

In the end the solution we chose was, not to re-use the Mime encoding function that is specific to MIME bodies according to RFC2045, but to write a completely new algorithm for Mime Headers, whose rules are specified in RFC2047. This is now done and unit-tests prove its working according to standard.

What is missing now is people trying that fix on as many Mail platforms as possible and giving feedback in the issue if a lengthy subject with non-ASCII chars is displayed correctly.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 107 http://www.whitewashing.de/blog/articles/107 2009-01-14 00:54:26
On Publishing Webservices within MVC Frameworks Webservices are a very important part in todays enterprise applications. They tie applications of different age or programming languages together or allow applications of different subcontracters to speak to each other. Because they use HTTP, a stateless network protocol, considerable overhead floods the pipes when you use them, which should be minimized.

Martin Fowler writes in his PEAA book, that if you have the option not to use distributed objects (which are implemented via webservice) you should not distribute them. Considerable effort has to be brought into keeping complex webservices performant.

Still people make mistakes about webservices all the time (me included for example proposing a dispatcher for the ZF that could be used for webservices).

When people report problems with the Zend Soap component they often post a stripped down example that involes their webservice being instantiated within a controller. This is a very bad decision based on different arguments:

  • Dispatching overhead: Dispatching, Routing, Pre- and Postfiltering is costly in all frameworks. You give up the performance of having numerous PHP scripts that act as controller on their own. You get centralized filtering, authentication and other benefits. But those benefits generally do not aply to XML, JSON or SOAP requests, because you cannot parse them or access their properties. You give up the performance of a page controller for webservices to gain mostly nothing.
  • HTTP Request uselessness: Web frameworks work with HTTP request objects. The request of webservices facilitates HTTP to act as a far more complex request. No framework I know off, allows to work with the webservice requests outside the Webservice handler. What a SOAP or XML-RPC request does in your MVC is only get passed through numerous costly stages that offer no benefit, before it hits the target. Only the parsing of HTTP-Headers might offer additional benefit, but the gain is low, since they are available to PHP scripts at no cost.
  • Webservices already seperate concerns: Take the PHP SOAPServer as an example. It is an MVC application on its own, the controlling aspect of the SOAPServer parses the SOAP Request and sends it to the model, a class given by the user, which in turn works and returns the result as an SOAP Response View. You have to decouple model and view for a webservice handler otherwise it would generate invalid responses. Why nest a perfectly separated operation into another one? You gain no more of this additional separation, except performance decrease.

So what are good practices to implement webservices?

  • Use a page controller that generates no MVC overhead. In context of the Zend Framework: Add a new php script to your web root and add a new route into your .htaccess file that redirectes the desired location of the webservice to the script that overwrites the standard catch-all incoming requests to the front controller script.
  • Use the proxy pattern and the invaluable __call() method to implement wrapper objects for authentication and session management of the webservice. These classes can easily be reused by all webservice page controllers of your site. If you do your homework you can even share parts of these objects inside your Web-MVC application to keep the code DRY. Those proxies keep authentication logic out of your service class.
  • Use the remote facade pattern to implement a few, powerful methods that delegate the service request to underlying domain objects. Never ever publish direct access to domain objects with your webservices. As a rule of thumb, talking to a webservice during a logical operation should never involve more than one or two calls. The first call is for data fetching, the second for data saving. Authentication should be handled via HTTP Authentication to save an additional call.

If you follow these simple rules, you should get around the performance issues that generally come with webservices, without loosing flexibility at all.

]]>
Programming Benjamin Eberlei <kontakt at beberlei dot de> 106 http://www.whitewashing.de/blog/articles/106 2009-01-12 16:15:19
Howto file a good bug report: Suggestions for framework users I have fixed quite a number of bugs for the ZF lately, which lead me to this post about how to file a good bug report. There are many annoying bug reports out there, where the reporter of the bug withholds important information to the bugfixer unintended. This advice applies bug reports in general of course.

What are the benefits of a good bug report? The bug generally gets fixed faster, when the developer has more information at hand. Additionally other developers might come to rescue since they can understand the issue faster. These benefits are good for both parties. If you take no time for a good bug report, your issue might risk to end up getting old or closed unfixed.

  • Post the whole Exception Stack Trace: If the library throws an Exception into your application that is unexpected and may indicate an bug: Do not post the Message or Exception name only. The exception may be thrown in many different places or due to different reasons. The PHP exception class offers the method getTraceAsString(), which offers many information to the developer what the cause of the exception might be. Please use it!
  • Post codefixes in a patch format: When you find a bug in the framework, it is quite possible that you can offer a fix directly. Writing "Replace x in line y with z" does not help very often. The component might be in flux and the line positions change more often than you think. Please create a diff file of this changes that indicate the precise position of the change. This diff also includes 2 lines above and below the patched code for direction of the developer. SVN Diffs are even more useful since they include the revision where you fixed the bug in.
  • Post reproducible cases as PHPUnit Test: If you find a bug and can show how to reproduce it: Write a unittest to prove it. It is ZF policy to create a unittest for each bugfix showing that the bug was indeed fixed and previous functionality remains the same, so this unit-test has to be written anyways. Many show-offs rely on massive echo statements or var_dump, which render them almost useless for the developer.
  • Attach a unit-test to a submitted patch: This is related to the previous point. If you add a unit test your patch will get more attention. It will prove that you have thought about the patch, its consequences and that you might have checked it does not break backwards compatibility. This is worth a lot.
  • Run the test suite with your patch: If you want to provide a patch. Run the testsuite of the Zend Framework. It might break expected behaviour. When you post a patch that will break BC, it will be recognized. Your bug report might be closed, which helps nobody.

When you find a bug you have probably thought about it and how to fix it. This is valuable information. Disregarding one of this points will lead to missing information on part of the developer that he has to "learn" again. This takes time, which may make your bug last longer than it should.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 105 http://www.whitewashing.de/blog/articles/105 2009-01-11 18:09:45
What will be new in ZF 1.8 In Februar or March 2009 the 1.8 version of the Zend Framework is schedulded to be released. I have contributed some stuff already regarding ZendX_JQuery and Zend_Soap.

Both components have seen numerous bugfixes and I managed to get the JQuery helper down to zero open issues. I have also taken over the Zend_Json_Expr proposal, which will be a huge benefit to everything JSON that can be done with ZF. Foremost it is an integral part for the jQuery component which heavily relies on javascript callbacks.

The Soap Autodiscover and WSDL classes compability with Java and .NET has been optimized due to great user feedback, aswell as some bugfixes to the newly added WSDL type detection strategies.

Additionally I went on another bug killing spree and fixed around 20-30 old bugs in a wide range of different components.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 104 http://www.whitewashing.de/blog/articles/104 2009-01-11 17:06:02
Seven Things I have been tagged by Freeaqingme and the blog letter machinery. So read on for seven things you probably may not know about me.

  • I will get my degree in some weeks, currently intensivly writting on my thesis. My major is economics though. I probably won't get a job with that sooner or later. I actually don't want to, I have a job as programmer already.
  • One christmas many years ago (Pentium PCs to 200Mhz were the coolest thing around) i wished and wished for a computer for playing Command and Conquer and stuff. What i got was a 3/86 i could only run crap with. So i had to start programming.
  • In 11th grade (7 years ago) I took part in the german computer science olympics (exercise still online) using PHP and writing thousands of lines of nested aray and for loop code and print the solution to the browser. No need to say I utterly failed, because I didn't know a bit about algorithms, pointers and objects at all.
  • I have only learned about what good programming practices are (OO, functional, whatever) really means in the last two years, spending almost every free minute of those many i had on projects to test around with patterns and programming styles.
  • I went to my first conference last year september, the IPC in Mainz, getting to know lots of great people in the community.
  • I don't have a license at all (Reference to Sara). I am afraid of driving cars, although I drive my bike through the biggest crossroads in town like nuts.
  • I am a timeline oriented reader, having made me masterplans to read both all the Discworld and Ian Rankin novels in the correct order to not miss a single reference.

Its sad that everyone I would want to tag was already tagged by someone else, still for the head count:

  • Matthew Weierophinney, because he helped me understand Zend Framework alot.
  • Ben Scholzen, because he is a fun guy to be around #zftalk.dev.
  • Thomas Weidner, because I like his dedication towards his ZF components.
  • Kore Nordmann, Bastian Feder and Thomas Weinert, because I had great discussions with him on IPC.
  • zomg aka Jani because of his skills to be referenced by PHPDeveloper.org (joke) and the good IRC discussions.
  • Petr Pisl because of the awesome NetBeans PHP support.
]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 103 http://www.whitewashing.de/blog/articles/103 2009-01-07 20:04:56
Dependency Injection with PHP: Introducing Sphicy I have written on dependency injection before christmas and how Guice, googles DI framework, offers a simple solution. I copied the functionality for a PHP clone of Guice and named it Sphicy. You saw an early prototype of it in the blogpost mentioned above.

Sphicy configures object dependencies with modules: You explicitly state which implementation should be bound to which interface. An injector then creates instances of these objects via reflection: All constructor dependencies are resolved by looking at the given type hints and initializes those according to the specified bindings.

Two examples included in the source code of Sphicy are Zend Framework and ezComponents MVC bootstrapping modules. Sadly both frameworks default front controllers are engineered in such a way that useful dependency injection needs some workarounds.

As an example I will now discuss the Sphicy Module for Zend Framework MVC applications. To circumvent the singleton and protected Constructor of Zend_Controller_Front, we have to build a new front controller that wraps around it and requires all the dependencies:

class Sphicy_Controller_Front
{
    protected $front;

    /**
     * Create Front Controller for Zend Framework using explicity dependencies created by Sphicy.
     *
     * @param Zend_Controller_Request_Abstract      $request
     * @param Zend_Controller_Response_Abstract     $response
     * @param Zend_Controller_Router_Interface      $router
     * @param Zend_Controller_Dispatcher_Interface  $dispatcher
     */
    public function __construct(
        Zend_Controller_Request_Abstract $request,
        Zend_Controller_Response_Abstract $response,
        Zend_Controller_Router_Interface $router,
        Zend_Controller_Dispatcher_Interface $dispatcher=null
    )
    {
        $front = Zend_Controller_Front::getInstance();
        $front->setRequest($request);
        $front->setResponse($response);
        $front->setRouter($router);

        if($dispatcher === null) {
            $dispatcher = $front->getDispatcher();
        }
        $front->setDispatcher($dispatcher);
    }

    public function dispatch()
    {
        $this->front->dispatch();
    }
}

You can see that the Sphicy_Controller_Front class requires dependencies in its constructor that are then forward injected into Zend_Controller_Front. You can now create a module that binds all the required dependencies to concrete implementations, for example a module for a Zend MVC Http Application might look like:

class Sphicy_ZendMvc_ExampleModule implements spModule {
     public function configure(spBinder $binder) {
         // Sphicy_Controller_Front does not extend Zend_Controller_Front, because of Singletonitis
         // It offers the dispatch method to proxy against Zend_Controller_Front::dispatch.
         $binder->bind("Sphicy_Controller_Front")->to("Sphicy_Controller_Front");
         $binder->bind("Zend_Controller_Request_Abstract")->to("Zend_Controller_Request_Http");
         $binder->bind("Zend_Controller_Response_Abstract")->to("Zend_Controller_Response_Http");
         // loads all routes
         $binder->bind("Zend_Controller_Router_Interface")->to("MyApplication_Router");
     }
 }

The class MyApplication_Router might look up all the routing information of the application via a hardcoded configuration mechanism. You may say this is a hard dependency, but actually you can just switch modules or implementations at this position to replace the router with another implementation. You can also see that no implementation for the dispatcher is bound. But this dependency is optional and will be created automatically as can be seen in the Sphicy_Controller_Front class.

The front controllers is now created by calling:

$injector = new spDefaultInjector(new Sphicy_ZendMvc_ExampleModule());
$front = $injector->getInstance("Sphicy_Controller_Front");
$front->dispatch();

What happens in the $injector->getInstance() line? Sphicy looks at Sphicy_Controller_Front's constructor and finds that four dependencies are needed: Request, Response, Router and Dispatcher implementations. It looks up the bindings and searches for them, creating Zend_Controller_Request_Http, Zend_Controller_Response_Http and MyApplication_Router objects. A dispatcher implementation is not found, but Sphicy recognizes that null is a valid paramater and injects it. The 3 concrete implementations and one null are instantiated and used to construct a valid Sphicy_Controller_Front instance.

You have now stated the dependencies of the Zend Controller Front explicitly and can switch them instantaneously by switching the bindings of interface to implementations in the configuration module.

Have a look at the Sphicy Website and FAQ to see more examples and information about the possibilites of this dependency injection framework.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 102 http://www.whitewashing.de/blog/articles/102 2008-12-30 14:47:31
Dependecy Injection the juicy way I have written on dependency injection before and came up with a solution for PHP via interface injection. Thinking about it twice I didn't like it very much. Its too much overkill that you have to implement all setter methods again and again.

Still dependency injection is the way to write good, testable and easily exchanged and re-wired object graphs. I tried to do lots of dependency injection via constructor lately and realized that it polutes my constructors when my object graph is too deep.

An example: When I setup my database connection in the bootstrap file and encapsulate it in my model creation factory object, i have to insert the model factory through the configuration into the dispatcher into the different controllers and views to be accessible in the MVC pattern. The model factory has to walk 3 nodes in the object graph without being used at all in the "higher" steps. This creates very unnecessary dependencies.

I came across Misko Hevery's Blog, which rocks. There are also some great Google Tech Talks by him, where he argues in favour of dependency injection and debunks singletons as being evil (he does that on his blog too). From there I learnt about Guice, a dependency injection framework for Java by Google.

What I like about Guice: Its easy to use and its immediatly obvious to someone without experience, why it works so good and you don't have to hand down objects deep down the object graph. I cloned the basic functionality for PHP and an example would work as follows.

We first have to implement a module, which defines which concrete implementation should be injected as a placeholder for which interface.

class ServiceModule implements Module
{
public function configure(Binder $b)
{
$b->bind("Service")->to("ConcreteService");
$b->bind("Add")->to("ConcreteAdd");
$b->bind("Sub")->to("ConcreteSub");
}
}

We can now use this module to instantiate an injector object:

$injector = new Injector( new ServiceModule() );
$service = $injector->getInstance("Service");

Given that the constructor of ConcreteService would expect an Add and a Sub object, the Injector would realize this and instantiate the concrete implementations ConcreteAdd and ConcreteSub and inject them into the constructor.

What makes this dependency injection so simple and great to use? You can instantiate an injector everywhere in your code and just have to configure it using the additional module implementation. This way you don't have to make sure that you pass down the dependency injection container from the bootstrap into all nodes of the application. You can also easily work with many frameworks and still be able to use dependency injection without having to hack the whole core of the framework.

My guice clone does more. It allows to pass down additional non-object arguments into constructors, even for object dependencies. It offers a Provider interface to be able to wrap adapters around your already existing ServiceLocator or Registry objects. But its reflection capabilities have to be extended to docblock comments, so that better dependency detection is possible.

Because using dependency injection with only this little example I will refrain from releasing the source code yet. I have to provide some useful documentation for it to be of use to anyone.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 101 http://www.whitewashing.de/blog/articles/101 2008-12-18 23:03:06
Bad news: jQuery UI 1.6 ships without Spinner and AutoComplete The jQuery UI team announced yesterday on its blog that jQuery UI 1.6 will not be shipped with AutoComplete and Spinner Plugin support. No further delay, for the orginal august 2008 estimated release, is wanted.

This brings about a problem on ZendX_JQuery. All view helpers and decorators that depend on AutoComplete and Spinner Plugins can only be run with SVN trunk or 1.6 release candidates, which have known bugs and problems.

I am adding a compability table to the ZendX jQuery manual today that will make its way to the manual of the 1.7.2 release. This will hopefully help and guide everyone to the correct dependencies.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 99 http://www.whitewashing.de/blog/articles/99 2008-12-12 10:02:24
REST and Ajax Aware controllers in ezcMvcTools There are essentially two major different ways to implement a restful application using a web framework. You either implement a router that routes to different controller actions based on the HTTP method used on a requested resource. This is the fancy way, which sadly is not always so practical because many browsers do not support sending more than GET and POST requests. The other way would be to define suburls of a resource such as /user/1/delete for the resource /user/1 and take GET a a request for deleting and POST for the confirmation of the delete.

ezcMvcTools HTTP Request Parser and routing mechanisms currently offer no real help to decide on this issues, but its easy to extend this missing functionality. What we first add are simple checks of the current http request method. We extend ezcMvcHttpRequestParser which will return a derived ezcMvcRequest object that implements 7 new methods: isPost(), isGet(), isDelete(), isPut(), isXmlHttpRequest(), isMethod() and getMethod(). These methods can now be easily used on the request object to determine which action will be undertaken:

class myMvcRequest extends ezcMvcRequest
{
public function isPost()
{
return $this->isMethod("POST");
}

public function isGet()
{
return $this->isMethod("GET");
}

public function isPut()
{
return $this->isMethod("PUT");
}

public function isDelete()
{
return $this->isMethod("DELETE");
}

public function isXmlHttpRequest()
{
if(isset($this->raw['HTTP_X_REQUESTED_WITH'])
&& strtolower($this->raw['HTTP_X_REQUESTED_WITH']) == "xmlhttprequest") {
return true;
}
return false;
}

public function getMethod()
{
if(isset($this->raw['REQUEST_METHOD']))
return strtolower($this->raw['REQUEST_METHOD']);
}
return false;
}

public function isMethod($method)
{
if(isset($this->raw['REQUEST_METHOD']) &&
$this->getMethod() == strtolower($method)) {
return true;
}
return false;
}
}

class myMvcHttpRequestParser extends ezcMvcHttpRequestParser
{
/**
* Uses the data from the superglobals.
*
* @return ezcMvcRequest
*/
public function createRequest()
{
$this->request = new myMvcRequest;
$this->processStandardHeaders();
$this->processAcceptHeaders();
$this->processUserAgentHeaders();
$this->processFiles();
$this->processAuthVars();

$this->request->raw = &$_SERVER;

return $this->request;
}
}

This helps us to implement simple decision mechanisms in a single controller action that takes both POST and GET requests. From the point separation of concerns this is not a good design decision. We need routes that can point to different controller actions based on their request method, so that two requests GET /user/1/delete and POST /user/1/delete lead to different methods, for example userController::doDeleteDialog and userController::doDelete. We will simply extend the ezcMvcRailsRoute to support decision based on http request methods:

class myMvcRestRoute extends ezcMvcRailsRoute
{
protected $method;

public function __construct( $method, $pattern, $controllerClassName, $action = null, array $defaultValues = array() )
{
$this->method = $method;
parent::__construct($pattern, $controllerClassName, $action, $defaultValues);
}

public function matches( ezcMvcRequest $request )
{
if(strtolower($this->method) == strtolower($request->raw['REQUEST_METHOD'])) {
return parent::matches($request);
}
return null;
}
}

This very simple extension is independent of the advanced request parser given above, so you could use it separatly. In the light of our delete user example, you would use the new router in the following way:

class myRouter extends ezcMvcRouter
{
public function createRoutes()
{
return array(
new myMvcRestRoute( 'GET', '/users/:id/delete', 'UserController', 'deleteDialog' ),
new myMvcRestRoute( 'POST', '/users/:id/delete', 'UserController', 'delete' ),
);
}
}

We have now simple rest route support in our ezcMvcTools application.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 95 http://www.whitewashing.de/blog/articles/95 2008-12-04 17:36:07
ezComponents View Handler for Zend_Pdf My previous posting discussed different view handlers based on routing information. One example was the PDF View which was implemented rather hackish through overwriting the createResponseBody() function of ezcMvcView. Derick told me the way to go would be writing my own PDF view handler. Since this is a rather lengthy topic I created this new post that only discusses using Zend_Pdf as a View Handler in the new ezComponents MvcTools.

The code for the View Handler would look like the following:

abstract class myPdfViewHandler implements ezcMvcViewHandler
{
    /**
     * Contains the zone name
     *
     * @var string
     */
    protected $zoneName;

    /**
     * Contains the variables that will be available in the template.
     *
     * @var array(mixed)
     */
    protected $variables = array();

    /**
     * Pdf object to be rendered.
     *
     * @var Zend_Pdf
     */
    protected $pdf;

    /**
     * Creates a new view handler, where $zoneName is the name of the block and
     * $templateLocation the location of a view template.
     *
     * @var string $zoneName
     * @var string $templateLocation
     */
    public function __construct( $zoneName, $templateLocation = null )
    {
        $this->zoneName = $zoneName;
    }

    /**
     * Adds a variable to the template, which can then be used for rendering
     * the view.
     *
     * @param string $name
     * @param mixed $value
     */
    public function send( $name, $value )
    {
        $this->variables[$name] = $value;
    }

    /**
     * Processes the template with the variables added by the send() method.
     * The result of this action should be retrievable through the getResult() method.
     */
    public function process( $last )
    {
        // template method
    }

    /**
     * Returns the value of the property $name.
     *
     * @throws ezcBasePropertyNotFoundException if the property does not exist.
     * @param string $name
     * @ignore
     */
    public function __get( $name )
    {
        return $this->variables[$name];
    }

    /**
     * Returns true if the property $name is set, otherwise false.
     *
     * @param string $name
     * @return bool
     * @ignore
     */
    public function __isset( $name )
    {
        return array_key_exists( $name, $this->variables );
    }

    /**
     * Returns the name of the template, as set in the constructor.
     *
     * @return string
     */
    public function getName()
    {
        return $this->zoneName;
    }

    /**
     * Returns the result of the process() method.
     *
     * @return mixed
     */
    public function getResult()
    {
        if($this->pdf instanceof Zend_Pdf) {
            return $this->pdf->render();
        } else {
            throw new Exception("Could not render PDF.");
        }
    }
}

Now you would implement a concrete PDF view handler by extending myPdfViewHandler.

class myConcretePdfViewHandler extends myPdfViewHandler {
    public function process( $last ) 
    {
        $pdf = new Zend_Pdf();
        // do concrete PDF drawing stuff here

        // save PDF here, will be rendered in getResult()
        $this->pdf = $pdf;
    }
}

And your ezcMvcView implementation will make of createZones() and look like the following:

class myPdfView extends ezcMvcView {
    function createZones( $layout )
    {
        $zones = array(); 
        // A decision which concrete Pdf Handler should be used would be decided on here.
        $zones[] = new myConcretePdfViewHandler( 'concreteA' );
        return $zones;
    }
}

There you go!

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 94 http://www.whitewashing.de/blog/articles/94 2008-12-03 13:25:13
ezComponents 2008.2 Beta - Mvc separation for win I have written on the new ezComponents MvcTools component before already. Just yesterday the beta of this component was released with the general beta of the 2008.2 version of ezComponents. Several bugfixes and enhancements were included into the MvcTools which make it a perfect component for any Mvc based application.

I reviewed lots of the code myself and can only say i love the beauty of the code. Its very simple but by default the most powerful mvc solution in the PHP market. People working with unittests will like it very much, since all the parts are perfectly separated from each other allowing to test controllers, views, routers and filters in complete separation.

To show one very simple example howto benefit of the seperation of view and controllers. If we need a view in both html and pdf, this should generally make no difference for the controller. We add two routes, one for the pdf one for the html view that execute the same controller and action:

class myRouter extends ezcMvcRouter
{
public function createRoutes()
{
return array(
new ezcMvcRailsRoute( '/pdf', 'SomeController', 'index'),
new ezcMvcRailsRoute( '/', 'SomeController', index' ),
);
}
}

class SomeController extends ezcMvcController
{
public function doIndex() {
$result = new ezcMvcResult();
$result->variables['items'] = Model::retrieveLotsOfItems();
return $result;
}
}

Now howto decide between PDF and Html view? We use the createView method of our dispatcher configuration, but we still only need the http response writer, nothing more.

class myMvcConfiguration implements ezcMvcDispatcherConfiguration {
[...]
function createView( ezcMvcRoutingInformation $routeInfo, ezcMvcRequest $request, ezcMvcResult $result )
{
if(strstr($routeInfo->matchedRoute, "/pdf")) {
return new myHtmlView( $request, $result );
} else {
return new myPdfView( $request, $result );
}
}
function createResponseWriter( ezcMvcRoutingInformation $routeInfo, ezcMvcRequest $request, ezcMvcResult $result, ezcMvcResponse $response )
{
return new ezcMvcHttpResponseWriter( $response );
}
[...]
}

Now both myHtmlView and myPdfView can create their ezcMvcResponse objects that fill the response body depending on their type. Please note that overwritting createResponseBody() in myPdfView is a shortcut that circumventes me having to write a new PDF View Handler (which would be the way to go).

class myHtmlView extends ezcMvcView {
function createZones( $layout )
{
$zones = array();
$zones[] = new ezcMvcPhpViewHandler( 'content', '../templates/index.phtml' );
$zones[] = new ezcMvcPhpViewHandler( 'page_layout', '../templates/layout.phtml' );
return $zones;
}
}

class myPdfView extends ezcMvcView {
function createZones() {
// empty, abstract method that has to be defined.
}

function createResponseBody()
{
// Set PDF Content-Type Response Header
$this->result->content->type = "application/pdf";

$pdf = new Zend_Pdf();
// do pdf stuff
return $pdf->render();
}
}

Now all the the logic that is potentially in the controller is completly seperated from the view handling that may depend on the routing information not on the controller. And views can be tested seperatly from the controller result. Testability is very high.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 93 http://www.whitewashing.de/blog/articles/93 2008-12-03 12:28:57
Zend + jQuery Enhancements: Ajax Forms, Tooltip and Autofill Some weeks ago Zend Framework 1.7 was released with the jQuery support I contributed. What is the essential advantage of using jQuery support in ZF? You can develop forms with ajax support either by using View Helpers or directly by the integrated Zend_Form support. The implementation of a DatePicker or AutoComplete functionality becomes as easy as using 2-3 lines of php code.

Currently only support for the jQuery UI library is shipped, but you can easily extend the jQuery support on your own and this blog post will show you how using three very popular jQuery plugins: AjaxForm, Tooltip and AutoFill. This will be a series of installments, beginning with the first one: AjaxForms

AjaxForm allows you to enhance any form of yours to submit the data with ajax to the server, so no additional overhead of loading a new page is necessary. Combining the power of Zend_Form and jQuery's ajaxForm you can even go so far as differentiating between successful and non-validated form submits. We will build a Form Decorator that integrates the AjaxForm plugin in any of your Zend_Form's. On submit it will send the form data to the server via ajax and clears the form afterwards. Clients that have javascript disabled will work too, the form is submitted to the server in a standard pre-ajax fashion and processed that way.

First what we need is obviously the new decorator, we will call it "My_JQuery_Form_Decorator_AjaxForm" and it will inherit from Zend_Form_Decorator_Form. What we then realize is, that this is just using a view helper to render, so what we need additionally is a "My_JQuery_View_Helper_AjaxForm" that extends from "Zend_View_Helper_Form". The code of the view helper will have to look as follows to fullfil our needs:

require_once "Zend/View/Helper/Form.php";

class ZendX_JQuery_View_Helper_AjaxForm extends Zend_View_Helper_Form
{
/**
* Contains reference to the jQuery view helper
*
* @var ZendX_JQuery_View_Helper_JQuery_Container
*/
protected $jquery;

/**
* Set view and enable jQuery Core and UI libraries
*
* @param Zend_View_Interface $view
* @return ZendX_JQuery_View_Helper_Widget
*/
public function setView(Zend_View_Interface $view)
{
parent::setView($view);
$this->jquery = $this->view->jQuery();
$this->jquery->enable()
->uiEnable();
return $this;
}

public function ajaxForm($name, $attribs = null, $content = false, array $options=array())
{
$id = $name;
if(isset($attribs['id'])) {
$id = $attribs['id'];
}

if(!isset($options['clearForm'])) {
$options['clearForm'] = true;
}

if(count($options) > 0) {
require_once "Zend/Json.php";
$jsonOptions = Zend_Json::encode($options);

// Fix Callbacks if present
if(isset($options['beforeSubmit'])) {
$jsonOptions = str_replace('"beforeSubmit":"'.$options['beforeSubmit'].'"', '"beforeSubmit":'.$options['beforeSubmit'], $jsonOptions);
}
if(isset($options['success'])) {
$jsonOptions = str_replace('"success":"'.$options['success'].'"', '"success":'.$options['success'], $jsonOptions);
}
} else {
$jsonOptions = "{}";
}

$this->jquery->addOnLoad(sprintf(
'$("#%s").ajaxForm(%s)', $id, $jsonOptions
));

return parent::form($name, $attribs, $content);
}
}

It takes all the form-tag building of the inherited view helper for granted and just appends the necessary jQuery code to the jQuery onLoadActions stack. They will be outputted to the clients browser when calling <?php $this->jQuery(); ?> in your layout or view script. Make sure that you include the jQuery Form plugin in your code, for example with <?php $view->jQuery()->addJavascriptFile(..); >

Programming the decorator becomes a simple trick now:

require_once "Zend/Form/Decorator/Form.php";

class My_JQuery_Form_Decorator_AjaxForm extends Zend_Form_Decorator_Form
{
protected $_helper = "ajaxForm";

protected $_jQueryParams = array();

public function getOptions()
{
$options = parent::getOptions();
if(isset($options['jQueryParams'])) {
$this->_jQueryParams = $options['jQueryParams'];
unset($options['jQueryParams']);
unset($this->_options['jQueryParams']);
}

return $options;
}

/**
* Render a form
*
* Replaces $content entirely from currently set element.
*
* @param string $content
* @return string
*/
public function render($content)
{
$form = $this->getElement();
$view = $form->getView();
if (null === $view) {
return $content;
}

$helper = $this->getHelper();
$attribs = $this->getOptions();
$name = $form->getFullyQualifiedName();
$attribs['id'] = $form->getId();
return $view->$helper($name, $attribs, $content, $this->_jQueryParams);
}
}

Now to use either the decorator for your form, or just the view helper to print your form tag with jQuery code you can invoke:

$form->addPrefixPath('My_JQuery_Form_Decorator', 'My/JQuery/Form/Decorator', 'decorator');
$form->removeDecorator('Form')->addDecorator(array('AjaxForm', array(
'jQueryParams' => array(),
)));

$view->addHelperPath("My/JQuery/View/Helper", "My_JQuery_View_Helper");
$view->ajaxForm("formId1", $attribs, $content, $options);

Now we finished up the view side of our script. Assuming that we use the Form Decorator instead of the View Helper, we can additionally add some fancy logic and error handling ajax fun to the action controller that is handling the Zend_Form instance.

class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$foo = new MyAjaxTestForm();
try {
if(!$foo->isValid($_POST)) {
throw new Exception("Form is not valid!");
} else {
// do much saving and stuff here
if($this->getRequest()->isXmlHttpRequest()) {
$this->_helper->json(array("success" => "SUCCESSMESSAGEHERE"));
}
}
} catch(Exception $e) {
if($this->getRequest()->isXmlHttpRequest()) {
$jsonErrors = array();
foreach( ( new RecursiveIteratorIterator(new RecursiveArrayIterator($form->getMessages())) ) AS $error) {
$jsonErrors[] = $error;
}
$this->_helper->json->sendJson($jsonErrors);
}
}
}
}

This has to be processed by a callback function of the AjaxForm and which may for example look like the following which uses a predefined div box (#formMessages, dont forget to implement it) to render either the success or the error messages.

$form->addDecorator(array('AjaxForm', array(
'jQueryParams' => array(
'success' => "formCallback1",
),
)));
$view->jQuery()->addJavascript('function formCallback1(data) {
if(data.errors) {
$("#formMessages").append("<ul>");
for each(var item in data.errors) {
$("#formMessages").append("<li>"+item+"</li>");
}
$("#formMessages").append("</ul>");
} else {
$("#formMessages").html(data.success);
}
}');

This seems very complex, but you could include that javascript code into the AjaxForm decorator and implement an Action Helper to do the action controller side of the stuff. This will be an exercise for a future post.

AutoFill and Tooltip extensions will be topic of the next installments of this series, so be aware of new content soonish.

]]>
PHP Benjamin Eberlei <kontakt at beberlei dot de> 92 http://www.whitewashing.de/blog/articles/92 2008-12-01 22:58:40