loading...

How do you write your PHP validator?

mofiqul profile image Mofiqul Islam ・1 min read

I recently started to write an MVC framework in PHP for the better understanding of object-oriented design and how the framework works. Today I was writing a validator for the MVC. I was wondering if there is are better ways to do than what I did.

Here is my validator class

class Validator{

    private $_errors = [];


    public function validate($src, $rules = [] ){

        foreach($src as $item => $item_value){
            if(key_exists($item, $rules)){
                foreach($rules[$item] as $rule => $rule_value){

                    if(is_int($rule))
                         $rule = $rule_value;

                    switch ($rule){
                        case 'required':
                        if(empty($item_value) && $rule_value){
                            $this->addError($item,ucwords($item). ' required');
                        }
                        break;

                        case 'minLen':
                        if(strlen($item_value) < $rule_value){
                            $this->addError($item, ucwords($item). ' should be minimum '.$rule_value. ' characters');
                        }       
                        break;

                        case 'maxLen':
                        if(strlen($item_value) > $rule_value){
                            $this->addError($item, ucwords($item). ' should be maximum '.$rule_value. ' characters');
                        }
                        break;

                        case 'numeric':
                        if(!ctype_digit($item_value) && $rule_value){
                            $this->addError($item, ucwords($item). ' should be numeric');
                        }
                        break;
                        case 'alpha':
                        if(!ctype_alpha($item_value) && $rule_value){
                            $this->addError($item, ucwords($item). ' should be alphabetic characters');
                        }
                    }
                }
            }
        }    
    }

    private function addError($item, $error){
        $this->_errors[$item][] = $error;
    }


    public function error(){
        if(empty($this->_errors)) return false;
        return $this->_errors;
    }
}

Now testing the validator.

$data = ['username' => '', 'password' => 'pass'];
$rules = [
    'username' => ['required', 'minLen' => 6,'maxLen' => 150, 'alpha'],
    'password' => ['required', 'minLen' => 8]
];
$v = new Validator();
$v->validate($data, $rules);
if($v->error()){
    print_r($v->error());
} else{
    echo 'Ok';
}

Result

Array
(
    [username] => Array
        (
            [0] => Username required
            [1] => Username should be minimum 6 characters
            [2] => Username should be alphabetic characters
        )

    [password] => Array
        (
            [0] => Password should be minimum 8 characters
        )

)

Discussion

pic
Editor guide
Collapse
bernhardwebstudio profile image
Bernhard Webstudio

Good start! You have courage to throw yourself into the wild. Don't take the rest of my comment too hard, and also with a grain of salt, everyone is always learning, and probably someone would/will be able to correct me.

I am suggesting the following, as you are writing a framework with the purpose to learn about OOP:

  1. It is becoming a framework? Make more frames! In this case, such things as a ValidatorInterface as well as a RuleInterface would open up for edge cases and extensions.
  2. The RuleInterface (and the corresponding instances, such as a RequiredRule, NumericRule, ...) would have methods validate($src) or isValid($src) with getErrorMessage(). This way, you can easily extend the validator to use sometimes more, sometimes less rules, as well as easily add a new rule without having to change array structures etc. just to add a new setting. Also, you get rid of the "ugly" switch statement.
  3. A ValidatorInterface will open up possibilities to validate not only forms or arrays. With a ValidatorInterface, you can easily implement other Validators, such as a silent validator. If you want to, you could get rid of the for/foreach loups by using Iterators, ValidatorGroups or similar.
  4. There is a variety of design patterns suitable for constructing the validator and injecting the corresponding rules: (Abstract) Factory, Builder, Prototype, Singleton, just to name the ones coming to my mind. Choose the one you use in the rest of the framework or suits your application best.
  5. Set yourself some sort of code limits, e.g. method max-lenght: 15 lines. This way, you will not even start to write switch statements as the one in your code, where other patterns are better readable and easier to maintain.

I kinda left not much of your code as is, sorry for that. I could even go on and suggest to abstract the input too, to a ValidatableInterface where you can set the errors on the input itself to get rid of complicated x-dimensional arrays. But that is gonna blow this already exploded comment up. I repeat: take my suggestions with a grain of salt, I can learn too.

One other suggestion: read on design patterns (classic: ISBN 0-201-63361-2), it will change your code style for good. Or bad, as you will realize as soon as you are lost in a jungle of interfaces and abstract classes ;)

Also, if you want to know how others do, compare with already established frameworks, such as Symfony or CakePHP, they use Validators too.

Collapse
aleksikauppila profile image
Aleksi Kauppila

Good take.

Imo arrays generally are something that are better used as internal representation of data. In OOP, objects communicate with each others interfaces.

It's useful just to avoid using (or hide usage of) some language features to make more OO designs.

Collapse
adhocore profile image
Jitendra Adhikari

i think you can leverage webmozart/assert library 😇

Collapse
turalesger profile image
Tural

Thank you very much. I got the idea and implemented that in my framework.