Reflection on Separation of Concerns

Working with larger projects a lot, I sometimes forget some of the earlier decisions I made to get here. Biting the bullet with Zend Framework 3 years ago made some of those decisions subconscious (or seem obvious), but after a little reflection, I am thankful. This post really has nothing to do with ZF, but it does relate to the idea of frameworks a lot. I’ve decided I need to start looking at what other developers are doing more – outside of the few dozen that I actively follow on Twitter. I need to go back, re-evaluate some of those decisions, and hopefully share some knowledge along the way.

After the last #LeanCoffeeKL event, I was brought into a discussion with a fellow developer who could not get mail setup locally. Another guy chipped in with some useful advice. I instantly thought in my head, “who cares? don’t send mail locally”. After thinking how obvious that was for a few minutes, I remember setting up my local dev server ages ago, and being pissed off that I couldn’t get mail working properly. All of the blog posts would explain how to set it up through your ISP. Some, smarter, would show you how to send it through SMTP (or through Gmail, etc.).

A big mindset change for me was when I discovered that I could code for different environments. Having distinct development, staging and production environments made configuration a lot easier. It also made dealing with external tools a lot easier. So, how did that help me with that pesky mail problem?

Mail is a service. My application code does not care how mail works, it just cares that it can call the mail service. If I’m testing things, I don’t want to actually send mail. That can have some very scary unintended problems. I do, however, want to make sure that the generated emails are correct. By abstracting what the mail service does, you can create a basic interface for that service that my application can call. My configuration (per environment) can determine what mail implementation I need.

For example, on development, I capture email to the database. On staging and production, I capture email to the email queue (in the database). However, there is no cron job set up on staging to actually send the mail. However, I can when I need to.

A lot of these problems come up all the time, but unless you know the right questions, it’s pretty hard to navigate forward. I’m hoping to start exploring these topics a lot more in the next few weeks on here.

Fixing a Broken Eclipse PDT Index

One my secondary machine, I noticed that Eclipse’s Open Type / Open Method dialog stopped working (not populating). I tried several things, such as rebuilding the index / projects, restarting eclipse, and several solutions from online. I actually couldn’t find anyone with this problem for Eclipse PDT (PHP edition), but some solutions for Java.

Here are the usual listed solutions:
-Restart Eclipse
-Clean or build broken projects
-Delete files from workspace (Java)

I finally got this fixed today after comparing both of my Eclipse directories (working and non). Shut down eclipse, and navigate to your Eclipse workspace directory. Delete the workspace/.metadata/.plugins/org.eclipse.dltk.core.index.sql.h2 directory, and load up eclipse. I noticed mine had grown to 6GB which is probably why it crapped out. My other installation’s directory was about 250mb by comparison.

Hopefully this helps someone else! Auto-complete, open type, etc. is a god-send when working with large projects.

Securely Storing Passwords in PHP

Tons of websites or applications are requiring us to register our username/password into their system. This scares the hell out of me as a developer. If I register to 40 websites, and one of them gets breached, is my information secure? Does that one breach potentially affect the other 39?

How are you storing your users’ passwords? Read more to see if your password protection can hold up to today’s hackers…

The Methods

Plain Text – If you are storing passwords in plain text, please unplug your internet connection because you are doing more harm than good.  People tend to do this for one of two reasons… 1) negligence, or 2) they need to be able to recover the password.

Encryption – If you do need to reverse the passwords, then you will want some sort of two-way encryption.  If your entire system is compromised, there is a chance passwords may be too.  If you take the route of encryption, I recommend AES, which is the current government-approved standard for data encryption.  Be warned though, proper encryption requires a lot of preparation.  Encrypting passwords is rarely necessary. Allowing users to reset their password via email address is typically preferred from having a way to actually reverse it.  Personally, this also gives me the peace of mind that they are not storing my password.

Hash (One-way encryption) – A hash is a one-way transformation, creating a very small representation of the original data.  It is impossible to reverse.  You can authenticate users by storing a hash of their password, and when they return, a hash of the password they log in with should match the one stored.  This is the preferred method of authenticating users (or, if you can, some sort of OpenID implementation with no password exchange).

Home Grown Solution – Unless you have been studying advanced cryptography for several years, please stop. Every home grown solution I’ve seen has been security-by-obscurity at best, and would not stop even an inexperienced malicious user.

Why You Shouldn’t Use md5 or sha1/sha2

MD5 is the most popular hashing algorithm, and has been around for a long time now. It is still being widely (ab)used. It creates a 128 bit (32 digit hex) hash of the input string. Generally, you will get a unique hash for every string.  SHA1 and its successor, SHA2 are also very popular and valid hashing algorithms.  While they are better than md5, they are also not meant for password storage.  These are general hashing functions – not safe for dealing with passwords.  Here is why…

Rainbow Tables – One of the main flaws of using a standard hash is hackers can compile a large table of strings, and their corresponding hashes. A simple test is to search on Google for a hash of your password (or any string) and see what you come up with. This easily gets past common passwords, but what about more advanced ones?

Adding Salt – Adding “salt” refers to appending or prepending random characters to the password, so it will not match other common passwords, or even the same password somewhere else. Each account should have a different salt! While this does solve the rainbow tables issue, it is still not foolproof.

Collisions – Unfortunately, md5/sha1/sha2 are  not perfect hashing algorithms. Multiple strings can yield the same hash, so there is a chance that a user would be able to log in with a different password than your own. While this is not very common, it lessens the time required to brute force passwords.

Brute Force – At the end of the day, if a user has the hashed password, they can try to brute force it. They’d need a script to generate all character combinations (or download a large db), and compare hashes with the hash that they are trying to break.  If time is the only weapon we have, the slower the hash, the better our chances are. A decent server can crack a 6 digit password in under a minute. If you actually have sensitive information, a few thousand dollars will allow you to try more than 700 million passwords per second. It will not take long.  More and more hackers are renting high-powered computers so they can work faster.

Speed is the Enemy

The faster a hash is calculated, the quicker a hacker can brute force it.   There is an enormous difference in computation power between your home PC, a decent server, and a super-computer that you can leverage for a few hundred dollars per hour.  Some computers can calculate every 6 or 7 digit md5 hash in a few seconds.

bcrypt is a very slow hashing algorithm based on Blowfish (popular encryption algorithm). You can set the number of encryption rounds between 4 and 31. By comparison, depending on the number of rounds you set, it can take a tenth of a second up to a few seconds for a single password. Just to drill it in… md5: millionth of a second, bcrypt: 0.1s-5s (very rough numbers).

bcrypt uses a salt internally, so it naturally avoids rainbow attacks, and due to its complexity, brute force attacks and collisions. Even with some sort of super-computer, it would take several years to crack a bcrypt hash, which is significantly more effective than MD5 or SHA1/2.

Implementing bcrypt in PHP

bcrypt is a lot more difficult to call than md5(), and has a few dependencies as well. Oddly enough, it is also not very well documented. In order to use it, you call the crypt function (yes, it’s a hash and not an encryption function). In order to set the hash type, you need to pass it specifically formatted salt.

string crypt ( string $str [, string $salt ] )
$str is your input string to hash, and $salt is a combination of configuration and the hash type to use. Here is the documentation for bcrypt (blowfish):

CRYPT_BLOWFISH – Blowfish hashing with a salt as follows: “$2a$”, a two digit cost parameter, “$”, and 22 base64 digits from the alphabet “./0-9A-Za-z”. Using characters outside of this range in the salt will cause crypt() to return a zero-length string. The two digit cost parameter is the base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithmeter and must be in range 04-31, values outside this range will cause crypt() to fail.

Here is an example:

crypt('string_to_hash', '$2a$10$abcdefghijklmnopqrstuv');

Broken down:

$password = 'TOP SECRET PASSWORD';
$rounds   = 10;                       // typically ~0.2s
$salt     = 'abcdefghijklmnopqrstuv'; // a-zA-Z0-9 / and .
 
$hash     = crypt($password, '$2a$' . $rounds . '$' . $salt);

When re-creating the hash for comparison, you’ll need to pass the same salt, so you should store it in your user table similar to how the hash is stored. Creating a user and authenticating users may take another 0.2s or so, but that’s really a small (and configurable) price to pay for security.

Accessing Parent Iframe Object

If you ever need to access your iframe object, from within that frame, there is an easy way. All the forum / QA site answers I’ve ran into all say to fetch the object by ID, but you don’t always have the luxury of that. Here is an easier way that doesn’t require any extra prep work and has fairly good browser support.

// actual iframe object
window.frameElement 
 
// jquery iframe object
$(window.frameElement)

One quick caveat for jQuery – any alterations you’ve made to that object will not work here (ex: custom data). Use the parent window’s jQuery object instead.

parent.$(window.frameElement)

After a few days of shitty implementations off the net, I thought I’d document this. I hate iframes.

Zend Framework Models – Part 1: Concepts

The power in Zend Framework lies in its uncompromising flexibility. However, evidently, this also means its very difficult for new ZF users to pick up the framework and hit the ground running. The most common question I see is usually “where is the model?”. The goal of this post is to show some examples and hopefully some new ideas on how to tackle models. There is no one-size-fits-all solution folks. Let’s look at some options and some background…

The concept of a model

Before we can go any further, we must first figure out what a model is. This stuff isn’t an exact science, so there will be some gray areas. Much of this post is my opinion (read: not fact). This doesn’t necessarily make them right or wrong. I like to think I’m right, so feel free to argue with me in the comments below.

In an MVC application, the model is responsible for all the business logic. The controller should handle flow control (taking input, calling models, redirection, etc.), and the view is responsible for representing your application, usually with some sort of data language (XML, HTML, JSON, etc.)

Implementation and and interpretation of the pattern is up to the developer… there are some gray areas so don’t worry if it doesn’t meet the exact specification. However, one thing I like to practice is skinny controllers, fat models. By shifting a lot of the work to the models (and their underlying libraries) you can usually organize your application much better. The result is simpler and more organized (primarily better encapsulated) code.

Simply said, a model should contain your business logic. Any processing that revolves around your application data should probably be put into models. I consider a model to be anything that does something in the big picture of your application… things like reading/writing data, sending/receiving data, processing data. They do the “work”.

One mistake I see is people simply setting up ORM (ex: Doctrine) models for each of their tables and leaving it at that. Your models’ public interfaces should be very simple. I prefer to have their interface represent their actual domain logic. For example, if you are making a post, then your controller (or calling code) should simply call something very self explanatory like post->create( info ). One personal guideline I follow is not to have more than 4 or 5 parameters to a method, and ideally, only 1 to 3.

One common implementation of this annoyance of mine is putting in chained query calls in your controller. Yes, the actual database code is encapsulated, but you are still revealing way too much information in your controller. The whole point of them is to encapsulate not only the code, but also the underlying logic. This way, when your business logic changes, your controllers can usually continue to function properly.

Working with databases

Most web applications revolve around storing information in the database. Whether it’s posts, comments or pictures, it all boils down to the same few operations. You can call this CRUD: create, read, update and destroy. In practice, it’s often much more complicated… but they remain to be the underlying concepts for most database interaction.

Most other frameworks come with a default model class/component which is a huge push in the right direction. Zend keeps an open mind about it, providing a few tools to use if you want to work with the database. Zend comes with a huge Zend_Db component to handle your database operations. It also contains Zend_Db_Table which is an implementation of the Table Data Gateway and Row Data Gateway patterns.

Personally, I’m not a big fan of Zend_Db_Table. I still think Doctrine is much more powerful, though I do really like Zend_Db. It operates under some of the same principles as PDO (database abstraction layer), so if you have used that before, you will be at home. I also really like Zend_Db_Select, which is what the table classes use quite a bit.

Using a base model

Because there are so many different types of models, I don’t think there is much point in having a do-it-all base class. However, for the group of models that will need database access, I use something like this:

class Site_Model {
    protected $_db;
 
    public function __construct(Zend_Db_Adapter_Abstract $db) {
        $this->_db = $db;
    }
}

You can probably tell that the default model is not even needed… and that’s the point. However, depending on your needs, this is a good place to start adding some common functionality that your db models will need. You may want to also make them all loader or dependency injector friendly if your application requires that.

Zend_Db

Zend’s database abstraction layer is really nice to work with. If you use it in combination with Zend_Db_Select you can make the database end of your application very portable. Here are some common methods I use from Zend_Db:

query(string)

fetchOne(query)
fetchRow(query)
fetchAll(query)

insert(table, data)
update(table, data, where)
delete(table, where)

quote(value)
quoteInto(string, value)

Abstracting your queries

If I’m working on an application that I plan to release to the public, then I always use Zend_Db_Select. It works on the same concept as the above insert/update/delete methods, meaning that you never have to write any of the SQL. If you let the Db libraries do it, then you are able to get much more portable code. Zend_Db supports IBM’s DB2, MySQL, MSSQL, Oracle, PostgreSQL and SQLite, so Db_Select is targetted at the same databases.

The concept of Zend_Db_Select is that the query is an object, and you can add/modify different parts of it. This gives you a lot more flexibility over dynamic query creation, as well as the added bonus of portability.

Summary

For your basic database-oriented models, all you your class will need is access to the Zend_Db_Adapter_Abstract interface. Keep your public methods very domain-oriented and your controllers will thank you for it. Break out of the mindset that models = database tables, or even model = database. Usually only around half my models deal with database operations. ZF also has a ton of service libraries available to help with all the common social sites APIs out there.

The next installment of this post will go into some concrete examples and also some ideas on how to implement your models. Comments and criticism welcomed and appreciated as always.

Testing Zend_Mail

Since I work on a local development machine/server, I’ve never taken the time to set up mail yet, nor do I want to. I think a staging environment is more appropriate to actually have email being sent out. Nevertheless, it has made testing any email functionality a little cumbersome. I’ve done a little research, and have found two ways to tackle the problem. I’ve also included code samples and other resources to get you started.

Create a new mail transport class

Zend has the ability to set a default mail transport class to be used when none is specified, which I’d imagine to be 99% of the time. To set it, all you need to do is put this somewhere early in your application before any mail code is executed.

Zend_Mail::setDefaultTransport(new Site_Mail_Transport_Debug());

The alternative (for the 1% who want to manually specify), you’d simply pass an instance of your mail transport object to Zend_Mail::send() when you call it. What should your class contain? It has to extend Zend_Mail_Transport_Abstract, which at this time of writing this, will specifically need to override the abstract _sendMail() method.

You can use it to create a new record in your database, create a file, or do whatever you need it to. I quickly hacked together one to log it to the database, and based it off of the Sendmail transporter, which is pretty much a wrapper for PHP’s mail function. Here is the code I came up with for those who want some direction. It’s very basic, but should be enough to get you started.

<?php
 
class Site_Mail_Transport_Debug extends Zend_Mail_Transport_Abstract {
 
    public function __construct(Zend_Db_Adapter_Abstract $db) {
        $this->_db = $db;
    }
 
    public function _sendMail() {
        $this->_db->insert(
            'mailtest',
            array(
                'recipients' => $this->recipients,
                'subject'    => $this->_mail->getSubject(),
                'body'       => $this->body,
                'header'     => $this->header
            )
        );
    }
}

Override it at the server level

This is a good idea if you don’t use Zend Framework, or don’t use it for all of your applications. There are two great techniques described on akrabat’s blog. Here they are.

The first, is to override php.ini’s ‘sendmail_path’ and create your own script to handle it. If you were to set it to

sendmail_path = /usr/local/bin/trapmail

then you’d use the following code

formail -R cc X-original-cc 
  -R to X-original-to 
  -R bcc X-original-bcc 
  -f -A"To: your@emailaddress.com" 
| /usr/sbin/sendmail -t -i

This requires you to have mail configured on your server, but it still solves the underlying problem of wanting to debug the emails, and also not send out test emails to real users in your application.

The second solution provided is platform independent is for Windows users, and it’s to install fakemail. This program acts as an outgoing mail server, but instead creates files containing any mail passed to it.

Hopefully this helps others out who are also frustrated with dealing with pesky email debugging.

Caching Zend Framework Forms

Generating a form is an expensive process in ZF. It’s always bugged me that I can’t find any resources on trying to cache the initial HTML anywhere, so I took a stab at it myself. I use a loader from inside my controller action to load forms and models, so I found that was a good place to start.

Here is my initial loader class, which I have stripped down and simplified for the sake of this example. Ideally, you’d want this in something like an action helper.

<?php
 
class Site_Loader {
    /**
     * Site's controller action
     * @var        Site_Controller_Action
     */
    protected $_controllerAction;
 
    /**
     * Sets the current controller action we're being called from
     * @param       Site_Controller_Action
     */
    public function setControllerAction(Site_Controller_Action $action) {
        $this->_controllerAction = $action;
    }
 
    /**
     * Loads the requested form class
     * Same conventions as Zend (Form_Name = Form/Name.php) class "Form_" . $Form_Name
     *
     * @param    string        The name of the form class
     * @param    string        Any options for the form class constructor
     * @return   object        Form class object - forms_$formName
     */
    public function form($formName, $options = null) {
        $path = APP_DIR . "/application/forms/" . str_replace('_', '/', $formName) . '.php';
        require_once $path;
 
        $class = "Form_" . $formName;
        return new $class($this->_controllerAction, $options);
    }
}

I always find it useful to have access to the controller in forms – especially to access the request information. Another reason is we can use it to determine the request method – more importantly, see if it’s POST. When it’s not, then we can enable caching, because the form output should not change. Only when they actually post something should we need to show anything different. I set a high cache TTL simply because I’d want it to be there forever, until I actually modify the form code, at which point I’d clear its cache. With that in mind, here is the updated (and relevant parts of) the loader.

<?php
 
class Site_Loader {
    /**
     * Site's controller action
     * @var        Site_Controller_Action
     */
    protected $_controllerAction;
 
    /**
     * Caching object used
     * @var         Zend_Cache_Core
     */
    protected $_cache;
 
    /**
     * Sets the current controller action we're being called from
     * @param       Site_Controller_Action
     */
    public function setControllerAction(Site_Controller_Action $action) {
        $this->_controllerAction = $action;
    }
 
    /**
     * Sets the cache object to be used
     * @param       Zend_Cache_Core
     */
    public function setCache(Zend_Cache_Core $cache) {
        $this->_cache = $cache;
    }
 
    /**
     * Loads the requested form class
     * Same conventions as Zend (Form_Name = Form/Name.php) class "Form_" . $Form_Name
     *
     * @param    string        The name of the form class
     * @param    string        Any options for the form class constructor
     * @return   object        Form class object - forms_$formName
     */
    public function form($formName, $options = null) {
        $path = APP_DIR . "/application/forms/" . str_replace('_', '/', $formName) . '.php';
        require_once $path;
 
        $class = "Form_" . $formName;
        return new $class($this->_controllerAction, $options);
    }
 
    /**
     * Loads the requested form class.
     * When request method is post, form is loaded normally.
     * When it's not, cache is used to reduce CPU load.
     *
     * @param   string      The name of the form class
     * @param   string      Any options for the form class constructor
     *
     * @return  mixed       Form class object, or rendered form HTML when caching is active
     */
    public function formCached($formName, $options = null) {
       if ($this->_controllerAction->getRequest()->isPost()) {
           return $this->form($formName, $options);
       }
 
       if ($out = $this->_cache->load($id = $this->_getFormCacheId($formName, $options))) {
           return $out;
       }
 
       $form = $this->form($formName, $options);
       $this->_cache->save($out = $form->__toString(), $id, array(), 31536000);
 
       return $out;
    }
 
    /**
     * Generates the id used for the cache.  It must be unique for the name of the
     * form, and the options passed to it.
     *
     * @param   string      Form name used
     * @param   mixed       Array of options passed to form, or null
     *
     * @return  string      Unique ID for this form cache
     */
    protected function _getFormCacheId($formName, $options = null) {
       if ($options === null) {
           return "Form_$formName";
       }
 
       return 'Form_' . $formName . md5(serialize($options));
    }
}

Enabling Caching

This is generally how a basic form action looks like in my controllers.

public function postAction() {
    $form = $this->loader->form('Post_Create', $options = array());
 
    if ($this->_request->isPost()) {
        if ($form->isValid($this->_request->getPost())) {
            $post = $this->model->create($form->getValues());
            $this->redirector->goToUrl($post->getUrl());
        }
    }
 
 
    $this->view->form = $form;
}

With it enabled, we’d simply change

$this->loader->form()

to

$this->loader->formCached()

Since the only interaction with my form and view script is

<?= $this->form ?>

we don’t even have to change it. The form’s __toString method will work normally when the caching isn’t active, and the form variable is just a string when it is. Simple.

Recap

This will allow for the caching of your rendered ZF forms. It is disabled automatically when the request method is POST, so it can properly re-populate your data and/or show your errors. If you use the simple form renderings in your view scripts, then they will work as-is. This is all just a proof of concept that I am testing on a few sites at the moment. If you have any feedback or questions, don’t hesitate to let me know.

Forms in Zend Framework

I’m often asked what my favorite component of Zend Framework is, and I invariably answer: “Forms”. Forms have always played an awkward role in the model-view-controller paradigm. Sure, the form is just HTML, but to me, it represents something more abstract than that. It represents the HTML form itself, taking user input, normalizing and validating it, and also being able to show the form again when errors occur. This can take quite a large amount of code.

If you’re able to automate all of that stuff, then all you are really left with is configuration. Each form consists of elements, and each element has several attributes which modify the overall functionality of the form. Let’s look at some of these aspects.

Defining a Form

A form itself is an instance of Zend_Form. There are many ways to define one. I prefer to extend Zend_Form for each of my forms, and define them inside the class itself. Each form contains a few important fields (action, method) and also it contains at least one element. Let’s look at how we define an element. Each element probably has a few common attributes: a field type, a label, an element name, and a description. Let’s represent this element in ZF. Note, there are several different ways to represent forms. They can literally be done via configuration, or by a few different PHP methods. This is my favorite.

$username = new Zend_Form_Element_Text('username', array(
    'label'         => 'Username',
    'description'   => 'This is a description'
));

In the above code, you can see we define these three things. There are also some other important attributes for elements. Let’s add a few more, and show a few fields at once.

$this->addElements(array(
    new Zend_Form_Element_Text('username', array(
        'label' => 'Username',
        'required' => true
    )),
));

Filters and Validators

One very helpful feature with the forms component is the ability to chain filters and validators. A filter is something that automatically manipulates incoming data to your desired format, and a validator is something that is checked when processing the form. This greatly simplifies your controller code, and your model code, because you are shifting all of this logic into a much more organized structure.

For example, if you are working with a username element on a registration form, then you may want check that the user does not already exist, the username does not contain any illegal characters, and the username is within a desired length.

If you had an element where the user can enter a few paragraphs about himself, then you would want to apply some filters to make sure the data is clean. You may want to add things like StripTags to remove any HTML, StringTrim to remove any extra whitespace, etc. You could also apply some custom BBCode parsing filters if you wanted. You could create your own filter for this, or use the Callback filter which you can use for everything else.

The idea is to do as much validation as possible so you know that your data is 100% ready for your application. If you have a VARCHAR(255) field, then limit your string to 255 characters so nothing gets truncated. Be very strict.

Filters are more of a time saver to me… but they are nice because they help keep all the data very consistent or can also be part of your cleaning process. If you are allowing user input, then remove any HTML is necessary. You get the idea.

Here is a more complete example of a registration form definition:

$this->addElements(array(
    new Zend_Form_Element_Text('username', array(
        'label'        => 'Username',
        'required'     => true,
        'validators'   => array(
            array('StringLength',      false, array(4, 16)),
            array('Alnum'),
            array('Db_NoRecordExists', false, array('users', 'username'))
        )
    )),
    new Zend_Form_Element_Text('email', array(
        'label'        => 'Email Address',
        'required'     => true,
        'validators'   => array(
            array('EmailAddress'),
            array('Db_NoRecordExists', false, array('users', 'email'))
        )
    )),
    new Zend_Form_Element_Password('password', array(
        'label'        => 'Password',
        'required'     => true
    ))
));

Skinny Controller, Fat Model

With a form containing the fields above, we can really simplify our controller code. To me, controller’s should contain the flow of an application, without really performing any of the work. Here is an example of a registration action.

if ($this->_request->isPost()) {
    if ($form->isValid($this->_request->getPost())) {
        $user->register($form->getValues());
        $this->redirector->goToUrl('/welcome');
    }
}
 
$this->view->form = $form;

If the user has submitted (posted) any information, then the form validates that posted information. If it’s valid, it will proceed to pass the data array to our model. At this point, all of our filters and validators have been executed, so we know exactly how the data is formatted, and that it’s safe to use. We can proceed to redirect the user away, or perform any other flow logic we need to at this point.

We also pass the form to the view, which is crucial. On a regular page view, the form will be loaded normally. On a failed submission, then it will show the form with all of the error messages, and the posted data populated back into the form elements.

View Scripts & Decorators

Here is all the code we need in our view to show a form. The rest can be done via CSS, or custom decorators if we need it.

<?= $this->form ?>

By default, Zend_Form outputs a pretty usable chunk of HTML. I have no problems styling it via CSS which is really great for our separation of concerns. However, there will be times when you need markup in certain format, and Zend can handle this with decorators. They are a little tricky to learn, so I will save that for another blog post. There should be sufficient documentation on their website.

Dealing with Models

As per our controller code, the model would receive $form->getValues(), which would be a pre-validated and pre-filtered array of our data. Here is an example:

// ...
public function register(array $user) {
 
}
// ...

To me, this is beautiful. We are working with a very basic interface, and do not have to manually specify every value that we pass or expect. While this is personal taste, I cringe whenever I see people pass 5-10 values to a model. Their controllers all end up being huge. The code is also not dependent on our form, because it’s just dealing with an array of data. It makes calling our models very simple, too. The model is where the code should start to get complicated. From this point, we can use our database adapter object, or deal with several other libraries.

Summary

The form component is one of the larger (largest?) components in Zend. Don’t be afraid to ask for help on the different forums, or ask below and I can point you to a good resource. Like I said above, this is the most useful component in Zend to me, so if you are considering taking the time to learn how to use it, I strongly advise to do so.

You may also be interested in caching forms.