henzeb / ruler-laravel
extends Laravel's validator using their own Rule interface
Requires
- php: ^8.1
- illuminate/support: ^10|^11
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^9.0|^10
README
This library allows you to use your Rule as a string, just like you use existing validators
like required
, required_if
or unique
.
For example: Laravel has bundled a rule for enums. As the parameter you pass is a string, you should be able to use it like this:
[ 'attribute'=>'required|enum:App\Enums\YourEnum' ]
right?
wrong!
In order to use it like this, you need to extend your Validator
and use the Illuminate\Validation\Rules\Enum
rule, or create your
own version. This library simplifies that process.
I've gone ahead and registered enum
for you, but you can just as easily add your own rules.
Installation
You can install the package via composer:
composer require henzeb/ruler-laravel
note: I only support PHP ^8.1 because of the enums.
Usage
Simply add the Henzeb\Ruler\Concerns\Ruler
trait to your service provider and
add your rules to the $rules
property.
use Henzeb\Ruler\Concerns\Ruler; use Illuminate\Support\ServiceProvider; use App\Rules\YourRule; use App\Rules\YourOtherRule; class YourProvider extends ServiceProvider { use Ruler; private array $rules = [ 'your_rule' => YourRule::class, YourOtherRule::class ]; }
You can either specify a name, or just let Ruler create a name for you.
For example: YourOtherRule
will get the name your_other_rule
.
If your provider needs to implement the boot method, just call the bootRuler
method inside that boot
method
use Henzeb\Ruler\Concerns\Ruler; use Illuminate\Support\ServiceProvider; use App\Rules\YourRule; use App\Rules\YourOtherRule; class YourProvider extends ServiceProvider { use Ruler; private array $rules = [ 'your_rule' => YourRule::class, YourOtherRule::class ]; public function boot() { $this->bootRuler(); // your code } }
It is also possible to do it yourself in case you need to do it conditionally.
use Henzeb\Ruler\Concerns\Ruler; use Illuminate\Support\ServiceProvider; use App\Rules\YourRule; use App\Rules\YourOtherRule; class YourProvider extends ServiceProvider { use Ruler; public function boot() { if(/** some condition */) { $this->rule(YourRule::class, 'your_rule'); } if(/** some condition */) { $this->rule(YourOtherRule::class); } // your code } }
The Rule class
The rules are implemented just like any other Rule
you'd normally define.
So you'll be familiar with the implementation.
use Illuminate\Contracts\Validation\Rule; class YourRule implements Rule { public function passes($attribute, $value) { // your validation code } public function message() { return 'Message when fails'; } }
Note: You can also use invokable rules here.
Parameters
You can use parameters. Just add a constructor with the parameters in the order you'd like to use them. Optional parameters are supported.
Note: As for now, you'll receive them as strings, no casting to other scalars is done at this time.
public function __construct(private string $param1, private string $param2 = null){}
Implicit rules
To add an implicit rule, all you have to do is implement
the Illuminate\Contracts\Validation\ImplicitRule
interface.
Ruler will do the rest for you.
use Illuminate\Contracts\Validation\ImplicitRule; class YourImplicitRule implements ImplicitRule { // the code }
Dependent rules
To add a dependent rule, just implement
the Illuminate\Contracts\Validation\DataAwareRule
interface.
interface Ruler will do the rest for you.
use Illuminate\Contracts\Validation\DataAwareRule; class DependentRule implements DataAwareRule { private array $data; public function setData(array $data) { $this->data = $data; return $this; } // your code }
Validator aware rules
Ruler also supports Validator aware rules. Just implement the required interface.
mixing up interfaces
You can mix up the interfaces just like you would in vanilla Laravel.
For instance: A rule that is implicit
can also
be dependent
The error message
The error message should be placed in the message
method
as defined in Illuminate\Contracts\Validation\Rule
,
just as you normally would.
The message method is called dynamically, which means you can store the message in your
Rule
instance and return it in the message
method.
use Henzeb\Ruler\Contracts\ReplacerAwareRule; use Illuminate\Contracts\Validation\Rule; class YourRule implements Rule { return string $message = 'Something went wrong'; public __construct($param_1, $paramTwo) {} public function passes($attribute, $value) { $this->message = 'Your error message'; return false; } public function message() { return return $this->message; } }
It also supports returning arrays. When an array is returned, the MessageBag
contains
the messages as if they were coming from different validation rules. This way your Rule
can do grouped validations (for instance using another Validator instance).
replacers
Out of the box, you can use :<number>
to point to a parameter, but if you want them named,
you can use the Henzeb\Ruler\Contracts\ReplacerAwareRule
interface.
use Henzeb\Ruler\Contracts\ReplacerAwareRule; class YourRule implements ReplacerAwareRule { public __construct($param_1, $paramTwo) {} public function message() { return ':attribute :param_1 :paramTwo'; } public function replacers(): array { return [ 'param_1', 'paramTwo' ]; } }
The parameters are in order as specified. param_1
will point to the value of $param_1
and so on.
Closures
You can add a Closure
to a replacer if you have specific needs. A Closure
always
receives the value of the current parameter, the attributes name, the other parameters (named)
and all the fields that are under validation.
class YourRule implements ReplacerAwareRule { public function message() { return ':attribute :param_1 :paramTwo'; } public function replacers(): array { return [ 'param_1'=> function(string $value, string $attribute, array $parameters, array $data) { return 'any string'.$parameters['paramTwo'] }, 'paramTwo' ]; } }
Overriding the Validator resolver
Because Ruler has a custom Validator instance set to resolve by Laravel, you need to extend
the Henzeb\Ruler\Validator\RulerValidator
class in case you want to change the resolver.
Testing
composer test
Changelog
Please see CHANGELOG for more information what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email henzeberkheij@gmail.com instead of using the issue tracker.
Credits
License
The GNU AGPLv. Please see License File for more information.