From eedb71682cc1f62bc9789945c952194e2f5efa03 Mon Sep 17 00:00:00 2001 From: Asko Nomm Date: Wed, 23 Feb 2022 18:01:02 +0100 Subject: Rename Bouncer to Hird --- README.md | 50 ++++----- composer.json | 4 +- composer.lock | 28 ++--- src/Bouncer.php | 200 ----------------------------------- src/Hird.php | 157 +++++++++++++++++++++++++++ src/Validators/EmailValidator.php | 2 +- src/Validators/LenValidator.php | 2 +- src/Validators/RequiredValidator.php | 2 +- src/Validators/Validator.php | 2 +- tests/BouncerTest.php | 68 ------------ tests/HirdTest.php | 68 ++++++++++++ 11 files changed, 271 insertions(+), 312 deletions(-) delete mode 100644 src/Bouncer.php create mode 100644 src/Hird.php delete mode 100644 tests/BouncerTest.php create mode 100644 tests/HirdTest.php diff --git a/README.md b/README.md index 6848e04..150a154 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,26 @@ -# Bouncer +# Hird -[![Latest Stable Version](http://poser.pugx.org/askonomm/bouncer/v)](https://packagist.org/packages/askonomm/bouncer) +[![Latest Stable Version](http://poser.pugx.org/askonomm/hird/v)](https://packagist.org/packages/askonomm/hird) -An extensible validation library for your data with sane defaults. +> Hirds, also known as housecarls, was a gathering of hirdmen, who functioned as the king's personal guards during the viking age and the early middle ages. -![Bouncer](https://user-images.githubusercontent.com/84135165/155233016-1dd9990f-ed60-44cc-b44c-ea90a11fc350.jpg) +Hird is an extensible validation library for your data with sane defaults. + +![Hird](https://user-images.githubusercontent.com/84135165/155233016-1dd9990f-ed60-44cc-b44c-ea90a11fc350.jpg) ## Installation You can install the package via composer: ``` -composer require askonomm/bouncer +composer require askonomm/hird ``` ## Usage -The Bouncer takes in an array of `$fields` and an array of `$rules`. +Hird takes in an array of `$fields` and an array of `$rules`. -The key of each item in the `$fields` array must correspond to the the key of each item in the `$rules` array, so that Bouncer would know how to connect the two to each other. +The key of each item in the `$fields` array must correspond to the the key of each item in the `$rules` array, so that Hird would know how to connect the two to each other. The `$rules` must have a value that is a string where the rules are separated by a `|` character, and each rule must match the key of the implemented validator, such as `len`, `email` or one that you have implemented yourself. Additionally, each rule can take in a modifier, where the name of the rule and the modifier is separated by a `:` character. @@ -26,38 +28,38 @@ For example, say we have a validator called `len` which takes a modifier that le ### Example usage -An example usage of Bouncer looks like this: +An example usage of Hird looks like this: ```php -use Askonomm\Bouncer\Bouncer; +use Askonomm\Hird\Hird; $fields = ['email' => 'asko@bien.ee']; $rules = ['email' => 'required|email|len:5']; -$bouncer = new Bouncer($fields, $rules); +$hird = new Hird($fields, $rules); -if ($bouncer->fails()) { - return $bouncer->errors(); +if ($hird->fails()) { + return $hird->errors(); } ``` -From the above example, you can see that there are two Bouncer methods being used such as `$bouncer->fails()` and `$bouncer->errors()`. The `$bouncer->fails()` method will return a boolean depending on whether the validation failed or not, `true` if it did. The `$bouncer->errors()` method will return an array of all the errors that occured, as defined by the validators. +From the above example, you can see that there are two Hird methods being used such as `$hird->fails()` and `$hird->errors()`. The `$hird->fails()` method will return a boolean depending on whether the validation failed or not, `true` if it did. The `$hird->errors()` method will return an array of all the errors that occured, as defined by the validators. -You can also get the first error rather than all errors by using the method `$bouncer->firstError()`. +You can also get the first error rather than all errors by using the method `$hird->firstError()`. ## Built-in validators -There are a number of built-in validators available for use by default. If you want to remove a built-in validator, you can remove one using the `$bouncer->removeValidator('rule-name')` method. +There are a number of built-in validators available for use by default. If you want to remove a built-in validator, you can remove one using the `$hird->removeValidator('rule-name')` method. ### `email` The `email` validator validates an e-mail address, and it is registered as the `email` rule. ```php -use Askonomm\Bouncer\Bouncer; +use Askonomm\Hird\Hird; $fields = ['email' => 'asko@bien.ee']; $rules = ['email' => 'email']; -$bouncer = new Bouncer($fields, $rules); +$hird = new Hird($fields, $rules); ``` ### `len` @@ -65,11 +67,11 @@ $bouncer = new Bouncer($fields, $rules); The `len` validator validates the length of a string, and it is registered as the `len` rule. The `len` validator also accepts, and requires, a modifier. A modifier can be passed to a rule by appending a color character `:` to it, and passing the modifier after it, like `len:8`. ```php -use Askonomm\Bouncer\Bouncer; +use Askonomm\Hird\Hird; $fields = ['password' => 'SuperSecretPassword']; $rules = ['password' => 'len:10']; -$bouncer = new Bouncer($fields, $rules); +$hird = new Hird($fields, $rules); ``` ### `required` @@ -77,24 +79,24 @@ $bouncer = new Bouncer($fields, $rules); The `required` validator validates the presence of value, and it is registered as the `required` rule. It will pass validation if the value is set and the value is not an empty string. ```php -use Askonomm\Bouncer\Bouncer; +use Askonomm\Hird\Hird; $fields = ['password' => 'SuperSecretPassword']; $rules = ['password' => 'required']; -$bouncer = new Bouncer($fields, $rules); +$hird = new Hird($fields, $rules); ``` ## Creating validators You can also create your own validators, or replace existing ones if you're not happy with them. -**Note:** To replace an existing one, first remove the built-in validator via `$bouncer->removeValidator('rule-name')` and then add your own via `$bouncer->registerValidator('rule-name', $validator)`. +**Note:** To replace an existing one, first remove the built-in validator via `$hird->removeValidator('rule-name')` and then add your own via `$hird->registerValidator('rule-name', $validator)`. A validator is a class that implements the `Validator` interface. A full example of a correct validator would look something like this: ```php -use Askonomm\Bouncer\Validators\Validator; +use Askonomm\Hird\Validators\Validator; class EmailValidator implements Validator { @@ -127,4 +129,4 @@ class EmailValidator implements Validator You can see that there are two methods, one for validating the `$value` and the other for composing an error message if the validation fails. Both functions take in a `$modifier` argument, which will only have value if the validator is using modifiers. For example, the `len` validator is using modifiers to determine how long of a string should be required, by passing the rule in as `len:{number-of-characters}`. -Once you've created the class for your validator, you can register it by calling `$bouncer->registerValidator('rule-name', (new YourValidatorClass))`. \ No newline at end of file +Once you've created the class for your validator, you can register it by calling `$hird->registerValidator('rule-name', (new YourValidatorClass))`. \ No newline at end of file diff --git a/composer.json b/composer.json index d3f36c0..162af24 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,11 @@ { - "name": "askonomm/bouncer", + "name": "askonomm/hird", "description": "An extensible validation library for your data with sane defaults.", "type": "library", "license": "MIT", "autoload": { "psr-4": { - "Askonomm\\Bouncer\\": "src/" + "Askonomm\\Hird\\": "src/" } }, "authors": [ diff --git a/composer.lock b/composer.lock index 791fdf9..b6ea53b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "60e57b17fa829992b0d33875b08a120a", + "content-hash": "8935913b6935a7a21d48feb4f199b5be", "packages": [], "packages-dev": [ { @@ -923,16 +923,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.11", + "version": "9.2.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "665a1ac0a763c51afc30d6d130dac0813092b17f" + "reference": "c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/665a1ac0a763c51afc30d6d130dac0813092b17f", - "reference": "665a1ac0a763c51afc30d6d130dac0813092b17f", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631", + "reference": "c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631", "shasum": "" }, "require": { @@ -988,7 +988,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.11" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.12" }, "funding": [ { @@ -996,7 +996,7 @@ "type": "github" } ], - "time": "2022-02-18T12:46:09+00:00" + "time": "2022-02-23T06:30:26+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1241,16 +1241,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.14", + "version": "9.5.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1883687169c017d6ae37c58883ca3994cfc34189" + "reference": "dc738383c519243b0a967f63943a848d3fd861aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1883687169c017d6ae37c58883ca3994cfc34189", - "reference": "1883687169c017d6ae37c58883ca3994cfc34189", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/dc738383c519243b0a967f63943a848d3fd861aa", + "reference": "dc738383c519243b0a967f63943a848d3fd861aa", "shasum": "" }, "require": { @@ -1266,7 +1266,7 @@ "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.7", + "phpunit/php-code-coverage": "^9.2.12", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -1328,7 +1328,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.14" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.15" }, "funding": [ { @@ -1340,7 +1340,7 @@ "type": "github" } ], - "time": "2022-02-18T12:54:07+00:00" + "time": "2022-02-23T08:53:20+00:00" }, { "name": "psr/container", diff --git a/src/Bouncer.php b/src/Bouncer.php deleted file mode 100644 index 517315b..0000000 --- a/src/Bouncer.php +++ /dev/null @@ -1,200 +0,0 @@ - '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/Hird.php b/src/Hird.php new file mode 100644 index 0000000..c1f5e4c --- /dev/null +++ b/src/Hird.php @@ -0,0 +1,157 @@ + 'asko@bien.ee']; + * $rules = ['email' => 'required|email']; + * $hird = new Hird($fields, $rules); + * + * if ($hird->fails()) { + * return $hird->errors(); + * } + * ``` + * + * @author Asko Nomm + */ +class Hird +{ + 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 void + */ + private 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/Validators/EmailValidator.php b/src/Validators/EmailValidator.php index d0e87fc..d5654c0 100644 --- a/src/Validators/EmailValidator.php +++ b/src/Validators/EmailValidator.php @@ -1,6 +1,6 @@ 'asko@bien.ee']; - $rules = ['email' => 'email']; - $bouncer = new Bouncer($fields, $rules); - - expect($bouncer->fails())->toBeFalse(); -}); - -test('Validate an incorrect e-mail address', function () { - $fields = ['email' => 'this-is-not-right']; - $rules = ['email' => 'email']; - $bouncer = new Bouncer($fields, $rules); - - expect($bouncer->errors())->toBe([ - 'email is not a valid e-mail address.' - ]); -}); - -test('Validate a correct length of string', function () { - $fields = ['string' => 'i-am-fine-as-i-am-long']; - $rules = ['string' => 'len:8']; - $bouncer = new Bouncer($fields, $rules); - - expect($bouncer->fails())->toBeFalse(); -}); - -test('Validate an incorrect length of string', function () { - $fields = ['string' => 'i-am-short']; - $rules = ['string' => 'len:15']; - $bouncer = new Bouncer($fields, $rules); - - expect($bouncer->errors())->toBe([ - 'string is shorter than the required 15 characters.' - ]); -}); - -test('Validate a correct required string', function () { - $fields = ['string' => 'i-am-required']; - $rules = ['string' => 'required']; - $bouncer = new Bouncer($fields, $rules); - - expect($bouncer->fails())->toBeFalse(); -}); - -test('Validate an incorrect required string', function () { - $fields = [ - 'empty-string' => '', - 'null-value' => null, - 'false-value' => false, - ]; - - $rules = [ - 'empty-string' => 'required', - 'null-value' => 'required', - 'false-value' => 'required', - ]; - - $bouncer = new Bouncer($fields, $rules); - - expect($bouncer->errors())->toBe([ - 'empty-string is required.', - 'null-value is required.', - ]); -}); diff --git a/tests/HirdTest.php b/tests/HirdTest.php new file mode 100644 index 0000000..273eff6 --- /dev/null +++ b/tests/HirdTest.php @@ -0,0 +1,68 @@ + 'asko@bien.ee']; + $rules = ['email' => 'email']; + $hird = new Hird($fields, $rules); + + expect($hird->fails())->toBeFalse(); +}); + +test('Validate an incorrect e-mail address', function () { + $fields = ['email' => 'this-is-not-right']; + $rules = ['email' => 'email']; + $hird = new Hird($fields, $rules); + + expect($hird->errors())->toBe([ + 'email is not a valid e-mail address.' + ]); +}); + +test('Validate a correct length of string', function () { + $fields = ['string' => 'i-am-fine-as-i-am-long']; + $rules = ['string' => 'len:8']; + $hird = new Hird($fields, $rules); + + expect($hird->fails())->toBeFalse(); +}); + +test('Validate an incorrect length of string', function () { + $fields = ['string' => 'i-am-short']; + $rules = ['string' => 'len:15']; + $hird = new Hird($fields, $rules); + + expect($hird->errors())->toBe([ + 'string is shorter than the required 15 characters.' + ]); +}); + +test('Validate a correct required string', function () { + $fields = ['string' => 'i-am-required']; + $rules = ['string' => 'required']; + $hird = new Hird($fields, $rules); + + expect($hird->fails())->toBeFalse(); +}); + +test('Validate an incorrect required string', function () { + $fields = [ + 'empty-string' => '', + 'null-value' => null, + 'false-value' => false, + ]; + + $rules = [ + 'empty-string' => 'required', + 'null-value' => 'required', + 'false-value' => 'required', + ]; + + $hird = new Hird($fields, $rules); + + expect($hird->errors())->toBe([ + 'empty-string is required.', + 'null-value is required.', + ]); +}); -- cgit v1.2.3