From a57d1e7b7a53be1736b4be2ec2334dbc6fd3dcbd Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 11 May 2021 16:42:30 -0400 Subject: [PATCH 1/3] Ability to have placeholders and replacements in validation rules --- src/Fields/Validator.php | 28 ++++++++++++++++++++++++++-- tests/Fields/ValidatorTest.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/Fields/Validator.php b/src/Fields/Validator.php index e0d194255c6..59b5a4c5562 100644 --- a/src/Fields/Validator.php +++ b/src/Fields/Validator.php @@ -4,11 +4,13 @@ use Illuminate\Support\Facades\Lang; use Illuminate\Support\Facades\Validator as LaravelValidator; +use Statamic\Support\Arr; +use Statamic\Support\Str; class Validator { protected $fields; - protected $data = []; + protected $replacements = []; protected $extraRules = []; public function make() @@ -34,7 +36,11 @@ public function rules() { return $this ->merge($this->fieldRules(), $this->extraRules) - ->all(); + ->map(function ($rules) { + return collect($rules)->map(function ($rule) { + return $this->parse($rule); + })->all(); + })->all(); } private function fieldRules() @@ -65,6 +71,13 @@ public function merge($original, $overrides) return collect($original); } + public function withReplacements($replacements) + { + $this->replacements = $replacements; + + return $this; + } + public function validate() { return LaravelValidator::validate( @@ -84,6 +97,17 @@ private function fieldAttributes() })->all(); } + private function parse($rule) + { + if (! Str::contains($rule, '{')) { + return $rule; + } + + return preg_replace_callback('/{\s*([a-zA-Z0-9_\-]+)\s*}/', function ($match) { + return Arr::get($this->replacements, $match[1], 'NULL'); + }, $rule); + } + public static function explodeRules($rules) { if (! $rules) { diff --git a/tests/Fields/ValidatorTest.php b/tests/Fields/ValidatorTest.php index a600ef03185..3dc8447500b 100644 --- a/tests/Fields/ValidatorTest.php +++ b/tests/Fields/ValidatorTest.php @@ -116,4 +116,32 @@ public function it_merges_additional_rules_into_field_rules() 'additional' => ['required'], ], $validation->rules()); } + + /** @test */ + public function it_makes_replacements() + { + $field = Mockery::mock(Field::class); + $field->shouldReceive('rules')->andReturn([ + 'one' => ['required', 'test:{foo}'], + ]); + + $fields = Mockery::mock(Fields::class); + $fields->shouldReceive('all')->andReturn(collect([$field])); + $fields->shouldReceive('preProcessValidatables')->andReturnSelf(); + + $validation = (new Validator)->fields($fields)->withRules([ + 'one' => 'test:{bar}', + 'two' => 'another:{baz},{qux},{quux}', + ])->withReplacements([ + 'foo' => 'FOO', + 'bar' => 'BAR', + 'baz' => 'BAZ', + 'quux' => 'QUUX', + ]); + + $this->assertEquals([ + 'one' => ['required', 'test:FOO', 'test:BAR'], + 'two' => ['another:BAZ,NULL,QUUX'], + ], $validation->rules()); + } } From dd9850a46f744a6820465d45a614d0398b665c67 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 11 May 2021 16:42:51 -0400 Subject: [PATCH 2/3] Pass along replacements in entries --- .../CP/Collections/EntriesController.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index 7974b10f8d3..118a2b0aca9 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -164,7 +164,14 @@ public function update(Request $request, $collection, $entry) $fields = $entry->blueprint()->fields()->addValues($data); - $fields->validate(Entry::updateRules($collection, $entry)); + $fields + ->validator() + ->withRules(Entry::updateRules($collection, $entry)) + ->withReplacements([ + 'id' => $entry->id(), + 'collection' => $collection->handle(), + 'site' => $entry->locale(), + ])->validate(); $values = $fields->process()->values(); @@ -302,7 +309,13 @@ public function store(Request $request, $collection, $site) $fields = $blueprint->fields()->addValues($data); - $fields->validate(Entry::createRules($collection, $site)); + $fields + ->validator() + ->withRules(Entry::createRules($collection, $site)) + ->withReplacements([ + 'collection' => $collection->handle(), + 'site' => $site->handle(), + ])->validate(); $values = $fields->process()->values()->except(['slug', 'date', 'blueprint']); From fe4c5af078fb8b652670a3de5a1fd22bf56df230 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 11 May 2021 16:50:23 -0400 Subject: [PATCH 3/3] add unique entry value rule to suggestions, and handle inserting a rule with a colon but isn't expecting params to be typed --- resources/js/components/field-validation/Builder.vue | 6 +++++- resources/js/components/field-validation/Rules.js | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/resources/js/components/field-validation/Builder.vue b/resources/js/components/field-validation/Builder.vue index 5da152c8084..beaf4635351 100644 --- a/resources/js/components/field-validation/Builder.vue +++ b/resources/js/components/field-validation/Builder.vue @@ -47,7 +47,7 @@ />