views:

51

answers:

3

hi there

im am making a php validation class with sub classes that extend it, eg, mobile, suburb, credit_card, ect

so, the idea is you can call

$validation = new Validation('mobile');
$valid = $validation->validate($number);

$validation->type('suburb');
$valid2 = $validation->validate($suburb);

now my idea for doing this is having

class Validation() {
    private $v_type = null;

    function __construct($type) {
        $this->type($type);
    }

    public function type($type) {
        $this->v_type = new $type();
    }

    public function validate($info) {
        return $this->v_type->validate($info);
    }
}

as a very basic example

but is there a better way of doing this?

+1  A: 

Usually you do these kind of things using the Factory pattern, something like this:

class ValidatorFactory {
    public static function get($type) {
        $validator = "Validator_$type";
        return new $validator();
    }
}

$valid = ValidatorFactory::get('mobile')->validate($number);

Would of course need some error checking and such, but you should get the idea

Dennis Haarbrink
A: 
...
public function type($type) {
    return new self($type);
}
...

Note: This one every time returns a new instance of your Validator class so it would be a better idea to use the Factory pattern as Dennis suggested or not to tie the new Validator to the type() method.

fabrik
+1  A: 

You could do it this way, but it could be improved. Having the actual validators capsule their own validation logic is good. Extending them from a base class isn't. Let's implement an interface instead. This way, any class can be a Validator.

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

Your validators would look like this then:

class IsNumeric implements IValidate
{
    public function validate($value)
    {
        return is_numeric($value);
    }
}

and

class GreaterThan implements IValidate
{
    protected $_value;
    public function __construct($value)
    {
        $this->_value = $value;
    }
    public function validate($value)
    {
        return $value > $this->_value;
    }
}

You'd still have a main Validator class. Unlike in your example, the Validator below accepts multiple Validators, which will allow you to create a Filter Chain.

class Validator implements IValidate
{
    protected $_validators;

    public function addValidator(IValidate $validator)
    {
        $this->_validators[] = $validator;
        return $this;
    }
    public function validate($value)
    {
        foreach($this->_validators as $validator) {
            if ($validator->validate($value) === FALSE) {
                return FALSE;
            }
        }
        return TRUE;
    }
}

And this could be used like:

$validator = new Validator;
$validator->addValidator(new IsNumeric)
          ->addValidator(new GreaterThan(5));

var_dump( $validator->validate('ten') ); // FALSE
var_dump( $validator->validate('10') );  // TRUE
var_dump( $validator->validate('1') );   // FALSE

The above is pretty much a Command pattern. And due to the Validator implementing IValidate as well, it is also a Composite. You could take the Validator chain from above and stack it into another Validator Chain, e.g.

$numericGreaterThanFive = new Validator;
$numericGreaterThanFive->addValidator(new IsNumeric)
                       ->addValidator(new GreaterThan(5));

$otherValidator = new Validator;
$otherValidator->addValidator(new Foo)
               ->addValidator(new Bar)
               ->addValidator($numericGreatherThanFive);

For convenience, you could add a static factory method for creating Validators with the actual Validation Command objects (as shown elsewhere).

On a sidenote: the Zend Framework already has an extensive number of Validators you can build on. Since ZF is a component library, you can use them without having to migrate your entire application to ZF.

Gordon