From 526c657f4746ff7da7b5e564d2f160874c4a2189 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 11:40:33 +0800 Subject: [PATCH] =?UTF-8?q?[A]=20=E5=A2=9E=E5=8A=A0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=80=BC=EF=BC=8C=E5=8F=AF=E7=94=A8=E4=BA=8E=E4=B8=BA=E5=8D=B3?= =?UTF-8?q?=E5=B0=86=E8=A6=81=E9=AA=8C=E8=AF=81=E7=9A=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E8=AE=BE=E5=AE=9A=E9=BB=98=E8=AE=A4=E5=80=BC=E6=88=96=E8=80=85?= =?UTF-8?q?=E6=8F=90=E5=89=8D=E6=A0=BC=E5=BC=8F=E5=8C=96=E7=AD=89=E6=93=8D?= =?UTF-8?q?=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Support/ValidateScene.php | 53 ++++++++++-- src/Validate.php | 104 ++++++++++++++++++++-- tests/Test/TestDataDefault.php | 152 +++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+), 16 deletions(-) create mode 100644 tests/Test/TestDataDefault.php diff --git a/src/Support/ValidateScene.php b/src/Support/ValidateScene.php index 75ac8c9..6fd0c54 100644 --- a/src/Support/ValidateScene.php +++ b/src/Support/ValidateScene.php @@ -12,6 +12,7 @@ namespace W7\Validate\Support; +use Closure; use Illuminate\Support\Arr; use RuntimeException; use W7\Validate\Support\Rule\BaseRule; @@ -21,9 +22,10 @@ use W7\Validate\Support\Storage\ValidateCollection; * Class ValidateScene * @package W7\Validate\Support * - * @property-read array $events Events to be processed - * @property-read array $afters Methods to be executed after validation - * @property-read array $befores Methods to be executed before validation + * @property-read array $events Events to be processed for this validate + * @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 bool $eventPriority Event Priority */ class ValidateScene extends RuleManagerScene @@ -35,23 +37,29 @@ class ValidateScene extends RuleManagerScene protected $checkData = []; /** - * Events to be processed + * Events to be processed for this validate * @var array */ - protected $events = []; + private $events = []; /** - * Methods to be executed after validation + * Methods to be executed before this validate * @var array */ - protected $afters = []; + private $befores = []; /** - * Methods to be executed before validation + * Methods to be executed after this validate * @var array */ - protected $befores = []; + private $afters = []; + /** + * This validation requires a default value for the value + * @var array + */ + private $defaults = []; + /** * Event Priority * @var bool @@ -147,6 +155,33 @@ class ValidateScene extends RuleManagerScene return $this; } + /** + * Set a default value for the specified field + * + * @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: + * + * + * e.g: + * + * function($value,$originalData){ + * return $value; + * } + * + * @param bool $any Whether to handle arbitrary values, default only handle values that are not null + * @return $this + */ + public function default(string $field, $callback, bool $any = false): ValidateScene + { + $this->defaults[$field] = ['value' => $callback, 'any' => $any]; + return $this; + } + /** * Set event priority * diff --git a/src/Validate.php b/src/Validate.php index 2ac72ad..15ebd0d 100644 --- a/src/Validate.php +++ b/src/Validate.php @@ -12,6 +12,7 @@ namespace W7\Validate; +use Closure; use Illuminate\Validation\Factory; use Illuminate\Validation\ValidationException; use LogicException; @@ -19,6 +20,7 @@ use W7\Validate\Exception\ValidateException; use W7\Validate\Support\Concerns\MessageProviderInterface; use W7\Validate\Support\Event\ValidateEventAbstract; use W7\Validate\Support\MessageProvider; +use W7\Validate\Support\Storage\ValidateCollection; use W7\Validate\Support\Storage\ValidateConfig; use W7\Validate\Support\ValidateScene; @@ -42,8 +44,16 @@ class Validate extends RuleManager */ protected $filled = true; + /** + * The filter. This can be a global function name, anonymous function, etc. + * @var array + */ protected $filter = []; + /** + * Sets the specified property to the specified default value. + * @var array + */ protected $default = []; /** @@ -53,23 +63,29 @@ class Validate extends RuleManager private $eventPriority = true; /** - * Validator event handling class + * Events to be processed for this validate * @var array */ private $events = []; /** - * Methods to be executed before validation + * Methods to be executed before this validate * @var array */ private $befores = []; /** - * Methods to be executed after validation + * Methods to be executed after this validate * @var array */ private $afters = []; + /** + * This validation requires a default value for the value + * @var array + */ + private $defaults = []; + /** * Error Message Provider * @var MessageProviderInterface @@ -121,8 +137,9 @@ class Validate extends RuleManager $this->init(); $this->checkData = $data; $this->addEvent($this->event); - $rule = $this->getCheckRules($this->getInitialRules()); - + $this->defaults = array_merge($this->default, $this->defaults); + $rule = $this->getCheckRules($this->getInitialRules()); + $data = $this->handleDefault($data, $rule); if ($this->filled) { $rule = $this->addFilledRule($rule); } @@ -186,6 +203,7 @@ class Validate extends RuleManager $this->event = array_merge($this->event, $scene->events); $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->eventPriority = $scene->eventPriority; return $scene->getRules(); } @@ -307,7 +325,7 @@ class Validate extends RuleManager $handler = new $callback(...$param); $handler->sceneName = $this->getCurrentSceneName(); $handler->data = $data; - if (($result = call_user_func([$handler, $method])) !== true) { + if (true !== call_user_func([$handler, $method])) { $message = $handler->message; if (isset($this->message[$message])) { $message = $this->getMessageProvider()->handleMessage($this->message[$message]); @@ -320,14 +338,86 @@ class Validate extends RuleManager } } + /** + * Processing the set defaults + * + * @param array $data + * @param array $rule + * @return array + */ + private function handleDefault(array $data, array $rule): 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 + if (false !== strpos($field, '*')) { + continue; + } + + if (is_array($value) && isset($value['any']) && isset($value['value'])) { + $this->setDefaultData($field, $value['value'], $newData, (bool)$value['any']); + } else { + $this->setDefaultData($field, $value, $newData); + } + } + + return $newData->toArray(); + } + + /** + * 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: + * + * + * e.g: + * + * 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 + */ + private function setDefaultData(string $field, $callback, ValidateCollection $data, bool $any = false) + { + $isEmpty = function ($value) { + return null === $value || [] === $value || '' === $value; + }; + $value = $data->get($field); + if (!$data->has($field) || $isEmpty($value) || true === $any) { + if (is_callable($callback)) { + $value = call_user_func($callback, $value, $this->checkData); + } elseif (is_string($callback) && method_exists($this, 'default' . ucfirst($callback))) { + $value = call_user_func([$this, 'default' . ucfirst($callback)], $value, $this->checkData); + } else { + $value = $callback; + } + } + $data->set($field, $value); + } + /** * Initialization validate */ private function init() { - $this->handlers = []; + $this->events = []; $this->afters = []; $this->befores = []; + $this->defaults = []; $this->eventPriority = true; } diff --git a/tests/Test/TestDataDefault.php b/tests/Test/TestDataDefault.php new file mode 100644 index 0000000..3e24a25 --- /dev/null +++ b/tests/Test/TestDataDefault.php @@ -0,0 +1,152 @@ + + * + * 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\Exception\ValidateException; +use W7\Validate\Support\ValidateScene; +use W7\Validate\Validate; + +class TestDataDefault extends BaseTestValidate +{ + public function testDefaultIsScalar() + { + $v = new class extends Validate { + protected $rule = [ + 'name' => 'required' + ]; + + protected $default = [ + 'name' => '123' + ]; + }; + + $data = $v->check([]); + + $this->assertEquals('123', $data['name']); + } + + public function testDefaultIsArray() + { + $v = new class extends Validate { + protected $rule = [ + 'name' => 'required' + ]; + + protected $default = [ + 'name' => ['a', 'b', 'any' => 123] + ]; + }; + + $data = $v->check([]); + + $this->assertEquals(['a', 'b', 'any' => 123], $data['name']); + + $v = new class extends Validate { + protected $rule = [ + 'name' => 'required' + ]; + + protected $default = [ + 'name' => ['value' => ['a', 'b'], 'any' => true] + ]; + }; + + $data = $v->check([]); + + $this->assertEquals(['a', 'b'], $data['name']); + } + + public function testDefaultIsCallback() + { + $v = new class extends Validate { + protected $rule = [ + 'name' => 'required', + 'age' => 'required|numeric', + 'sex' => 'required' + ]; + + public function __construct() + { + $this->default = [ + 'name' => function ($value) { + return '小张'; + }, + 'age' => [$this, 'setAge'], + 'sex' => 'setSex' + ]; + } + + public function setAge($value) + { + return 100; + } + + public function defaultSetSex($value) + { + return '男'; + } + }; + + $data = $v->check([]); + + $this->assertEquals(['name' => '小张', 'age' => 100, 'sex' => '男'], $data); + } + + public function testHandlerData() + { + $v = new class extends Validate { + protected $rule = [ + 'id' => 'required' + ]; + + public function __construct() + { + $this->default = [ + 'id' => ['value' => function ($value) { + if (is_string($value)) { + return explode(',', $value); + } + return $value; + }, 'any' => true] + ]; + } + }; + + $data = $v->check([ + 'id' => '1,2,3,4' + ]); + + $this->assertEquals([1, 2, 3, 4], $data['id']); + } + + public function testDefaultForScene() + { + $v = new class extends Validate { + protected $rule = [ + 'name' => 'required' + ]; + + protected function sceneTest(ValidateScene $scene) + { + $scene->only(['name']) + ->default('name', '小张'); + } + }; + $this->expectException(ValidateException::class); + $v->check([]); + + $data = $v->scene('test')->check([]); + $this->assertEquals('小张', $data['name']); + } +} -- Gitee