CuyZ / Valinor

PHP library that helps to map any input into a strongly-typed value object structure.

Home Page:https://valinor.cuyz.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

LogicException: Namespace not found

JanMikes opened this issue · comments

Hi, seems that token parser does not expect namespace without backslash - when trying to map nested classes in same (single level) namespace, i get Namespace not found exception.

namespace Acme;

readonly final class Foo
{
    public function __construct(
        /** @var list<Bar> */
        public array $items,
    ) {
    }
}
namespace Acme;

readonly final class Bar
{
    public function __construct(
        public string $value,
    ) {
    }
}
(new MapperBuilder())->mapper()->map(Foo::class, Source::array([
    'items' => [
        ['value' => 'baz'],
    ],
]));

Stacktrace:

LogicException: Namespace not found.
vendor/cuyz/valinor/src/Utility/Reflection/TokenParser.php:129
vendor/cuyz/valinor/src/Utility/Reflection/TokenParser.php:49
vendor/cuyz/valinor/src/Utility/Reflection/PhpParser.php:61
vendor/cuyz/valinor/src/Utility/Reflection/PhpParser.php:30
vendor/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php:65
vendor/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php:39
vendor/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php:28
vendor/cuyz/valinor/src/Type/Parser/Lexer/TypeAliasLexer.php:27
vendor/cuyz/valinor/src/Type/Parser/LexingParser.php:30
vendor/cuyz/valinor/src/Type/Parser/LexingParser.php:29
vendor/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionTypeResolver.php:90
vendor/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionTypeResolver.php:65
vendor/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionTypeResolver.php:30
vendor/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionPropertyDefinitionBuilder.php:26
vendor/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionClassDefinitionRepository.php:81
vendor/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionClassDefinitionRepository.php:77
vendor/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionClassDefinitionRepository.php:65
vendor/cuyz/valinor/src/Definition/Repository/Cache/CacheClassDefinitionRepository.php:32
vendor/cuyz/valinor/src/Mapper/Tree/Builder/InterfaceNodeBuilder.php:48
vendor/cuyz/valinor/src/Mapper/Tree/Builder/CasterProxyNodeBuilder.php:26
vendor/cuyz/valinor/src/Mapper/Tree/Builder/IterableNodeBuilder.php:28
vendor/cuyz/valinor/src/Mapper/Tree/Builder/StrictNodeBuilder.php:37
vendor/cuyz/valinor/src/Mapper/Tree/Builder/ErrorCatcherNodeBuilder.php:33
vendor/cuyz/valinor/src/Mapper/Tree/Builder/RootNodeBuilder.php:18
vendor/cuyz/valinor/src/Mapper/TypeTreeMapper.php:45
vendor/cuyz/valinor/src/Mapper/TypeTreeMapper.php:26
Script.php:26

We probably have the same problem with the infer method, which is currently a showstopper for us.

<?php

declare(strict_types=1);

namespace Dev;

use CuyZ\Valinor\Mapper\Source\Source;
use CuyZ\Valinor\MapperBuilder;
use RuntimeException;

require_once __DIR__ . '/../vendor/autoload.php';

interface SomeInterface {}

final readonly class ImplementationOne implements SomeInterface {}

final readonly class ImplementationTwo implements SomeInterface {}

$mapper = (new MapperBuilder())->infer(
    SomeInterface::class,
    /** @return class-string<ImplementationOne|ImplementationTwo> */
    static fn (string $type): string => match ($type) {
        'one' => ImplementationOne::class,
        'two' => ImplementationTwo::class,
        default => throw new RuntimeException(),
    },
)
    ->mapper();

$mapper->map(
    SomeInterface::class,
    Source::array(
        [
            'type' => 'one',
        ],
    ),
);

throws

PHP Fatal error:  Uncaught CuyZ\Valinor\Mapper\Tree\Exception\MissingObjectImplementationRegistration: No implementation of `Dev\SomeInterface` found with return type `class-string<ImplementationOne|ImplementationTwo>` of `Closure (lines 22 to 26 of ...

Changing the line

/** @return class-string<ImplementationOne|ImplementationTwo> */

to

/** @return class-string<\Dev\ImplementationOne|\Dev\ImplementationTwo> */

or removing

namespace Dev;

solves the issue, which both violates our CS.

Even the official example at https://valinor.cuyz.io/1.6/how-to/infer-interfaces/ fails, when put into a namespace.

Should be fixed by #446.

@l-x the issue you described was something else, that should have been solved with #457