From 1f39a6393b9f0b2c1e69b246adf88bd927418d1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=99=9E=E7=81=AA?= <995645888@qq.com>
Date: Fri, 28 May 2021 16:31:10 +0800
Subject: [PATCH] =?UTF-8?q?[A]=20=E5=A2=9E=E5=8A=A0=E8=BF=87=E6=BB=A4?=
=?UTF-8?q?=E5=99=A8=EF=BC=8C=E7=94=A8=E4=BA=8E=E5=A4=84=E7=90=86=E9=AA=8C?=
=?UTF-8?q?=E8=AF=81=E5=90=8E=E7=9A=84=E6=95=B0=E6=8D=AE=20[U]=20=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9=E7=A8=8B=E5=BA=8F=E8=BF=90=E8=A1=8C=E6=97=B6=E7=9A=84?=
=?UTF-8?q?=E5=BC=82=E5=B8=B8=E7=B1=BB=E4=B8=BAValidateRuntimeException?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Exception/ValidateRuntimeException.php | 19 ++++
src/Support/Concerns/FilterInterface.php | 18 ++++
src/Support/ValidateScene.php | 32 ++++++
src/Validate.php | 108 ++++++++++++++++-----
tests/Test/TestDataFilter.php | 104 ++++++++++++++++++++
5 files changed, 257 insertions(+), 24 deletions(-)
create mode 100644 src/Exception/ValidateRuntimeException.php
create mode 100644 src/Support/Concerns/FilterInterface.php
create mode 100644 tests/Test/TestDataFilter.php
diff --git a/src/Exception/ValidateRuntimeException.php b/src/Exception/ValidateRuntimeException.php
new file mode 100644
index 0000000..ee09e6c
--- /dev/null
+++ b/src/Exception/ValidateRuntimeException.php
@@ -0,0 +1,19 @@
+
+ *
+ * This is not a free software
+ * Using it under the license terms
+ * visited https://www.w7.cc for more details
+ */
+
+namespace W7\Validate\Exception;
+
+use RuntimeException;
+
+class ValidateRuntimeException extends RuntimeException
+{
+}
diff --git a/src/Support/Concerns/FilterInterface.php b/src/Support/Concerns/FilterInterface.php
new file mode 100644
index 0000000..fb23c88
--- /dev/null
+++ b/src/Support/Concerns/FilterInterface.php
@@ -0,0 +1,18 @@
+
+ *
+ * This is not a free software
+ * Using it under the license terms
+ * visited https://www.w7.cc for more details
+ */
+
+namespace W7\Validate\Support\Concerns;
+
+interface FilterInterface
+{
+ public function handle($value);
+}
diff --git a/src/Support/ValidateScene.php b/src/Support/ValidateScene.php
index 6fd0c54..d02dc17 100644
--- a/src/Support/ValidateScene.php
+++ b/src/Support/ValidateScene.php
@@ -15,6 +15,7 @@ namespace W7\Validate\Support;
use Closure;
use Illuminate\Support\Arr;
use RuntimeException;
+use W7\Validate\Support\Concerns\FilterInterface;
use W7\Validate\Support\Rule\BaseRule;
use W7\Validate\Support\Storage\ValidateCollection;
@@ -26,6 +27,7 @@ use W7\Validate\Support\Storage\ValidateCollection;
* @property-read array $befores Methods to be executed before this validate
* @property-read array $afters Methods to be executed after this validate
* @property-read array $defaults This validation requires a default value for the value
+ * @property-read array $filters The filter. This can be a global function name, anonymous function, etc.
* @property-read bool $eventPriority Event Priority
*/
class ValidateScene extends RuleManagerScene
@@ -59,6 +61,12 @@ class ValidateScene extends RuleManagerScene
* @var array
*/
private $defaults = [];
+
+ /**
+ * The filter. This can be a global function name, anonymous function, etc.
+ * @var array
+ */
+ private $filters = [];
/**
* Event Priority
@@ -182,6 +190,30 @@ class ValidateScene extends RuleManagerScene
return $this;
}
+ /**
+ * Set a filter for the specified field
+ *
+ * Filter is a data processor.
+ * It invokes the specified filter callback to process the attribute value
+ * and save the processed value back to the attribute.
+ * @param string $field Name of the data field to be processed
+ * @param string|callable|Closure|FilterInterface $callback The filter. This can be a global function name, anonymous function, etc.
+ * The filter must be a valid PHP callback with the following signature:
+ *
+ * function foo($value) {
+ * // compute $newValue here
+ * return $newValue;
+ * }
+ *
+ * Many PHP functions qualify this signature (e.g. `trim()`).
+ * @return $this
+ */
+ public function filter(string $field, $callback): ValidateScene
+ {
+ $this->filters[$field] = $callback;
+ return $this;
+ }
+
/**
* Set event priority
*
diff --git a/src/Validate.php b/src/Validate.php
index 15ebd0d..7e51ae0 100644
--- a/src/Validate.php
+++ b/src/Validate.php
@@ -13,10 +13,14 @@
namespace W7\Validate;
use Closure;
+use Illuminate\Support\Str;
use Illuminate\Validation\Factory;
+use Illuminate\Validation\ValidationData;
use Illuminate\Validation\ValidationException;
use LogicException;
use W7\Validate\Exception\ValidateException;
+use W7\Validate\Exception\ValidateRuntimeException;
+use W7\Validate\Support\Concerns\FilterInterface;
use W7\Validate\Support\Concerns\MessageProviderInterface;
use W7\Validate\Support\Event\ValidateEventAbstract;
use W7\Validate\Support\MessageProvider;
@@ -86,6 +90,12 @@ class Validate extends RuleManager
*/
private $defaults = [];
+ /**
+ * Filters to be passed for this validation
+ * @var array
+ */
+ private $filters = [];
+
/**
* Error Message Provider
* @var MessageProviderInterface
@@ -137,9 +147,12 @@ class Validate extends RuleManager
$this->init();
$this->checkData = $data;
$this->addEvent($this->event);
- $this->defaults = array_merge($this->default, $this->defaults);
$rule = $this->getCheckRules($this->getInitialRules());
- $data = $this->handleDefault($data, $rule);
+ $fields = array_keys($rule);
+ $this->defaults = array_merge($this->default, $this->defaults);
+ $this->filters = array_merge($this->filter, $this->filters);
+ $data = $this->handleDefault($data, $fields);
+
if ($this->filled) {
$rule = $this->addFilledRule($rule);
}
@@ -157,6 +170,7 @@ class Validate extends RuleManager
}
$data = $this->getValidationFactory()->make($data, $rule, $this->message, $this->customAttributes)->validate();
+ $data = $this->handlerFilter($data, $fields);
if ($this->eventPriority) {
$this->handleCallback($data, 2);
@@ -204,6 +218,7 @@ class Validate extends RuleManager
$this->afters = array_merge($this->afters, $scene->afters);
$this->befores = array_merge($this->befores, $scene->befores);
$this->defaults = array_merge($this->defaults, $scene->defaults);
+ $this->filters = array_merge($this->filters, $scene->filters);
$this->eventPriority = $scene->eventPriority;
return $scene->getRules();
}
@@ -333,26 +348,83 @@ class Validate extends RuleManager
throw new ValidateException($message, 403);
}
} else {
- throw new ValidateException('Event error or nonexistence');
+ throw new ValidateRuntimeException('Event error or nonexistence');
}
}
}
/**
- * Processing the set defaults
+ * Filters for processing settings
*
* @param array $data
- * @param array $rule
+ * @param array $fields
* @return array
*/
- private function handleDefault(array $data, array $rule): array
+ private function handlerFilter(array $data, array $fields): array
+ {
+ if (empty($this->filters)) {
+ return $data;
+ }
+
+ $newData = validate_collect($data);
+ $filters = array_intersect_key($this->filters, array_flip($fields));
+ foreach ($filters as $field => $callback) {
+ if (false !== strpos($field, '*')) {
+ $flatData = ValidationData::initializeAndGatherData($field, $data);
+ $pattern = str_replace('\*', '[^\.]*', preg_quote($field));
+ foreach ($flatData as $key => $value) {
+ if (Str::startsWith($key, $field) || preg_match('/^' . $pattern . '\z/', $key)) {
+ $this->filterValue($key, $callback, $newData);
+ }
+ }
+ } else {
+ $this->filterValue($field, $callback, $newData);
+ }
+ }
+
+ return $newData->toArray();
+ }
+
+ /**
+ * Filter the given value
+ *
+ * @param string $field Name of the data field to be processed
+ * @param callable|Closure|FilterInterface $callback The filter. This can be a global function name, anonymous function, etc.
+ * @param ValidateCollection $data
+ */
+ private function filterValue(string $field, $callback, ValidateCollection $data)
+ {
+ $value = $data->get($field);
+
+ if (is_callable($callback)) {
+ $value = call_user_func($callback, $value);
+ } elseif (class_exists($callback) && is_subclass_of($callback, FilterInterface::class)) {
+ /** @var FilterInterface $filter */
+ $filter = new $callback;
+ $value = $filter->handle($value);
+ } elseif (is_string($callback) && method_exists($this, 'filter' . ucfirst($callback))) {
+ $value = call_user_func([$this, 'filter' . ucfirst($callback)], $value);
+ } else {
+ throw new ValidateRuntimeException('The provided filter is wrong');
+ }
+
+ $data->set($field, $value);
+ }
+
+ /**
+ * Defaults for processing settings
+ *
+ * @param array $data
+ * @param array $fields
+ * @return array
+ */
+ private function handleDefault(array $data, array $fields): array
{
if (empty($this->defaults)) {
return $data;
}
$newData = validate_collect($data);
- $fields = array_keys($rule);
$defaults = array_intersect_key($this->defaults, array_flip($fields));
foreach ($defaults as $field => $value) {
// Skip array members
@@ -374,22 +446,9 @@ class Validate extends RuleManager
* Applying default settings to data
*
* @param string $field Name of the data field to be processed
- * @param callable|Closure|mixed $callback the default value or an anonymous function that returns the default value which will
- * be assigned to the attributes being validated if they are empty. The signature of the anonymous function
- * should be as follows,The anonymous function has two parameters:
- *
- * function($value,$originalData){
- * return $value;
- * }
- *
- * @param ValidateCollection $data Data to be processed
- * @param bool $any Whether to handle arbitrary values, default only handle values that are not null
+ * @param callable|Closure|mixed $callback The default value or an anonymous function that returns the default value which will
+ * @param ValidateCollection $data Data to be processed
+ * @param bool $any Whether to handle arbitrary values, default only handle values that are not null
*/
private function setDefaultData(string $field, $callback, ValidateCollection $data, bool $any = false)
{
@@ -418,6 +477,7 @@ class Validate extends RuleManager
$this->afters = [];
$this->befores = [];
$this->defaults = [];
+ $this->filters = [];
$this->eventPriority = true;
}
@@ -439,7 +499,7 @@ class Validate extends RuleManager
$this->setMessageProvider($messageProvider);
return $this;
} else {
- throw new ValidateException('The provided message processor needs to implement the MessageProviderInterface interface');
+ throw new ValidateRuntimeException('The provided message processor needs to implement the MessageProviderInterface interface');
}
return $this;
diff --git a/tests/Test/TestDataFilter.php b/tests/Test/TestDataFilter.php
new file mode 100644
index 0000000..6766882
--- /dev/null
+++ b/tests/Test/TestDataFilter.php
@@ -0,0 +1,104 @@
+
+ *
+ * This is not a free software
+ * Using it under the license terms
+ * visited https://www.w7.cc for more details
+ */
+
+namespace W7\Tests\Test;
+
+use W7\Tests\Material\BaseTestValidate;
+use W7\Validate\Support\Concerns\FilterInterface;
+use W7\Validate\Validate;
+
+class UniqueFilter implements FilterInterface
+{
+ public function handle($value)
+ {
+ return array_unique($value);
+ }
+}
+class TestDataFilter extends BaseTestValidate
+{
+ public function testSetFilterIsSystemMethod()
+ {
+ $v = new class extends Validate {
+ protected $rule = [
+ 'id' => 'required|numeric'
+ ];
+
+ protected $filter = [
+ 'id' => 'intval'
+ ];
+ };
+
+ $data = $v->check(['id' => '1']);
+
+ $this->assertTrue(1 === $data['id']);
+ }
+
+ public function testSetFilterIsClassMethod()
+ {
+ $v = new class extends Validate {
+ protected $rule = [
+ 'id' => 'required'
+ ];
+
+ protected $filter = [
+ 'id' => 'toArray'
+ ];
+
+ public function filterToArray($value)
+ {
+ return explode(',', $value);
+ }
+ };
+
+ $data = $v->check(['id' => '1,2,3,4,5']);
+
+ $this->assertEquals([1, 2, 3, 4, 5], $data['id']);
+ }
+
+ public function testSetFilterIsFilterClass()
+ {
+ $v = new class extends Validate {
+ protected $rule = [
+ 'id' => 'required|array',
+ 'id.*' => 'numeric'
+ ];
+
+ protected $filter = [
+ 'id' => UniqueFilter::class
+ ];
+ };
+
+ $data = $v->check(['id' => [1, 1, 2, 3, 4, 4, 5, 6, 7]]);
+
+ $this->assertEquals([1, 2, 3, 4, 5, 6, 7], array_values($data['id']));
+ }
+
+ public function testSetFilterForArrayField()
+ {
+ $v = new class extends Validate {
+ protected $rule = [
+ 'id' => 'required|array',
+ 'id.*' => 'numeric'
+ ];
+
+ protected $filter = [
+ 'id.*' => 'intval'
+ ];
+ };
+
+ $data = $v->check(['id' => ['1', '2', 3, '4']]);
+
+ foreach ($data['id'] as $id) {
+ $this->assertEquals('integer', gettype($id));
+ }
+ }
+}
--
Gitee