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
)
)
Top comments (5)
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:
ValidatorInterface
as well as aRuleInterface
would open up for edge cases and extensions.validate($src)
orisValid($src)
withgetErrorMessage()
. 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.for
/foreach
loups by using Iterators, ValidatorGroups or similar.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.
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.
If you wish allow spaces in alpha types, just change at line 41 for this using str_replace
case 'alpha':
if(!ctype_alpha(str_replace(' ', '', $item_value)) && $rule_value){
$this->addError($item, ucwords($item). ' should be alphabetic characters');
}
or create a new type in switch case
Thanks for you code man!!!!!
i think you can leverage webmozart/assert library π
Thank you very much. I got the idea and implemented that in my framework.