Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.x] Support for validation Rule objects #9332

Merged

Conversation

martyf
Copy link
Contributor

@martyf martyf commented Jan 16, 2024

Laravel 10 has marked the existing Illuminate\Contracts\Validation\Rule as deprecated, and new rules are created using Illuminate\Contracts\Validation\ValidationRule, which can't be added to Laravel's Validator using the extend method (unless I'm missing something).

This PR adds support for a new syntax for using your own custom rules for Blueprint validation.

You can make your Laravel Rule as per Laravel's docs, such as:

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class MyCustomRule implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        // your rule logic
        // call $fail('your error message') when validation fails
    }
}

In the YAML or Blueprint editor, you can attach this rule to the validation using the rule: prefix:

validate:
  - rule:\App\Rules\MyCustomRule

This also supports rules that have custom parameters:

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class HasOneDefaultRule implements ValidationRule
{
    protected $varA;
    protected $varB;

    public function __construct($a, $b)
    {
        $this->varA = $a;
        $this->varB = $b;
    }

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        // your rule logic
    }
}

Params are in the key:value syntax, with multiple separated by commas. Such as:
rule:{class}:{keyA}:{valueA},{keyB}:{valueB},{keyC}:{valueC}

rule:\App\Rules\MyCustomRule:varA:valueA,varB:valueB

This will call the MyCustomRule, and pass valueA and valueB as the parameters.

There may be a neater way to handle the parameters but this keeps it as open-ended as possible for the user's rule implementation.

@jasonvarga
Copy link
Member

Hey Marty. I've pushed some tweaks to this PR and if you could try it out that'd be great.

We opted for more of a PHP syntax that would match what the Laravel docs tell you to do.

Instead of:

rule:\App\Rules\MyCustomRule:varA:valueA,varB:valueB

you can do:

new App\Rules\MyCustomRule('value a', 'value b')

Named arguments should work too:

new App\Rules\MyCustomRule(varB: 'value b')

It should feel quite natural when typing into the control panel, as if you're writing PHP.

CleanShot 2024-02-27 at 17 31 37

If you're writing directly in the yaml, you'll need to be careful of escaping quotes though. (If you use the control panel, that'll be automatic)

validate:
  - required
  - 'new App\Rules\MyCustomRule(''value a'', ''value b'')'

@martyf
Copy link
Contributor Author

martyf commented Feb 28, 2024

Absolute perfection. I love this!

@jasonvarga jasonvarga changed the title [4.x] Support for class-based rules with new “rule:” syntax [4.x] Support for validation Rule objects Feb 28, 2024
@jasonvarga jasonvarga merged commit b9b56ad into statamic:4.x Feb 28, 2024
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants