As always, before I get my hands dirty and show how to build a flexible program that permits us to create different validation strategies at run time using all of the classes built in previous installments of the series, it'd be useful to recall how these classes looked. So first, here's the definition of a trivial form helper. Via its "addValidator()" method, it will take a predefined set of data checking objects, handy for setting up different validation strategies on the fly. Take a peek at it: (FormHelper.php) <?php class FormHelper { protected $_validators = array(); protected $_errors = array();
// add a validator public function addValidator(AbstractValidator $validator) { $this->_validators[] = $validator; return $this; }
// get all the validators public function getValidators() { return !empty($this->_validators) ? $this->_validators : null; }
// validate inputted data public function validate() { $validators = $this->getValidators(); if (null !== $validators) { foreach ($validators as $validator) { if (!$validator->validate()) { $this->_errors[] = $validator->getFormattedError(); } } } return empty($this->_errors) ? true : false; }
// get validation errors as an array public function getErrors() { return $this->_errors; }
// get validation errors as a string public function getErrorString() { $errors = $this->getErrors(); return !empty($errors) ? implode('', $errors) : ''; }
// clear state of the form helper public function clear() { $this->_validators = array(); $this->_errors = array(); } } As you can see, the "FormHelper" class behaves like a container that houses different validation objects eventually injected via its "addValidator()" method. Once these objects are stored on the protected $_validators property, they're used internally to check whether or not the supplied data is valid. Of course, you'll understand the inner workings of this process much better when I show you a functional example, so pay attention to the following class, which defines the structure and behavior of generic validation objects: (AbstractValidator.php) <?php abstract class AbstractValidator { protected $_value = ''; protected $_filter = ''; protected $_options = null; protected $_errorMessage = ''; protected $_errorPrefix = '<p>'; protected $_errorSufix = '</p>';
// constructor public function __construct($value, array $options = null) { $this->_value = $value; if (null !== $options) { $this->setOptions($options); } }
// get supplied value public function getValue() { return $this->_value; }
// set validation options public function setOptions(array $options) { if (empty($options)) { throw new ValidatorException('Invalid options for the validator.'); } $this->_options = $options; }
// get validation options public function getOptions() { return $this->_options; }
// set the validation filter public function setFilter($filter) { if (!is_string($filter)) { throw new ValidatorException('Invalid filter for the validator.'); } $this->_filter = $filter; }
// get the validation filter public function getFilter() { return $this->_filter; }
// set the error message public function setErrorMessage($errorMessage) { if (!is_string($errorMessage)) { throw new ValidatorException('Invalid error message for the validator.'); } $this->_errorMessage = $errorMessage; }
// get error message public function getErrorMessage() { return $this->_errorMessage; }
// get formatted error string public function getFormattedError() { return $this->_errorPrefix . 'The value ' . $this->getValue() . ' is incorrect. ' . $this->getErrorMessage() . $this->_errorSufix; }
// validate the supplied value public function validate() { return filter_var($this->getValue(), $this->getFilter(), $this->getOptions()); } } (ValidatorException.php) <?php class ValidatorException extends Exception{} As you can see, this class validates a value passed to its constructor by using a specific PHP filter. This can be easily understood by analyzing the implementation of the class' "validate()" method, which is merely a proxy for the built-in PHP "filter_var()" function. Do you understand the logic behind this abstract validator? Great. Now, take a look at the following concrete classes, which are refined implementations of their abstract parent and can be used for checking integers, float numbers, email addresses and URLs by simply overriding a couple of inherited properties. Here they are: (IntegerValidator.php) <?php class IntegerValidator extends AbstractValidator { protected $_filter = FILTER_VALIDATE_INT; protected $_errorMessage = 'Please enter an integer value.'; } (FloatValidator.php) <?php class FloatValidator extends AbstractValidator { protected $_filter = FILTER_VALIDATE_FLOAT; protected $_errorMessage = 'Please enter a float value.'; } (EmailValidator.php) <?php class EmailValidator extends AbstractValidator { protected $_filter = FILTER_VALIDATE_EMAIL; protected $_errorMessage = 'Please enter a valid email address.'; } (UrlValidator.php) <?php class UrlValidator extends AbstractValidator { protected $_filter = FILTER_VALIDATE_URL; protected $_errorMessage = 'Please enter a valid URL.'; }
Done. At this point it's clear to see that defining concrete subclasses that can be used for validating a specific type of data is a breeze. Of course, I could go on and on creating more validators, but that would be a waste of time, as the four we have now are enough to demonstrate how to set up distinct validation strategies at run time. Now that we've reviewed all of the sample classes developed so far, the next step is to put these elements to work together. This way you can see how easy it is to validate incoming data using the set of strategy classes just analyzed. This will be done in the coming section. So click on the link below and keep reading.
blog comments powered by Disqus |
|
|
|
|
|
|
|