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

[9.x] Introduce Invokable validation classes #42689

Merged
merged 3 commits into from Jun 7, 2022

Conversation

timacdonald
Copy link
Member

@timacdonald timacdonald commented Jun 7, 2022

This PR aims to introduce a new class based validation implementation that mixes the brevity + simplicity of Closure based rules with the shareable, extendable, and chainable nature of class based rules by introducing an Invokable validation rule.

Some additional notes:

  • Brings 1st party translation support to failure messages, without the need to reach for the translation helper.
  • You no longer need to manage state around messages and failures when it comes to complex validation where multiple validation errors may occur.
  • Within a complex validation rule, you can no longer add a messaged and return true. Adding a messages causes the rule to fail - so no more double handling.
  • Having the error messages managed in another layer also creates consistency across validation rules.
  • An exception is thrown when it is unable to find a validation key, if $fail('key')->translate() is called. I've see this a bit where validation messages are not added. This makes it strict about finding the validation message.

Below is a comparison of the two implementations with a rule that handles a rich object...

class Quantity implements Rule
{
    protected $messages = [];

    public function passes($attribute, $value)
    {
        if (! is_array($value)) {
            $this->messages[] = trans('validation.quantity.must_be_an_object');

            return false;
        }

        if (! array_key_exists('magnitude', $value)) {
            $this->messages[] = trans('validation.quantity.missing_magnitude');
        }

        if (! array_key_exists('units', $value)) {
            $this->messages[] = trans('validation.quantity.missing_units');
        }

        return $this->messages === [];
    }

    public function message()
    {
        return $this->messages;
    }
}
class InvokableQuantity implements InvokableRule
{
    public function __invoke($attribute, $value, $fail)
    {
        if (! is_array($value)) {
            return $fail('validation.quantity.must_be_an_object')->translate();
        }

        if (! array_key_exists('magnitude', $value)) {
            $fail('validation.quantity.missing_magnitude')->translate();
        }

        if (! array_key_exists('units', $value)) {
            $fail('validation.quantity.missing_units')->translate();
        }
    }
}

@timacdonald timacdonald changed the title Introduce Invokable validation classes [9.x] Introduce Invokable validation classes Jun 7, 2022
@tpetry
Copy link
Contributor

tpetry commented Jun 7, 2022

I would love to get rid of the boilerplate of passes() and message() just to have a failure-specific error messages. Really like the approach of also using $fail()!

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

4 participants