Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve object constructors parameters types inferring #552

Merged
merged 3 commits into from
Sep 2, 2024

Conversation

romm
Copy link
Member

@romm romm commented Sep 2, 2024

The collision system that checks object constructors parameters types is
now way more clever, as it no longer checks for parameters' names only.
Types are now also checked, and only true collision will be detected,
for instance when two constructors share a parameter with the same name
and type.

Note that when two parameters share the same name, the following type
priority operates:

  1. Non-scalar type
  2. Integer type
  3. Float type
  4. String type
  5. Boolean type

With this change, the code below is now valid:

final readonly class Money
{
    private function __construct(
        public int $value,
    ) {}

    #[\CuyZ\Valinor\Mapper\Object\Constructor]
    public static function fromInt(int $value): self
    {
        return new self($value);
    }

    #[\CuyZ\Valinor\Mapper\Object\Constructor]
    public static function fromString(string $value): self
    {
        if (! preg_match('/^\d+€$/', $value)) {
            throw new \InvalidArgumentException('Invalid money format');
        }

        return new self((int)rtrim($value, ''));
    }
}

$mapper = (new \CuyZ\Valinor\MapperBuilder())->mapper();

$mapper->map(Money::class, 42); // ✅
$mapper->map(Money::class, '42€'); // ✅

Fixes #377

This, for instance, allows to more easily check for unexpected keys in
the source.
The collision system that checks object constructors parameters types is
now way more clever, as it no longer checks for parameters' names only.
Types are now also checked, and only true collision will be detected,
for instance when two constructors share a parameter with the same name
and type.

Note that when two parameters share the same name, the following type
priority operates:

1. Non-scalar type
2. Integer type
3. Float type
4. String type
5. Boolean type

With this change, the code below is now valid:

```php
final readonly class Money
{
    private function __construct(
        public int $value,
    ) {}

    #[\CuyZ\Valinor\Mapper\Object\Constructor]
    public static function fromInt(int $value): self
    {
        return new self($value);
    }

    #[\CuyZ\Valinor\Mapper\Object\Constructor]
    public static function fromString(string $value): self
    {
        if (! preg_match('/^\d+€$/', $value)) {
            throw new \InvalidArgumentException('Invalid money format');
        }

        return new self((int)rtrim($value, '€'));
    }
}

$mapper = (new \CuyZ\Valinor\MapperBuilder())->mapper();

$mapper->map(Money::class, 42); // ✅
$mapper->map(Money::class, '42€'); // ✅
```
@romm romm merged commit 2150dca into master Sep 2, 2024
21 checks passed
@romm romm deleted the feat/better-object-constructor-narrowing branch September 2, 2024 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow multiple object builders with same argument names but different types
1 participant