Skip to content

Commit

Permalink
fix: properly handle class sharing class name and namespace group name
Browse files Browse the repository at this point in the history
  • Loading branch information
romm committed Sep 2, 2024
1 parent 4e0bc8b commit 594d5cd
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 72 deletions.
24 changes: 14 additions & 10 deletions src/Type/Parser/Factory/Specifications/AliasSpecification.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
use ReflectionFunction;
use Reflector;

use function array_shift;
use function explode;
use function strtolower;

/** @internal */
final class AliasSpecification implements TypeParserSpecification
{
Expand Down Expand Up @@ -52,10 +56,10 @@ private function resolveAlias(string $symbol): string
$alias = $symbol;

$namespaceParts = explode('\\', $symbol);
$lastPart = array_shift($namespaceParts);
$firstPart = array_shift($namespaceParts);

if ($lastPart) {
$alias = strtolower($lastPart);
if ($firstPart) {
$alias = strtolower($firstPart);
}

$aliases = PhpParser::parseUseStatements($this->reflection);
Expand All @@ -64,17 +68,17 @@ private function resolveAlias(string $symbol): string
return $symbol;
}

if ($aliases[$alias] === $symbol) {
return $symbol;
}
$fqcn = $aliases[$alias]['fqcn'];

$full = $aliases[$alias];
if ($namespaceParts === []) {
return $fqcn;
}

if (! empty($namespaceParts)) {
$full .= '\\' . implode('\\', $namespaceParts);
if (! $aliases[$alias]['isExplicitAlias']) {
return $symbol;
}

return $full;
return $fqcn . '\\' . implode('\\', $namespaceParts);
}

private function resolveNamespaced(string $symbol): string
Expand Down
6 changes: 3 additions & 3 deletions src/Utility/Reflection/PhpParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
*/
final class PhpParser
{
/** @var array<string, array<string, string>> */
/** @var array<string, array<non-empty-string, array{fqcn: non-empty-string, isExplicitAlias: bool}>> */
private static array $statements = [];

/**
* @param ReflectionClass<object>|ReflectionFunction|ReflectionMethod $reflection
* @return array<string, string>
* @return array<non-empty-string, array{fqcn: non-empty-string, isExplicitAlias: bool}>
*/
public static function parseUseStatements(\ReflectionClass|\ReflectionFunction|\ReflectionMethod $reflection): array
{
Expand All @@ -34,7 +34,7 @@ public static function parseUseStatements(\ReflectionClass|\ReflectionFunction|\

/**
* @param ReflectionClass<object>|ReflectionFunction|ReflectionMethod $reflection
* @return array<string, string>
* @return array<non-empty-string, array{fqcn: non-empty-string, isExplicitAlias: bool}>
*/
private static function fetchUseStatements(\ReflectionClass|\ReflectionFunction|\ReflectionMethod $reflection): array
{
Expand Down
15 changes: 11 additions & 4 deletions src/Utility/Reflection/TokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function __construct(string $content)
}

/**
* @return array<string, string>
* @return array<non-empty-string, array{fqcn: non-empty-string, isExplicitAlias: bool}>
*/
public function parseUseStatements(string $namespaceName): array
{
Expand Down Expand Up @@ -58,7 +58,7 @@ public function parseUseStatements(string $namespaceName): array
}

/**
* @return array<string, string>
* @return array<non-empty-string, array{fqcn: non-empty-string, isExplicitAlias: bool}>
*/
private function parseUseStatement(): array
{
Expand Down Expand Up @@ -86,12 +86,18 @@ private function parseUseStatement(): array
$explicitAlias = true;
$alias = '';
} elseif ($name === ',') {
$statements[strtolower($alias)] = $groupRoot . $class;
$statements[strtolower($alias)] = [
'fqcn' => $groupRoot . $class,
'isExplicitAlias' => $explicitAlias,
];
$class = $alias = '';
$explicitAlias = false;
} elseif ($name === ';') {
if ($alias !== '') {
$statements[strtolower($alias)] = $groupRoot . $class;
$statements[strtolower($alias)] = [
'fqcn' => $groupRoot . $class,
'isExplicitAlias' => $explicitAlias,
];
}
break;
} elseif ($name === '{') {
Expand All @@ -100,6 +106,7 @@ private function parseUseStatement(): array
}
}

/** @var array<non-empty-string, array{fqcn: non-empty-string, isExplicitAlias: bool}> */
return $statements;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace CuyZ\Valinor\Tests\Integration\Mapping\Namespace;

use CuyZ\Valinor\Mapper\MappingError;
use CuyZ\Valinor\Tests\Integration\IntegrationTestCase;
use SomeNamespace\SomeClass;
use SomeNamespace\SomeNamespace;

final class SameClassNameAsNamespaceGroupMappingTest extends IntegrationTestCase
{
// @see https://github.com/CuyZ/Valinor/issues/554
public function test_class_name_has_same_name_as_namespace_group_dot_not_block_type_resolution(): void
{
require_once 'class-name-with-same-name-as-namespace-group.php';

try {
$result = $this->mapperBuilder()->mapper()->map(ClassContainingNamespacedClasses::class, [
'objectA' => ['stringValue' => 'foo'],
'objectB' => ['integerValue' => 42],
]);
} catch (MappingError $error) {
$this->mappingFail($error);
}

self::assertSame('foo', $result->objectA->stringValue);
self::assertSame(42, $result->objectB->integerValue);
}
}

final class ClassContainingNamespacedClasses
{
public SomeNamespace $objectA;
public SomeClass $objectB;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace SomeNamespace;

final class SomeNamespace
{
public string $stringValue;
}

final class SomeClass
{
public int $integerValue;
}
Loading

0 comments on commit 594d5cd

Please sign in to comment.