Skip to content

Releases: CuyZ/Valinor

1.7.0

23 Oct 11:05
Compare
Choose a tag to compare

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

  • Handle non-negative integer type (f444ea)
  • Handle non-positive integer type (53e404)

Bug Fixes

  • Add missing @psalm-pure annotation to pure methods (004eb1)
  • Handle comments in classes when parsing types imports (3b663a)

Other

  • Add comment for future PHP version change (461898)
  • Fix some typos (5cf8ae)
  • Make NativeBooleanType a BooleanType (d57ffa)

1.6.1

11 Oct 08:41
Compare
Choose a tag to compare

Bug Fixes

  • Correctly handle multiline type alias in classes (c23102)
  • Handle integer key in path mapping modifier (9419f6)
  • Handle variadic parameters declared in docblock (f4884c)

1.6.0

25 Aug 10:27
Compare
Choose a tag to compare

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

  • Improve attributes arguments compilation (c4acb1)
  • Replace regex-based type parser with character-based one (ae8303)
  • Simplify symbol parsing algorithm (f260cf)
  • Update Rector dependency (669ff9)

1.5.0

07 Aug 18:30
Compare
Choose a tag to compare

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

  • Avoid using unserialize when caching NULL default values (5e9b4c)
  • Catch json_encode exception to help identifying parsing errors (861c3b)
  • Update dependencies (c31e5c, 5fa107)

1.4.0

17 Apr 11:26
Compare
Choose a tag to compare

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 match mixed (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

13 Feb 05:56
Compare
Choose a tag to compare

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

08 Feb 09:40
Compare
Choose a tag to compare

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

18 Jan 09:52
Compare
Choose a tag to compare

Bug Fixes

  • Use PHP 8.0 Polyfill where needed (d90a95)

1.2.0

09 Jan 12:55
Compare
Choose a tag to compare

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

  • Remove unneeded internal check (86cca5)
  • Remove unneeded internal checks and exceptions (157723)

1.1.0

20 Dec 22:09
Compare
Choose a tag to compare

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

  • Add support for class inferring (5a90ad)
  • Handle class generic types inheritance (6506b7)

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)

Other

  • Adapt code with PHP 8.0 syntax (3fac3e)
  • Add isAbstract flag in class definition (ad0c06)
  • Add isFinal flag in class definition (25da31)
  • Enhance TreeMapper::map() return type signature (dc32d3)
  • Improve return type signature for TreeMapper (c8f362)
  • Prevent multiple cache round-trip (13b620)