diff --git a/src/Extend/Validator.php b/src/Extend/Validator.php new file mode 100644 index 000000000..62301e93c --- /dev/null +++ b/src/Extend/Validator.php @@ -0,0 +1,58 @@ +validator = $validatorClass; + } + + /** + * Configure the validator. This is often used to adjust validation rules, but can be + * used to make other changes to the validator as well. + * + * @param callable $callable + * + * The callable can be a closure or invokable class, and should accept: + * - \Flarum\Foundation\AbstractValidator $flarumValidator: The Flarum validator wrapper + * - \Illuminate\Validation\Validator $validator: The Laravel validator instance + */ + public function configure($callback) + { + $this->configurationCallbacks[] = $callback; + + return $this; + } + + public function extend(Container $container, Extension $extension = null) + { + $container->resolving($this->validator, function ($validator, $container) { + foreach ($this->configurationCallbacks as $callback) { + if (is_string($callback)) { + $callback = $container->make($callback); + } + + $validator->addConfiguration($callback); + } + }); + } +} diff --git a/src/Foundation/AbstractValidator.php b/src/Foundation/AbstractValidator.php index 37fff96bd..980558337 100644 --- a/src/Foundation/AbstractValidator.php +++ b/src/Foundation/AbstractValidator.php @@ -18,6 +18,16 @@ use Symfony\Component\Translation\TranslatorInterface; abstract class AbstractValidator { + /** + * @var array + */ + protected $configuration = []; + + public function addConfiguration($callable) + { + $this->configuration[] = $callable; + } + /** * @var array */ @@ -92,10 +102,17 @@ abstract class AbstractValidator $validator = $this->validator->make($attributes, $rules, $this->getMessages()); + /** + * @deprecated in beta 15, removed in beta 16. + */ $this->events->dispatch( new Validating($this, $validator) ); + foreach ($this->configuration as $callable) { + $callable($this, $validator); + } + return $validator; } } diff --git a/src/Foundation/Event/Validating.php b/src/Foundation/Event/Validating.php index c8a6befcb..86c6d4cd3 100644 --- a/src/Foundation/Event/Validating.php +++ b/src/Foundation/Event/Validating.php @@ -13,6 +13,7 @@ use Flarum\Foundation\AbstractValidator; use Illuminate\Validation\Validator; /** + * @deprecated in Beta 15, remove in beta 16. Use the Validator extender instead. * The `Validating` event is called when a validator instance for a * model is being built. This event can be used to add custom rules/extensions * to the validator for when validation takes place. diff --git a/tests/integration/extenders/ValidatorTest.php b/tests/integration/extenders/ValidatorTest.php new file mode 100644 index 000000000..6a93e8bb6 --- /dev/null +++ b/tests/integration/extenders/ValidatorTest.php @@ -0,0 +1,97 @@ +extend((new Extend\Validator(UserValidator::class))->configure(function ($flarumValidator, $validator) { + $validator->setRules([ + 'password' => [ + 'required', + 'min:20' + ] + ] + $validator->getRules()); + })); + } + + private function extendToRequireLongPasswordViaInvokableClass() + { + $this->extend((new Extend\Validator(UserValidator::class))->configure(CustomValidatorClass::class)); + } + + /** + * @test + */ + public function custom_validation_rule_does_not_exist_by_default() + { + $this->app()->getContainer()->make(UserValidator::class)->assertValid(['password' => 'simplePassword']); + + // If we have gotten this far, no validation exception has been thrown, so the test is succesful. + $this->assertTrue(true); + } + + /** + * @test + */ + public function custom_validation_rule_exists_if_added() + { + $this->extendToRequireLongPassword(); + + $this->expectException(ValidationException::class); + + $this->app()->getContainer()->make(UserValidator::class)->assertValid(['password' => 'simplePassword']); + } + + /** + * @test + */ + public function custom_validation_rule_exists_if_added_via_invokable_class() + { + $this->extendToRequireLongPasswordViaInvokableClass(); + + $this->expectException(ValidationException::class); + + $this->app()->getContainer()->make(UserValidator::class)->assertValid(['password' => 'simplePassword']); + } + + /** + * @test + */ + public function custom_validation_rule_doesnt_affect_other_validators() + { + $this->extendToRequireLongPassword(); + + $this->app()->getContainer()->make(GroupValidator::class)->assertValid(['password' => 'simplePassword']); + + // If we have gotten this far, no validation exception has been thrown, so the test is succesful. + $this->assertTrue(true); + } +} + +class CustomValidatorClass +{ + public function __invoke($flarumValidator, $validator) + { + $validator->setRules([ + 'password' => [ + 'required', + 'min:20' + ] + ] + $validator->getRules()); + } +}