summaryrefslogtreecommitdiff
path: root/src/Http
diff options
context:
space:
mode:
Diffstat (limited to 'src/Http')
-rw-r--r--src/Http/Exceptions/ValidationException.php37
-rw-r--r--src/Http/Validation/Rules/In.php21
-rw-r--r--src/Http/Validation/Rules/NotIn.php15
-rw-r--r--src/Http/Validation/ValidatesRequest.php37
-rw-r--r--src/Http/Validation/ValidationServiceProvider.php25
-rw-r--r--src/Http/Validation/Validator.php122
6 files changed, 257 insertions, 0 deletions
diff --git a/src/Http/Exceptions/ValidationException.php b/src/Http/Exceptions/ValidationException.php
new file mode 100644
index 00000000..e48fb0c3
--- /dev/null
+++ b/src/Http/Exceptions/ValidationException.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Engelsystem\Http\Exceptions;
+
+use Engelsystem\Http\Validation\Validator;
+use RuntimeException;
+use Throwable;
+
+class ValidationException extends RuntimeException
+{
+ /** @var Validator */
+ protected $validator;
+
+ /**
+ * @param Validator $validator
+ * @param string $message
+ * @param int $code
+ * @param Throwable|null $previous
+ */
+ public function __construct(
+ Validator $validator,
+ string $message = '',
+ int $code = 0,
+ Throwable $previous = null
+ ) {
+ $this->validator = $validator;
+ parent::__construct($message, $code, $previous);
+ }
+
+ /**
+ * @return Validator
+ */
+ public function getValidator(): Validator
+ {
+ return $this->validator;
+ }
+}
diff --git a/src/Http/Validation/Rules/In.php b/src/Http/Validation/Rules/In.php
new file mode 100644
index 00000000..d585cc3d
--- /dev/null
+++ b/src/Http/Validation/Rules/In.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Engelsystem\Http\Validation\Rules;
+
+use Respect\Validation\Rules\In as RespectIn;
+
+class In extends RespectIn
+{
+ /**
+ * @param mixed $haystack
+ * @param bool $compareIdentical
+ */
+ public function __construct($haystack, $compareIdentical = false)
+ {
+ if (!is_array($haystack)) {
+ $haystack = explode(',', $haystack);
+ }
+
+ parent::__construct($haystack, $compareIdentical);
+ }
+}
diff --git a/src/Http/Validation/Rules/NotIn.php b/src/Http/Validation/Rules/NotIn.php
new file mode 100644
index 00000000..7f223c42
--- /dev/null
+++ b/src/Http/Validation/Rules/NotIn.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Engelsystem\Http\Validation\Rules;
+
+class NotIn extends In
+{
+ /**
+ * @param mixed $input
+ * @return bool
+ */
+ public function validate($input)
+ {
+ return !parent::validate($input);
+ }
+}
diff --git a/src/Http/Validation/ValidatesRequest.php b/src/Http/Validation/ValidatesRequest.php
new file mode 100644
index 00000000..33ff76af
--- /dev/null
+++ b/src/Http/Validation/ValidatesRequest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Engelsystem\Http\Validation;
+
+use Engelsystem\Http\Exceptions\ValidationException;
+use Engelsystem\Http\Request;
+
+trait ValidatesRequest
+{
+ /** @var Validator */
+ protected $validator;
+
+ /**
+ * @param Request $request
+ * @param array $rules
+ * @return array
+ */
+ protected function validate(Request $request, array $rules)
+ {
+ if (!$this->validator->validate(
+ (array)$request->getParsedBody(),
+ $rules
+ )) {
+ throw new ValidationException($this->validator);
+ }
+
+ return $this->validator->getData();
+ }
+
+ /**
+ * @param Validator $validator
+ */
+ public function setValidator(Validator $validator)
+ {
+ $this->validator = $validator;
+ }
+}
diff --git a/src/Http/Validation/ValidationServiceProvider.php b/src/Http/Validation/ValidationServiceProvider.php
new file mode 100644
index 00000000..14530ae6
--- /dev/null
+++ b/src/Http/Validation/ValidationServiceProvider.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Engelsystem\Http\Validation;
+
+use Engelsystem\Application;
+use Engelsystem\Container\ServiceProvider;
+use Engelsystem\Controllers\BaseController;
+
+class ValidationServiceProvider extends ServiceProvider
+{
+ public function register()
+ {
+ $validator = $this->app->make(Validator::class);
+ $this->app->instance(Validator::class, $validator);
+ $this->app->instance('validator', $validator);
+
+ $this->app->afterResolving(function ($object, Application $app) {
+ if (!$object instanceof BaseController) {
+ return;
+ }
+
+ $object->setValidator($app->get(Validator::class));
+ });
+ }
+}
diff --git a/src/Http/Validation/Validator.php b/src/Http/Validation/Validator.php
new file mode 100644
index 00000000..976f5682
--- /dev/null
+++ b/src/Http/Validation/Validator.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Engelsystem\Http\Validation;
+
+use Illuminate\Support\Str;
+use InvalidArgumentException;
+use Respect\Validation\Exceptions\ComponentException;
+use Respect\Validation\Validator as RespectValidator;
+
+class Validator
+{
+ /** @var string[] */
+ protected $errors = [];
+
+ /** @var array */
+ protected $data = [];
+
+ /** @var array */
+ protected $mapping = [
+ 'accepted' => 'TrueVal',
+ 'int' => 'IntVal',
+ 'required' => 'NotEmpty',
+ ];
+
+ /** @var array */
+ protected $nestedRules = ['optional', 'not'];
+
+ /**
+ * @param array $data
+ * @param array $rules
+ * @return bool
+ */
+ public function validate($data, $rules)
+ {
+ $this->errors = [];
+ $this->data = [];
+
+ foreach ($rules as $key => $values) {
+ $v = new RespectValidator();
+ $v->with('\\Engelsystem\\Http\\Validation\\Rules', true);
+
+ $value = isset($data[$key]) ? $data[$key] : null;
+ $values = explode('|', $values);
+
+ $packing = [];
+ foreach ($this->nestedRules as $rule) {
+ if (in_array($rule, $values)) {
+ $packing[] = $rule;
+ }
+ }
+
+ $values = array_diff($values, $this->nestedRules);
+ foreach ($values as $parameters) {
+ $parameters = explode(':', $parameters);
+ $rule = array_shift($parameters);
+ $rule = Str::camel($rule);
+ $rule = $this->map($rule);
+
+ // To allow rules nesting
+ $w = $v;
+ try {
+ foreach (array_reverse(array_merge($packing, [$rule])) as $rule) {
+ if (!in_array($rule, $this->nestedRules)) {
+ call_user_func_array([$w, $rule], $parameters);
+ continue;
+ }
+
+ $w = call_user_func_array([new RespectValidator(), $rule], [$w]);
+ }
+ } catch (ComponentException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ if ($w->validate($value)) {
+ $this->data[$key] = $value;
+ } else {
+ $this->errors[$key][] = implode('.', ['validation', $key, $this->mapBack($rule)]);
+ }
+
+ $v->removeRules();
+ }
+ }
+
+ return empty($this->errors);
+ }
+
+ /**
+ * @param string $rule
+ * @return string
+ */
+ protected function map($rule)
+ {
+ return $this->mapping[$rule] ?? $rule;
+ }
+
+ /**
+ * @param string $rule
+ * @return string
+ */
+ protected function mapBack($rule)
+ {
+ $mapping = array_flip($this->mapping);
+
+ return $mapping[$rule] ?? $rule;
+ }
+
+ /**
+ * @return array
+ */
+ public function getData(): array
+ {
+ return $this->data;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getErrors(): array
+ {
+ return $this->errors;
+ }
+}