What

Validators are referenced in the schema.xml file and are rules that the data being inserted into that column must follow. You can also apply multiple rule entries per validator entry in the schema.xml file. Validators are applied at a PHP level, they are bound into the mutator functions of the created objects, they are not created as constraints on the database itself so be warned if you also use another language to work with the database that these will not be enforced when it is accessing the tables.

How

Here's a little code snippet to give you an idea of how to use validate(). Assuming we have a User object with for instance a minLength validator on it's username, with a minLength of 4. (See the minLength validator for an example of how to add such a Validator in your schema.xml)

$objUser = new User();
// Set a username with length 3, which is too short...
$objUser->setUsername("foo");

if ($objUser->validate()) {

    // we save it, since we get no validation errors, or do whatever else you like.
    $objUser->save(); 

} else {

    // Something went wrong. We can now get the validationFailures and handle them. 
    // For instance print the messages.
    $validationFailuresArray = $objUser->getValidationFailures();
    foreach($validationFailuresArray as $objValidationFailure) {

        echo $objValidationFailure->getMessage() . "<br />\n";

    }

}


Validators

Below you find a list of the Validators that currently exist in propel (1.1 and 1.2) and for each and example of how to use them.

  • MatchValidator
  • MaxLengthValidator
  • MaxValueValidator
  • MinLengthValidator
  • MinValueValidator
  • NotMatchValidator
  • RequiredValidator
  • UniqueValidator
  • ValidValuesValidator

MatchValidator

<validator column="username">
  <!-- allow strings that match the email adress pattern -->
  <rule
    name="match"
    value="/^([a-zA-Z0-9])+([\.a-zA-Z0-9_-])*@([a-zA-Z0-9])+(\.[a-zA-Z0-9_-]+)+$/"
    message="Please enter a valid email address." />
</validator>

The MatchValidator is used to run a regex of choice against the column. Note that this is a preg, not ereg. http://www.php.net/preg_match for more information about regex's.

MaxLengthValidator

<!-- LONGVARCHAR has length completely ignored by some databases -->
<column name="comment" type="LONGVARCHAR" required="true" />
<validator column="comment">
  <rule
    name="maxLength"
    value="1024"
    message="Comments can be no larger than ${value} in size" />
</validator>

Note that if you have specified the size attribute in the column tag you do not have to specify it as value in the validator rule again as this is done automatically.

MaxValueValidator

<column name="security_level" type="INTEGER" required="true" />
<validator column="security_level">
  <rule
    name="maxValue"
    value="1000"
    message="Maximum security level is ${value} !" />
</validator>

MinLengthValidator

<column name="username" type="VARCHAR" size="34" required="true" />
<validator column="username">
  <rule
    name="minLength"
    value="4"
    message="Username must be at least ${value} characters !" />
</validator>

MinValueValidator

<column name="cost" type="INTEGER" required="true" />
<validator column="cost">
  <rule
    name="minValue"
    value="0"
    message="Products can cost us negative $ can they?" />
</validator>

NotMatchValidator

<column name="ISBN" type="VARCHAR" size="20" required="true" />
<validator column="ISBN">
  <!-- disallow everything that's not a digit or minus -->
  <rule
    name="notMatch"
    value="/[^\d-]+/"
    message="Please enter a valid ISBN" />
</validator>

Opposite of match, if the regex would return true then this will return false.

RequiredValidator

<column name="username" type="VARCHAR" size="25" required="true" />
<validator column="username">
  <rule
    name="required"
    message="Username is required." />
</validator>

required=true on the column will do the same thing however it will not give you a clean error to work with, a validator error may be simpler for some people to work with.

UniqueValidator

<column name="username" type="VARCHAR" size="25" required="true" />
<validator column="username">
  <rule
    name="unique"
    message="Username already exists !" />
</validator>

Often you will want a unique-index not a unique validator.

ValidValuesValidator

<column name="address_type" type="VARCHAR" required="true" default="delivery" />
<validator column="address_type">
  <rule
    name="validValues"
    value="account|delivery"
    message="Please select a valid address type." />
</validator>

Allow any value out of a | delimited list

Combined Example

<column name="security_level" type="INTEGER" required="true" default="10" />
<validator column="security_level" translate="none">
  <rule
    name="minValue"
    value="0"
    message="Invalid security level, range: 0-10" />
  <rule
    name="maxValue"
    value="10"
    message="Invalid security level, range: 0-10" />
</validator>

As you can see, we can run multiple validators against a single column too

How to add your own Validator

Adding your own Validator is possible. There's just some things you have to keep in mind!! When adding your own validator do the following:

1. create your own Validator object. Do this by extending the BasicValidator.

require_once 'propel/validator/BasicValidator.php';

/**
 * A simple validator for email fields.
 * 
 * @package propel.validator
 */
class EmailValidator implements BasicValidator
{

        // Warning: Make sure this function returns a boolean! So either true of false. (Propel is very strict about this)
        // Doing this will save you a lot of frustration :P
	public function isValid (ValidatorMap $map, $str) {

		return preg_match("'^[a-z0-9_.=-]+@(?:[a-z0-9-]+\.)+([a-z]{2,4})\$'i", $str) !== 0;

	}
}

  • Again a warning: Make sure that isValid() returns a boolean, so really true or false. Propel is very strict about this. Returning a mixed value just won't do.

2. Edit your schema.xml and add your validator.

<validator column="<column_name>">
    <rule name="class" class="my.dir.EmailValidator" message="Invalid e-mail address!" />
</validator>

  • make sure you use name="class" and add the class= attribute.
  • the class attribute points to a directory (and then Object). It is vital that your php include_path is properly set, so my.dir.YourValidator can be included relatively from one of the dirs in your include_path.

Future working of validation (most likely)

In Propel 2.0, validation will probably be done in the save() function. Also there will be more Validators built-in! Here's a little wishlist.

  • EmailValidator
  • RangeValidator
  • LengthValidator
  • HexValidator/HashValidator
  • NoHTMLValidator
  • Others?

EmailValidator

This is a simplified and smart email validator with flags that can be set via the rule to decide how strenuously we test the address.

RangeValidator

Instead of MinValue and MaxValue on a single column, we RangeValidator it and have a single validator instead of two on that column.

LengthValidator

Same as RangeValidator but for string lengths.

HexValidator/HashValidator

Undecided if it should just be a basic hex test or if it should test that the input is a valid hash of a specific hash type. Possibly turn this into a HashValidator that knows to expect 0-9a-f and the correct character count for that type. If left as HexValidator then it's just testing for 0-9a-f of the character count it is told to expect.

NoHTMLValidator

Something to barf if html (safe or not) is present in a field.