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

[12.x] Compilable for Validation Contract #54882

Merged
merged 3 commits into from
Mar 5, 2025

Conversation

peterfox
Copy link
Contributor

@peterfox peterfox commented Mar 3, 2025

Changes

  • Adds a new validation contract called Compilable.
  • Updates the ValidationRuleParser to use the Compilable contract instead of the NestedRules class for type checks.
  • Moves some of the code from NestedRules into a static Rule::compile() method so it's easier to reuse.
  • Applies Compilable contract to the original NestedRules class.

No tests added because there's no new logic added. Just refactoring. I don't believe any of the code would be breaking in this situation. The NestedRules class just behaves the same even if someone extended it. I wouldn't expect the RulesParser to be extended but no method signatures have been changed.

Why

NestedRules are great but can't be extended as a class easily without fiddling with the constructor and overloading the compile method while duplicating that logic. This PR seeks to make NestedRules use a contract that developers can use themselves to determine nested rule logic instead of being forced to use a closure.

for instance:

class FooNestedRules extends NestedRules
{
    public function __construct()
    {
        // callable property has to be set with empty closure
        parent::__construct(function() {});
    }

    public function compile($attribute, $value, $data = null, $context = null)
    {
       $rules = // do some logic to make the rules.

        $parser = new ValidationRuleParser(
            Arr::undot(Arr::wrap($data))
        );

        if (is_array($rules) && ! array_is_list($rules)) {
            $nested = [];

            foreach ($rules as $key => $rule) {
                $nested[$attribute.'.'.$key] = $rule;
            }

            $rules = $nested;
        } else {
            $rules = [$attribute => $rules];
        }

        return $parser->explode(ValidationRuleParser::filterConditionalRules($rules, $data));
    }
}

Could become a class like:

class FooNestedRules implements CompilableRules
{
    public function compile($attribute, $value, $data = null, $context = null)
    {
       $rules = // do some logic to make the rules.

       return Rule::compile($attribute, $rules, $data);
    }
}

This will make it possible for people to implement classes to manage their own nested rules.

Validation::make([
    'form' => [
        'fields' => [
           [
               'type' => 'text',
               'text'  => 'foobar',
           ],
           [
               'type'  => 'image',
               'path'  => 'foobar.jpg',
               'alt'     => 'photo of foobar',
           ]
        ]
    ]
], [
    'form.fields.*' => new FormFields();
]);

@crynobone crynobone changed the title Compilable for Validation Contract [12.x] Compilable for Validation Contract Mar 4, 2025
@taylorotwell taylorotwell merged commit 4284e61 into laravel:12.x Mar 5, 2025
39 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.

2 participants