From b0fd14cd71d60c1b9926aff10fe9e8eeebe1285c Mon Sep 17 00:00:00 2001 From: Asko Nomm Date: Tue, 22 Feb 2022 21:32:37 +0100 Subject: Lots of documentation and basic tests --- src/Bouncer.php | 205 +++++++++++++++++++++++++++++++++++ src/Validator.php | 175 ------------------------------ src/Validators.php | 68 ------------ src/Validators/EmailValidator.php | 37 +++++++ src/Validators/LenValidator.php | 46 ++++++++ src/Validators/RequiredValidator.php | 37 +++++++ src/Validators/Validator.php | 9 ++ 7 files changed, 334 insertions(+), 243 deletions(-) create mode 100644 src/Bouncer.php delete mode 100644 src/Validator.php delete mode 100644 src/Validators.php create mode 100644 src/Validators/EmailValidator.php create mode 100644 src/Validators/LenValidator.php create mode 100644 src/Validators/RequiredValidator.php create mode 100644 src/Validators/Validator.php (limited to 'src') diff --git a/src/Bouncer.php b/src/Bouncer.php new file mode 100644 index 0000000..9c16b52 --- /dev/null +++ b/src/Bouncer.php @@ -0,0 +1,205 @@ + 'asko@bien.ee']; + * $rules = ['email' => 'required|email']; + * $bouncer = new Bouncer($fields, $rules); + * + * if ($bouncer->fails()) { + * return $bouncer->errors(); + * } + * ``` + * + * If you want to implement your own validators then simply create + * a data structure that looks like this: + * + * ```php + * // Create the validator + * $validator = [ + * 'error' => function(string $field, $modifier): string { + * return "${field} had some sort of an error."; + * }, + * 'validates' => function(string $value, $modifier): bool { + * // validate your $value here and return true if + * // the validation succeeded, or false if there was + * // an error, in which case the rule's error will be + * // added to the array of errors used by Bouncer. + * } + * ]; + * + * // Add validator to Bouncer + * $bouncer = new Bouncer($fields, $rules, [ + * 'rule-name' => $validator + * ]); + * ``` + * + * If you want to also use the default validators, and add yours as an extra, + * simply join the array of your validators with the array that you get from + * `$bouncer->defaultValidators()`, for example: + * + * ```php + * $validators = [ + * ...$this->defaultValidators(), + * 'rule-name' => $validator, + * ]); + * + * $bouncer = new Bouncer($fields, $rules, $validators); + * ``` + * + * Additionally, you can register your own validators via the + * `$bouncer->registerValidator` function like this: + * + * ```php + * $bouncer->registerValidator('rule-name', $validator]); + * ``` + * + * @author Asko Nomm + */ +class Bouncer +{ + private array $errors = []; + private array $validators = []; + + public function __construct( + private array $fields, + private array $rules, + ) { + $this->registerDefaultValidators(); + $this->validate(); + } + + /** + * Registers the default, built-in validators. + * + * @return array + */ + public function registerDefaultValidators(): void + { + $this->registerValidator('len', (new LenValidator)); + $this->registerValidator('email', (new EmailValidator)); + $this->registerValidator('required', (new RequiredValidator)); + } + + /** + * Registers a validator to a `$ruleName`. + * + * @param string $ruleName + * @param Validator $validator + * @return void + */ + public function registerValidator(string $ruleName, Validator $validator): void + { + $this->validators[$ruleName] = $validator; + } + + /** + * Removes a validator assigned to the `$ruleName`. + * + * @param string $ruleName + * @return void + */ + public function removeValidator(string $ruleName): void + { + unset($this->validators[$ruleName]); + } + + /** + * Runs `$this->rules` over `$this->fields` to construct + * potential errors that will be stored as an array of strings + * in `$this->errors`. + * + * @return void + */ + private function validate(): void + { + foreach ($this->rules as $field => $rule) { + $value = $this->fields[$field]; + + foreach (explode('|', $rule) as $item) { + if (str_contains($item, ':')) { + [$name, $modifier] = explode(':', $item); + + if (!$this->validators[$name]->validate($value, $modifier)) { + $this->errors[] = $this->validators[$name]->composeError($field, $modifier); + } + } else { + if (!$this->validators[$item]->validate($value)) { + $this->errors[] = $this->validators[$item]->composeError($field); + } + } + } + } + } + + /** + * Returns a boolean `true` if there have been any errors. + * Returns `false` otherwise. + * + * @return boolean + */ + public function fails(): bool + { + return count($this->errors) !== 0; + } + + /** + * Returns an array of strings where each string + * is a single error that happened during validation. + * + * @return array + */ + public function errors(): array + { + return $this->errors; + } + + /** + * If errors are present, returns the first one. + * Otherwise returns an empty string. + * + * @return string + */ + public function firstError(): string + { + if (count($this->errors) > 0) { + return $this->errors[0]; + } + + return ''; + } +} diff --git a/src/Validator.php b/src/Validator.php deleted file mode 100644 index 72ae8ee..0000000 --- a/src/Validator.php +++ /dev/null @@ -1,175 +0,0 @@ - 'asko@bien.ee']; - * $rules = ['email' => 'required|email']; - * $validator = new Validator($fields, $rules); - * - * if ($validator->fails()) { - * return $validator->errors(); - * } - * ``` - * - * If you want to implement your own validators then simply create - * a data structure that looks like this: - * - * ```php - * // Create the validator - * $validator = [ - * 'error' => function(string $field, $modifier): string { - * return "${field} had some sort of an error."; - * }, - * 'validates' => function(string $value, $modifier): bool { - * // validate your $value here and return true if - * // the validation succeeded, or false if there was - * // an error, in which case the rule's error will be - * // added to the array of errors used by Validator. - * } - * ]; - * - * // Add validator to Validator - * $validator = new Validator($fields, $rules, [ - * 'rule-name' => $validator - * ]); - * ``` - * - * If you want to also use the default validators, and add yours as an extra, - * simply join the array of your validators with the array that you get from - * `$validator->defaultValidators()`, for example: - * - * ```php - * $validators = [ - * ...$this->defaultValidators(), - * 'rule-name' => $validator, - * ]); - * - * $validator = new Validator($fields, $rules, $validators); - * ``` - * @author Asko Nomm - */ -class Validator -{ - private array $errors = []; - - public function __construct( - private array $fields, - private array $rules, - array $validators = [], - ) { - if (empty($validators)) { - $this->validators = $this->defaultValidators(); - } - - $this->validate(); - } - - /** - * Returns the default, built-in validators. - * - * @return array - */ - public function defaultValidators(): array - { - return [ - 'len' => Validators::len(), - 'email' => Validators::email(), - 'required' => Validators::required(), - ]; - } - - /** - * Runs `$this->rules` over `$this->fields` to construct - * potential errors that will be stored as an array of strings - * in `$this->errors`. - * - * @return void - */ - private function validate(): void - { - foreach ($this->rules as $field => $rule) { - $value = $this->fields[$field]; - - foreach (explode('|', $rule) as $item) { - if (str_contains($item, ':')) { - [$name, $modifier] = explode(':', $item); - - if (!$this->rules[$name]['validates']($value, $modifier)) { - $this->errors[] = $this->rules[$name]['error']($field, $modifier); - } - } else { - - if (!$this->rules[$item]['validates']($value)) { - $this->errors[] = $this->rules[$item]['error']($field); - } - } - } - } - } - - /** - * Returns a boolean `true` if there have been any errors. - * Returns `false` otherwise. - * - * @return boolean - */ - public function fails(): bool - { - return count($this->errors) !== 0; - } - - /** - * Returns an array of strings where each string - * is a single error that happened during validation. - * - * @return array - */ - public function errors(): array - { - return $this->errors; - } - - /** - * If errors are present, returns the first one. - * Otherwise returns an empty string. - * - * @return string - */ - public function firstError(): string - { - if (count($this->errors) > 0) { - return $this->errors[0]; - } - - return ''; - } -} diff --git a/src/Validators.php b/src/Validators.php deleted file mode 100644 index 0040657..0000000 --- a/src/Validators.php +++ /dev/null @@ -1,68 +0,0 @@ - function (string $field, mixed $modifier = 0): string { - return "{$field} is shorter than the required ${modifier} characters."; - }, - 'validates' => function (string $value, mixed $modifier = 0): bool { - if (!isset($value) || strlen($value) < (int) $modifier) { - return false; - } - - return true; - } - ]; - } - - /** - * Undocumented function - * - * @return array - */ - public static function email(): array - { - return [ - 'error' => function (string $field): string { - return "${field} is not a valid e-mail address."; - }, - 'validates' => function (string $value): bool { - if (!isset($value) || !filter_var($value, FILTER_VALIDATE_EMAIL)) { - return false; - } - - return true; - } - ]; - } - - /** - * Undocumented function - * - * @return array - */ - public static function required(): array - { - return [ - 'error' => function (string $field): string { - return "${field} is required."; - }, - 'validates' => function (string $value): bool { - return isset($value) && $value !== ''; - } - ]; - } -} diff --git a/src/Validators/EmailValidator.php b/src/Validators/EmailValidator.php new file mode 100644 index 0000000..5d69b5b --- /dev/null +++ b/src/Validators/EmailValidator.php @@ -0,0 +1,37 @@ + + */ +class EmailValidator implements Validator +{ + /** + * Returns a boolean `true` when given `$value` is a valid e-mail + * address. Returns `false` otherwise. + * + * @param string $value + * @param mixed $modifier + * @return boolean + */ + public static function validate(string $value, mixed $modifier = null): bool + { + return filter_var($value, FILTER_VALIDATE_EMAIL); + } + + /** + * Composes the error message in case the validation fails. + * + * @param string $field + * @param mixed $modifier + * @return string + */ + public static function composeError(string $field, mixed $modifier = null): string + { + return "${field} is not a valid e-mail address."; + } +} diff --git a/src/Validators/LenValidator.php b/src/Validators/LenValidator.php new file mode 100644 index 0000000..b4b5e2b --- /dev/null +++ b/src/Validators/LenValidator.php @@ -0,0 +1,46 @@ + + */ +class LenValidator implements Validator +{ + /** + * Returns a boolean `true` when given `$value` is as long as + * required. Returns `false` otherwise. + * + * @param string $value + * @param mixed $modifier + * @return boolean + */ + public static function validate(string $value, mixed $modifier = null): bool + { + // If no modifier present then this validator will always validate. + if (!$modifier) { + return true; + } + + if (!isset($value) || strlen($value) < (int) $modifier) { + return false; + } + + return true; + } + + /** + * Composes the error message in case the validation fails. + * + * @param string $field + * @param mixed $modifier + * @return string + */ + public static function composeError(string $field, mixed $modifier = null): string + { + return "{$field} is shorter than the required ${modifier} characters."; + } +} diff --git a/src/Validators/RequiredValidator.php b/src/Validators/RequiredValidator.php new file mode 100644 index 0000000..4cf6bfc --- /dev/null +++ b/src/Validators/RequiredValidator.php @@ -0,0 +1,37 @@ + + */ +class RequiredValidator implements Validator +{ + /** + * Returns a boolean `true` when given `$value` is present + * and not empty. Returns `false` otherwise. + * + * @param string $value + * @param mixed $modifier + * @return boolean + */ + public static function validate(string $value, mixed $modifier = null): bool + { + return isset($value) && $value !== ''; + } + + /** + * Composes the error message in case the validation fails. + * + * @param string $field + * @param mixed $modifier + * @return string + */ + public static function composeError(string $field, mixed $modifier = null): string + { + return "${field} is required."; + } +} diff --git a/src/Validators/Validator.php b/src/Validators/Validator.php new file mode 100644 index 0000000..11f2b01 --- /dev/null +++ b/src/Validators/Validator.php @@ -0,0 +1,9 @@ +