Skip to content

Commit 96ef41e

Browse files
authored
Merge pull request #2603 from acelaya-forks/valinor-migration-adr
Add ADR file for migration to cuyz/valinor for request mapping
2 parents 38e805c + 3a8c69b commit 96ef41e

5 files changed

Lines changed: 53 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
1414

1515
### Changed
1616
* [#2555](https://github.com/shlinkio/shlink/issues/2555) Update docker image to PHP 8.5.
17+
* [#2590](https://github.com/shlinkio/shlink/issues/2590) Migrate to `cuyz/valinor` for request input mapping, filtering and validation.
1718

1819
### Deprecated
1920
* *Nothing*
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.

docs/adr/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Here listed you will find the different architectural decisions taken in the project, including all the reasoning behind it, options considered, and final outcome.
44

5+
* [2026-05-14 Map requests using Valinor](2026-05-14-map-requests-using-valinor.md)
56
* [2024-10-24 Handle dev and tests config via env vars instead of local config files](2024-10-24-handle-dev-and-tests-config-via-env-vars-instead-of-local-config-files.md)
67
* [2023-07-09 Build `latest` docker image only for actual releases](2023-07-09-build-latest-docker-image-only-for-actual-releases.md)
78
* [2023-01-06 Support any HTTP method in short URLs](2023-01-06-support-any-http-method-in-short-urls.md)

module/CLI/test/Command/ShortUrl/ListShortUrlsCommandTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ public static function provideOptionalFlags(): iterable
202202
// phpcs:enable
203203
}
204204

205+
/**
206+
* @param positive-int|null $page
207+
*/
205208
#[Test, DataProvider('provideArgs')]
206209
public function serviceIsInvokedWithProvidedArgs(
207210
array $commandArgs,

module/Core/src/ShortUrl/Model/ShortUrlsParams.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
public DateRange|null $dateRange;
2424

2525
/**
26+
* @param positive-int $page
27+
* @param -1|positive-int $itemsPerPage
2628
* @param string[] $tags
2729
* @param string[] $excludeTags
2830
*/

0 commit comments

Comments
 (0)