-
Notifications
You must be signed in to change notification settings - Fork 776
Create All rule and all prefix
#1578
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
base: main
Are you sure you want to change the base?
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1578 +/- ##
============================================
+ Coverage 97.49% 97.51% +0.01%
- Complexity 986 990 +4
============================================
Files 205 206 +1
Lines 2236 2249 +13
============================================
+ Hits 2180 2193 +13
Misses 56 56 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
Pull request overview
This PR introduces a new All rule that validates all items in an array or iterable against a given rule, similar to Each but with simplified single-message presentation. It also adds an all prefix to enable composition patterns like v::allStringType().
- Implements the
Allrule class extendingFilteredNonEmptyArraywith simplified messaging - Adds
allprefix support in thePrefixtransformer for easier rule composition - Updates all mixin interfaces to support the new rule and prefix patterns
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
library/Rules/All.php |
Core implementation of the All rule with template definition and validation logic |
library/Transformers/Prefix.php |
Adds 'all' to RULES_TO_SKIP and implements prefix transformation for 'all*' methods |
library/Mixins/AllChain.php |
New mixin interface defining chainable methods for all prefixed rules |
library/Mixins/AllBuilder.php |
New mixin interface defining static builder methods for all prefixed rules |
library/Mixins/Chain.php |
Extends Chain interface with AllChain and adds all() method |
library/Mixins/Builder.php |
Extends Builder interface with AllBuilder and adds static all() method |
library/Mixins/KeyChain.php |
Adds keyAll() method signature for composing All rule with Key |
library/Mixins/KeyBuilder.php |
Adds static keyAll() method signature |
library/Mixins/NotChain.php |
Adds notAll() method signature for negating All rule |
library/Mixins/NotBuilder.php |
Adds static notAll() method signature |
library/Mixins/NullOrChain.php |
Adds nullOrAll() method signature for optional validation |
library/Mixins/NullOrBuilder.php |
Adds static nullOrAll() method signature |
library/Mixins/PropertyChain.php |
Adds propertyAll() method signature for object property validation |
library/Mixins/PropertyBuilder.php |
Adds static propertyAll() method signature |
library/Mixins/UndefOrChain.php |
Adds undefOrAll() method signature for undefined-or validation |
library/Mixins/UndefOrBuilder.php |
Adds static undefOrAll() method signature |
tests/unit/Rules/AllTest.php |
Unit tests covering valid and invalid inputs for the All rule |
tests/feature/Rules/AllTest.php |
Feature tests verifying default and inverted template messages |
tests/feature/Transformers/PrefixTest.php |
Tests the all prefix transformation with message validation |
docs/rules/All.md |
Documentation for the All rule with usage examples and categorization |
docs/rules/Each.md |
Adds cross-reference to All rule and fixes trailing whitespace |
docs/rules/Length.md |
Adds cross-references to All and Each rules |
docs/rules/Max.md |
Adds cross-reference to All rule |
docs/rules/Min.md |
Adds cross-reference to All rule |
docs/09-list-of-rules-by-category.md |
Adds All rule to Comparisons, Transformations, and Alphabetically sections |
bin/create-mixin |
Updates mixin generator to include AllBuilder and AllChain with proper configuration |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
c9e10b6 to
af52ddc
Compare
This rule behaves similarly to ``Each, but the difference is that it presents the messages in a simpler manner. This allows users to have a simpler message when validating all items in an array or iterable value. I’m also introducing the `all` prefix, making it easier for users to apply the `All` rule in combination with other rules.
af52ddc to
8836a5d
Compare
| // Message: All items in `[1.5, 2]` must be float | ||
|
|
||
| v::not(v::all(v::intType()))->assert([1, 2, -3]); | ||
| // Message: All items in `[1, 2, -3]` must not be an integer |
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 should be something like:
Message: All items in
[1, 2, -3]must not be integers
However, that would be impractical for how we build messages (would imply adding plural forms to all rules).
We can get around this by using something like:
Message: Every item in
[1, 2, -3]must not be an integer
This way, we use "every item" (singular) as the subject, instead of "all items" (plural) and we can reuse the messages without introducing a new form.
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.
That's a very nice catch! Indeed, the "All items in" will make messages grammatically incorrect.
|
|
||
| ## Alphabetically | ||
|
|
||
| - [All](rules/All.md) |
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.
I'm worried about introducing a confusion between AllOf and All.
They have very similar names, but very different behaviors. While AllOf operates on rules (the name refers to rules that must pass), All operates on input (the name refers to items that must pass a single rule).
The Each name suffers from a similar confusion (is "each" referring to rules or input items? It's not clear just from the name).
In the current state of naming, I would be more comfortable with names like these:
Collectioninstead ofAll: it says that we're going to validate the input as a single collection, hinting that individual messages for each item are not relevant, the "whole collection" is.CollectionMapinstead ofEach: it says we're doing a "map" on each item of the Collection, and therefore getting more detailed results.
This also puts these two together in the alphabetical list and closer in auto-completion actions, making it easier for developers.
The all name does sound better in chains. For example, allPositive is much more intuitive than collectionPositive. Perhaps by using CollectionOf instead would lead to something like collectionOfPositive, which is more verbose.
What we're dealing here is a category conflict. Rules such AllOf and AnyOf are referring to rules themselves and Each is referring to items. It's hard to be consistent, because we need to be able to target both. I considered using LogicAnd and LogicOr for those in the past. This has the benefit of being more explicit, but it results to a less readable chain (the names "all of" and "one of" could be used in english sentences, but "logic and" and "logic or" are more geeky).
I think the Logic prefix makes more sense. The rules that do that (AllOf, AnyOf, NoneOf, When) are the exception (they are talking about the rules, not the input). So they should get a special prefix instead, and all other rules are assuming to be talking about the input instead.
- AllOf -> LogicAnd
- AnyOf -> LogicOr
- NoneOf -> LogicNand
TL;DR: the All name is the best, but AllOf is a problematic legacy naming. We need to decide, one of those categories of validators will get more verbose.
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.
Excellent point, perhaps would be a good idea to rename those rules before we release 3.0.
I think it makes sense to keep this one as "all", it's quite intuitive, and then we could do something like this:
| Old | New |
|---|---|
| AllOf | LogicAnd |
| AnyOf | LogicOr |
| OneOf | LogicXor |
| NoneOf | LogicNor |
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.
Oops, I previously associated NoneOf with LogicNand, but you're right, it's LogicNor!
Also, When could be LogicTernary, it also belongs to that family somehow.
There's an argument for making Not into LogicNot as well, but I would make an exception to that one for brevity.
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.
I'm not so sure about the LogicTernary, it looks very verbose even though it makes sense.
About "Not" I think it's more like "Inversion" than "Not", but brevity indeed wins there
This rule behaves similarly to ``Each, but the difference is that it presents the messages in a simpler manner. This allows users to have a simpler message when validating all items in an array or iterable value.
I’m also introducing the
allprefix, making it easier for users to apply theAllrule in combination with other rules.