Commit graph

359 commits

Author SHA1 Message Date
Henrique Moody
7f66bcea10
Bump PHP support from 8.1 to 8.5
We want to release version 3.0 as fresh as possible, without having to
maintain backward compatibility with the previous versions. Because that
version will be on for some time, we decided it will be best to support
only PHP version 8.5 or higher.

Acked-by: Alexandre Gomes Gaigalas <alganet@gmail.com>
2025-12-18 19:03:38 +01:00
steven.lewis
2b364764f7 Extend UUID rule support to versions 1 through 8 2025-05-27 14:54:20 +01:00
Henrique Moody
94d53df8ea
Allow to use certain rules as class attributes
There are a few cases in which we want to validate the object as a
whole, and that validation could be attached to the class as a PHP
attribute. This commit enables that capability and changes a few rules
to be class attributes.
2025-01-16 10:27:16 +01:00
Henrique Moody
a0d6355980
Update some templates and improve tests
Some templates were a bit confusing, and I would like to favour adding
the `{{name}}` at the beginning of the templates as it helps when
reading nested messages.

I also deleted the regression tests for issue #1348, because it's a
non-issue, actually. The best approach to that problem is indeed using
`When` insteaf of `OneOf`.
2024-12-27 15:55:55 +01:00
Henrique Moody
a3c197f600
Handle names via the Named rule
Because of how the validation engine works now [1], there's no reason to
keep adding names to each rule. Instead, create a single rule that
handles naming rules with a few other accessories. This change is not
necessarily simple, but it shrinks the `Rule` interface, and it's more
aligned with how the library works right now.

Personally, I think this API is much more straightforward than the
`setName()` method, as it's way more explicit about which rule we're
naming. Because of this change, the behaviour changed slightly, but it's
for the best.

Because of this change, I managed to remove a lot of code, but
unfortunately, it's quite a big-bang commit. It would be too complicated
to make it atomic since names are an intrinsic part of the library.

[1]: 238f2d506a
2024-12-26 23:10:19 +01:00
Henrique Moody
1d1da7f099
Create "Templated" rule
Because of how the validation engine works, there's no reason to keep
adding templates to each rule. Instead, creating a single rule that
handles templating rules will simplify the library greatly and shrink
the `Rule` interface.

Personally, I think this API is much more straightforward than the
`setTemplate()` method, as it's way more explicit which rule is being
templated.
2024-12-26 14:40:09 +01:00
Henrique Moody
634a155c63
Always display the input
The "NotBlank", "NotEmpty", and "NotUndef" rules do not display the
input in all cases and instead displays the string "The value". The
problem with that is that one doesn't see which value was passed, which
is not so useful.

This commit will changes those rules to always display the input. If
someone doesn't want the input to show, they can always set a name for
the rule.
2024-12-22 06:55:21 +01:00
Henrique Moody
873be39105
Fix grammar error in the "AllOf" rule 2024-12-20 17:06:53 +01:00
Henrique Moody
0c07060a04
Rename "Consecutive" to "Circuit"
The "Consecutive" rule is now renamed to "Circuit" to better reflect its
behavior of stopping at the first failure. I also favour this name
because it's much shorter.
2024-12-20 16:53:56 +01:00
Dominick Johnson
243f91c3d4
Allow Min and Max to wrap chained rules
This follows the same pattern as the `Length` rule.

I've also removed the separate named and standard templates from these
rules. I didn't see a good way to implement these in the new pattern,
and also felt the language of the old standard template was somewhat
difficult to read anyway.
2024-12-20 15:08:31 +01:00
Henrique Moody
aa293dea72
Only create Length with subsequents when possible
Since I updated the validation engine[1], it became possible to create
results with subsequents[2]. This commit changes the "Length", allowing
it to create a result with a subsequent only when it's possible. That
will improve the clarity of the error messages.

[1]: 238f2d506a
[2]: 52e628fc6f
2024-12-16 21:47:53 +01:00
Henrique Moody
6e3ed793b8
Refactor Size rule
Currently, the Size rule does multiple things, yet it's limited. Because
it does many things, it's also confusing. Turning the Size rule into a
transformation allows for way more flexibility and clarity.

The syntax becomes more verbose, but the rule becomes more reusable.
2024-12-16 20:56:12 +01:00
Henrique Moody
7cec227520
Create "Attribute" rule
With this change, any rule can be used as a PHP attribute. I have wanted
to implement this feature for a while, as it allows you to bind the
validation to a specific property and just validate the object
afterwards.
2024-12-13 03:49:29 +01:00
Henrique Moody
4a16ad3d09
Allow templates to be callables
There are a few use cases in which you would like to have a custom
exception but, at the same time, reuse the message or exception that
validation might give you.

This commit creates a new feature that allows users to define a callable
that will generate an exception when it fails.
2024-12-11 17:50:47 +01:00
Henrique Moody
bba39a4bfb
Add headings to the templates 2024-12-09 01:34:50 +01:00
Henrique Moody
d5cf1311c8
Update DateTimeDiff to generate results with siblings
Since I updated the validation engine[1], it became possible to create
results with siblings. This commit changes the "DateTimeDiff", allowing
it to create a result with a sibling when possible. That will improve
the clarity of the error messages.

While at it, I noticed that we were not translating the type of
interval, so I fixed that and improved the documentation.

[1]: 238f2d506a
2024-12-09 01:31:26 +01:00
Henrique Moody
be72a54845
Add templates to each rule documentation
They only know what message a rule produces when they try running it.
Including the messages in the documentation will make it easier for
people to know what to expect.

There are a couple of undocumented placeholders, but I can live with
that for now.
2024-12-06 00:21:47 +01:00
Henrique Moody
7f1eef6bf7
Improve several validation messages
I'm not a native English speaker, and the same goes for many
contributors from this library. Because of that, some messages just
don't sound very good, so I updated a lot of them.
2024-12-05 23:37:42 +01:00
Henrique Moody
e6af762fe4
Rename "Validatable" to "Rule"
Besides the interface's name, everything already calls this type "Rule",
not "Validatable." This commit puts a stone on it and renames the
interface for better naming.
2024-12-05 19:32:14 +01:00
Henrique Moody
d356696af9
Upgrade translation mechanism
Currently, defining translations is quite cumbersome, and the translator
callback is passed to the constructor of multiple classes, which makes
it quite ugly and could make translations inconsistent.

This commit completely changes how translations are done in Validation.
Instead of using a callback, it uses a specific class, and `Validator`
will pass that object through the objects that render the messages.
2024-12-05 15:42:40 +01:00
Henrique Moody
3833ad70f8
Improve the "Feature Guide" documentation
Because the document was quite big already, I split the exception
handling part to another document.
2024-12-05 00:21:34 +01:00
Henrique Moody
eb459ad7e4
Update UndefOr to generate results with siblings
Since I updated the validation engine[1], it became possible to create
results with siblings. This commit changes the "UndefOr", allowing it to
create a result with a sibling when possible. That will improve the
clarity of the error message.

[1]: 238f2d506a
2024-12-04 19:08:32 +01:00
Henrique Moody
d1e0c8b0c1
Update NullOr to generate results with siblings
Since I updated the validation engine[1], it became possible to create
results with siblings. This commit changes the "NullOr", allowing it to
create a result with a sibling when possible. That will improve the
clarity of the error message.

I also updated the documentation, since it was still called "Nullable"

[1]: 238f2d506a
2024-12-04 18:06:12 +01:00
Henrique Moody
061a3c9c09
Rename method "validate()" to "isValid()"
The method has been renamed some time ago, but I haven't updated the
documentation to cause less confusion. Now that I want to start updating
the documentation, I switched the default branch on GitHub to the latest
stable version, so I assume there will be less confusion in the
documentation, and I can start updating the docs for the next version.
2024-12-02 22:11:57 +01:00
Henrique Moody
2aa5e39c54
Improve KeySet rule
After changes in the key-related rules, the KeySet rule became unusable.
Besides, when evaluating an input, it wasn't reporting every single
failure because it would not validate the items in the array if they had
missing or extra keys.

This commit will make several improvements to the rule. It will create
some not(keyExists($key)) rules for the extra keys, which makes the
error reporting much better. A limit of 10 additional keys will show up
when asserting an input with extra keys. I put that limit in place to
prevent the creation of too many rules.
2024-12-02 20:09:47 +01:00
Henrique Moody
de9e310f99
Deprecate age-related rules
Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-11-26 20:32:01 +01:00
Henrique Moody
cf03f8ad5f
Create "DateTimeDiff" rule
Co-authored-by: Gabriel Goulart <vieirabiel2009@hotmail.com>
2024-11-26 18:25:29 +01:00
Henrique Moody
4fd26e39bb
Rename "NotOptional" to "NotUndef"
Since I've already renamed the "Optional" rule to "UnderOf," it makes
sense to rename this rule too.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-05-06 20:45:27 +02:00
Henrique Moody
2ae1df177a
Allow to customise messages while asserting
Because we now have a single "assert()" method, we have more freedom to
add more customizations to it. This specific one is handy if someone
wants to use the library to validate but wants to use their own
exceptions.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-26 15:04:04 +01:00
Henrique Moody
707dcae65f
Refactor the "UndefOr" rule and related classes
This commit will rename the "Optional" rule to"UndefOr" while soft
deprecating the old name. It should work the same as the previous one
but with a different name. It will also prefix the result ID, allowing
more message customization.

While working on it, I realized that the prefix "undefOr" had a typo,
and it was using "undefOf" instead. I fixed that, too.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-26 01:35:36 +01:00
Henrique Moody
66faefd695
Remove previous validation engine
After many refactorings, no rules use the previous validation engine.
That means we can remove the unused code from the repository and switch
from the previous to the new validation engine everywhere.

This commit will also soft deprecate the methods "validate()", and
"check()" in all the rules and the "assert()" in all rules but the
Validator itself. That means using those methods will still be allowed,
but static analysis tools might complain.

This is a big step toward releasing the next major version, as the code
is pretty much the way it should be when I release the next version.
There's some documentation to be updated, and I would like to change the
behavior of a couple of rules.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-25 12:28:25 +01:00
Henrique Moody
9eafe52252
Refactor the Length rule
Currently, the Length rule does multiple things, yet it's limited.
Because it does many things, it's also confusing. Turning the Length
rule into a transformation allows for way more flexibility and clarity.

The syntax becomes more verbose, but I can solve that later by creating
a Transformer enables creating rules with the "length" as a prefix.

While making this change, I also removed the support for counting
objects and integers. I find that way too confusing.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-19 15:38:29 +01:00
Ville Hukkamäki
a5d042be7b
Create "Hetu" rule
This rule validates Finnish personal identity codes.

Co-authored-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-15 11:28:08 +01:00
Henrique Moody
52b75bc1ed
Create BetweenExclusive rule
Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-11 11:57:24 +01:00
Henrique Moody
2610a380dc
Replace "LazyConsecutive" with "Consecutive"
With this and the Lazy rule, the LazyConsecutive lost its purpose.

While working on it, I did refactor the Domain rule a bit, but mainly to
check how this rule could behave.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-06 23:57:49 +01:00
Henrique Moody
78715fb844
Create "Lazy" rule
This rule resembles a proper replacement for the old "KeyValue" rule
rather than the "LazyConsecutive" rule[1]. I will soon delete the
"LazyConsecutive" rule and replace it with something else.

[1]: 41245f663f

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-06 22:06:44 +01:00
Henrique Moody
24885e4a5f
Remove "KeyNested" rule
Because we have the Key and Property rules, the KeyNested is redundant,
although it's a helpful shortcut.

The real problem is dealing with messages and templates because the
structure of the validator needs to match the structure of the rule.
When using the `getMessages()` method from the exception we throw in
`assert()`, we get a flat structure, which is often not the intended
structure.

The KeyNested rule is cool, but it adds some complexity to the codebase
that I'm unwilling to deal with. It's not nice to remove a rule,
especially because I know people use it, but it's for the best. I'm
trying to keep the codebase small, so hopefully, it will get easier to
maintain.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-05 02:28:16 +01:00
Henrique Moody
d36572cc25
Split the "Property" rule
Currently, the Property rule has a third parameter that allows the
validation of the wrapped rule to be optional, meaning that the
validation will only happen if the property exists. That parameter makes
the rule harder to understand at times.

I'm splitting the Property rule into Property, PropertyExists, and
PropertyOptional. That way, it becomes apparent when someone wants only
to validate whether a property exists or if they will validate the value
of the property only when it exists.

I deliberately didn't create an abstract class because those rules are
different enough not to have an abstraction. In fact, I can see myself
deleting the AbstractRelated after I refactor the KeyNested rule.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-05 00:48:31 +01:00
Henrique Moody
a647a4737b
Split "Key" rules
Currently, the Key rule has a third parameter that allows the validation
of the wrapped rule to be optional, meaning that the validation will
only happen if the key exists. That parameter makes the rule harder to
understand at times.

I'm splitting the Key rule into Key, KeyExists, and KeyOptional. That
way, it becomes apparent when someone wants only to validate whether a
key exists or if they're going to validate the value of the key only
when it exists.

I deliberately didn't create an abstract class because those rules are
different enough not to have an abstraction. In fact, I can see myself
deleting the  "AbstractRelated" in the upcoming changes.

With these changes, the KeySet rule will not accept validating if the
key exists or validating the value only if the key exists. I should
refactor that soon, and I will likely need to create a common interface
for Key, KeyExists, and KeyOptional.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-04 00:06:18 +01:00
Henrique Moody
cea77d2a46
Recreate "Max" rule
The "Max" rule is not a transformation, validating the maximum value in
the input against a given rule.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-03 16:39:44 +01:00
Henrique Moody
433ceb4452
Update the validation engine of the "Each" rule
These changes will also introduce an abstract rule that validates
non-empty-iterable values. The abstract rule can also be the parent of
the recently created "Min" rule. Therefore, I've changed that class too.

I've introduced many tests for the "Each" rule to make sure what its
expected behavior is. I'm not super happy with its output, but I tried a
couple of options, and it is the best choice.

Note that Each now rejects `stdClass` and empty iterable values. I
thought that would make sense, as it would be useless when the input is
empty.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-03 14:45:47 +01:00
Henrique Moody
210aa4ac01
Recreate "IterableType" rule
The difference with this rule is that it matches the behavior of
`is_iterable()`, which is different from `IterableVal` that also allows
instances of `stdClass.`

This is a necessary change because PHP will trigger an error when trying
to pass any object to anything typed as `iterable`

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-03-02 13:20:13 +01:00
Henrique Moody
980ab28707
Rename "IterableType" into "IterableVal"
When we created this rule in version 1.0 in 2015, PHP was in version
5.6, and the `is_iterable()` function didn't exist. Only in version 7.1,
released at the end of 2016, was the pseudo-type "iterable" introduced
to PHP.

This old "IterableType" rule is almost obsolete. Still, I decided to
keep it because it is possible to use foreach in any object, as it will
iterate over its public properties. I did rename the rule because that
makes more sense. An "IterableType" rule should guarantee that the input
type is the real-(pseudo)-iterable.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-29 23:02:32 +01:00
Henrique Moody
471e147c4d
Rename "Aggregations" category into "Transformations"
I think that name gives a better idea of what those rules do.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-29 21:54:37 +01:00
Henrique Moody
cc96ee9102
Create "Min" rule
With this rule, we introduce a new type of rule, which is only possible
due to the changes in the validation engine.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-27 22:36:06 +01:00
Henrique Moody
2f12b6c8d8
Rename "Max" to "LessThanOrEqual"
Although the name is much longer, it's more explicit what it does. I
confess that after a while without using Validation, even I get confused
about that. Besides, I would like to create another rule with the same
name, but that will behave differently.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-27 21:12:13 +01:00
Henrique Moody
7658187720
Rename "Min" to "GreaterThanOrEqual"
Although the name is much longer, it's more explicit what it does. I
confess that after a while without using Validation, even I get confused
about that. Besides, I would like to create another rule with the same
name, but that will behave differently.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-27 21:04:45 +01:00
Henrique Moody
c04034c2a4
Update the validation engine of composite-based rules
This change will also make the composite-based rules require at least
two rules in their constructor because those rules do not make sense
with only one rule.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-23 00:56:30 +01:00
Henrique Moody
41245f663f
Replace "KeyValue" with "LazyConsecutive" rule
I want to avoid having the Factory inside the rules. If a rule needs to
create another, it can simply instantiate that. The "KeyValue" rule does
too many things under the hood, and the behavior can be unpredictable.

The "LazyConsecutive" rule makes the validation more explicit and way
more flexible, as there could be other cases in which someone only wants
to validate something if the previous validator passes.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-22 20:45:50 +01:00
Henrique Moody
a45a0a26ab
Use PHP ISO Codes in the "LanguageCode" rule
Since we now have PHP ISO Codes as a dependency[1], it doesn't make
sense to keep dealing with this data ourselves.

[1]: 04b2722d02

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
2024-02-22 19:27:49 +01:00