-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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] Add validation Rule::raw($rule, $parameters)
#43779
[9.x] Add validation Rule::raw($rule, $parameters)
#43779
Conversation
|
||
return $result; | ||
}); | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change has been added so that parameters that have been given as key => value
pairs (such as with the dimensions
rule), are properly pushed onto the result, rather than attempting to explode the array, throwing an exception.
A default empty array has also been added, so that the $result
starts out as an array, allowing array_push
to function. It previous would be null
, until it being converted into an array via $result[$key]
.
Is this needed? For rules that use those reserved characters
E.g: $data = [
'|name' => 'Gary',
'name2' => 'Gary',
'role' => 'user',
];
$rules = [
'name2' => ['required', ['same', '|name']],
'test' => ['string', ['required_if', '|name', 'Gary']],
'role' => ['string', ['regex', '/^(super|admin)$/i']],
];
$v = Validator::make($data, $rules);
dd($v->errors()); Output:
|
See above @stevebauman |
|
Disregard the above. @garygreen, this syntax doesn't work with arrays: $data = [
'items' => [
['|name' => 'foo'],
]
];
$rules = [
'items' => ['array'],
'items.*' => ['array', ['required_array_keys', '|name']]
];
// BadMethodCallException: Method Illuminate\Validation\Validator::validateName does not exist
Validator::make($data, $rules)->passes(); However, this works: $data = [
'items' => [
'|name' => 'foo',
]
];
$rules = [
'items' => ['array', ['required_array_keys', '|name']],
];
// true
Validator::make($data, $rules)->passes(); |
Hmm that's strange, I'm actually testing this on our Laravel 6 LTS release - your first code works in Laravel 6, it passes. So presumably something in a newer Laravel version has caused this? Edit: seems to also work in Laravel 8... haven't tested 9 yet. |
Yep, your example is broken in Laravel 9... but Laravel 6, 7, 8 all works with your first example. What's changed in 9 to cause that bug? I have no idea. |
@taylorotwell Maybe we should just revert framework/src/Illuminate/Validation/ValidationRuleParser.php Lines 154 to 160 in 2d6d02a
To it's previous state (before Laravel 9): foreach ((array) $rules) as $rule) {
// ...
}
https://laravel.com/docs/9.x/validation#accessing-nested-array-data $data = [
'items' => [
['name' => ['foo']],
],
];
$rules = [
'items.*' => [
Rule::forEach(function () {
return ['name' => 'regex:/^(foo)$/i'];
})
],
];
Validator::make($data, $rules)->passes(); The correct, documented syntax: $data = [
'items' => [
['name' => ['foo']],
],
];
$rules = [
'items.*' => Rule::forEach(function () {
return ['name' => 'regex:/^(foo)$/i'];
}),
];
Validator::make($data, $rules)->passes(); Removing the mentioned What are your thoughts? Here's a branch where I've removed flatten and updated the tests: 9.x...stevebauman:framework:fix-nested-array-validation-rules https://github.com/stevebauman/framework/actions/runs/2891116673 |
It looks like the issue was accidentally introduced with this PR? #40498 I think it makes sense to revert a change that introduces that bug, especially as Laravel 6 LTS is coming to an end soon and many people will be looking to upgrade to Laravel 9 and could stumble into the issue.
Does this mean the below is not possible? (I've yet to use Rule::forEach, so excuse my ignorance!) $rules = [
'items.*' => Rule::forEach(function () {
return ['more_items' => Rule::forEach(function() {
return ['name' => 'regex:/^(foo)$/i'],
});
}),
]; |
@garygreen Well it was intentionally introduced to allow for multiple $rules = [
'users.*.name' => [
Rule::forEach(function ($value, $attribute, $data) {
// ...
}),
Rule::forEach(function ($value, $attribute, $data) {
// ...
}),
],
]; But it was never documented, and it introduced the regression we're talking about now 😞
Nope, your example will still work -- see this test case in the above mentioned, fixed branch: It will only not work (if updated) when a |
@stevebauman Ahh that's cool then that nested one will still work. I thought the |
That's incorrect -- it is actually looping over each item in the array. It allows you to adjust validation rules per item, depending on the value of that item, as well as further nest array rules. |
To throw my 2 cents in; I'm broadly supportive of the idea that we roll back the change to flatten the rules. However, would this not be considered a "breaking" change given that users could be using the rule inside of an array of rules - even if it wasn't explicitly written to work that way, it worked and therefore there could be people that find it breaks by reverting that change. In the example of multiple
Additionally, by rolling back the change you'd have the option of removing the fix put in place for regex rules as that shouldn't be needed anymore right? |
Yeah agreed 👍 . I initially did this so you can place rules alongside a $rules = [
'users.*.name' => [
'in:foo,bar',
Rule::forEach(function ($value, $attribute, $data) {
// ...
}),
],
]; But in hindsight, you might as well place it inside.
Yup I believe so. I (personally) think this would be the best way to go, so we can keep the |
@stevebauman Will you be making a PR for those two things? So that's for the array regression issue introduced in Laravel 9 (#40498) and removing the unnecessary regex thing (was that part of that same PR or different one?) Also it might be worth chiming in on #43751 because it looks like nobody realised the alternative syntax could be used, so that whole discussion of hacky fixes and proposals wasn't necessary. |
@garygreen I've just submitted it, please see #43897 👍
Removing a |
Closes #43751
Related #43192
Related #40924
Description
This PR implements
Rule::raw()
, which will return aRawRule
class instance to be consumed by theValidationRuleParser
, and transformed into a rawarray
based validation rule:Problem
As described by @jyd and @timacdonald in #43751 and #43192, the validator can not properly parse reserved keywords used to extract rules, parameters, and parameter values (such as pipe
|
and comma,
):Solution
With
Rule::raw()
we can supply any string based existing Laravel validation rule and so that reserved keywords can be used in validation rule parameters, as well as input field names:Rule::raw()
also supports parameter arrays:As well as
key => value
pairs:As well rules without parameters and nesting:
As well as
Rule::forEach()
:Let me know your thoughts and if you'd like anything changed or adjusted.
Thanks for your time!