|
| 1 | +# Map requests using Valinor |
| 2 | + |
| 3 | +* Status: Accepted |
| 4 | +* Date: 2026-05-14 |
| 5 | + |
| 6 | +## Context and problem statement |
| 7 | + |
| 8 | +Shlink has traditionally been using the `laminas/laminas-inputfilter` package for input filtering and validation, and then mapped DTOs manually from the result of InputFilter objects. |
| 9 | + |
| 10 | +This package (together with `laminas/laminas-filter` and `laminas/laminas-validation`) has a few problems: |
| 11 | + |
| 12 | +* Is starting to be left behind, blocking the update to `laminas/laminas-servicemanager` 4 for a couple of years already. |
| 13 | +* Defining filtering and validation rules is verbose. |
| 14 | +* It's not super straightforward to follow when dealing with complex or nested data structures (see [RedirectRulesInputFilter](https://github.com/shlinkio/shlink/blob/f3f351afe56b31baaf4124caa31b191c44dd620e/module/Core/src/RedirectRule/Model/Validation/RedirectRulesInputFilter.php)). |
| 15 | +* Forces some type definitions to be duplicated between validation rules and DTOs (a field is a number, a field is a date with a particular format, etc.) |
| 16 | + |
| 17 | +Because of that, I've been considering using the `cuyz/valinor` package, which allows to map data structures into objects, with implicit validation based on types and PHPStan annotations. |
| 18 | + |
| 19 | +For more complex filtering and validation rules, it supports [custom converters](https://valinor-php.dev/latest/how-to/convert-input/), which can replace existing custom input filters. |
| 20 | + |
| 21 | +## Considered options |
| 22 | + |
| 23 | +1. Keep `laminas/laminas-inputfilter`. |
| 24 | +2. Migrate to `cuyz/valinor`. |
| 25 | + |
| 26 | +## Decision outcome |
| 27 | + |
| 28 | +Using `cuyz/valinor` will save many lines of code and make data mapping more straightforward, even with a couple rough edges in mind. |
| 29 | + |
| 30 | +## Pros and Cons of the Options |
| 31 | + |
| 32 | +### 1 - Keep `laminas/laminas-inputfilter` |
| 33 | + |
| 34 | +* Good: because no code changes are needed. |
| 35 | +* Good: because we can continue using some custom rules created over the years to work with this package. |
| 36 | +* Bad: because it's blocking the update to `laminas/laminas-servicemanager` 4, without a clear path for this to change. |
| 37 | +* Bad: because working with it is a bit cumbersome and requires a lot of boilerplate. |
| 38 | +* Bad: because it causes type definition duplication between DTO fields and validation rules. |
| 39 | + |
| 40 | +### 2 - Migrate to `cuyz/valinor` |
| 41 | + |
| 42 | +* Good: because it reduces the amount of dependencies and unblocks the update to `laminas/laminas-servicemanager` 4. |
| 43 | +* Good: because it reduces duplication and allows to rely on nested DTOs for complex data structures, which are more intuitive to use. |
| 44 | +* Bad: because it relies in an external mapper to fully ensure DTOs are valid on creation, since some filtering and validation is defined in the mapper configuration or attributes only applied by the mapper. |
| 45 | +* Bad: because it requires refactoring a lot of code and adjusting tests. |
| 46 | +* Bad: because many custom filtering and validation rules need to be recreated. |
0 commit comments