-
-
Notifications
You must be signed in to change notification settings - Fork 82
Description
Hi @romm
I am using converters to map $_POST data to strongly typed objects. Since all values in the $_POST array are strings, I manually convert them to their respective scalar type using converter functions. Here is a stripped down example:
class MyClass {
public function __construct(
public int $value,
) {}
}
$result = (new \CuyZ\Valinor\MapperBuilder())
// Convert string to int
->registerConverter(function (string $value, callable $next): int {
$result = filter_var($value, \FILTER_VALIDATE_INT);
if ($result === false) {
throw MessageBuilder::newError('Invalid integer format.')->build();
}
return $next($result);
})
->mapper()
->map(MyClass::class, ['value' => '42']);
echo $result->value; // 42This works fine. However, any attribute converters that I define on the property are skipped:
#[\CuyZ\Valinor\Mapper\AsConverter]
#[\Attribute(\Attribute::TARGET_PROPERTY)]
class ClampToSeven {
public function map(int $value, callable $next): int {
return $next(min($value, 7));
}
}
class MyClass {
public function __construct(
#[ClampToSeven]
public int $value,
) {}
}
$result = (new \CuyZ\Valinor\MapperBuilder())
// Convert string to int
->registerConverter(function (string $value, callable $next): int {
$result = filter_var($value, \FILTER_VALIDATE_INT);
if ($result === false) {
throw MessageBuilder::newError('Invalid integer format.')->build();
}
return $next($result);
})
->mapper()
->map(MyClass::class, ['value' => '42']);
echo $result->value; // expected 7, actual 42I believe the reason for this behavior lies in the the order of the converter stack:
Valinor/src/Mapper/Tree/Builder/ValueConverterNodeBuilder.php
Lines 60 to 67 in 35470e5
| $stack = [ | |
| ...array_map( | |
| // @phpstan-ignore method.notFound (we know the `map` method exists) | |
| static fn (AttributeDefinition $attribute) => $attribute->instantiate()->map(...), | |
| $converterAttributes->toArray(), | |
| ), | |
| ...$this->converterContainer->converters(), | |
| ]; |
The attribute converters are on the top of the stack above the function converters. When the ClampToSeven converter is popped from the stack, the shell value is still the string '42' and the converter is therefore not executed. For my example to work as expected, ClampToSeven should run after the value was converted from string to int.