Federico Cargnelutti

Simple is better than complex. Complex is better than complicated. | @fedecarg

Archive for the ‘PHP’ Category

Managing Multiple Build Environments

without comments

One of the challenges of Web development is managing multiple build environments. Most applications pass through several environments before they are released. These environments include: A local development environment, a shared development environment, a system integration environment, a user acceptance environment and a production environment.

Automated Builds

Automated builds provide a consistent method for building applications and are used to give other developers feedback about whether the code was successfully integrated or not. There are different types of builds: Continuous builds, Integration builds, Release builds and Patch builds.

A source control system is the main point of integration for source code. When your team works on separate parts of the code base, you have to ensure that your checked in code doesn’t break the Integration build. That’s why it is important that you run your unit tests locally before checking in code.

Here is a recommended process for checking code into source control:

  • Get the latest code from source control before running your tests
  • Verify that your local build is building and passing all the unit tests before checking in code
  • Use hooks to run a build after a transaction has been committed
  • If the Integration build fails, fix the issue because you are now blocking other developers from integrating their code

Hudson can help you automate these tasks. It’s extremely easy to install and can be configured entirely from a Web UI. Also, it can be extended via plug-ins and can execute Phing, Ant, Gant, NAnt and Maven build scripts.

Build File

We need to create a master build file that contains the actions we want to perform. This script should make it possible to build the entire project with a single command line.

First we need to separate the source from the generated files, so our source files will be in the “src” directory and all the generated files in the “build” directory. By default Ant uses build.xml as the name for a build file, this file is usually located in the project root directory.

Then, you have to define whatever environments you want:

project/
    build/
        files/
            local/
            development/
            integration/
            production/
        packages/
            development/
                project-dev-0.1RC-1.noarch.rpm
            integration/
            production/
    src/
    tests/
    build.xml

Build files tend to contain the same actions:

  • Delete the previous build directory
  • Copy files
  • Manage dependencies
  • Run unit tests
  • Generate HTML and XML reports
  • Package files

The target element is used as a wrapper for a sequences of actions. A target has a name, so that it can be referenced from elsewhere, either externally from the command line or internally via the “depends” or “antcall” keyword. Here’s a basic build.xml example:

<?xml version="1.0" encoding="iso-8859-1"?>
<project name="project" basedir="." default="main">

    <property environment="env"/>

    <property name="src.dir" value="src"/>
    <property name="tests.dir" value="tests"/>
    <property name="build.dir" value="build"/>
    <property name="build.env" value="local"/>

    <target name="init"></target>
    <target name="test"></target>
    <target name="clean"></target>
    <target name="build" depends="test, clean"></target>
    <target name="package-rpm"></target>
    <target name="deploy"></target>
    <target name="profile"></target>
    <target name="test-selenium"></target>

    <target name="build-development" depends="init"></target>
    <target name="build-integration" depends="init"></target>
    <target name="build-production" depends="init"></target>

</project>

The property element allows the declaration of properties which are like user-definable variables available for use within an Ant build file. The following example intends to describe a typical Ant build file, of course, it can be easily modified to suit your personal needs.

<?xml version="1.0" encoding="iso-8859-1"?>
<project name="project" basedir="." default="main">

    <property environment="env"/>

    <property name="src.dir" value="src"/>
    <property name="tests.dir" value="tests"/>
    <property name="build.dir" value="build"/>
    <property name="build.env" value="local"/>

    <target name="init">
        <echo message="Hudson build ID: ${env.BUILD_ID}"/>
        <echo message="Hudson build number: ${env.BUILD_NUMBER}"/>
        <echo message="SVN revision: ${env.SVN_REVISION}"/>
        <tstamp>
            <format property="build.datetime" pattern="dd-MMM-yy HH:mm:ss"/>
        </tstamp>
        <echo message="Build started at ${build.datetime}"/>
    </target>

    <target name="test">
        ...
    </target>

    <target name="clean">
        <delete dir="${build.dir}/files/${build.env}"/>
        <delete dir="${build.dir}/packages/${build.env}"/>
        <mkdir dir="${build.dir}/files/${build.env}"/>
        <mkdir dir="${build.dir}/packages/${build.env}"/>
    </target>

    <target name="build" depends="test, clean">
        <echo message="Environment: ${build.env}"/>
        ...
    </target>

    ...

    <target name="build-development" depends="init">
        <property name="build.env" value="development"/>
        <antcall target="build"/>
        <antcall target="package-rpm"/>
        <antcall target="deploy"/>
        <antcall target="profile"/>
    </target>

    <target name="build-integration" depends="init">
        <property name="build.env" value="integration"/>
        <antcall target="build"/>
        <antcall target="package-rpm"/>
        <antcall target="deploy"/>
        <antcall target="test-selenium"/>
    </target>

    <target name="build-production" depends="init">
       ...
    </target>

</project>

Properties can be defined either inside the buildfile or in a standalone properties file. For example:

<?xml version="1.0" encoding="iso-8859-1"?>
<project name="project" basedir="." default="main">

    <property environment="env"/>
    <property file="local.properties"/>

    ...

    <target name="build" depends="test, clean">
        <echo message="Environment: ${build.env}"/>
        ...
    </target>

    <target name="build-development" depends="init">
        <property file="development.properties"/>
        <antcall target="build"/>
        ...
    </target>

    <target name="build-integration" depends="init">
        <property file="integration.properties"/>
        <echo message="Environment: ${build.env}"/>
        ...
    </target>

</project>

There are different ways to target multiple environments. I hope I have covered enough of the basic functionality to get you started. Good luck.

Written by Federico

November 14, 2009 at 6:31 pm

Testing Zend Framework Action Controllers With Mocks

with 8 comments

In this post I’ll demonstrate a unit test technique for testing Zend Framework Action Controllers using Mock Objects. Unit testing controllers independently has a number of advantages:

  1. You can develop controllers test-first (TDD).
  2. It allows you to develop and test all of your controller code before developing any of the view scripts.
  3. It helps you quickly identify problems in the controller, rather than problems in one of the combination of Model, View and Controller.

The Action Controller I’m going to test has only one method, profileAction():

tests/application/controllers/UserController.php

class UserController extends Zend_Controller_Action
{
    public function profileAction()
    {
        $this->view->userId = $this->_getParam('user_id');
        return $this->render();
    }
}

tests/application/ControllerTestCase.php

class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
    public $application;

    public function setUp()
    {
        $this->application = new Zend_Application(
            APPLICATION_ENV,
            APPLICATION_PATH . '/config/application.ini'
        );

        $this->bootstrap = array($this, 'bootstrap');
        parent::setUp();
    }

    public function tearDown()
    {
        Zend_Controller_Front::getInstance()->resetInstance();

        $this->resetRequest();
        $this->resetResponse();

        $this->request->setPost(array());
        $this->request->setQuery(array());
    }

    public function bootstrap()
    {
        $this->application->bootstrap();
    }
}

tests/application/controllers/UserControllerTest.php

require_once TESTS_PATH . '/application/ControllerTestCase.php';
require_once APPLICATION_PATH . '/controllers/UserController.php';

class UserControllerTest extends ControllerTestCase
{
    public function testStubRenderMethodCall()
    {
        $request = $this->getRequest()
            ->setRequestUri('/user/profile/1')
            ->setParams(array('user_id'=>1))
            ->setPathInfo(null);

        $response = $this->getResponse();

        $this->getFrontController()
            ->setRequest($request)
            ->setResponse($response)
            ->throwExceptions(true)
            ->returnResponse(false);

        $controller = $this->getMock(
            'UserController',
            array('render'),
            array($request, $response, $request->getParams())
        );
        $controller->expects($this->once())
                 ->method('render')
                 ->will($this->returnValue(true));

        $this->assertTrue($controller->profileAction());
        $this->assertTrue($controller->view->user_id == 1);
    }
}

You can go further making both the tests and the implementation more sophisticated. The main point is that you can build and test a controller in a way that doesn’t require a view script to be written to do so.

Zend Framework Known Issues

By default Zend_Test_PHPUnit_ControllerTestCase sets the redirector exit value to false, leading to unexpected behavior when unit testing your code. For that reason, make sure you always add a return statement after calling a utility method:

class UserController extends Zend_Controller_Action
{
    public function profileAction()
    {
        if (null == $this->_getParam('user_id', null) {
            return $this->_redirect('/');
        }
        return $this->render();
    }
}

If you want the Front Controller to throw exceptions, you have no other choice than to overwrite the dispatch method and pass a boolean TRUE to the throwExceptions() method:

class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
    ...

    public function dispatch($url = null)
    {
        // redirector should not exit
        $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
        $redirector->setExit(false);

        // json helper should not exit
        $json = Zend_Controller_Action_HelperBroker::getStaticHelper('json');
        $json->suppressExit = true;

        $request = $this->getRequest();
        if (null !== $url) {
            $request->setRequestUri($url);
        }
        $request->setPathInfo(null);

        $this->getFrontController()
             ->setRequest($request)
             ->setResponse($this->getResponse())
             ->throwExceptions(true)
             ->returnResponse(false);

        $this->getFrontController()->dispatch();
    }

    ...
}

The Dispatcher not only violates the DRY principle but also suffers from amnesia. The problem is that it doesn’t store the instance of the Action Controller, instead, it destroys it (Zend_Controller_Dispatcher_Standard Line 305). You can easily get around this issue by extending the standard dispatcher and overwriting the dispatch() method:

class Zf_Controller_Dispatcher_Standard extends Zend_Controller_Dispatcher_Standard
{
    ...

    public function dispatch($url = null)
    {
        ...
        Zend_Registry::set('Zend_Controller_Action', $controller);

        // Destroy the page controller instance and reflection objects
        $controller = null;
    }

This will allow you to access the view object after dispatching the request:

class ExampleControllerTest extends ControllerTestCase
{
    public function testDefaultActionRendersViewObject()
    {
        $this->dispatch('/');

        $controller = Zend_Registry::get('Zend_Controller_Action');

        $this->assertEquals('ExampleController', get_class($controller));
        $this->assertTrue(isset($controller->view));
    }

Links

PHPUnit: Testing Zend Framework Controllers
PHPUnit: Mock Objects

Written by Federico

November 1, 2009 at 1:33 pm

Symfony 1.3 Web Application Development

with 3 comments

Packt Publishing recently sent me a copy of the book “Symfony 1.3 Web Application Development” to review.

This book is not a reference guide, but an example driven tutorial that takes you through the process of building Model-View-Controller-based web applications. You will learn how to create and develop a simple online store application. It also covers best practices for better and quicker application development.

The book is based on the latest version of the Symfony Framework, and does a great job telling you what you get out of the box and how it works, which is perfect for hitting the ground running. During the development you are introduced to the concepts and features of the MVC framework. However, for those who want to know more about the framework, the book doesn’t explain how things work under the covers. This book is more for beginners who want to get started with Symfony 1.3.

One thing I didn’t like about this book is that it uses Propel instead of Doctrine as the default ORM framework. Apart from that, it does a great job explaining and demonstrating with practical examples how to build a Web application from scratch.

Overall, and considering that some of the topics in this book have already been covered in Practical Symfony 1.3, I rate this book 4 out of 5.

Symfony 1.3 Web Application Development

Written by Federico

October 13, 2009 at 11:24 am

Posted in Frameworks, PHP

Adding theme support to your Zend Framework application

with 10 comments

This is a brief explanation on how to add theme support to your Zend Framework application and how to ensure those themes are self-contained, easy to distribute and install.

Themes are very powerful and extremely easy to develop. They allow you to quickly switch between layouts and change the look and feel of your application. You can use themes to show, for example, a mobile friendly version of your site.

Making a Zend Framework application theme-able is a three-step process.

First, modify your directory structure:

application/
    controllers/
library/
public/
    themes/
        default/
            css/
            images/
            templates/
        custom/
            css/
            images/
            templates/

Then, edit your Bootstrap class:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    protected function _initView()
    {
        $theme = 'default';
        if (isset($this->config->app->theme)) {
            $theme = $this->config->app->theme;
        }
        $path = PUBLIC_PATH.'/themes/'.$theme.'/templates';

        $layout = Zend_Layout::startMvc()
            ->setLayout('layout')
            ->setLayoutPath($path)
            ->setContentKey('content');

        $view = new Zend_View();
        $view->setBasePath($path);
        $view->setScriptPath($baseDir);

        return $view;
    }
}

And finally, copy your view scripts and layouts to the templates directory:

application/
library/
public/
    themes/
        full-site/
            css/
            images/
            templates/
                error/
                index/
                partials/
                layout.phtml
        mobile-site/
            css/
            images/
            templates/

Voila, mission accomplished.

Written by Federico

September 20, 2009 at 10:43 pm

Posted in Frameworks, Open-source, PHP

Increase speed and reduce bandwidth usage with ZF and Apache

with 18 comments

Apache’s mod_deflate module provides the DEFLATE output filter that allows output from your server to be compressed before being sent to the client over the network.

There are two ways of enabling gzip compression:

  1. Using Apache’s mod_deflate
  2. Using PHP’s built-in functions

Encoding the output and setting the appropriate headers manually makes the code more portable. Keep in mind that there are hundreds of Linux distributions, each slightly different to significantly different. To allow portability the application should not make assumptions about the OS or config involved.

Using Apache

1. Enable mod_deflate

Debian/Ubuntu:

$ a2enmod deflate
$ /etc/init.d/apache2 force-reload

2. Configure mode_deflate

$ nano /etc/apache2/mods-enabled/deflate.conf

#
# mod_deflate configuration
#
<IfModule mod_deflate.c>
 AddOutputFilterByType DEFLATE text/plain
 AddOutputFilterByType DEFLATE text/html
 AddOutputFilterByType DEFLATE text/xml
 AddOutputFilterByType DEFLATE text/css
 AddOutputFilterByType DEFLATE application/xml
 AddOutputFilterByType DEFLATE application/xhtml+xml
 AddOutputFilterByType DEFLATE application/rss+xml
 AddOutputFilterByType DEFLATE application/javascript
 AddOutputFilterByType DEFLATE application/x-javascript

 DeflateCompressionLevel 9

 BrowserMatch ^Mozilla/4 gzip-only-text/html
 BrowserMatch ^Mozilla/4\.0[678] no-gzip
 BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

 DeflateFilterNote Input instream
 DeflateFilterNote Output outstream
 DeflateFilterNote Ratio ratio
</IfModule>

Using PHP

Create a gzip compressed string in your bootstrap file:

try {
    $frontController = Zend_Controller_Front::getInstance();
    if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) {
        ob_start();
        $frontController->dispatch();
        $output = gzencode(ob_get_contents(), 9);
        ob_end_clean();
        header('Content-Encoding: gzip');
        echo $output;
    } else {
        $frontController->dispatch();
    }
} catch (Exeption $e) {
    if (Zend_Registry::isRegistered('Zend_Log')) {
        Zend_Registry::get('Zend_Log')->err($e->getMessage());
    }
    $message = $e->getMessage() . "\n\n" . $e->getTraceAsString();
    /* trigger event */
}

Reference

Use mod_deflate to compress Web content delivered by Apache

Written by Federico

July 6, 2009 at 11:09 am

Format a time interval with the requested granularity

with 8 comments

This class, a refactored version of Drupal’s format_interval function, makes it relatively easy to format an interval value. The format will automatically format as compactly as possible. For example: if the difference between the two dates is only a few hours and both dates occur on the same day, the year, month, and day parts of the date will be omitted.

class DateIntervalFormat
{
    /**
     * Format an interval value with the requested granularity.
     *
     * @param integer $timestamp The length of the interval in seconds.
     * @param integer $granularity How many different units to display in the string.
     * @return string A string representation of the interval.
     */
    public function getInterval($timestamp, $granularity = 2)
    {
        $seconds = time() - $timestamp;
        $units = array(
            '1 year|:count years' => 31536000,
            '1 week|:count weeks' => 604800,
            '1 day|:count days' => 86400,
            '1 hour|:count hours' => 3600,
            '1 min|:count min' => 60,
            '1 sec|:count sec' => 1);
        $output = '';
        foreach ($units as $key => $value) {
            $key = explode('|', $key);
            if ($seconds >= $value) {
                $count = floor($seconds / $value);
                $output .= ($output ? ' ' : '');
                if ($count == 1) {
                    $output .= $key[0];
                } else {
                    $output .= str_replace(':count', $count, $key[1]);
                }
                $seconds %= $value;
                $granularity--;
            }
            if ($granularity == 0) {
                break;
            }
        }

        return $output ? $output : '0 sec';
    }
}

Usage:

$dateFormat = new DateIntervalFormat();
$timestamp = strtotime('2009-06-21 20:46:11');
print sprintf('Submitted %s ago',  $dateFormat->getInterval($timestamp));

Outputs:

Submitted 3 days 4 hours ago

Written by Federico

June 25, 2009 at 12:49 am

Face Detection Using PHP

without comments

Maurice Svay explains how to detect faces in photos with PHP:

Nowadays, face detection is built in many consumer products (camera obviously, but also Google and iPhoto), and seems to be a pretty common job. So I expected to find many solutions for doing it with PHP. Surprisingly, the only one I could find is OpenCV, an opensource lib that was originally developed by Intel. OpenCV seems to perform well but you need to be able to install it on your server. In my case, I wanted to have a pure PHP solution, so it can work with most hosts.

Face detection in pure PHP (without OpenCV)

Written by Federico

June 24, 2009 at 4:09 pm

Posted in PHP

TypeFriendly: A Documentation And User Manual Builder

without comments

TypeFriendly is a documentation generation script written in PHP5. It was designed to be easy in use and it allows to achieve the first results immediately, a couple of minutes after you start the work. The script contains everything you need to write clear, multilingual documentation for your project, so that you do not have to code everything on your own.

The most important features of TypeFriendly:

  1. Modular documentation structure – it is generated from text files and the structure and navigation are generated from the file names.
  2. Simple syntax – the text is written in intuitive and clean Markdown syntax.
  3. Multilingual support and tools – TypeFriendly allows you to create your manuals in many language versions. It also contains a tool that shows whether the derived languages are up-to-date.
  4. Configurable output formats – currently, TypeFriendly is able to generate the documentation in XHTML (many pages) and XHTML (single page). There is also a third format – metadata – still under development. It will allow to import the docs to a database in order to make an on-line version with, for example, user comments.
  5. Various add-ons such as syntax highlighting, references, class description fields.
  6. Navigation generators.
  7. It is portable – works under Linux, FreeBSD and Windows. All you need is the PHP interpreter available.

TypeFriendly is distributed under the terms of GNU General Public License 3, which means that you can use, modify and share it for free.

Demo
http://static.invenzzia.org/docs/tf/0_1/book/en/index.html

Screenshots

http://www.invenzzia.org/en/projects/typefriendly/screenshots

Source Code
http://svn.invenzzia.org/browser/TypeFriendly/trunk/

Website
http://www.invenzzia.org/en/projects/typefriendly

Written by Federico

May 16, 2009 at 11:30 am

Posted in Open-source, PHP, Tools, Web Apps

Real Time Web-Based Service Monitoring Tool

without comments

phpWatch is a general purpose service monitor that is able to send notifications of outages via e-mail or text-message (SMS). The purpose of this system is to allow administrators to easily check the status of many different services running on any number of servers and also allow developers to interface with the query and notification APIs.

Installation

The basic installation is very simple: chmod config.php to 777 and simply navigate to the install directory in your browser. Fill in the database information and the setup will create the required tables and setup the configuration file as needed. The only required task beyond the automated install is to add cron.php as a cron job (Unix/Linux) or scheduled task (Windows).

SMS Alerts

phpWatch uses pre-existing SMS gateways provided by the cell-carriers themselves. For example, to send a message to a Verizon subscriber with the phone number 123-456-7890, an e-mail can be sent to 1234567890@vtext.com and it will then be forwarded to the individual’s phone.

Links

Written by Federico

May 12, 2009 at 7:34 pm

Posted in Open-source, PHP, Tools, Web Apps

New Zend Framework Book Published

with one comment

This book shows you how to build websites fast using PHP and MySQL. What’s more, it shows you how to supercharge your use of these technologies by taking advantage of a powerful, free web development solution known as the Zend Framework, which helps developers build websites with speed and efficiency.

This book embraces a teaching strategy of learning by doing, showing you how to build website features you’ll actually want to use within your own websites. Among other things you’ll learn how to manage data submitted through web forms, send unformatted and HTML e-mails through your website, manage user registrations, logins, and recover forgotten passwords, and even create the structure for a simple social network.

Along the way, you’ll learn how to take advantage of popular online services such as Google Maps, Amazon Web Services, the Facebook Platform, and PayPal to create even more compelling websites.

Easy PHP Websites with the Zend Framework

Written by Federico

May 11, 2009 at 7:26 pm

Posted in Frameworks, PHP, Programming