summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsko Nomm <asko@bien.ee>2022-02-22 17:54:18 +0100
committerAsko Nomm <asko@bien.ee>2022-02-22 17:54:18 +0100
commit2bb257006e8f2dd792c46c868b3bf80c5a25a64b (patch)
tree094fcb8c4be50623fdafe33ced279f6706732e7a
Initial commit
-rw-r--r--.gitignore1
-rw-r--r--composer.json18
-rw-r--r--src/Validator.php111
-rw-r--r--src/ValidatorRules.php50
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 !== '';
+ }
+ ];
+ }
+}