Custom Zend_Application Resources

11th January 2010

Sooner or later, you want to leverage Zend_Application better by creating your own resource plugins. This lets you reuse your initialisation work in multiple application that much easier and keeps your Boostrap class that much shorter!

In my case, I wanted to create a resource for CouchDb that checked that the database was created and if not, create it.

Creating your own plugin is easy enough. The obvious place is library/App/Application/Resource and a typical resource would look like this:


class App_Application_Resource_Couchdb extends Zend_Application_Resource_ResourceAbstract
{
    /**
     * Defined by Zend_Application_Resource_Resource
     *
     * @return Phly_Couch|null
     */
    public function init()
    {
         // do stuff here to init CouchDB
        $options $this->getOptions(); 
        // $options contains everything under 'resources.couchdb' in application.ini
    }
}

You then need to tell Zend_Application about your new plugins. This is done with this line in application.ini:


pluginPaths.App_Application_Resource_ "App/Application/Resource"

You can now have as many resource plugins as you like within the App_Application_Resource_ class-space.

Also, Matthew Weier O'Phinney has also written an article on Zend_Application which you should read too.

Zend Framework on a shared host

8th January 2010

When you deploy a Zend Framework website to a shared host, you usually cannot change the DocumentRoot to point at the public/ folder of the website. As a result the URL to the website is now http://www.example.com/public/. This doesn't look very professional, so we'd like to remove it.

The easiest way, given a ZF project created using Zend_Tool is this:

Create /index.php

<?php 
define('RUNNING_FROM_ROOT'true);
include 'public/index.php';

This uses the index.php already created by Zend_Tool and means that we don't have to change anything if we move to a VPS host where we can set the DocumentRoot directly to public/.

Create /.htaccess


SetEnv APPLICATION_ENV development

RewriteEngine On
RewriteRule .* index.php

We create a .htaccess file that redirects every request to index.php. We want to do this so that no one can try and read application/configs/application.ini. Obviously, set the APPLICATION_ENV to the correct value!

Referencing public facing files

Having created a very aggressive, rewrite rule, what about CSS/JS/image files though?

Fortunately, we already have a .htaccess file in the public/ folder that correctly handles this situation. As Apache will execute the .htaccess files in the deepest directory it finds, any reference to a public facing file within the public/ folder will correctly be served.

You do have to be aware of this when referencing public facing files though and add the /public to the baseUrl yourself.

For example, you may set up your CSS file and other view settings within a Front Controller plugin like this:


class App_Controller_Plugin_View extends Zend_Controller_Plugin_Abstract
{
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        $frontController Zend_Controller_Front::getInstance();
        $view $frontController->getParam('bootstrap')->getResource('view'); 

        $view->doctype('XHTML1_STRICT');
            
        $baseUrl $request->getBaseUrl();
        if (defined('RUNNING_FROM_ROOT')) {
            $baseUrl .= '/public'; 
            $frontController->setBaseUrl($baseUrl); 
        }
        $view->headLink()->appendStylesheet($baseUrl '/css/main.css');
        $view->headLink()->appendStylesheet($baseUrl '/css/screen.css''screen');
        $view->headLink()->appendStylesheet($baseUrl '/css/print.css''print');
    }   
}

(This code assumes you have added a resources.view[] = "" to your application.ini)

As we have a constant that tells us if we're running from the root, we can dynamically add the /public into the URL. If we change to a host where the DocumentRoot is set directly to the public/ folder, then we don't need to change our code.

That's it. Your Zend Framework application works nicely with shared hosts.

Speaking at TEK·X

6th January 2010

I'm delighted to be able to announce that I'm speaking at TEK X in May, in Chicago. This is one of the big US PHP conferences and I feel privileged to be invited.

I'll be concentrating on Zend Framework with a tutorial called "Building a Zend Framework application" and a talk on "Working with Zend_Form". After a couple of less technical talks recently, it'll be fun to dive into more technical content. Hopefully, I'll be able to explain Zend_Form well enough that people will understand it too!

Pragmatic Version Control Using Git

5th January 2010

I've recently been looking at different version control systems, specifically distributed ones like git, Bazaar and Mercurial. At IPC I was talking to Travis Swicegood about wanting to learn and he very kindly organised a copy of his book for me to review and learn from.

I didn't know much about git at all before reading the book. I do now :)

It turns out that git is fairly easy when you have a good explanation of how to use it. The book starts from the basics of what version control is, which I already knew. It was good to see equal coverage of how to set up git in Windows, OSX and Linux. I was aware that Windows support wasn't prime-time, but at least doable with msys.

The bulk of the book covers how to actually use git and this is where I learnt enough about git to actually understand it. There were two main surprises for me:

  • You need to re-add a modified file every time you want to commit it. This puts it in the staging area. Fortunately the -a switch to git add will auto-add for you!
  • Directories are not stored under version control. It's like CVS :)

Other than that, it's just like Subversion, only faster! (You also have that distributed thing going on.)

I suck at reviewing.

Pragmatic Version Control Using Git is a very good book if you want to learn git.

It's even better as a reference book as you can actually find things in it too.

If you want to know all there is to know about git, then get this book.

Even the paper feels good in your hand when you turn the page.

2009 end-of-year wrap-up

1st January 2010

Like last year, my wrap up is mostly an excuse to show off some of the photos I took in 2009!

January

Other than the snow, The big thing that happened in January was that an article I wrote was published in php|architect.

My php|architect article in the Jan 2009 issue

February

We had daffodils in snow at the start of this month and then towards the end, the PHPUK conference took place.

Paying attention during Chris' talk

March

Spring arrived in March. The Severn Valley Railway had its Festival of Steam gala, and I took a day off so that I could photograph it.

Festival of Steam at the SVR

April

A month of punctures. I went to a Microsoft community event in London too.

Scott and Derick

May

This is birthday month in our household. It was also our first trip away camping this year.

Camping

June

What little good weather we had this year, was in June. I popped up to Manchester for a PHPNW meet. DPC 09 was also held in June and I spoke on caching.

Cal and Ivo interview Andrei

July

We finished decorating the living room in July. We also had a week's holiday in Wales.

Cilgerran Castle

August

I started using a Wacom tablet in August as I was getting a pain in my wrist. August is school holiday month, so we went away for another week, to Cumbria.

Old van at the pencil museum

September

We sold our Pathfinder in September and didn't do much else. I took the kids to visit to the Gloucestershire Warwickshire Railway during the month too.

Giving up the token

October

PHP Conference season started again for me with PHPNW 09. I spoke on project management.

Kevlin's keynote was excellent

November

Another month, two conferences! ZendCon 09 where I gave a tutorial on the Zend Framework certification and spoke on project management. I also visited Alcatraz. IPC 09 was also held in November, where I spoke on caching and deployment.

Andi wraps up ZendCon 09

December

The final month of the year saw me working way too hard. We did take the kids to see Santa though.

Teddy Bears

Here's to 2010!

PHP Advent 2009: On deployment

6th December 2009

This year I was asked to write an article for PHP Advent 2009 an it's now been published!

Automate your Deployment is a look at how to automate the process of deploying your application to the web server. At my company we started automating our deployment systems just over a year and the number of issues we have around deployment of new code to a website has dropped considerably and is no longer a stressful event.

If you aren't currently using an automated deployment script, I can't recommend highly enough that you set yourself a New Year's resolution to investigate the options and implement a system for yourself.

Accessing your configuration data that's stored in application.ini

27th November 2009

Zend_Application will read the data in your application.ini and make it available from your bootstrap's getOptions() method. It then sets the bootstrap as a parameter in the front controller. Note that the top level keys are all normalised to lowercase too.

You can then retrieve the options in a number of ways.

In the controller you can do this:


    public function someAction()
    {
        $bootstrap $this->getInvokeArg('bootstrap'); 
        $options $bootstrap->getOptions();
    }

Outside of the controller you can do this:


    $bootstrap Zend_Controller_Front::getInstance()->getParam('bootstrap');
    $options $bootstrap->getOptions();

One downside is that $options is a nested array, and not a Zend_Config object. If you prefer to work with a Zend_Config object you need to create it yourself as Zend_Application discards the one it creates. The easiest way to do this is to create a new method in your bootstrap to create the Zend_Config object and store to the registry.


    protected function _initConfig()
    {
        $config = new Zend_Config($this->getOptions());
        Zend_Registry::set('config'$config);
        return $config;
    }

You can then get at your config data wherever you need it. Try not to depend too much on Zend_Registry keys though, as it can make testing harder.

IPC 2009

23rd November 2009

The International PHP Conference 2009 took place last week in Karlsrule, Germany.

The audience

This conference has presentations in both English and German, though fortunately, there was always at least one English session in each time slot! I managed to get to a fair few sessions.

Cal Evans' talk on Zend Framework command line applications was an especial highlight as it's an area that we could do better and I now know how to! Similarly, we recently wrote a SOAP Server for a project using Zend_Soap which has been educational. David Zülke's talk on SOAP filled in some gaps in my knowledge which was useful.

Zend Framework URL Rewriting in IIS6

16th November 2009

I've written before about URL rewriting with IIS7's URL Rewrite module.

IIS6, which ships with Windows Server 2003 does not have this module though and guess which version my client's IT dept run? As usual, they wouldn't install ISAPI_Rewrite or one of the other solutions for me. In the past, I've simply written a new router that creates URLs with normal GET variables, but this is ugly and I wanted better.

One thing IIS6 does let you do is configure a URL to be called upon a 404 error, which then allows you to have "pretty" URLs and be able to route them.

Firstly, I set up the URL handler in the IIS Manager:

Screen shot 2009-11-13 at 07.46.59-1.jpg

This will result in all unrecognised URLs being redirected to index.php. The standard Zend_Controller_Request_Http object will automatically extract the URL and routing works as expected.

However, there are three problems:

  1. The $_POST array is always empty
  2. $_SERVER['REQUEST_METHOD'] is always GET, even for a post request
  3. The first key in $_GET has been mangled by IIS

As Zend Framework wraps up the request into a Request object, this is fairly simple to work around by creating our own Request object.


class App_Controller_Request_Iis404 extends Zend_Controller_Request_Http
{
    /**
     * Constructor
     *
     * If a $uri is passed, the object will attempt to populate itself using
     * that information.
     *
     * @param string|Zend_Uri $uri
     * @return void
     * @throws Zend_Controller_Request_Exception when invalid URI passed
     */
    public function __construct($uri null)
    {
        // As Zend_Controller_Request_Http accesses the superglobals directly, we
        // will have to write into $_GET and $_POST directly

        // The post variables can be accessed from php://input
        $input file_get_contents('php://input');
        if (strlen($input)) {
            $input urldecode($input);
            parse_str($input$_POST);
        }
        
        // fix $_GET
        foreach ($_GET as $key=>$value) {
            if (substr($key04) == '404;') {
                // special key created by IIS - the actual key name is after the ?
                $bits explode('?'$key);
                if (count($bits) > 1) {
                    $_GET[$bits[1]] = $value;
                }
            }
        }
        
        return parent::__construct($uri);
    }
    
    /**
     * Return the method by which the request was made
     *
     * @return string
     */
    public function getMethod()
    {
        if (!empty($_POST)) {
            return 'POST';
        }
        
        return parent::getMethod();
    }
}

We start by reading the php://input stream which on a POST request will hold the POST variables. We can then transfer them to the $_POST array. Similarly, the key in the $_GET array that has been mangled, is easy to detect as it starts with '404;'. We can then find the ? and the part after it is the real key, so we create a new $_GET element for that item. Finally, we override getMethod() and return 'POST' if there are any elements in $_POST.

To use a custom Request object, you need to create an _init method in your Bootstrap:


class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    function _initIis404RequestObject()
    {
        $this->bootstrap('frontController');
        $frontController $this->getResource('frontController');
        $frontController->setRequest($options['frontController']['requestClass']);  
    }

Zend Framework's standard URLs now work nicely with IIS6 on Window Server 2003.

ZendCon 2009

13th November 2009

I know I'm late on this one, and I only have the pathetic excuse of being busy. However, ZendCon 2009 was a great conference and I want to thank Eli, Zend and S&S for putting it on.

Andi wraps up ZendCon 09

I gave two talks; a Zend Framework Certification refresher tutorial and a talk on project management. Overall I was happy with how both talks went. I think that my presentation style has improved considerably over the last year as I am much more confident and it shows. Hopefully most of the people in the sessions gained from them.

As always, I learnt new things in other sessions I attended, learning about Solar, Zend Framework, deployment, MySQL and countless other things. I also gained from meeting the many people who were there. The conversations outside of the sessions are equally as valuable as I learn tips and tricks from people facing the same sort of problems that I do.

We also socialised after hours too:
Ilia and the elephpant!

All in all, a great conference, and I hope that I manage to get there again in 2010.