Skip to content

Conversation

@henriquemoody
Copy link
Member

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.

@codecov
Copy link

codecov bot commented Dec 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.51%. Comparing base (562d98d) to head (8836a5d).

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a 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 All rule class extending FilteredNonEmptyArray with simplified messaging
  • Adds all prefix support in the Prefix transformer 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.

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.
// 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
Copy link
Member

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.

Copy link
Member Author

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)
Copy link
Member

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:

  • Collection instead of All: 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.
  • CollectionMap instead of Each: 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.

Copy link
Member Author

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

Copy link
Member

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.

Copy link
Member Author

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

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