Commit graph

406 commits

Author SHA1 Message Date
Alexandre Gomes Gaigalas
ec16b3d2df Refactor case sensitiveness support
This is a mid-size refactor that affects several validators.

Most prominently, the ones that had an `$identical` parameter
to deal with case sensitiveness.

This parameter was confusing, effectively making validators such
as `Contains` behave very differently for arrays versus strings.

In arrays, `$identical` meant "the same type", while it in strings
it meant "case sensitive".

That parameter was removed, and the default behavior is now to
always compare **case sensitive** and strict typing.

A document explaining how to combine other validators in order
to achieve case _insensitive_ comparisons was added.

Additionally, the `Call` validator was refactored back to be
suitable to take on the task of being a fast, quick composable
validator.

With the introduction of `Circuit`, we can shift the responsibility
of dealing with possible mismatches to the user. This kind of type
handling is demonstrated in how I refactored `Tld` to account for
the type mismatch without setting error handlers.
2026-01-30 17:11:13 +00:00
Alexandre Gomes Gaigalas
47f8f82d7f Remove mathematical, niche and deprecated validators
This commit removes validators described in #1642, refactoring
to clean up after their removal.

 - Url was refactored to use the function `filter_var` instead.
 - tests/bootstrap.php is no longer needed and was removed.
 - Updated migration guide with recommendations for replacements.
2026-01-30 16:08:27 +00:00
Alexandre Gomes Gaigalas
2a7f345e32 Streamline validators.md index
Makes it so the index looks more like a cheatsheet, condensing
information instead of making long lists that require lots of
scrolling to explore.

Additionally, the happy path for each validator was also
added, providing a quick reference use for comparison.

The direct markdown links were replaced by titled markdown
references, offering mouse-over tooltips over links that
display the validator one-line description.

To ensure a proper source of truth for these new index
goodies, the AssertionMessageLinter was modified to
verify that the first assertion in each doc is a
single-line validator that passes (a happy path), further
making our documentation conventions more solid.
2026-01-28 12:47:08 +00:00
Henrique Moody
68ed5d20d1
Create migration guide from v2 to v3
As we approach the release of version 3.0, it is important to provide our users
with a clear guide to migrating from version 2.x to 3.0. This commit provides
guidance by creating a document that will remain in the repository, so users can
always access it.
2026-01-27 14:40:28 +01:00
Henrique Moody
00e7f2a6ff
Fix ResultQuery::findByPath() for nested paths
The `findByPath()` method was failing to return results when using nested
dot-notation paths such as `user.email` or `items.1`. However, it’s returning
`null` instead of the expected result in some cases.

The root cause was a mismatch between how paths are stored vs searched:

- Storage: Validators like Key and Each create results where the path is stored
  as a linked list. For `user.email`, the "email" result has `path="email"` with
  `parent="user"`.

- Search (old): The method expected a tree structure where it would find a child
  with `path="user"`, then search that child for `path="email"`. But no child
  had `path="user"` - only "email" (with "user" as its parent).

The fix computes each result's full path by walking up the parent chain and
compares it against the search path. Also converts numeric strings to integers
when parsing paths (e.g., `items.1` → `['items', 1]`) since array indices are
stored as integers.

While working on this fix, I also realised that to expose the result's status,
it’s best to use `hasFailed()` instead of `isValid()` in `ResultQuery`, since
users will mostly use results when validation failed, not when it passed.

Assisted-by: Claude Code (Opus 4.5)
2026-01-27 13:25:40 +01:00
Alexandre Gomes Gaigalas
bd48bdcda4 Lint Changelog format in validator docs
Introduces a Markdown linter for checking the Changelog format.

"See Also" was transformed into a section to make it easier to
handle it with the `Content` class. The "Related" linter was
simplified to reflect that change too.

An additional "alignment" parameter was added to markdown table
generators, allowing the padding and headers to be explicitly
marked with a specific left (-1), middle (0) or right(1)
alignment.

Existing files were fixed using the `fix` option after the
changes.
2026-01-26 19:11:00 +00:00
Henrique Moody
d1d8980ff9
Use awesome-pages to customize the menus
We tried using `mkdocs-nav-weight` but it turned out quiet limited. Not
only we have to add specific frontmatter to the Markdown files, but we
could also not hide and sort directories.

This commit introduces awesome-pages, which allows us to customize the
order of pages and not list the content of the "validators" directory in
the left menu.
2026-01-26 12:26:06 +01:00
Henrique Moody
aee9123eac
Simplify placeholder pipes documentation
Reference StringFormatter project for modifier details instead of
duplicating documentation.

Assisted-by: Claude Code (Opus 4.5)
2026-01-26 12:00:47 +01:00
Henrique Moody
316200d8ce
Update message placeholder conversion documentation
This documentation had become outdated after significant changes to the
codebase, including the replacement of the template rendering code with
Respect\StringFormatter.

Assisted-by: Claude Code (Opus 4.5)
2026-01-26 12:00:39 +01:00
Henrique Moody
9e22fb02d7
Update "Message Translation" documentation
After many changes to the codebase, this documentation was outdated.

Assisted-by: Claude Code (Opus 4.5)
2026-01-26 12:00:30 +01:00
Henrique Moody
f85d34db3d
Update "Handling Exceptions" documentation
After many changes in the codebase, the documentation was outdated.
2026-01-26 12:00:17 +01:00
Henrique Moody
a12cabb1a9
Remove "license.md" file
Since we have the license in several different places, we might as well
remove the license from the documentation.
2026-01-26 10:34:40 +01:00
Henrique Moody
140bd36aa3
Rename library/ to src/
We've always considered renaming this directory, as it's not a common
standard to name `library` the directory where the source code of a
library it. Having it as `src/` is a common pattern we find in several
PHP libraries these days.

Acked-by: Alexandre Gomes Gaigalas <alganet@gmail.com>
2026-01-22 13:13:15 +01:00
Henrique Moody
a372a0b90b
Replace template rendering code with Respect\StringFormatter
I've moved almost all the code for placeholder replacement and parameter
modifiers into an external library called Respect\StringFormatter. This approach
allows us to evolve the template capabilities without making major changes to the
Validation's code.

This commit will introduce another dependency, `respect/string-formatter`, and
will upgrade the version of `respect/string-formatter`, which simplifies our
internal API greatly.

While making this change, I also updated how we generate exceptions. Instead of
rendering the full message and the array of messages, we delegate that creation
to the `ResultQuery`, which improves performance because we don’t need to render
those big messages unless the user actually needs them.
2026-01-21 17:29:15 +01:00
Alexandre Gomes Gaigalas
d9cdc118b2 Introduce REUSE compliance
This commit introduces REUSE compliance by annotating all files
with SPDX information and placing the reused licences in the
LICENSES folder.

We additionally removed the docheader tool which is made obsolete
by this change.

The main LICENSE and copyright text of the project is now not under
my personal name anymore, and it belongs to "The Respect Project
Contributors" instead.

This change restores author names to several files, giving the
appropriate attribution for contributions.
2026-01-21 06:28:11 +00:00
Henrique Moody
66a92cdd91
Update "Feature guide" documentation
The documentation was quite outdated after the many changes I made in
the main branch. This commit will make sure it's up-to-date.

I'm also creating a "Placeholder pipes" documentation, so there's not
too much content in the "Feature guide"

Assisted-by: Zed (devstral-2:123b)
2026-01-19 10:47:37 +01:00
Henrique Moody
9e768ccae3
Fix wrong links in the list of validators
The file changed directory and I forgot to rename it. This commit fixes
that.
2026-01-18 18:15:43 +01:00
Alexandre Gomes Gaigalas
8e5938a059 Introduce ContainsCount validator
This validator is similar to Contains, but also checks how many
times the needle appears.

Additionally, the Domain validator was changed to use it instead
of relying on an unserializable callback, thus, making it
serializable.
2026-01-15 13:39:46 +00:00
Henrique Moody
d2198dfd01
Replace isValid() calls with assert()
There's more value on showing how `assert()` displays the validation
messages than simply showing if `isValid()` returns `true` or `false`.

However, that increases the chances of having outdated documentation, so
I created a doc linter that updates the Markdown files with the
correct message.
2026-01-13 23:37:06 -07:00
Henrique Moody
98150c7065
Add doc linter to check outdated templates
We don't often change the tempaltes of validators, but when we do it's
extremely important that the documentation of the validators match the
exact template the validator has.
2026-01-13 23:37:06 -07:00
Henrique Moody
7aef3763f2
Add doc linter to check related validators
This commit ensures that if validator A has a direct link to validator
B, validator B will have a direct link to validator A too.
2026-01-13 23:37:06 -07:00
Henrique Moody
d38736d167
Add doc linter to check validator constructors
When we make changes to the code, renaming variables, or adding
parameters to a validator, it's easy to forget to update the
documentation.

With this change, we avoid having a disparity between the documentation
and the code.
2026-01-13 23:37:05 -07:00
Henrique Moody
098c973a2a
Add GitHub action to lint documentation files
When we make changes to the category of a validator, it's easy to forget
to update overall list of validators. This commit a GitHub actions that
will run a console command to check if the documentation it up-to-date.

The job will fail when we need to change the document, but the console
command will fix the issues, so there isn't a lot of friction there.
2026-01-13 23:37:05 -07:00
Henrique Moody
4cc45b55a8
Create a "Getting started" page
That allows users to quickly start playing with Validation.
2026-01-10 15:43:31 +01:00
Henrique Moody
6022914cf0
Remove Yes and No rules
I created those validators to make it easy to parse parameters or
console command inputs that were answers to questions one might ask.

One of the biggest problems is that it depends on the machine's locale,
which can be a bit troublesome, rather than receiving a locale in the
constructor. That doesn’t allow for a lot of flexibility when someone
has a multi-lingual application. Additionally, these validators rely on
the regex from `nl_langinfo()`, which is very permissive, resulting in
false positives.

I have a working version of a console command that retrieves data from
the Unicode Common Locale Data Repository (CLDR) and updates a list of
`yesstr` and `nostr` strings from the main XML file of each language.
However, I came to realise that the whole thing is not worth it.

The validators Yes and No can be replaced by using rules like `Regex`
and `In`. They won’t have the ease of multilingual support, but I don’t
think those validators are used a lot. So, I decided I would just remove
them, and if users really ask for it in the next major version, I’d be
happy to revive my branch.
2026-01-10 05:47:28 +01:00
Henrique Moody
35ea95c6f0
Remove number prefixes from Markdown files
We used to have those to preserve the order of the pages when generating
the documentation with MkDocs. This commit introduces the
`mkdocs-nav-weight`, that allows us to make that order without having
those prefixes.
2026-01-07 14:46:06 +01:00
Henrique Moody
7892a7c902
Port Bash scripts to PHP
It makes more sense to use PHP to generate PHP code than to use Bash. I
love writing Bash scripts, but I know it's not for everyone, and they
can become quite complex. Porting them to PHP code also lowers the
barrier for people to change them.

While I was making those changes, I also noticed a problem with how we
save the domain suffixes. We're converting all of them to ASCII, so we
are not preserving languages such as Chinese, Thai, and Hebrew, which
use non-ASCII characters.
2026-01-06 10:06:22 +01:00
Henrique Moody
905cef85c7
Improve syntax highlighting in MkDocs pages
The syntax of PHP code was not showing with different colors, but shown
as plain/text.
2026-01-05 17:54:43 +01:00
Henrique Moody
81310cc4d9
Rename namespace Rules to Validators
Since that namespace contains our “validators”, naming it as such makes
much more sense.
2026-01-05 17:36:35 +01:00
Henrique Moody
5afb69d6ad
Rename RuleFactory to ValidatorFactory
Since this factory creates “validators”, it makes sense that its name
follows the same name as the objects it creates.
2026-01-05 17:36:35 +01:00
Henrique Moody
54ac76adce
Rename Rule to Validator
The name "rule" has always been confusing to me. It can be when you talk
about "validation rules", but it’s a very verbose way to describe it,
and it doesn’t work all the time.

This commit will rename the interface `Rule` to `Validator`, but it will
also rename the concept of "rule" to "validator".
2026-01-05 17:36:34 +01:00
Henrique Moody
1a2c52079f
Rename Validator to ValidatorBuilder
The `Validator` class implements the Builder patterns, because it builds
a complex validator within a chain. This is a major breaking change, as
the `Validator` class is the foundation of the library. However, that’s
something relatively easy to replace everywhere.
2026-01-05 11:57:40 +01:00
Henrique Moody
daf3d9389d
Change order of arguments in Templated rule
Having the template itself as a first argument makes the rule way more
intuitive. The third parameter is not as used as the first one, so, even
though it's very connected with the template, I thought it was better to
keep it as the third argument.
2026-01-04 15:21:50 +01:00
Henrique Moody
accd4ac36f
Change order of arguments in Named rule
Having the name as the first argument makes it more intuitive.
2026-01-04 15:07:26 +01:00
Henrique Moody
0a45eaf9e4
Create All rule and all prefix
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.
2026-01-04 12:23:01 +01:00
Henrique Moody
b5ad7aa47a
Make Validator immutable
Mutable objects can be challenging to work with in larger codebases
because different parts of a system may modify the same instance, making
it difficult to trace where and when changes occurred. This becomes
especially problematic when debugging unexpected behaviour.

By making `Validator` immutable, we ensure that adding rules via
`with()` returns a new instance rather than mutating the original, and
we use the `with()` method inside `__call()`, making every call to a
rule into a clone of the current `Validator`.

This provides several benefits:

1. Predictability: A `Validator` instance will always behave the same
   way throughout its lifetime, regardless of what other parts of the
   codebase do.

2. Safe dependency injection: Users can now confidently inject a base
   `Validator` from a DI container, knowing that any modifications made
   elsewhere will not affect their instance.

3. Easier debugging: Since validators cannot be mutated after creation,
   there's no need to track down where an unexpected rule was added.

4. Reusability: Users can create an initial `Validator` with some base
   rules and reuse it by just adding new rules to the chain without
   affecting the base `Validator`.
2026-01-02 15:45:23 +01:00
Henrique Moody
8d08f47152
Remove the setName() method from Validator
The `setName()` method can be confusing, as it can be tricky for someone
to determine which chain is being named. Using the `Named` rule makes
this much more explicit and adds a little bit of verbosity. For users,
this will be a significant change, but there are easy ways to update
this code in their projects, so I’m not overly concerned about it.

Another benefit of this change is that it makes the `Validator` much
simpler, as it no longer needs to track the name.
2026-01-02 15:45:23 +01:00
Henrique Moody
562d98d805
Refactor the NotEmpty rule
Since we have the ability to use `not` as a prefix, having rules that
validate negative behaviour makes them a bit inflexible, verbose, and
harder to understand.

This commit will refactor the `NotEmpty`, and rename it to `Falsy`. It
will no longer trim strings, because Blank does a much better job at it;
it only simulates the behaviour of PHP’s native `empty()` function.

Because `Falsy`, `Blank`, and `Undef` have similar behaviour, I created
a page to demonstrate the difference and show when the user should use
one or the other.

Assisted-by: Cursor (claude-4.5-opus-high)
2025-12-29 12:48:35 +01:00
Henrique Moody
951c16e8e6
Refactor the NotEmoji rule
Since we have the ability to use `not` as a prefix, having rules that
validate negative behaviour makes them a bit inflexible, verbose, and
harder to understand.

This commit will refactor the `NotEmoji` and rename it to `Emoji`. It
will no longer check if the string contains emojis, but rather if the
string is an emoji or not. I’m also adding support to more emojis, since
the rule was a bit outdated.

This change will make the validator more strict, but will make it useful
in other scenarios. However, later on, I would like to create a rule
called `has` which, could use a validator like `Emoji` to check if the
input _has_ emojis.

Assisted-by: Cursor (claude-4.5-opus-high)
2025-12-29 11:16:25 +01:00
Henrique Moody
a37cac7142
Invert the behaviour of NoWhitespace
Since we have the ability to use `not` as a prefix, having rules that
validate negative behavior makes them a bit inflexible, verbose, and
harder to understand.

This commit will refactor the `NoWhitespace` rule by inverting its
behaviour and renaming it to `Spaced`. Although this is a breaking
change, users will still be able to have a similar behavior with the
prefix `not` + `Spaced`.
2025-12-29 09:11:01 +01:00
Henrique Moody
7046560f77
Invert the behaviour of NotUndef
Since we have the ability to use `not` as a prefix, having rules that
start with not becomes a bit inflexible, verbose, and harder to
understand.

This commit will refactor the `NotUndef` rule by inverting its behaviour
and renaming it to `Undef`.
2025-12-27 18:49:46 +01:00
Henrique Moody
338c186803
Invert the behaviour of NotBlank
Since we have the ability to use `not` as a prefix, having rules that
start with not becomes a bit inflexible, verbose, and harder to
understand.

This commit will refactor the `NotBlank` rule by inverting its behaviour
and renaming it to `Blank`. Although this is a breaking change, users
will not feel it because "NotBlank" will still be available by using the
`not` prefix followed by the `Blank` rule.
2025-12-27 17:18:30 +01:00
Henrique Moody
8e77021ce7
Reformat documentation files
There was some inconsistent Markdown, and some links were out of sync.
2025-12-27 17:03:25 +01:00
Henrique Moody
7636944ea6
Register v as a class alias to Validator
This is a pattern that we already use everywhere, so it makes sense to
simply turn `v` into a class alias to `Validator`, which will allow
people to use all the examples in the documentation without needing to
import the namespace.

We already do that when we run tests, so I just changed it to be a
global setting.
2025-12-27 00:08:35 +01:00
Henrique Moody
48405271c5
Replace placeholder "name" with "subject"
The `{{name}}` placeholder could represent different things depending on
the state of the Result, and referring to it as `{{name}}` seems
arbitrary. This commit changes it to `{{subject}}`, which is much more
generic and it describes well what that placeholder can mean.
2025-12-26 21:30:01 +01:00
Henrique Moody
8332d28acc
Do not overwrite existing names
This commit addresses the skipped tests by modifying certain core
concepts in the library. The way names work has always been somewhat
confusing, even to me. I’ve established that existing names will never
be overwritten, and if a path is already defined, we will change the
name to also include the path.

I’m not very happy with how I’m solving this problem, because the
`FirstResultStringFormatter` is changing some behaviour in the results
that seems to be something that should always happen before. But, for
the moment, I will keep it as is.
2025-12-26 14:48:23 +01:00
Henrique Moody
fd7438f9c7
Use a DI container to create instances of Validator
The `ValidatorDefaults` is cumbersome, and customising it can be
annoying. Most projects use some sort of dependency injection container,
and by integrating the creation of the `Validator` with the PSR-11, we
allow users to easily customise how they create validators.

Some tasks, like overwriting the `Translator`, become a bit more
verbose, if the user is not already using a PSR-11 container, but I
think that’s a good tradeoff.
2025-12-22 13:12:04 +01:00
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