Effective Data Validation
- by John Conde
What's an effective way to handle data validation, say, from a form submission?
Originally I had a bunch of if statements that checked each value and collected invalid values in an array for later retrieval (and listing).
// Store errors here
$errors = array();
// Hypothetical check if a string is alphanumeric
if (!preg_match('/^[a-z\d]+$/i', $fieldvalue))
{
$errors[$fieldname] = 'Please only use letters and numbers for your street address';
}
// etc...
What I did next was create a class that handles various data validation scenarios and store the results in an internal array. After data validation was complete I would check to see if any errors occurred and handle accordingly:
class Validation
{
private $errorList = array();
public function isAlphaNumeric($string, $field, $msg = '')
{
if (!preg_match('/^[a-z\d]+$/i', $string))
{
$this->errorList[$field] = $msg;
}
}
// more methods here
public function creditCard($cardNumber, $field, $msg = '')
{
// Validate credit card number
}
// more methods here
public function hasErrors()
{
return count($this->errorList);
}
}
/* Client code */
$validate = new Validation();
$validate->isAlphaNumeric($fieldvalue1, $fieldname1, 'Please only use letters and numbers for your street address');
$validate->creditCard($fieldvalue2, $fieldname2, 'Please enter a valid credit card number');
if ($validate->hasErrors())
{
// Handle as appropriate
}
Naturally it didn't take long before this class became bloated with the virtually unlimited types of data to be validated. What I'm doing now is using decorators to separate the different types of data into their own classes and call them only when needed leaving generic validations (i.e. isAlphaNumeric()) in the base class:
class Validation
{
private $errorList = array();
public function isAlphaNumeric($string, $field, $msg = '')
{
if (!preg_match('/^[a-z\d]+$/i', $string))
{
$this->errorList[$field] = $msg;
}
}
// more generic methods here
public function setError($field, $msg = '')
{
$this->errorList[$field] = $msg;
}
public function hasErrors()
{
return count($this->errorList);
}
}
class ValidationCreditCard
{
protected $validate;
public function __construct(Validation $validate)
{
$this->validate = $validate;
}
public function creditCard($cardNumber, $field, $msg = '')
{
// Do validation
// ...
// if there is an error
$this->validate->setError($field, $msg);
}
// more methods here
}
/* Client code */
$validate = new Validation();
$validate->isAlphaNumeric($fieldvalue, $fieldname, 'Please only use letters and numbers for your street address');
$validateCC = new ValidationCreditCard($validate);
$validateCC->creditCard($fieldvalue2, $fieldname2, 'Please enter a valid credit card number');
if ($validate->hasErrors())
{
// Handle as appropriate
}
Am I on the right track? Or did I just complicate data validation more then I needed to?