I need a php validator class that validates user inputs.
I want it to be able to accept an assoc array of fields => values like:
array(
"username" => "Alex",
"email_address" => "@@#3423£alex@my.mail.com"
);
and then return an array of errors like this:
array(
"username" => "",
"email_address" => "Invalid Email Address"
);
But I'm really struggling on HOW the hell I'm going to do this!
I've read countless pages on PHP validators and read that the best way to do this is with the strategy pattern. But i dont know how??
Like... This is what I've got so far:
class Validator {
private
$_errors,
$_fields,
static private $_map = array (
"firstname" => "name",
"surname" => "name",
"agency_name" => "name",
"agency_office" => "name",
"username" => "username",
"email_address" => "email_address",
);
public function __construct( array $fields ) {
$this->_fields = $fields;
}
public function validate() {
foreach ( $this->_fields as $field => $value ) {
if ( method_exists( __CLASS__, self::$_map[$field] ) ) {
if ( in_array( $field, self::$_map ) ) {
$this->{self::$_map[$field]}( $field, $value );
}
}
else {
die( " Unable to validate field $field" );
}
}
}
public function get_errors() {
return $this->_errors;
}
private function name( $field, $value ) {
if ( !preg_match( "/^[a-zA-Z]{2,50}$/", $value ) ) {
$this->errors[$field] = "Invalid. Must be 2 to 50 alphanumerical characters";
}
}
private function username( $field, $value ) {
if ( !preg_match( "/^[a-zA-Z0-9_\-]{10,50}$/", $value ) ) {
$this->errors[$field] = "Invalid. Must be 10 to 50 characters. Can contain digits, characters, _ (underscore) and - (hyphen)";
}
}
private function password( $field, $value ) {
if ( !preg_match( "/^[a-zA-Z0-9\.\-]{8,30}$/", $value ) ) {
$this->_errors[$field] = "Invalid. Must be 8 to 30 characters. Can contain digits, characters, . (full stop) and - (hyphen)";
}
}
private function email_address( $field, $value ) {
if ( !filter_var( $value, FILTER_VALIDATE_EMAIL ) ) {
$this->_errors[$field] = "Invalid Email Address";
}
}
}
The problems with this is, it doesn't even consider database connections for like, already registered usernames,
Also is doesn't match passwords
I've just got coders block at the moment and its destroying me on the inside :(
Can anybody give a an explaination of the classes required and functions each class will need to do?
I really need the inputs and outputs to be in the format already explained though!
Thankyou Very Much Internet People!
As a part of the my MVC I have solved the same problem. I could give you a listing, but in a few lines try to describe how.
I got 3 base classes Form
, Validator
, Field
, each of object of this classes configuring through one YAML file, structured somehow like this:
name: // field name
i18n: [ ru, en ] // is the field i18n
field:
class: Base // class to use for field
options: { specific_save: true } // options from available (defined in class)
attributes: { } // attributes, for HTML rendering
validator:
class: String // Class to validate with
options: { required: true, max: 100 } // options for validator
So, lets start with Form
, when object is constructing the form takes the YAML file described above, and due to that configuration creates fields. Something like this:
// Imlement this function to configure form;
foreach ($this->_config as $f => $c)
{
$class = '\\Lighty\\Form\\Field\\' . (isset($c['field']['class']) && $c['field']['class'] ? $c['field']['class'] : 'Base');
$o = isset($c['field']['options']) && is_array($c['field']['options']) ? $c['field']['options'] : array();
$a = isset($c['field']['attributes']) && is_array($c['field']['attributes']) ? $c['field']['attributes'] : array();
$field = new $class($this, $o, $a);
$field->setName($f);
$class = '\\Lighty\\Form\\Validator\\' . (isset($c['validator']['class']) && $c['validator']['class'] ? $c['validator']['class'] : 'Base');
$o = isset($c['validator']['options']) && is_array($c['validator']['options']) ? $c['validator']['options'] : array();
$m = isset($c['validator']['messages']) && is_array($c['validator']['messages']) ? $c['validator']['messages'] : array();
$field->setValidator($validator = new $class($field, $o, $m));
if (isset($this->_options['default'][$f]))
{
$field->setValue($this->_options['default'][$f]);
}
if (isset($c['i18n']))
{
if (is_array($c['i18n']))
{
$field->setCultures($c['i18n']);
}
$field->setI18n((bool) $c['i18n']);
}
$this->addField($field);
So, now we have form with fields and validator for each field, then to validate I use this mechanism:
Form goes through each field, calling validate()
method,
Field (got the binded value) call validate($value)
method of binded Validator, passing the stored value. Inside this method Validator calls the validateOption()
method, in which there is a simple switch for each options, for example:
switch ($o)
{
case 'required':
$valid = $state && trim($value) != '' || !$state;
break;
default:
return \warning(sprintf('Undefined validator option "%s" in %s validator class', $o, get_class($this->getField()->getValidator())), null);
}
Here you can see validating on required option. If I need more validators, I extend class of the Base validator, defined few more options, and redefine validateOption()
, where in default
statement of the option's switch
put parent::validateOption()
. So specified options validates in new class, and old one in base validator Class.
If there any questions... You're welcome.