-
Notifications
You must be signed in to change notification settings - Fork 11.3k
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] Introduce Rule::anyOf() for Validating Against Multiple Rule Sets #55191
Conversation
* feat: add more validation tests * wip: add failing test * wip: add basic string rule validations * chore: rename object fields for better debugging * refactor: rename ruleSets to rules * fix: respect array rule validation --------- Co-authored-by: Christian Ascone <[email protected]> * fix: this should be passing because AnyOf has no type relevance and 'required' only checks to see if the field has something in it --------- Co-authored-by: Christian Ascone <[email protected]> --------- Co-authored-by: Christian Ascone <[email protected]>
@brianferri One thing that is driving me kinda crazy with this PR is the |
… properties to be more descriptive/analogous to use cases
I dunno - something about this just doesn't sit right with me. I don't like the nested array syntax for defining anyOf rules as it's inconsistent with how nested rules are defined in other ways. If I wanted to define a anyOf rule for a nested attribute I would want to just do this: `user.profile.age' => ['required', Rule::anyOf(...)], I just want to use this like a normal rule but it feels like it has all this special behavior I have to think about. |
That is definitely still possible, I've added some assertions in the test to verify that. The nesting tests I made we're mostly to make sure that the the validations don't break with nesting of different anyOf rules; As well as demonstrate the possibility of using anyOf as a way to make nested validations without having to necessarily use the dot notation. Should this behavior be prevented in some way instead? Maybe prevent recursive anyOf rules on instantiation; Though I find that limiting, and it'd go against the spec |
I can't figure out why this passes... @brianferri $v = Validator::make([
'persons' => [
[
'age' => 12,
],
[
'age' => 'foobar',
],
],
], [
'persons.*.age' => [
'required',
Rule::anyOf([
['min:10'],
['integer'],
]),
],
]); |
Thanks! |
…ets (#55191) * [12.x] introduce `Rule::oneOf()` (#laravel/framework#54880) * chore: apply styleCI * feat: add nested oneOf validation test * chore: apply styleCI * refactor: rename `oneof` into `anyof` to fit implementation * fix: wrong failure message * feat: update base tests * feat: add test case * chore: apply styleCI * formatting * feat: allow string fields * feat: add test and clean nested rules * chore: apply styleCI * failing test * Validation tests (#1) * feat: add more validation tests * wip: add failing test * wip: add basic string rule validations * chore: rename object fields for better debugging * refactor: rename ruleSets to rules * fix: respect array rule validation --------- Co-authored-by: Christian Ascone <[email protected]> * fix: this should be passing because AnyOf has no type relevance and 'required' only checks to see if the field has something in it --------- Co-authored-by: Christian Ascone <[email protected]> --------- Co-authored-by: Christian Ascone <[email protected]> * chore: correspond with recent changes brianferri/framework@de3b902 * chore: remove unused private property * feat: attribute mapping in favor of potentially indexed mapping * feat: add more tests * refactor(tests): remove unnecessary amount of tests, rename parameter properties to be more descriptive/analogous to use cases * chore: apply styleCI * feat: add tests to verify compliance with dot notation nesting validator * formatting * fix: remove messages * fix(wip): regression introduced in 14598f62bf8305bbe2a94ee4e2848d6ec2e05587 laravel/framework#55191 (comment) * feat: implement star rule counter tests for simple and nested rules Co-authored-by: Christian Ascone <[email protected]> * chore: apply styleCI --------- Co-authored-by: Taylor Otwell <[email protected]> Co-authored-by: Christian Ascone <[email protected]>
…ets (#55191) * [12.x] introduce `Rule::oneOf()` (#laravel/framework#54880) * chore: apply styleCI * feat: add nested oneOf validation test * chore: apply styleCI * refactor: rename `oneof` into `anyof` to fit implementation * fix: wrong failure message * feat: update base tests * feat: add test case * chore: apply styleCI * formatting * feat: allow string fields * feat: add test and clean nested rules * chore: apply styleCI * failing test * Validation tests (#1) * feat: add more validation tests * wip: add failing test * wip: add basic string rule validations * chore: rename object fields for better debugging * refactor: rename ruleSets to rules * fix: respect array rule validation --------- Co-authored-by: Christian Ascone <[email protected]> * fix: this should be passing because AnyOf has no type relevance and 'required' only checks to see if the field has something in it --------- Co-authored-by: Christian Ascone <[email protected]> --------- Co-authored-by: Christian Ascone <[email protected]> * chore: correspond with recent changes brianferri/framework@de3b902 * chore: remove unused private property * feat: attribute mapping in favor of potentially indexed mapping * feat: add more tests * refactor(tests): remove unnecessary amount of tests, rename parameter properties to be more descriptive/analogous to use cases * chore: apply styleCI * feat: add tests to verify compliance with dot notation nesting validator * formatting * fix: remove messages * fix(wip): regression introduced in 14598f62bf8305bbe2a94ee4e2848d6ec2e05587 laravel/framework#55191 (comment) * feat: implement star rule counter tests for simple and nested rules Co-authored-by: Christian Ascone <[email protected]> * chore: apply styleCI --------- Co-authored-by: Taylor Otwell <[email protected]> Co-authored-by: Christian Ascone <[email protected]>
Note
Non-Breaking Change
This PR does not modify any existing validation rules—it only introduces a new rule.
This PR introduces a new validation rule,
Rule::anyOf()
, allowing a field to be validated against multiple predefined rule sets, ensuring that at least one set fully passes. This feature is particularly useful for validating tagged unions, discriminator-based validation (as seen in OpenAPI specs), or alternative input structures in FormRequest validation.Some keypoints on how this would benefit end users:
required_if
,sometimes
, or custom logic,anyOf()
provides an expressive way to define alternative validation paths using objects which don't need to be necessarily flat maps of validation rules.A practical example is the one I've mentioned in my discussion, with some additional attempts to implement this as a custom rule as well.
A sort of "emergent behavior" from this implementation is also the possibility of nested validations using nested
AnyOf
rules as well, which would allow for deep parsing of body parameters inFormRequests
I look forward to receiving feedback and fixing, implementing or improving the implementation in the event that the current one is not deemed worthy.
Example Usage
Regular rule declaration (Base case for
anyOf
)The
p1
value effectively determines what the "shape" of the object to be validated should beRegular rule declaration using dynamic sets from OpenAPI Spec [Discussion Example]
Nested rules (Which becomes emergent from the nature of the
passes()
method inanyOf
validation)