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>
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.
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`.
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
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.
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.
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.
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.
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
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.
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.
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.
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
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.
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.
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.
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.
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
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
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.
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.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>