Releases: CuyZ/Valinor
1.7.0
Notable changes
Non-positive integer
Non-positive integer can be used as below. It will accept any value equal to or lower than zero.
final class SomeClass
{
/** @var non-positive-int */
public int $nonPositiveInteger;
}
Non-negative integer
Non-negative integer can be used as below. It will accept any value equal to or greater than zero.
final class SomeClass
{
/** @var non-negative-int */
public int $nonNegativeInteger;
}
Features
Bug Fixes
- Add missing
@psalm-pure
annotation to pure methods (004eb1) - Handle comments in classes when parsing types imports (3b663a)
Other
1.6.1
1.6.0
Notable changes
Symfony Bundle
A bundle is now available for Symfony applications, it will ease the integration and usage of the Valinor library in the framework. The documentation can be found in the CuyZ/Valinor-Bundle repository.
Note that the documentation has been updated to add information about the bundle as well as tips on how to integrate the library in other frameworks.
PHP 8.3 support
Thanks to @TimWolla, the library now supports PHP 8.3, which entered its beta phase. Do not hesitate to test the library with this new version, and report any encountered issue on the repository.
Better type parsing
The first layer of the type parser has been completely rewritten. The previous one would use regex to split a raw type in tokens, but that led to limitations — mostly concerning quoted strings — that are now fixed.
Although this change should not impact the end user, it is a major change in the library, and it is possible that some edge cases were not covered by tests. If that happens, please report any encountered issue on the repository.
Example of previous limitations, now solved:
// Union of strings containing space chars
(new MapperBuilder())
->mapper()
->map(
"'foo bar'|'baz fiz'",
'baz fiz'
);
// Shaped array with special chars in the key
(new MapperBuilder())
->mapper()
->map(
"array{'some & key': string}",
['some & key' => 'value']
);
More advanced array-key handling
It is now possible to use any string or integer as an array key. The following types are now accepted and will work properly with the mapper:
$mapper->map("array<'foo'|'bar', string>", ['foo' => 'foo']);
$mapper->map('array<42|1337, string>', [42 => 'foo']);
$mapper->map('array<positive-int, string>', [42 => 'foo']);
$mapper->map('array<negative-int, string>', [-42 => 'foo']);
$mapper->map('array<int<-42, 1337>, string>', [42 => 'foo']);
$mapper->map('array<non-empty-string, string>', ['foo' => 'foo']);
$mapper->map('array<class-string, string>', ['SomeClass' => 'foo']);
Features
- Add support for PHP 8.3 (5c44f8)
- Allow any string or integer in array key (12af3e)
- Support microseconds in the Atom / RFC 3339 / ISO 8601 format (c25721)
Bug Fixes
- Correctly handle type inferring for method coming from interface (2657f8)
- Detect missing closing bracket after comma in shaped array type (2aa4b6)
- Handle class name collision while parsing types inside a class (044072)
- Handle invalid Intl formats with
intl.use_exceptions=1
(29da9a) - Improve cache warmup by creating required directories (a3341a)
- Load attributes lazily during runtime and cache access (3e7c63)
- Properly handle class/enum name in shaped array key (1964d4)
Other
1.5.0
Features
- Introduce method to get date formats supported during mapping (873961)
Bug Fixes
- Allow filesystem cache to be cleared when directory does not exist (782408)
- Allow negative timestamp to be mapped to a datetime (d358e8)
- Allow overriding of supported datetime formats (1c70c2)
- Correctly handle message formatting for long truncated UTF8 strings (0a8f37)
- Make serialization of attributes possible (e8ca2f)
- Remove exception inheritance from
UnresolvableType
(eaa128) - Remove previous exception from
UnresolvableType
(5c89c6)
Other
1.4.0
Notable changes
Exception thrown when source is invalid
JSON or YAML given to a source may be invalid, in which case an exception can
now be caught and manipulated.
try {
$source = \CuyZ\Valinor\Mapper\Source\Source::json('invalid JSON');
} catch (\CuyZ\Valinor\Mapper\Source\Exception\InvalidSource $error) {
// Let the application handle the exception in the desired way.
// It is possible to get the original source with `$error->source()`
}
Features
- Introduce
InvalidSource
thrown when using invalid JSON/YAML (0739d1)
Bug Fixes
- Allow integer values in float types (c6df24)
- Make
array-key
type matchmixed
(ccebf7) - Prevent infinite loop when class has parent class with same name (83eb05)
Other
- Add previous exception in various custom exceptions (b9e381)
1.3.1
Bug Fixes
- Check if temporary cache file exists before deletion (3177bf)
- Display useful error message for invalid constructor return type (dc7f5c)
- Keep input path when error occurs in single node (d70257)
- Properly handle class static constructor for other class (d34974)
- Properly handle union of
null
and objects (8f03a7)
Other
- Update dependencies (f7e7f2)
1.3.0
Notable changes
Handle custom enum constructors registration
It is now possible to register custom constructors for enum, the same way it could be done for classes.
(new \CuyZ\Valinor\MapperBuilder())
->registerConstructor(
// Allow the native constructor to be used
SomeEnum::class,
// Register a named constructor
SomeEnum::fromMatrix(...)
)
->mapper()
->map(SomeEnum::class, [
'type' => 'FOO',
'number' => 2,
]);
enum SomeEnum: string
{
case CASE_A = 'FOO_VALUE_1';
case CASE_B = 'FOO_VALUE_2';
case CASE_C = 'BAR_VALUE_1';
case CASE_D = 'BAR_VALUE_2';
/**
* @param 'FOO'|'BAR' $type
* @param int<1, 2> $number
* /
public static function fromMatrix(string $type, int $number): self
{
return self::from("{$type}_VALUE_{$number}");
}
}
An enum constructor can be for a specific pattern:
enum SomeEnum
{
case FOO;
case BAR;
case BAZ;
}
(new \CuyZ\Valinor\MapperBuilder())
->registerConstructor(
/**
* This constructor will be called only when pattern
* `SomeEnum::BA*` is requested during mapping.
*
* @return SomeEnum::BA*
*/
fn (string $value): SomeEnum => /* Some custom domain logic */
)
->mapper()
->map(SomeEnum::class . '::BA*', 'some custom value');
Note that this commit required heavy refactoring work, leading to a regression for union types containing enums and other types. As these cases are considered marginal, this change is considered non-breaking.
Features
- Handle custom enum constructors registration (217e12)
Other
- Handle enum type as class type (5a3caf)
0.17.1
1.2.0
Notable changes
Handle single property/constructor argument with array input
It is now possible, again, to use an array for a single node (single class property or single constructor argument), if this array has one value with a key matching the argument/property name.
This is a revert of a change that was introduced in a previous commit: see hash 72cba32
Features
- Allow usage of array input for single node during mapping (686186)
Bug Fixes
- Do not re-validate single node with existing error (daaaac)
Other
1.1.0
Notable changes
Handle class generic types inheritance
It is now possible to use the @extends
tag (already handled by PHPStan and Psalm) to declare the type of a parent class generic. This logic is recursively applied to all parents.
/**
* @template FirstTemplate
* @template SecondTemplate
*/
abstract class FirstClassWithGenerics
{
/** @var FirstTemplate */
public $valueA;
/** @var SecondTemplate */
public $valueB;
}
/**
* @template FirstTemplate
* @extends FirstClassWithGenerics<FirstTemplate, int>
*/
abstract class SecondClassWithGenerics extends FirstClassWithGenerics
{
/** @var FirstTemplate */
public $valueC;
}
/**
* @extends SecondClassWithGenerics<string>
*/
final class ChildClass extends SecondClassWithGenerics
{
}
$object = (new \CuyZ\Valinor\MapperBuilder())
->mapper()
->map(ChildClass::class, [
'valueA' => 'foo',
'valueB' => 1337,
'valueC' => 'bar',
]);
echo $object->valueA; // 'foo'
echo $object->valueB; // 1337
echo $object->valueC; // 'bar'
Added support for class inferring
It is now possible to infer abstract or parent classes the same way it can be done for interfaces.
Example with an abstract class:
abstract class SomeAbstractClass
{
public string $foo;
public string $bar;
}
final class SomeChildClass extends SomeAbstractClass
{
public string $baz;
}
$result = (new \CuyZ\Valinor\MapperBuilder())
->infer(
SomeAbstractClass::class,
fn () => SomeChildClass::class
)
->mapper()
->map(SomeAbstractClass::class, [
'foo' => 'foo',
'bar' => 'bar',
'baz' => 'baz',
]);
assert($result instanceof SomeChildClass);
assert($result->foo === 'foo');
assert($result->bar === 'bar');
assert($result->baz === 'baz');
Features
Bug Fixes
- Handle
object
return type in PHPStan extension (201728) - Import plugin class file in PHPStan configuration (58d540)
- Keep nested errors when superfluous keys are detected (813b3b)