Commit graph

12 commits

Author SHA1 Message Date
Alexandre Gomes Gaigalas
91ceaafd2d Update translation docs
The documents on translation were updated to feature symfony with
an array provider. Duplicated container notes were extracted to
a single configuration.md file.

An API for accessing the messages, so users don't have to copy
and paste them from the source or docs, was provided and
TemplateResolver was refactored to use it.
2026-02-06 17:11:34 +00:00
Henrique Moody
7c681fec66
Fix SPDX headers in all files
I ran the `bin/console spdx --fix` with different strategies for
different files. For most of the core classes, since they've been
drastically rebuilt, I've run it with the `git-blame` strategy, for for
the `src/Validators`, in which the API changed completely but the logic
remains the same, I use the `git-log` strategy.
2026-02-03 15:23:23 +01:00
Alexandre Gomes Gaigalas
1b584d88a3 Handle more collision scenarios on NestedArrayFormatter
See #1668 for more info.

There is a new test "Deep name collision" on AllOfTest that
exemplifies the kind of collision this change solves.

Some extra `__root__` keys needed to be added to a select few
other scenarios for consistency.
2026-02-02 20:21:14 +00: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
Alexandre Gomes Gaigalas
cd96d01364 Fix message overriding bug in NestedArrayFormatter
This commit resolves an issue where validation messages would overwrite
each other when multiple validators failed on the same path or key
(e.g., within an `Each` or `Key` validator).

Changes to `NestedArrayFormatter`:
- Implemented a merge strategy: Key collisions now result in a list of
  messages instead of the last message winning.
- Improved handling of mixed key types: When both numeric and string
  keys are present (common in composite validators), numeric keys are now
  replaced by the validator's ID (e.g., `arrayType`, `equals`) to provide
  meaningful, distinct keys.
- Preserved list behavior: Purely numeric key sets are treated as lists,
  maintaining their sequence without re-keying logic.
- Refactored the class to use smaller, single-purpose methods and
  `array_reduce` for clarity.

Tests:
- Updated feature tests (`EachTest`, `AttributesTest`, etc.) to expect the
  full set of validation errors.
- Enhanced `NestedArrayFormatterTest` with scenarios for key collisions,
  mixed keys, and ID substitution.
2026-01-12 10:42:11 +00: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
5b00d69766
Update how we handle templates
Currently, the templates that a user provides when running `assert()`
can significantly impact how the message is displayed. Because of this,
the formatters become complex as they all need to handle similar
conditions to format results.

This commit changes this behaviour, letting only the
`InterpolationRenderer` handle the templates. This makes the code
simpler and allows people to use the `InterpolationRenderer` directly,
without needing to figure out how to handle templates. Thinking about it
further, I believe handling templates is a concern for the `Renderer`
anyway, and this will open the way to other improvements using the
renderer.

I also removed the exception that is thrown when the template is not a
string, because I think that after validation has failed, we should not
throw any other exceptions, as that could cause unexpected errors for
users.
2025-12-22 14:05:55 +01:00
Henrique Moody
644ecb5190
Change the contract of the formatters
Both `ArrayFormatter` and `StringFormatter` accept an instance of the
`Translator`. Thinking about it a bit better, I realised that a
formatter might not always need a `Translator`, but it will surely need
a `Renderer`.

Besides, the `InterpolationRenderer` needs to take translation into
account, so it seems more natural to me that this is the one that will
get an instance of the `Translator`, as other implementations of the
`Renderer` might not even deal with translations.
2025-12-22 13:43:59 +01:00
Henrique Moody
bf9b970e24
Move important value objects to the root namespace
The `Id`, `Name`, and `Path` value objects are not only message-related
concerns, they're part of the core of the library, hence it makes sense
to place them at the root namespace.
2025-12-21 11:14:47 +01:00
Henrique Moody
137c74c5b3
Change how we trace the path of results
Currently, we’re using scalar values to trace paths. The problem with
that approach is that we can’t create a reliable hierarchy with them, as
we can’t know for sure when a path is the same for different rules. By
using an object, we can easily compare and create a parent-child
relationship with it.

While making these changes, I deemed it necessary to also create objects
to handle Name and Id, which makes the code simpler and more robust. By
having Name and Path, we can create specific stringifiers that allow us
to customise how we render those values.

I didn’t manage to make those changes atomically, which is why this
commit makes so many changes. I found myself moving back and forth, and
making all those changes at once was the best solution I found.
2025-12-20 22:19:17 +01:00
Henrique Moody
82e0722443
Split the Formatter into different formatters
I've noticed that the `StandardFormatter` was quite bloated, which made
it difficult to maintain. Understanding what each method was doing was
quite complicated. Besides, the name "Standard" doesn't mean anything,
because it doesn't say what the implementation does.

I split the `Formatter` into two different interfaces: `StringFormatter`
and `ArrayFormatter`, and I moved some code around:

*  `StandardFormatter::main()` -> `FirstResultStringFormatter`
* `StandardFormatter::full()` -> `NestedListStringFormatter`
* `StandardFormatter::array()` -> `NestedArrayFormatter`

That opens up new ways of handling error messages, potentially
introducing features like `JsonStringFormatter` or `FlatArrayFormatter`
in the future.

While working on this, I removed a significant amount of unnecessary
code, which also improved my overall understanding of those formatters.

I'm not very happy with all the methods in `ValidatorDefaults`, but I
will refactor that later.
2025-12-19 16:20:28 +01:00