Updated Tutorial for Zend Framework 1.5

17th March 2008

Zend Framework 1.5 has now been released to mark the occasion I have significantly updated my Zend Framework Tutorial! The tutorial was first released on 16th August 2006 and was written against version 0.1 of Zend Framework and had one major revision to bring in support for the ViewRenderer component.

Tutorial-Screenshot

The new tutorial produces exactly the same application as before, but now uses the new 1.5 goodies of Zend_Form and Zend_Layout, so you can see how these key components fit into a Zend Framework MVC application.

As always, when you find bugs and typos, please let me know and I'll fix them!

PHPWM March Meeting: Symfony

13th March 2008

On Tuesday, PHPWM had a meeting at PSL Connect's offices where Darren Beale talked about Symfony.

Darren, about to start presenting

I took a few pictures and have stuck them up on Flickr. I should have taken my other lens though as the 50mm isn't wide enough for taking pictures in room!

It was a very good talk that covered the basics of Symfony and what it can do. At the start, Darren asked us which frameworks we use and pretty much everyone used a different one! He then went though how Symfony worked and we got to see some code in action too. It was a nice step up from Ian's talk at the PHP UK Conference.

Afterwards we had a drink down the pub which was good :)

Site Stats

9th March 2008

One thing I get asked a lot about at work is site stats. Usually, the client wants to know how many visitors they get on any other day along with other data such as where the visitors came from and which search terms they may have used.

So far, I've used Google Analytics and PHPMyVisites JS based logging along with Analog on the logs themselves. I've also experimented with Mint on one site.

Generally, I've found that Analytics requires lots of drilling down to find anything, PHPMyVisites can be a little simplistic (though it is getting more features with each release) and Mint doesn't provide enough history.

Are there better solutions out that that are cost-effective for relatively small clients?

IE8 will work like IE8 by default!

4th March 2008

We’ve decided that IE8 will, by default, interpret web content in the most standards compliant way it can. This decision is a change from what we’ve posted previously.

From Microsoft's Interoperability Principles and IE8.

This is good news all round. It's nice to see that Microsoft have listened to the comments surrounding their original intention to make IE8 render like IE7 by default. Well done!

PHP London 08

2nd March 2008

The PHP UK Conference in London is over for another year and this year's event was another evolutionary improvement on last year's. It was held in Inmarsat's conference facilities in the City of London. There were two conference rooms in use: a 300 seat main auditorium and a smaller 75 seat second room. There were also a large social area for food, drinks and networking. I thought it worked really well, kudos to Paul Morgan and the rest of PHPLondon for the organisation.

Lunch!
Lunch!

The day kicked off with a talk by Ivo Jansch on "Enterprise PHP". Ivo is an engaging speaker and talked about designing and building PHP applications with a more structured approach for long term benefits. After the break, the conference split into two tracks with Scott MacVicar & Mike Sullivan talking about their development experiences and Stefan Esser talking about security. I have to admit that I missed both these talks as I was talking too much with Lorna and Kathryn at the PHPWomen stand. I've been "talking" with Lorna on IRC and via blogs for a little while now, and it was great to meet her in person along with Kevin, her better half. They had t-shirts which were snapped up and I got one of the last ones and it wasn't even lunchtime. (I hope my donation at least covered its cost!) Here's a picture Dave the codemonkey and an elePHPant wearing a phpwomen t-shirt:

phpwomen t-shirts
PHPWomen t-shirts

Lunch was excellent too (Beef Stroganof for me) and I caught up with the PHP West Midlands people. We have a meeting in couple of weeks on 11th March, by the way. After lunch Marcus Bointon talked about mail whilst Scott MacVicar talked about SQLite3. Again, I managed to miss this slot, but I understand that both were well received and covered their subject well. The next slot in the main room was the Frameworks comparison with Ian Christian (Symfony), Toby Beresford (CodeIgniter) and myself (Zend Framework). We each had 20 minutes to present a bit about our framework and then there was a Q&A session afterwards. I thought it went okay. I was very nervous whilst speaking and so talked too fast. Fortunately, I had enough slides to cover and finished at the 20 minute mark. Ian and Toby gave very different talks but both covered their respective frameworks strengths. I thought that the Q&A went well and none of us embarrassed ourselves which was nice!

Whilst we were speaking, Zoe Slattery gave a talk on testing PHP and then Anthony Phillips talked about IBM's Project Zero. I wanted to see both of these, so I'm looking forward to the MP3s that the conference will be providing. The conference was wrapped up by Derick Rethans who talked about how PHP and usage of PHP has changed since he first started working with the language. It was funny and informative and it was interesting that pretty much all the questions afterwards were on testing.

All in all it was a great conference and I'm looking forward to next year's.

Cure for BSS announced!

23rd February 2008

Cal Evans has announced a cure for Blank Stare Syndrome!

You know the problem: you're in a conversation and someone mentions something about a new technology that you haven't heard of. Your eyes glaze and you have that Blank Stare

Sixty Second Tech is the solution. Once a week, it will deliver a short podcast (presumably about 60 seconds long!) that explains one technological concept per episode that you (or your less-techy friends!) need to know.

Head on over there and subscribe to the RSS Feed now - or wait for it to turn up on iTunes shortly.

Simple Zend_Form Example

21st February 2008

Following on from the Simple Zend_Layout Example, Zend_Form is now in the trunk, so here's a super simple, complete example that shows it in action:

Zend_Form screenshot1.png

(clearly the form is unstyled :)

You can construct a Zend_Form directly from a config file or can build it in code. This example builds it in code.

Setting up

This example uses the same basic skeleton as the Zend_Layout code with the addition of a forms directory:

Zend_Form Directory Layout.png

As you can see, I've added a forms directory within the application subdirectory with our form file, ContactForm.php, in it.

The contact form

To keep the form contained, I've put it in its own class which extends from Zend_Form. The file is application/forms/ContactForm.php and so the class is forms_ContactForm so that Zend_Loader can easily load it:


class forms_ContactForm extends Zend_Form 
{ 
    public function __construct($options null) 
    { 
        parent::__construct($options);
        $this->setName('contact_us');
        
        $title = new Zend_Form_Element_Select('title');
        $title->setLabel('Title')
              ->setMultiOptions(array('mr'=>'Mr''mrs'=>'Mrs'))
              ->setRequired(true)->addValidator('NotEmpty'true);
        
        $firstName = new Zend_Form_Element_Text('firstName');
        $firstName->setLabel('First name')
                  ->setRequired(true)
                  ->addValidator('NotEmpty');

        $lastName = new Zend_Form_Element_Text('lastName');
        $lastName->setLabel('Last name')
                 ->setRequired(true)
                 ->addValidator('NotEmpty');
             
        $email = new Zend_Form_Element_Text('email');
        $email->setLabel('Email address')
              ->addFilter('StringToLower')
              ->setRequired(true)
              ->addValidator('NotEmpty'true)
              ->addValidator('EmailAddress'); 
              
        
        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setLabel('Contact us');
        
        $this->addElements(array($title$firstName, 
            $lastName$email$submit));
        
    } 
}

We set the name of the form first and then create five elements; one select box for the title, three text boxes for first name, surname and email address and then finally a submit button. Note that as we have overridden the constructer, we also call up to the parent's constructor so that all the Zend_Form initialisation happens.

Creating an element is quite simple. Each element is of the type Zend_Form_Element_Xxx where Xxx is the type, such as Text, Submit, Select, etc. We then configure the element how we want it, such as setting a label and adding filters and validators. Finally we add all the elements to the form using the addElements() function.

Note that if you have multiple validators, you can pass in true as the second parameter ($breakChainOnFailure) to stop processing the remaining validators at that point. This can be because the further validators do not make sense or because you only ever want the user to see one message per field to avoid overwhelming them.

Displaying the form

Having defined out form, we need to get it to the screen. In the controller we need the following:


class IndexController extends Zend_Controller_Action
{
    function indexAction()
    {
        $this->view->pageTitle "Zend_Form Example";
        $this->view->bodyCopy "<p >Please fill out this form.</p>";

        $form = new forms_ContactForm();
        $this->view->form $form;
    }
}

This code assigns some variables to the view, then instantiates the form and assigns that to the view also. The view script is similarly simple:

view/scripts/index/index.phtml:

<?php echo $this->pageTitle ;?>
<?php echo $this->bodyCopy ;?>

<?php echo $this->form ;?>

To render the form, we simply echo it. By default, the form is marked up as a definition list and its HTML looks like this:


<form name="contact_us" id="contact_us" enctype="application/x-www-form-urlencoded" action="" method="post"><dl class="zend_form">
<dt><label for="title" class="required">Title</label></dt>
<dd>
<select name="title" id="title">
    <option value="mr" label="Mr">Mr</option>
    <option value="mrs" label="Mrs">Mrs</option>
</select></dd>
<dt><label for="firstName" class="required">First name</label></dt>
<dd>
<input type="text" name="firstName" id="firstName" value=""></dd>
<dt><label for="lastName" class="required">Last name</label></dt>
<dd>
<input type="text" name="lastName" id="lastName" value=""></dd>
<dt><label for="email" class="optional">Email address</label></dt>
<dd>
<input type="text" name="email" id="email" value=""></dd>
<dt></dt><dd>
<input type="submit" name="submit" id="submit" value="Contact us"></dd></dl></form>

Notice how the setRequired() has resulted in the "required" CSS class name being applied to those elements.

Decorators

If you do not want to use a definition list, then this can easily be changed using decorators. For instance, adding the following to the bottom of the form's constructor after the addElements() call:


        $this->clearDecorators();
        $this->addDecorator('FormElements')
         ->addDecorator('HtmlTag', array('tag' => '<ul>'))
         ->addDecorator('Form');
        
        $this->setElementDecorators(array(
            array('ViewHelper'),
            array('Errors'),
            array('Description'),
            array('Label', array('separator'=>' ')),
            array('HtmlTag', array('tag' => 'li''class'=>'element-group')),
        ));

        // buttons do not need labels
        $submit->setDecorators(array(
            array('ViewHelper'),
            array('Description'),
            array('HtmlTag', array('tag' => 'li''class'=>'submit-group')),
        ));

will result in the form being marked up as an unsigned list with each label and element pair inside each <li>. The marked up form looks like this:


<form name="contact_us" id="contact_us" enctype="application/x-www-form-urlencoded" action="" method="post"><ul>
<li class="element-group"><label for="title" tag="" class="required">Title</label> 
<select name="title" id="title">
    <option value="mr" label="Mr" selected="selected">Mr</option>
    <option value="mrs" label="Mrs">Mrs</option>
</select></li>
<li class="element-group"><label for="firstName" tag="" class="required">First name</label> 
<input type="text" name="firstName" id="firstName" value=""></li>
<li class="element-group"><label for="lastName" tag="" class="required">Last name</label> 
<input type="text" name="lastName" id="lastName" value=""></li>
<li class="element-group"><label for="email" tag="" class="required">Email address</label> 
<input type="text" name="email" id="email" value=""></li>
<li class="submti-group"><input type="submit" name="submit" id="submit" value="Contact us"></li></ul></form>

As you can see, the decorator system makes it easy to render our form in the manner we wish. As a note of warning, pay attention to the order of the decorators as it matters!

Processing

The form is now displayed, so when the user presses the button we need to process it. In this example, this is done in the indexAction() controller function, so that the complete function looks like this with the addition in bold:


class IndexController extends Zend_Controller_Action
{
    function indexAction()
    {
        $this->view->pageTitle "Zend_Form Example";
        $this->view->bodyCopy "<p>Please fill out this form.</p>";

        $form = new forms_ContactForm();

        if ($this->_request->isPost()) {
            $formData $this->_request->getPost();
            if ($form->isValid($formData)) {
                echo 'success';
                exit;
            } else {
                $form->populate($formData);
            }
        }

        $this->view->form $form;
    }
}

Firstly we check the the request is a POST using the request object's isPost() function and then we use validate the submitted data using the form's isValid() function. If this returns true, then we have valid data and can process. If the data is not valid, we populate the form's elements with it and then redisplay so that the user can correct appropriately. The default decorators will display an error message next to each element that failed validation.

Conclusion

So there you have it. A very simple example of how to use Zend_Form.

Here's a zip file of this project: Zend_Form_Example.zip (It includes a snapshot of the trunk of the Zend Framework which is why it's 3MB big.)

It works for me, at least.

Update

With the release of Zend Framework 1.5, a change was made to the way buttons work and you should not put a label decorator on a button as the label property of a button is used for the text value of the button itself.

I have updated the code above to show that if you use setElementDecorators() you then need to reset the decorators for any buttons, the $submit button, in this case. I have also put back the Errors decorator when using an unsigned list.

A View Stream with Zend_View

5th February 2008

One of my biggest issues with using PHP as the templating engine in View scripts is that the easiest way to echo a variable is the least secure.

Consider:

<?= $this->var ?>

Perfectly legal, dead easy to understand, but doesn't escape $var which is what you want more often than not. To resolve this you need something like:

<?= $this->escape($this->var?>

But who remembers to do that?!

I don't and I have short-open-tags turned off too!

So, I decided to leverage a post by Mike Naberezny from a while ago about streams. The idea is all his; I just modified it to work with Zend Framework's Zend_View the way I wanted it to.

This is what I want to happen:

My Code:

<?= @$var?>

is translated to

<?php echo $this->escape($this->var); ?>

As you can see, this significantly cuts down the amount of typing that we need to do and also makes view templates much easier to read!

PHP stream wrappers are a mechanism that allows us to write our own protocol handlers for files. In our case, we want to intercept the view script file and alter the code within short tags to escape the variable for us. We use the short tag so that if we decide that we do not want a variable to be escaped we can use:

<?php echo $this->var;?> 

and it will work as expected.

Let's look at the code!
Read the rest of this entry »

Subversion Externals

27th January 2008

Subversion's svn:externals property is the mechanism that is used to automatically check out data from other repositories into your working directory. This post is to remind me how to do it as each time I need the information, I end up Googling for it.

To start, let's assume you have a lib/ directory and want to put ZF's library/ and incubator/library/ code within it so that the result looks like this:

myApplication/
	lib/
		incubator/Zend/
		Zend/

This is what you do:

$ cd lib/
$ export SVN_EDITOR=vim
$ svn propedit svn:externals .

(Change vim to your own choice of editor as required!)

Vim now starts up and you need the following lines:

incubator http://framework.zend.com/svn/framework/branch/release-1.0/incubator/library
Zend http://framework.zend.com/svn/framework/branch/release-1.0/library/Zend

Note that release-1.0 is the current released version of Zend Framework and release-1.5 will be the next one. The ongoing development work for 1.5 is being done on release-1.5PR.

Save and exit from vim and you will see this message:

Set new value for property 'svn:externals' on '.'

That's it! Don't forget to commit and then you can run svn up to keep your copy of the Zend Framework up to date.

UK PHP Conference

23rd January 2008

I'm not sure how many people follow my the Zend Framework in Action website yet, so I thought I'd advertise here that I've just posted about my upcoming session at the UK PHP Conference.

Go and read it and then subscribe to the RSS feed!