Tutorials

Zend Framework Blog Application Tutorial – Part 6: Introduction to Zend_Form and Authentication with Zend_Auth

Oct 14, 2008 insic 9 Comments

In the previous entry, we created a new Administration Module to hold blog management functionality, added a Module specific layout for it, and discussed the upcoming need to ensure this is only accessible by authorised Authors. In this entry I’ll unravel some of Zend_Form’s mysteries in adding a login form, before using Zend_Auth to implement authentication for authors.

Previously: Part 5: Creating Models with Zend_Db and adding an Administration Module

Authentication in the Zend Framework is the domain of the Zend_Auth component, and it is really easy to use. Zend_Auth is really an abstract API to a number of components working in concert, and without the usual micromanagement of database interaction, sessions, cookies and user data persistence, it makes my life a lot simpler. Of course authentication demands a login form, and so I’ll first visit using Zend_Form. Zend_Form is an interesting component because it’s one of the worst to get started with. The manual, as it does for all components, does not impose a best practice to setting up forms. Mix that with the number of form organisations possible (class based, config based, view template based) and it can be very confusing.

Step 1: Adding a Login Action and View

Before we actually perform authentication, we need a login form. I’ve decided to attach all Author account actions to an Author Controller. Add a new file called AuthorController.php in /application/controllers/ containing the following:

<?php

class AuthorController extends Zend_Controller_Action
{
   
    public function loginAction()
    {
    }

    public function logoutAction()
    {
        $this->_forward(‘index’, ‘index’);
    }
   
}

The logout action for the moment does nothing, but forwards /author/logout requests to the main index, just as I would intend to occur after a real logout.

We’ll also add a matching template at /application/views/scripts/author/login.phtml:

<h2>Authentication</h2>
<p>Enter your author name and password below.</p>

<?php echo $this->loginForm ?>

Nothing major here, except for a mysterious reference to a view variable, $loginForm!

Step 2: Creating a Login form with Zend_Form

Zend_Form is one of the most recent additions to the Zend Framework with the release of 1.5. It’s not surprising it took so long since a decent Form library is not a trivial component to get through development.

The object oriented approach to developing forms takes a bit of getting used to but it works wonders for simple forms that don’t need a heavy design hand. I suppose from my own perspective it was design over functionality that first struck me as problematic when I started using Zend_Form but I think I’m over that learning curve, so let’s see how this look at a simple two field login form goes ;-).

I’ve deliberately selected a preferred form style to adhere to so this will necessitate customising Zend_Form options and decorators. It’s standard based, tableless, composed of semantic markup, and still looks okay without CSS styling or when using a screenreader (which is one of the more important facets for a form im my opinion).

Like a lot of areas in the Zend Framework, actually organising Form objects is left to your imagination. My first question when approaching any potential object nearly always concerns how reusable I can make it. A reusable form object assumes I’ll end up implementing a standard subclass of Zend_Form so I don’t have to repeat myself a dozen times in concrete classes. Hopefully this section provides you with a few good ideas – I have seen Zend_Form examples in the wild that are horrific so I will spend a chunk of time on Zend_Form on this outing.

Since I don’t intend on mucking about with forms using the traditional design form, apply filtering, extract clean data, process data, re-add data and errors to form template, blah, blah, blah if I can avoid it – I’ll use Zend_Form for almost every form in Maugrim’s Marvelous Blog application. Besides, the only public facing form for now would be for comments ;-).

Here’s the proposed output I’d be seeking with all this:

<form action=“/author/login”
<fieldset> 
    <legend>Author Authentication</legend> 
    <ol> 
        <li> 
            <label for=“name”>Name:</label> 
            <input type=“text” name=“name” id=“name” /> 
        </li> 
        <li> 
            <label for=“password”>Password:</label> 
            <input type=“password” name=“password” id=“password” /> 
        </li>
    </ol>
</fieldset>
<fieldset class=“form-button”
    <input type=“submit” value=“Submit” /> 
</fieldset>
</form>

Let’s see if I can kick Zend_Form into cooperating with me on generating that! Or something similar at least…

If Zend_Form has a flaw, the biggest one is its documentation because like most of the Zend components it doesn’t dictate a best practice for organising the final classes. It also appears a little vague at times, but still it does answer a lot of questions if you read it attentive to detail. If something here is just not making sense do ask in the comments or on the Zend Framework mailing lists.

My own take is to take the term “Divide and Conquer” as my motto for dealing with Zend_Form. Break down each specific stage, and from there dump each stage into its own class family. Tackling the whole thing up front without some groundwork is a recipe for the most unmaintainable ugly looking Zend_Form implementation imaginable.

With forms our divisions to conquer are quite simple to visualise. We have the form elements which are segregated from any hint of presentation and which carry elements of business logic by virtue of them containing validation/filtering logic. We have the form element decoration which surrounds form elements with semantic markup styled by CSS we can write independently. Finally we have overall layout which groups all elements logically.

At it’s simplest, this suggests we’ll have two sets of classes. One group for form elements, and another for decorating those form elements. Take the suggested markup from earlier. The li tags are obviously decorators of the form elements they wrap. The fieldset tags pose another difficultly in that they are not specific to a form element group (there are 2 of them, and the placement is purely for presentation) and so we need some sort of form element grouping mechanism to apply decorators to.

The Zend_Form component does precisely that. Despite any confusion it may cause you, it does have a very logical setup for grouping and decorating elements.

Decorators will cause you a few headaches but they aren’t completely nuts :-). The four main standard types are ViewHelper, Label, HtmlTag and Error. There are fourteen in total for even more decorating madness. By default, each of these effects the form element by adding to it’s markup in a predefined (but usually configurable) way.

For example, you can use Label to prepend a form element with some markup. Obviously the name suggests a label tag for the form element but any tag is allowable. Or you can use HtmlTag to wrap tags around a form element like a set of li tags. Hit the manual for a full description of all 14 decorators.

Revisiting our markup, we can suggest a few decorator steps, by working our way out from the form element. The more specific we get here the better.

1. Prepend form element with label tags
2. Wrap form element and label with li tags

3. Prevent application of 1 and 2 to submit element

4. Eliminate default decoration of submit element

Once we hit this point in the decorator flow, we leave the domain of the individual form element. ol and fieldset decorate groups of form elements. Zend_Form wins again by letting us create Display Groups for decorating groups of form elements.

5. Create display group for each fieldset
6. Wrap display group (name, password) with ol tags
7. Prepend display group (name, password) with legend tags
8. Wrap display group (name, password) with fieldset tags
9. Wrap display group (submit) with fieldset tags

Hopefully you’re getting the picture. Pick apart your form, and take it step by step. There is a very logical flow with Zend_Form that makes implementing each step simple once you identify those steps! If you just jump in you will get lost unless you’re already very comfortable with Zend_Form.

It’s again really important that you watch the ordering of decorators – the first decorator added to the stack will be the first applied to the bare bones form element. So each step should be implemented from the inside out in order.

Delving back into PHP, we can now encode a few standard decorator arrays in a Zend_Form subclass. We do need to remember we have one exception above – the submit element requires special treatment since it’s not decorated as an unordered list. In this subclass we’ll also set a few defaults for all forms such as setting a new “accept-charset” attribute for the form element, and ensuring the rendered form object is free of any default decoration apart from the wrapping form element itself obviously.

Create the file /library/ZFBlog/Form.php as part of our slowly growing application specific library.

<?php

class ZFBlog_Form extends Zend_Form
{

    protected $_standardElementDecorator = array(
        ‘ViewHelper’,
        array(‘Label’),
        array(‘HtmlTag’, array(‘tag’=>‘li’))
    );

    protected $_buttonElementDecorator = array(
        ‘ViewHelper’
    );

    protected $_standardGroupDecorator = array(
        ‘FormElements’,
        array(‘HtmlTag’, array(‘tag’=>‘ol’)),
        ‘Fieldset’
    );

    protected $_buttonGroupDecorator = array(
        ‘FormElements’,
        ‘Fieldset’
    );

    public function __construct($options = null)
    {
        parent::__construct($options);

        $this->setAttrib(‘accept-charset’, ‘UTF-8′);
        $this->setDecorators(array(
            ‘FormElements’,
            ‘Form’
        ));
    }

}

The decorator arrays defined as protected properties are quite simple. For example the standardGroupDecorator wraps a display group with the HTML ol tag, and then wraps this again with a fieldset tag. The “FormElements” decorator is sort of a group dynamic – we want to render these group HTML tags around all the form elements included in this display group. You’ll see this decorator used for any decoration of a display group of form elements, including the parent form as a single display block (helps to think of a form as a single parent display group with children).

As another example, the standardElementDecorator prepends a form element with a label (notably the label content is not defined yet), and wraps both the form element and label in li tags. You’ll notice the standard group decorator wraps the parent ol tags around all of this.

See how easy that was? Once you break down your form markup into a series of specific decoration steps, writing Zend_Form decorator arrays tailored to those steps is pretty simple.

So we have a platform for making forms. How about something specific – like a Login form?

Create a new file /library/ZFBlog/Form/AuthorLogin.php:

<?php

class ZFBlog_Form_AuthorLogin extends ZFBlog_Form
{

    public function init()
    {
        $this->setAction(‘/author/login’);

        // Display Group #1 : Credentials

        $this->addElement(‘text’, ‘name’, array(
            ‘decorators’ => $this->_standardElementDecorator,
            ‘label’ => ‘Name:’
        ));

        $this->addElement(‘password’, ‘password’, array(
            ‘decorators’ => $this->_standardElementDecorator,
            ‘label’ => ‘Password:’
        ));

        $this->addDisplayGroup(
            array(‘name’, ‘password’), ‘authorlogin’,
            array(
                ‘disableLoadDefaultDecorators’ => true,
                ‘decorators’ => $this->_standardGroupDecorator,
                ‘legend’ => ‘Credentials’
            )
        );

        // Display Group #2 : Submit

        $this->addElement(‘submit’, ‘submit’, array(
            ‘decorators’ => $this->_buttonElementDecorator,
            ‘label’ => ‘Submit’
        ));

        $this->addDisplayGroup(
            array(‘submit’), ‘authorloginsubmit’,
            array(
                ‘disableLoadDefaultDecorators’ => true,
                ‘decorators’ => $this->_buttonGroupDecorator
            )
        );
    }

}

How’s that for something interesting? Now all we do for an author login form is define the elements, assign a standard or specific decorator array from the parent class, and assign to a display group which also gets a decorator array from the parent class assigned.

The only real sore point here perhaps, is that I’m declaring the text content of labels and legends in the source code. Some bright mind might find it better to stuff these into a configuration file, and maybe link up a Translator for good measure (not covered here but is a documented possibility in the manual), but for now it’s enough to work with.

Let’s now revise our AuthorController to create this form and pass it to the View.

<?php

class AuthorController extends Zend_Controller_Action
{
   
    public function loginAction()
    {
        $form = new ZFBlog_Form_AuthorLogin;
        $this->view->loginForm = $form;
    }

    public function logoutAction()
    {
    }
   
}

Go ahead and open up your browser to http://zfblog/author/login.

Here’s the exact output I get from Firefox without tinkering with element separator options:

<form enctype=“application/x-www-form-urlencoded” action=“/author/login” accept-charset=“UTF-8″ method=“post”>
<fieldset id=“authorlogin”><legend>Credentials</legend>
<ol>
<li><label for=“name” class=“optional”>Name:</label>

<input type=“text” name=“name” id=“name” value=“”></li>
<li><label for=“password” class=“optional”>Password:</label>

<input type=“password” name=“password” id=“password” value=“”></li></ol></fieldset>
<fieldset id=“authorloginsubmit”>

<input type=“submit” name=“submit” id=“submit” value=“Submit”></fieldset></form>

Apart from needing a few newline separators, it’s pretty much what I set out to create :-). Zend_Form just added a few default classes and attribute values.

Step 3: Adding Validation to Login Form

Zend_Form isn’t just for presentation since you can also make forms self validating. This takes advantage of all the standard validators you might expect to use manually. Let’s revisit the ZFBlog_Form_AuthorLogin form class after including some validation rules.

<?php

class ZFBlog_Form_AuthorLogin extends ZFBlog_Form
{

    public function init()
    {
        $this->setAction(‘/author/login’);

        // Display Group #1 : Credentials

        $this->addElement(‘text’, ‘name’, array(
            ‘decorators’ => $this->_standardElementDecorator,
            ‘label’ => ‘Name:’,
            ‘validators’ => array(
                array(‘StringLength’, false, array(5,20))
            ),
            ‘required’ => true
        ));

        $this->addElement(‘password’, ‘password’, array(
            ‘decorators’ => $this->_standardElementDecorator,
            ‘label’ => ‘Password:’,
            ‘required’ => true
        ));

        $this->addDisplayGroup(
            array(‘name’, ‘password’), ‘authorlogin’,
            array(
                ‘disableLoadDefaultDecorators’ => true,
                ‘decorators’ => $this->_standardGroupDecorator,
                ‘legend’ => ‘Credentials’
            )
        );

        // Display Group #2 : Submit

        $this->addElement(‘submit’, ‘submit’, array(
            ‘decorators’ => $this->_buttonElementDecorator,
            ‘label’ => ‘Submit’
        ));

        $this->addDisplayGroup(
            array(‘submit’), ‘authorloginsubmit’,
            array(
                ‘disableLoadDefaultDecorators’ => true,
                ‘decorators’ => $this->_buttonGroupDecorator,
                ‘class’ => ‘submit’ // fieldset class attribute for some later styling
            )
        );
    }

}

Note the additions including a new “required” flag dictating these values are required (i.e. must not be empty) and also a “validator” array giving a string length minimum and maximum for the “name” form element. I also just threw in a class attribute for our authorloginsubmit fieldset display group – it’ll make styling that fieldset easier.

One thing blatantly missing is error messages – we haven’t added any decorators to our form elements to include error message text somewhere.

Step 4: Handling Error Messages with a Custom Decorator

We now have another interesting problem on our hands. Assuming validation fails, where will we display error messages? Usually I prefer to stick them into each form element’s label tag (I like really short error messages ;-)) whereas by default, remembering that we’ve now either disabled or overridden Zend_Form’s decoration defaults, it’s displayed separately by an appending Error decorator.

Since we’re departing from the norm, it’s time to customise how labels are generated.

What we need to do is intercept a label before it’s rendered, and append error messages to it’s content. Simplest way of doing that is to subclass the Label decorator. There is one additional thing to watch out for which is the fact that the standard Label decorator (when used to generate a label element) makes use of the FormLabel View Helper in Zend_View. If we intend appending HTML to the label name (as here) we’ll need to disable the FormLabel Helper’s default treatment of escaping the label name.

This points out another interesting nugget to remember. Many form decorators use Zend_View’s View Helpers. And any options passed to a decorator, are also made available to the relevant View Helper. So it does pay to know the View Helpers as well as Zend_Form – the helpers have another layer of configurable behaviour you might find handy.

About that custom decorator, it’s very simple. It just grabs the error messages for any element it’s decorating and appends them to the label name wrapped in strong tags for styling access with CSS. Create a new file for the decorator at /library/ZFBlog/Form/Decorator/LabelError.php:

<?php

class ZFBlog_Form_Decorator_LabelError extends Zend_Form_Decorator_Label
{

    public function getLabel()
    {
        $element = $this->getElement();
        $errors = $element->getMessages();
        if (empty($errors)) {
            return parent::getLabel();
        }

        $label = trim($element->getLabel());
        $label .= ‘ <strong>’
            . implode(‘</strong><br /><strong>’, $errors)
            . ‘</strong>’;

        $element->setLabel($label);

        return parent::getLabel();
    }

}

Here we’re subclassing the getLabel() method – easier this way than retyping the whole original render() method! All the method does is append the error messages – we refer back to the parent class version of this method afterwards so we don’t duplicate any source code from the standard decorator we’re extending.

This is great – so let’s wrap up by amending our ZFBlog_Form class to tell Zend_Form where to find our custom decorator (and indeed any future ones), and also add the new LabelError decorator to one of our decorator stacks.

<?php

class ZFBlog_Form extends Zend_Form
{

    protected $_standardElementDecorator = array(
        ‘ViewHelper’,
        array(‘LabelError’, array(‘escape’=>false)),
        array(‘HtmlTag’, array(‘tag’=>‘li’))
    );

    protected $_buttonElementDecorator = array(
        ‘ViewHelper’
    );

    protected $_standardGroupDecorator = array(
        ‘FormElements’,
        array(‘HtmlTag’, array(‘tag’=>‘ol’)),
        ‘Fieldset’
    );

    protected $_buttonGroupDecorator = array(
        ‘FormElements’,
        ‘Fieldset’
    );

    public function __construct($options = null)
    {
        // Path setting for custom decorations MUST ALWAYS be first!
        $this->addElementPrefixPath(‘ZFBlog_Form_Decorator’, ‘ZFBlog/Form/Decorator/’, ‘decorator’);

        parent::__construct($options);

        $this->setAttrib(‘accept-charset’, ‘UTF-8′);
        $this->setDecorators(array(
            ‘FormElements’,
            ‘Form’
        ));
    }

}

The new decorator reference receives a new option – we disable escaping of the label’s name value so any included HTML doesn’t get the htmlspecialchars treatment. This option is passed into the FormLabel View Helper when called from the decorator class.

In our constructor we have a comment. Never, ever, ever, forget that comment. It is essential that decorator paths for your custom decorators are added as early as possible – in fact they should be the first thing you do in a subclass of Zend_Form even before passing options to the parent’s constructor.

Feel like taking a peek? Go ahead and browse to http://zfblog/author/login. The form is still there, and it looks like it hasn’t broken yet ;-). Go team!

Step 5: Replacing Those Cumbersome Default Errors

One final step I’ll make is layering in a Translation object for our forms. This has a few purposes. First it will allow for translating labels, legends, etc., but to be honest I’m really doing because it’s the simplest method of getting rid of the long error messages the Validators generate. Life is never easy, eh? ;-)

We’ll start simple and only address error messages as a quick example. Add a new file at /translate/forms.php containing:

<?php

return array(
    Zend_Validate_NotEmpty::IS_EMPTY => ‘Required’,
    Zend_Validate_StringLength::TOO_SHORT => ‘Minimum Length of %min%’,
    Zend_Validate_StringLength::TOO_LONG => ‘Maximum Length of %max%’
);

With the translation file in place (using the Zend_Translate Array adapter) we just need to tell Zend_Form where to find it. Zend_Form uses a static method for this, so I’ll create a quick static check and helper function for our ZFBlog_Form class.

<?php

class ZFBlog_Form extends Zend_Form
{

    protected $_standardElementDecorator = array(
        ‘ViewHelper’,
        array(‘LabelError’, array(‘escape’=>false)),
        array(‘HtmlTag’, array(‘tag’=>‘li’))
    );

    protected $_buttonElementDecorator = array(
        ‘ViewHelper’
    );

    protected $_standardGroupDecorator = array(
        ‘FormElements’,
        array(‘HtmlTag’, array(‘tag’=>‘ol’)),
        ‘Fieldset’
    );

    protected $_buttonGroupDecorator = array(
        ‘FormElements’,
        ‘Fieldset’
    );

    public function __construct($options = null)
    {
        // Path setting for custom decorations MUST ALWAYS be first!
        $this->addElementPrefixPath(‘ZFBlog_Form_Decorator’, ‘ZFBlog/Form/Decorator/’, ‘decorator’);

        $this->_setupTranslation();

        parent::__construct($options);

        $this->setAttrib(‘accept-charset’, ‘UTF-8′);
        $this->setDecorators(array(
            ‘FormElements’,
            ‘Form’
        ));
    }

    protected function _setupTranslation()
    {
        if (self::getDefaultTranslator()) {
            return;
        }
        $path = dirname(dirname(dirname(<u>_FILE_</u>)))
            . ‘/translate/forms.php’;
        $translate = new Zend_Translate(‘array’, $path, ‘en’);
        Zend_Form::setDefaultTranslator($translate);
    }

}

Easy as pie. Now all error messages will be replaced.

Step 6: Introducing Joe Bloggs

Before we go further, we’re missing one essential aspect of Authentication. We don’t have a user! Let’s resolve that quickly. I’m not going to pounce on registration since a) this is a one-person blog, and b) I can add it later. So I’ll use some filler data for a theoretical user instead. I’m cheap I know. Sorry ;-).

Here’s Joe. Rumour has it he’s The Common Man (TM). If you prefer, Joe can be a Jane. Nobody intends hunting him/her down to check anyway…

INSERT INTO `authors` (`realname`, `username`, `password`, `email`) VALUES ('Joe Bloggs', 'joebloggs', '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', '[email protected]');

The hashed password is “password” hashed using the SHA256 algorithm.

Run the SQL insert on your users table in the database to manually register Joe (or Jane).

Step 7: Adding Authentication and Form Processing to AuthorController

Zend_Auth operates by referencing an adapter for our storage system. Since we’re using a database, we’ll use the Zend_Auth_Adapter_DbTable adapter. The adapter works by allowing us to define specific fields on that table used for the login process, i.e. the username and password fields. It also lets us define an operation needed for these fields which in our case is primarily the need to apply SHA256 to any password before comparing it to the database stored value. Unfortunately since MySQL and SHA256 aren’t happy campers I’ve explicitly applied the hashing here.

Once the Adapter is configured we need only add two steps. Firstly we tell the Adapter to attempt authentication using the values provided from our login form, and secondly we store the authenticated author’s data for future reference elsewhere in the application.

Since the only authenticated user is the author, on a successful login we’ll redirect them to the Administration Module’s index page.

Here’s the updated version of our AuthorController class.

<?php

class AuthorController extends Zend_Controller_Action
{
   
    public function loginAction()
    {
        $form = new ZFBlog_Form_AuthorLogin;

        if (!$this->getRequest()->isPost() || !$form->isValid($_POST)) {
            $this->view->loginForm = $form;
            return;
        }

        $values = $form->getValues();

        // Setup DbTable adapter
        $adapter = new Zend_Auth_Adapter_DbTable(
            Zend_Db_Table::getDefaultAdapter() // set earlier in Bootstrap
        );
        $adapter->setTableName(‘authors’);
        $adapter->setIdentityColumn(‘username’);
        $adapter->setCredentialColumn(‘password’);
        $adapter->setIdentity($values[‘name’]);
        $adapter->setCredential(
            hash(‘SHA256′, $values[‘password’])
        );

        // authentication attempt
        $auth = Zend_Auth::getInstance();
        $result = $auth->authenticate($adapter);

        // authentication succeeded
        if ($result->isValid()) {
            $auth->getStorage()
                ->write($adapter->getResultRowObject(null, ‘password’));
            $this->_helper->redirector(‘index’, ‘index’, ‘admin’);
        } else { // or not! Back to the login page!
            $this->view->failedAuthentication = true;
            $this->view->loginForm = $form;
        }   
    }

    public function logoutAction()
    {
        Zend_Auth::getInstance()->clearIdentity();
        $this->_helper->redirector(‘index’, ‘index’);
    }
   
}

As you can see, using Zend_Auth is pretty easy. Authentication is driven by the Adapter in use, and performed by a quick call to the singleton (there can only be one such object globally) Zend_Auth instance. The rest is storing the credentials and setting View result values for our template to make use of.

Note that the getResultRowObject() method parameters tell the storage driver not to remember the password hash. Personally I don’t want the hash leaving the database if I can help it – it serves no purpose and is the kind of user data you might consider not persisting outside authentication. You could drop that entire line if you didn’t care if passwords are stored or not since Zend_Auth will store the identity by default.

I’ve also added a logout call to clearIdentity() which does exactly what it says on the tin ;-). Might be useful when you’re testing at home – I’ll add a logout link to the interface another time.

A little feedback would probably be appreciated by the author if their login attempt failed, so let’s amend our login View at /application/views/scripts/author/login.phtml accordingly.

<h2>Authentication</h2>
<p>Enter your author name and password below.</p>

<?php if (isset($this->failedAuthentication)): ?>
    <p class=“error”>Sorry, but the credentials supplied could not be authenticated. Please try again.</p>
<?php endif; ?>

<?php echo $this->loginForm->render() ?>

Go ahead, open a browser and take the new login form for a test run.

Conclusion

Since authentication is really simple with the Zend_Auth component, the bulk of this installment concerned using Zend_Form. I really do advise taking a form apart before calling on Zend_Form because you really need to know how a form’s structure can be built up in layers using the Zend_Form decorators.

If anything, the decorators are the main obstacle you’ll meet using Zend_Form since almost everything else is straight forward once you put in place a bit of structure. At all costs avoid the umpteen line approach to Zend_Form usage where elements, decorators and validators are tied so closely together maintenance is a lost cause. One point I didn’t cover was adding custom Element classes – in a form heavy application that could save you even more typing.

Our authentication now in place, the next Part will introduce two unrelated areas. Authorisation with Zend_Acl, followed by a brief detour into applying some styling to the growing bank of HTML (I’m getting a little tired by the CSSless look ;-)).

All Contents Copyrighted to Pádraic Brady.

About the author: insic

Subscribe in my RSS Feed for more updates on Web Design and Development related articles. Follow me on twitter or drop a message to my inbox.

  • http://blog.insicdesigns.com insic2.0

    Posting Part 6 delayed a little bit due to my blog migration.

  • www.phpconsulant.in Murugan
  • Lee

    Hi,

    I’ve been following along with this tutorial series and it has taught me a lot. I have one question though about something you mentioned in an earlier tutorial. You mentioned a comments table. Now i’m wondering, since you have set up this application with a public module and a admin module, where exactly do you put the commenting functionality. Do you have a comments controller in each of the public and admin modules, or do you do something different. Just curious, because I know that both public and admin need the ability to add comments.

  • http://www.codeandpixels.co.uk Pete

    This is the best ZF tutorial I’ve come across so far, it finally makes it all seem as simple as I’ve been told it is!

    Any idea when the next part is coming? The Astrum Futura site seems to be down :(

  • http://none Thijs

    Hmm.

    small inquiry about the label error function.

    I have changed mine to:

    $label = ‘
    . implode(‘
    ‘, $errors)
    . ‘
    ‘;
    $label .= trim($element->getLabel());

    so that I atleast keep a nice straight display. cause as it is now it shows:

    username: required

    now it goes:
    required
    username:

    Is there anyway to change it to the following:

    Username:
    Required

    (ps. Username = label, Field = inputfield and Required is error message)

    I’ve tried but cant quite figure it out.

    thanks in advance (

  • http://hiptop.ru/map.html goolloog

    Excellent blog! Interesting article and very informative! I will necessarily subscribe for this blog. http://hiptop.ru/map.html

  • http://bac.chaukhe.com Nguyen Duc Manh

    Mới đọc đến đây mà mệt hết cả người. Toát hết mồ hôi mới config đúng.Lẽ ra ông viết cái này phải gói lại thành 1 file zip để mọi người còn xem và chỉnh sửa chứ. Ko hay bằng anh em Việt Nam ! :D

  • Lotus

    Hi,

    Thank you so much. And I would like to know one more thing at this part, $auth->getStorage()->write($adapter->getResultRowObject(null, ‘password’));

    Is that possible to write more data in Auth Storage by retrieving other data from another tables for later use.

  • http://techiesindiainc.com/ Zend Framework

    You Actually shared the valid tutorial about Zend Framework, i read some other blogs as well but there are so many points they lacked with. Going to bookmark and waiting for the next part.