Skip to content

Commit dc6e07d

Browse files
authored
Support native union return typing (#467)
* fix: Allows union types in native returns * refactor test to work on < php8
1 parent d19b219 commit dc6e07d

File tree

3 files changed

+70
-8
lines changed

3 files changed

+70
-8
lines changed

src/Mappers/Parameters/TypeHandler.php

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use ReflectionParameter;
2929
use ReflectionProperty;
3030
use ReflectionType;
31+
use ReflectionUnionType;
3132
use TheCodingMachine\GraphQLite\Annotations\HideParameter;
3233
use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations;
3334
use TheCodingMachine\GraphQLite\Annotations\UseInputType;
@@ -43,6 +44,7 @@
4344
use TheCodingMachine\GraphQLite\Types\TypeResolver;
4445
use Webmozart\Assert\Assert;
4546

47+
use function array_map;
4648
use function array_merge;
4749
use function array_unique;
4850
use function assert;
@@ -419,17 +421,36 @@ private function appendTypes(Type $type, ?Type $docBlockType): Type
419421
*/
420422
private function reflectionTypeToPhpDocType(ReflectionType $type, ReflectionClass $reflectionClass): Type
421423
{
422-
assert($type instanceof ReflectionNamedType);
423-
$phpdocType = $this->phpDocumentorTypeResolver->resolve($type->getName());
424-
Assert::notNull($phpdocType);
424+
assert($type instanceof ReflectionNamedType || $type instanceof ReflectionUnionType);
425+
if ($type instanceof ReflectionNamedType) {
426+
$phpdocType = $this->phpDocumentorTypeResolver->resolve($type->getName());
427+
Assert::notNull($phpdocType);
425428

426-
$phpdocType = $this->resolveSelf($phpdocType, $reflectionClass);
429+
$phpdocType = $this->resolveSelf($phpdocType, $reflectionClass);
427430

428-
if ($type->allowsNull()) {
429-
$phpdocType = new Nullable($phpdocType);
430-
}
431+
if ($type->allowsNull()) {
432+
$phpdocType = new Nullable($phpdocType);
433+
}
431434

432-
return $phpdocType;
435+
return $phpdocType;
436+
}
437+
return new Compound(
438+
array_map(
439+
function ($namedType) use ($reflectionClass): Type {
440+
\assert($namedType instanceof ReflectionNamedType);
441+
$phpdocType = $this->phpDocumentorTypeResolver->resolve($namedType->getName());
442+
Assert::notNull($phpdocType);
443+
444+
$phpdocType = $this->resolveSelf($phpdocType, $reflectionClass);
445+
446+
if ($namedType->allowsNull()) {
447+
$phpdocType = new Nullable($phpdocType);
448+
}
449+
return $phpdocType;
450+
},
451+
$type->getTypes()
452+
)
453+
);
433454
}
434455

435456
/**

tests/Fixtures80/UnionOutputType.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TheCodingMachine\GraphQLite\Fixtures80;
6+
7+
use TheCodingMachine\GraphQLite\Fixtures\TestObject;
8+
use TheCodingMachine\GraphQLite\Fixtures\TestObject2;
9+
10+
class UnionOutputType
11+
{
12+
public function objectUnion(): TestObject|TestObject2 {
13+
return new TestObject((''));
14+
}
15+
}

tests/Mappers/Parameters/TypeMapperTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
namespace TheCodingMachine\GraphQLite\Mappers\Parameters;
44

55
use DateTimeImmutable;
6+
use GraphQL\Type\Definition\NonNull;
67
use GraphQL\Type\Definition\ResolveInfo;
8+
use GraphQL\Type\Definition\UnionType;
79
use ReflectionMethod;
810
use Symfony\Component\Cache\Adapter\ArrayAdapter;
911
use Symfony\Component\Cache\Psr16Cache;
1012
use Symfony\Component\Cache\Simple\ArrayCache;
1113
use TheCodingMachine\GraphQLite\AbstractQueryProviderTest;
1214
use TheCodingMachine\GraphQLite\Annotations\HideParameter;
15+
use TheCodingMachine\GraphQLite\Fixtures80\UnionOutputType;
1316
use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeException;
1417
use TheCodingMachine\GraphQLite\Mappers\Root\BaseTypeMapper;
1518
use TheCodingMachine\GraphQLite\Mappers\Root\CompositeRootTypeMapper;
@@ -34,6 +37,29 @@ public function testMapScalarUnionException(): void
3437
$typeMapper->mapReturnType($refMethod, $docBlockObj);
3538
}
3639

40+
/**
41+
* @requires PHP >= 8.0
42+
*/
43+
public function testMapObjectUnionWorks(): void
44+
{
45+
$typeMapper = new TypeHandler($this->getArgumentResolver(), $this->getRootTypeMapper(), $this->getTypeResolver());
46+
47+
$cachedDocBlockFactory = new CachedDocBlockFactory(new Psr16Cache(new ArrayAdapter()));
48+
49+
$refMethod = new ReflectionMethod(UnionOutputType::class, 'objectUnion');
50+
$docBlockObj = $cachedDocBlockFactory->getDocBlock($refMethod);
51+
52+
$gqType = $typeMapper->mapReturnType($refMethod, $docBlockObj);
53+
$this->assertInstanceOf(NonNull::class, $gqType);
54+
assert($gqType instanceof NonNull);
55+
$memberType = $gqType->getOfType();
56+
$this->assertInstanceOf(UnionType::class, $memberType);
57+
assert($memberType instanceof UnionType);
58+
$unionTypes = $memberType->getTypes();
59+
$this->assertEquals('TestObject', $unionTypes[0]->name);
60+
$this->assertEquals('TestObject2', $unionTypes[1]->name);
61+
}
62+
3763
public function testHideParameter(): void
3864
{
3965
$typeMapper = new TypeHandler($this->getArgumentResolver(), $this->getRootTypeMapper(), $this->getTypeResolver());

0 commit comments

Comments
 (0)