First release of the v2 series! 🎉
This release introduces some new features but also backward compatibility breaks that are detailed in the upgrading chapter: it is strongly recommended to read it carefully before upgrading.
Notable new features
Mapper converters introduction
A mapper converter allows users to hook into the mapping process and apply custom logic to the input, by defining a callable signature that properly describes when it should be called:
- A first argument with a type matching the expected input being mapped
- A return type representing the targeted mapped type
These two types are enough for the library to know when to call the converter and can contain advanced type annotations for more specific use cases.
Below is a basic example of a converter that converts string inputs to uppercase:
(new \CuyZ\Valinor\MapperBuilder())
->registerConverter(
fn (string $value): string => strtoupper($value)
)
->mapper()
->map('string', 'hello world'); // 'HELLO WORLD'
Converters can be chained, allowing multiple transformations to be applied to a value. A second callable
parameter can be declared, allowing the current converter to call the next one in the chain.
A priority can be given to a converter to control the order in which converters are applied. The higher the priority, the earlier the converter will be executed. The default priority is 0.
(new \CuyZ\Valinor\MapperBuilder())
->registerConverter(
function(string $value, callable $next): string {
return $next(strtoupper($value));
}
)
->registerConverter(
function(string $value, callable $next): string {
return $next($value . '!');
},
priority: -10,
)
->registerConverter(
function(string $value, callable $next): string {
return $next($value . '?');
},
priority: 10,
)
->mapper()
->map('string', 'hello world'); // 'HELLO WORLD?!'
More information can be found in the mapper converter chapter.
NormalizerBuilder
introduction
The NormalizerBuilder
class has been introduced and will now be the main entry to instantiate normalizers. Therefore, the methods inMapperBuilder
that used to configure and return normalizers have been removed.
This decision aims to make a clear distinction between the mapper and the normalizer configuration API, where confusion could arise when using both.
The NormalizerBuilder
can be used like this:
$normalizer = (new \CuyZ\Valinor\NormalizerBuilder())
->registerTransformer(
fn (\DateTimeInterface $date) => $date->format('Y/m/d')
)
->normalizer(\CuyZ\Valinor\Normalizer\Format::array())
->normalize($someData);
Changes to messages/errors handling
Some changes have been made to the way messages and errors are handled.
It is now easier to fetch messages when error(s) occur during mapping:
try {
(new \CuyZ\Valinor\MapperBuilder())->mapper()->map(/* … */);
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
// Before (1.x):
$messages = \CuyZ\Valinor\Mapper\Tree\Message\Messages::flattenFromNode(
$error->node()
);
// After (2.x):
$messages = $error->messages();
}
Upgrading from 1.x to 2.x
⚠ BREAKING CHANGES
- Add purity markers in
MapperBuilder
andNormalizerBuilder
(123058) - Add type and source accessors to
MappingError
(378141) - Change exposed error messages codes (15bb11)
- Introduce
NormalizerBuilder
as the main entry for normalizers (f79ce2) - Introduce internal cache interface and remove PSR-16 dependency (dfdf40)
- Mark some class constructors as
@internal
(7fe5fe) - Remove
MapperBuilder::alter()
in favor of mapper converters (bee098) - Remove
MapperBuilder::enableFlexibleCasting()
(f8f16d) - Remove unused class
PrioritizedList
(0b8c89) - Remove unused interface
IdentifiableSource
(aefb20) - Rename
MapperBuilder::warmup()
method towarmupCacheFor()
(963156) - Rework mapper node and messages handling (14d5ca)
Features
- Allow
MapperBuilder
andNormalizerBuilder
to clear cache (fe318c) - Introduce mapper converters to apply custom logic during mapping (46c823)
Bug Fixes
- Update file system cache entries permissions (6ffb0f)