Model validations with Zend & Doctrine

Posted by hobodave, Thu Jul 17 14:15:00 UTC 2008

In working with with Doctrine I found the built-in validations (Doctrine_Validator) to be sorely lacking. Specifically, there is no capability to define custom error messages. The doctrine validators work on the concept of ‘error codes’ which are totally vague, and not very useful.

Meanwhile Zend Framework does it’s validations in something called Zend_Form. I don’t currently use Zend_Form, and personally don’t believe validations belong in a ‘Form’ object, but in the model itself.

Thus I rolled together something I dub Hobo_Validator. Please help yourself to my implementation, and modify it as you see fit. You can find it hosted at my github. I suggest cloning the git tree via:

git clone git://github.com/hobodave/hobo_validator.git

To use, first enable the validation in a manner similar to the following (you will need to use your own condition for the if statement):


// Use your OWN conditional :)
if(dConfig::get('server_validation')) {
    Zend_Registry::set(Hobo::ATTR_VALIDATE, Hobo::VALIDATE_ALL);
} else {
    Zend_Registry::set(Hobo::ATTR_VALIDATE, Hobo::VALIDATE_NONE);
}

Then, you simply add the required validations in the construct() ( NOT: __construct ) method of your Hobo_Record models. e.g.


public function construct() {
    $this->_validator = new Hobo_Validator($this);
    $this->addValidation(explode(' ', 'requestor company_id requestor_email requestor_phone'), 'notBlank');
    $this->addValidation('age', 'greaterThan', array('params' => array(21));

The default validators provided are listed below, as well as their associated default error messages.


/**
 * Default error messages.
 * 
 *
 * @var array
 **/
protected static $_defaultErrorMessages = array(
    'inclusion'    => 'is not included in the list',
    'exclusion'    => 'is reserved',
    'invalid'      => 'is invalid',
    'notEmpty'     => "can't be empty",
    'notBlank'     => "can't be blank",
    'tooLong'      => "is too long (maximum is %d characters)",
    'tooShort'     => "is too short (minimum is %d characters)",
    'length'       => "is the wrong length (should be %d characters)",
    'notTaken'     => 'has already been taken',
    'notNumber'    => 'is not a number',
    'notOdd'       => 'must be odd',
    'notEven'      => 'must be even',
    'greaterThan'  => "must be greater than %d",
    'lessThan'     => "must be less than %d",
    'greaterThanOrEqualTo' => "must be greater than or equal to %d",
    'lessThanOrEqualTo'    => "must be less than or equal to %d" 
    );

The intent and scope of the Hobo_Validator is to provide a set of ‘core’ validations, those that are mostly likely to be used, as well as a method to roll your own.

To write your own custom validations, simply override the validate(), validateOnInsert(), or validateOnUpdate() methods in your models. For example, in my Files model (stores files in db) I use the following custom validate() method. This particular validation was copied/inspired by Rob Allan in his Zend_Form File Upload Example.


/**
 *
 * @return void
 * @author David Abdemoulaie
 **/
public function validate()
{
    $value = $this->_file;
    $error = UPLOAD_ERR_NO_FILE;

    if (is_array($value) && array_key_exists('error', $value)) {
        $error = $value['error'];
    }

    $result = false;
    switch ($error) {
        case UPLOAD_ERR_OK:
            $result = true;
            break;

        case UPLOAD_ERR_NO_FILE:
            $this->getErrors()->addToBase(self::$_errorMessages[self::NO_FILE]);
            break;

        case UPLOAD_ERR_INI_SIZE:
            $this->getErrors()->addToBase(self::$_errorMessages[self::INI_SIZE]);
            break;

        case UPLOAD_ERR_FORM_SIZE:
            $this->getErrors()->addToBase(self::$_errorMessages[self::FORM_SIZE]);
            break;

        case UPLOAD_ERR_PARTIAL:
            $this->getErrors()->addToBase(self::$_errorMessages[self::PARTIAL]);
            break;

        case UPLOAD_ERR_NO_TMP_DIR:
            $this->getErrors()->addToBase(self::$_errorMessages[self::NO_TMP_DIR]);
            break;

        case UPLOAD_ERR_CANT_WRITE:
            $this->getErrors()->addToBase(self::$_errorMessages[self::CANT_WRITE]);
            break;

        case UPLOAD_ERR_EXTENSION:
            $this->getErrors()->addToBase(self::$_errorMessages[self::EXTENSION]);
            break;

        default:
            $this->getErrors()->addToBase(self::$_errorMessages[self::ERROR]);
            break;
    }
    return $result;
}

I’ll be updating this post periodically with further examples, as well as providing additional examples in the README.

Filed Under: PHP | Tags:

Comments

  1. tumeNulse 09.28.08 / 05AM
    nice work, brother

Have your say

A name is required. You may use HTML in your comments.