diff --git a/include.forms.php b/include.forms.php index 42b0f88..2099a03 100644 --- a/include.forms.php +++ b/include.forms.php @@ -26,122 +26,243 @@ class FormValidationException extends Exception { } } -class CPHPFormValidator +class ImmediateAbort extends FormValidationException { } + +class CPHPFormValidatorPromiseBaseClass { - public function GenerateResultObject($failed, $critical) + public $previous = null; + public $next = null; + + public function __construct($creator) { - if($failed === true && $critical === true) + $this->previous = $creator; + } + + public function StartResolve() + { + /* Back and forth! */ + if(is_null($this->previous) === true) { - $object = new CPHPFormValidatorAbort(); + $this->next->ContinueResolve(array()); } else { - $object = new CPHPFormValidatorResult(); + $this->previous->StartResolve(); + } + } + + public function ContinueResolve($results) + { + $own_result = $this->Resolve($results); + + if(is_null($own_result) === false) + { + $results[] = $own_result; } - $object->handler = $this->handler; - return $object; + if(is_null($this->next) === false) + { + $this->next->ContinueResolve($results); + } + else + { + $this->ValidationFinished($results); + } + } + + public function ValidationFinished($results) + { + if(count($results) > 0) + { + throw new FormValidationException("One or more validation steps failed.", $results); + } } + public function Done() + { + /* Trigger validation routine */ + try + { + $this->StartResolve(); + } + catch (ImmediateAbort $e) + { + throw new FormValidationException("A critical validation step failed.", $e->exceptions); + } + } + + /* Operators */ + public function Either($error_message) + { + $this->next = new CPHPFormValidatorOperatorEither($this, $error_message, array_slice(func_get_args(), 1)); + return $this->next; + } + + public function All($error_message) + { + $this->next = new CPHPFormValidatorOperatorAll($this, $error_message, array_slice(func_get_args(), 1)); + return $this->next; + } + + /* Validators */ public function RequireKey($key, $critical = false) { - return $this->ProcessSingleValidationResult($key, (!isset($this->handler->formdata[$key])), "required", "A value is required for this field.", $critical); + $this->next = new CPHPFormValidatorPromise($this, $this->handler, $key, array(), "required", "A value is required for this field.", $critical, function($key, $value, $args, $handler){ + return isset($handler->formdata[$key]); + }); + return $this->next; } public function ValidateEmail($key, $critical = false) { - return $this->ProcessValidation($key, function($key, $value){ + $this->next = new CPHPFormValidatorPromise($this, $this->handler, $key, array(), "email", "The value is not a valid e-mail address.", $critical, function($key, $value, $args, $handler){ return filter_var($value, FILTER_VALIDATE_EMAIL) !== false; - }, "email", "The value is not a valid e-mail address.", $critical); + }); + return $this->next; + } +} + +class CPHPFormValidatorPromise extends CPHPFormValidatorPromiseBaseClass +{ + public function __construct($creator, $handler, $key, $args, $error_type, $error_message, $critical, $function) + { + parent::__construct($creator); + $this->key = $key; + $this->func = $function; + $this->args = $args; + $this->error_type = $error_type; + $this->error_message = $error_message; + $this->critical = $critical; + $this->handler = $handler; } - public function ProcessValidation($key, $validator, $error_type, $error_message, $critical) + public function Resolve($results) { - if(is_array($this->handler->formdata[$key])) + $func = $this->func; /* WTF PHP? Why can't I call $this->func directly? */ + + $exceptions = array(); + + $values = isset($this->handler->formdata[$this->key]) ? $this->handler->formdata[$this->key] : null; + + if(is_array($values) === true) { - foreach($this->handler->formdata[$key] as $i => $value) + /* Array */ + foreach($values as $i => $value) { - $result = $validator($key, $this->handler->formdata[$key], $this->handler); - $return_object = $this->ProcessArrayValueValidationResult($key, $i, $result, $error_type, $error_message, $critical); - - if($result !== true && $critical === true) + if($func($this->key, $value, $this->args, $this->handler) !== true) { - return $return_object; + $exceptions[] = array( + "type" => "array_value", + "key" => $this->key, + "index" => $i, + "error_type" => $this->error_type, + "error_msg" => $this->error_message + ); } } - - return $return_object; } else { - $result = $validator($key, $this->handler->formdata[$key], $this->handler); - return $this->ProcessSingleValidationResult($key, $result, $error_type, $error_message, $critical); - } - } - - public function ProcessSingleValidationResult($key, $result, $error_type, $error_message, $critical) - { - if($result === false) - { - $this->handler->StoreValidationException(array( - "type" => "single", - "key" => $key, - "error_type" => $error_type, - "error_msg" => $error_message - )); - $failed = true; + /* Single value */ + if($func($this->key, $values, $this->args, $this->handler) !== true) + { + $exceptions[] = array( + "type" => "single", + "key" => $this->key, + "error_type" => $this->error_type, + "error_msg" => $this->error_message + ); + } } - else + + if(count($exceptions) > 0 && $this->critical === true) { - $failed = false; + $results[] = $exceptions; + throw new ImmediateAbort("Critical validation did not pass.", $results); } - return $this->GenerateResultObject($failed, $critical); - } - - public function ProcessArrayValueValidationResult($key, $i, $result, $error_type, $error_message, $critical) - { - if($result === false) + if(count($exceptions) == 0) { - $this->handler->StoreValidationException(array( - "type" => "array_value", - "key" => $key, - "index" => $i, - "error_type" => $error_type, - "error_msg" => $error_message - ), $this); - $failed = true; + return null; } else { - $failed = false; + return $exceptions; } - - return $this->GenerateResultObject($failed, $critical); } - - public function Done() - { - $this->handler->RaiseValidationExceptions(false); - } - - public function Either() +} + +class CPHPFormValidatorOperator extends CPHPFormValidatorPromiseBaseClass +{ + public function __construct($creator, $error_message, $children) { - $statements = + parent::__construct($creator); + $this->error_message = $error_message; + $this->children = $children; } - - public function All() +} + +class CPHPFormValidatorOperatorEither extends CPHPFormValidatorOperator +{ + public function Resolve($results) { + $exceptions = array(); + foreach($this->children as $child) + { + $result = $child->Resolve(); + if(is_null($result) === false) + { + $exceptions[] = $result; + } + } + if(count($exceptions) == count($this->children)) + { + $exceptions[] = array( + "type" => "operator", + "error_type" => "either", + "error_msg" => $this->error_message, + "children" => $exceptions + ); + } + else + { + return null; + } } - - public function ValidateIf($condition, $validation) +} + +class CPHPFormValidatorOperatorAll extends CPHPFormValidatorOperator +{ + public function Resolve($results) { + $exceptions = array(); + foreach($this->children as $child) + { + $result = $child->Resolve($results); + if(is_null($result) === false) + { + $exceptions[] = $result; + } + } + if(count($exceptions) > 0) + { + $exceptions[] = array( + "type" => "operator", + "error_type" => "both", + "error_msg" => $this->error_message, + "children" => $exceptions + ); + } + else + { + return null; + } } } -class CPHPFormHandler extends CPHPFormValidator +class CPHPFormHandler extends CPHPFormValidatorPromiseBaseClass { public function __construct($formdata = null, $no_csrf = false) { @@ -257,21 +378,3 @@ class CPHPFormHandler extends CPHPFormValidator } } } - -class CPHPFormValidatorResult extends CPHPFormValidator -{ - -} - -class CPHPFormValidatorAbort -{ - public function Abort() - { - $this->handler->RaiseValidationExceptions(true); - } - - public function __get($anything) - { - return $this->Abort; - } -}