views:

150

answers:

3

I'm currently working on an OO PHP application. I have a class called validation which I would like to use to check all of the data submitted is valid, however I obviously need somewhere to define the rules for each property to be checked. At the moment, I'm using arrays during the construction of a new object. eg:

$this->name = array(
'maxlength' => 10,
'minlength' => 2,
'required' => true,
'value' => $namefromparameter
)

One array for each property.

I would then call a static method from the validation class which would carry out various checks depending on the values defined in each array.

Is there a more efficient way of doing this? Any advice appreciated. Thanks.

+3  A: 

I know the associative array is used commonly to configure things in PHP (it's called magic container pattern and is considered bad practice, btw), but why don't you create multiple validator classes instead, each of which able to handle one rule? Something like this:

interface IValidator {
    public function validate($value);
}

$validators[] = new StringLengthValidator(2, 10);
$validators[] = new NotNollValidator();
$validators[] = new UsernameDoesNotExistValidator();

This has multiple advantages over the implementation using arrays:

  • You can document them (very important), phpdoc cannot parse comments for array keys.
  • Your code becomes typo-safe (array('reqiured' => true))
  • It is fully OO and does not introduce new concepts
  • It is more readable (although much more verbose)
  • The implementation of each constraint can be found intuitively (it's not in a 400-line function, but in the proper class)

EDIT: Here is a link to an answer I gave to a different question, but that is mostly applicable to this one as well.

soulmerge
Good point there with the documentation!
Gergely Orosz
Thanks, I had not heard of interfaces before. I'll check them out!
Dan
A: 

Since using OO it would be cleaner if you used classes for validating properties. E.g.

class StringProperty
{
  public $maxLength;
  public $minlength;
  public $required;
  public $value;
  function __construct($value,$maxLength,$minLength,$required)
  {
     $this->value = $value;
     $this-> maxLength = $maxLength;
     $this-> minLength = $minLength;
     $this-> required = $required;
  }
  function isValidat()
  {
    // Check if it is valid
  }
  function getValidationErrorMessage()
  {
  }
}

$this->name = new StringProperty($namefromparameter,10,2,true);
if(!$this->name->isValid())
{
  $validationMessage = $this->name-getValidationErrorMessage();
}

Using a class has the advantage of encapsulating logic inside of it that the array (basically a structure) does not have.

Gergely Orosz
A: 

Maybe get inspired by Zend-Framework Validation.

So define a master:

class BaseValidator {
    protected $msgs = array();
    protected $params = array();    

    abstract function isValid($value);
    public function __CONSTRUCT($_params) {
         $this->params = $_params;
    }
    public function getMessages() {
         // returns errors-messages
         return $this->msgs;
    }
}

And then build your custom validators:

class EmailValidator extends BaseValidator {
    public function isValid($val=null) {
        // if no value set use the params['value']
        if ($val==null) {
            $val = $this->params['value'];
        }
        // validate the value
        if (strlen($val) < $this->params['maxlength']) {
            $this->msgs[] = 'Length too short';
        }
        return count($this->msgs) > 0 ? false : true;   
    }
}

Finally your inital array could become something like:

$this->name = new EmailValidator(
        array(
            'maxlength' => 10,
            'minlength' => 2,
            'required' => true,
            'value' => $namefromparameter,
        ),
    ),
);

validation could then be done like this:

if ($this->name->isValid()) {
    echo 'everything fine';
} else {
    echo 'Error: '.implode('<br/>', $this->name->getMessages());
}
justastefan