diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | composer.json | 18 | ||||
| -rw-r--r-- | src/Validator.php | 111 | ||||
| -rw-r--r-- | src/ValidatorRules.php | 50 |
4 files changed, 180 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c15582f --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "askonomm/validator", + "description": "A modular validation library with sane default", + "type": "library", + "license": "MIT", + "autoload": { + "psr-4": { + "Askonomm\\Validator\\": "src/" + } + }, + "authors": [ + { + "name": "Asko Nomm", + "email": "asko@bien.ee" + } + ], + "require": {} +} diff --git a/src/Validator.php b/src/Validator.php new file mode 100644 index 0000000..8d91bb9 --- /dev/null +++ b/src/Validator.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace Askonomm\Validator; + +/** + * The Validator class takes in an array of fields and + * an array of validators. Each field must have a key + * that matches the validator key so that `Validator` class + * would know how to connect the two, and the value of the each + * validator is a string that consists of rules separated by the + * `|` character. + * + * Example use: + * + * ```php + * $fields = ['email' => 'test@example.com']; + * $validators = ['email' => 'required|email']; + * $validator = new Validator($fields, $validators); + * + * if ($validator->fails()) { + * return $validator->errors(); + * } + * ``` + * + * @author Asko Nomm <asko@bien.ee> + */ +class Validator +{ + private array $errors = []; + + public function __construct( + private array $fields, + private array $validators, + array $rules = [], + ) { + if (empty($rules)) { + $this->rules = $this->defaultRules(); + } + + $this->validate(); + } + + public function defaultRules(): array + { + return [ + 'len' => ValidatorRules::len(), + 'email' => ValidatorRules::email(), + 'required' => ValidatorRules::required(), + ]; + } + + /** + * Runs `$this->validators` 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->validators as $field => $validator) { + $value = $this->fields[$field]; + + foreach (explode('|', $validator) 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. + */ + public function errors(): array + { + return $this->errors; + } + + public function firstError(): string + { + if (count($this->errors) > 0) { + return $this->errors[0]; + } + + return ''; + } +} diff --git a/src/ValidatorRules.php b/src/ValidatorRules.php new file mode 100644 index 0000000..d3599e0 --- /dev/null +++ b/src/ValidatorRules.php @@ -0,0 +1,50 @@ +<?php + +namespace Askonomm\Validator; + +class ValidatorRules +{ + public static function len(): array + { + return [ + 'error' => 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; + } + ]; + } + + 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; + } + ]; + } + + public static function required(): array + { + return [ + 'error' => function (string $field): string { + return "${field} is required."; + }, + 'validates' => function (string $value): bool { + return isset($value) && $value !== ''; + } + ]; + } +} |
