Skip to content

Commit d7c2e25

Browse files
authored
Merge pull request #780 from murtukov/enhancement/type-fields-callbacks
Update generated types
2 parents 6f78dc3 + 5cdf100 commit d7c2e25

File tree

3 files changed

+19
-123
lines changed

3 files changed

+19
-123
lines changed

src/Generator/TypeBuilder.php

+18-7
Original file line numberDiff line numberDiff line change
@@ -144,22 +144,32 @@ public function build(array $config, string $type): PhpFile
144144

145145
/**
146146
* Converts a native GraphQL type string into the `webonyx/graphql-php`
147-
* type literal.
147+
* type literal. References to user-defined types are converted into
148+
* TypeResovler method call and wrapped into a closure.
148149
*
149150
* Render examples:
150151
*
151152
* - "String" -> Type::string()
152153
* - "String!" -> Type::nonNull(Type::string())
153154
* - "[String!] -> Type::listOf(Type::nonNull(Type::string()))
154-
* - "[Post]" -> Type::listOf($globalVariables->get('typeResolver')->resolve('Post'))
155+
* - "[Post]" -> fn() => Type::listOf($globalVariables->get('typeResolver')->resolve('Post'))
155156
*
156157
* @return GeneratorInterface|string
157158
*/
158159
protected function buildType(string $typeDefinition)
159160
{
160161
$typeNode = Parser::parseType($typeDefinition);
161162

162-
return $this->wrapTypeRecursive($typeNode);
163+
$isReference = false;
164+
$type = $this->wrapTypeRecursive($typeNode, $isReference);
165+
166+
if ($isReference) {
167+
// References to other types should be wrapped in a closure
168+
// for performance reasons
169+
return ArrowFunction::new($type);
170+
}
171+
172+
return $type;
163173
}
164174

165175
/**
@@ -169,27 +179,28 @@ protected function buildType(string $typeDefinition)
169179
*
170180
* @return DependencyAwareGenerator|string
171181
*/
172-
protected function wrapTypeRecursive($typeNode)
182+
protected function wrapTypeRecursive($typeNode, bool &$isReference)
173183
{
174184
switch ($typeNode->kind) {
175185
case NodeKind::NON_NULL_TYPE:
176-
$innerType = $this->wrapTypeRecursive($typeNode->type);
186+
$innerType = $this->wrapTypeRecursive($typeNode->type, $isReference);
177187
$type = Literal::new("Type::nonNull($innerType)");
178188
$this->file->addUse(Type::class);
179189
break;
180190
case NodeKind::LIST_TYPE:
181-
$innerType = $this->wrapTypeRecursive($typeNode->type);
191+
$innerType = $this->wrapTypeRecursive($typeNode->type, $isReference);
182192
$type = Literal::new("Type::listOf($innerType)");
183193
$this->file->addUse(Type::class);
184194
break;
185-
default:
195+
default: // NodeKind::NAMED_TYPE
186196
if (in_array($typeNode->name->value, static::BUILT_IN_TYPES)) {
187197
$name = strtolower($typeNode->name->value);
188198
$type = Literal::new("Type::$name()");
189199
$this->file->addUse(Type::class);
190200
} else {
191201
$name = $typeNode->name->value;
192202
$type = "$this->globalVars->get('typeResolver')->resolve('$name')";
203+
$isReference = true;
193204
}
194205
break;
195206
}

src/Resolver/TypeResolver.php

+1-47
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44

55
namespace Overblog\GraphQLBundle\Resolver;
66

7-
use GraphQL\Type\Definition\NullableType;
87
use GraphQL\Type\Definition\Type;
98
use Overblog\GraphQLBundle\Event\Events;
109
use Overblog\GraphQLBundle\Event\TypeLoadedEvent;
1110
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
12-
use function json_encode;
1311
use function sprintf;
14-
use function strlen;
15-
use function substr;
1612

1713
class TypeResolver extends AbstractResolver
1814
{
@@ -53,22 +49,13 @@ public function resolve($alias): ?Type
5349
}
5450

5551
if (!isset($this->cache[$alias])) {
56-
$type = $this->string2Type($alias);
52+
$type = $this->baseType($alias);
5753
$this->cache[$alias] = $type;
5854
}
5955

6056
return $this->cache[$alias];
6157
}
6258

63-
private function string2Type(string $alias): Type
64-
{
65-
if (null !== ($type = $this->wrapTypeIfNeeded($alias))) {
66-
return $type;
67-
}
68-
69-
return $this->baseType($alias);
70-
}
71-
7259
private function baseType(string $alias): Type
7360
{
7461
$type = $this->getSolution($alias);
@@ -81,39 +68,6 @@ private function baseType(string $alias): Type
8168
return $type;
8269
}
8370

84-
private function wrapTypeIfNeeded(string $alias): ?Type
85-
{
86-
// Non-Null
87-
if ('!' === $alias[strlen($alias) - 1]) {
88-
/** @var NullableType $type */
89-
$type = $this->string2Type(substr($alias, 0, -1));
90-
91-
return Type::nonNull($type);
92-
}
93-
// List
94-
if ($this->hasNeedListOfWrapper($alias)) {
95-
return Type::listOf($this->string2Type(substr($alias, 1, -1)));
96-
}
97-
98-
return null;
99-
}
100-
101-
private function hasNeedListOfWrapper(string $alias): bool
102-
{
103-
if ('[' === $alias[0]) {
104-
$got = $alias[strlen($alias) - 1];
105-
if (']' !== $got) {
106-
throw new UnresolvableException(
107-
sprintf('Malformed ListOf wrapper type "%s" expected "]" but got "%s".', $alias, json_encode($got))
108-
);
109-
}
110-
111-
return true;
112-
}
113-
114-
return false;
115-
}
116-
11771
protected function supportedSolutionClass(): ?string
11872
{
11973
return Type::class;

tests/Resolver/TypeResolverTest.php

-69
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44

55
namespace Overblog\GraphQLBundle\Tests\Resolver;
66

7-
use GraphQL\Type\Definition\ListOfType;
8-
use GraphQL\Type\Definition\NonNull;
97
use GraphQL\Type\Definition\ObjectType;
108
use GraphQL\Type\Definition\Type;
11-
use GraphQL\Type\Definition\WrappingType;
129
use Overblog\GraphQLBundle\Resolver\TypeResolver;
1310
use Overblog\GraphQLBundle\Resolver\UnresolvableException;
1411
use Overblog\GraphQLBundle\Resolver\UnsupportedResolverException;
@@ -60,72 +57,6 @@ public function testResolveUnknownType(): void
6057
$this->resolver->resolve('Fake');
6158
}
6259

63-
public function testWrongListOfWrappingType(): void
64-
{
65-
$this->expectException(UnresolvableException::class);
66-
$this->expectExceptionMessage('Malformed ListOf wrapper type "[Tata" expected "]" but got ""a"".');
67-
$this->resolver->resolve('[Tata');
68-
}
69-
70-
public function testResolveWithListOfWrapper(): void
71-
{
72-
/** @var WrappingType $type */
73-
$type = $this->resolver->resolve('[Tata]');
74-
75-
$this->assertInstanceOf(ListOfType::class, $type);
76-
$this->assertSame('Tata', $type->getWrappedType()->name);
77-
}
78-
79-
public function testResolveWithNonNullWrapper(): void
80-
{
81-
/** @var WrappingType $type */
82-
$type = $this->resolver->resolve('Toto!');
83-
84-
$this->assertInstanceOf(NonNull::class, $type);
85-
$this->assertSame('Toto', $type->getWrappedType()->name);
86-
}
87-
88-
public function testResolveWithNonNullListOfWrapper(): void
89-
{
90-
/** @var NonNull $type */
91-
$type = $this->resolver->resolve('[Toto]!');
92-
93-
$this->assertInstanceOf(NonNull::class, $type);
94-
$this->assertInstanceOf(ListOfType::class, $type->getWrappedType());
95-
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->name);
96-
}
97-
98-
public function testResolveWitListOfNonNullWrapper(): void
99-
{
100-
/** @var ListOfType $type */
101-
$type = $this->resolver->resolve('[Toto!]');
102-
103-
$this->assertInstanceOf(ListOfType::class, $type);
104-
$this->assertInstanceOf(NonNull::class, $type->getWrappedType());
105-
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->name);
106-
}
107-
108-
public function testResolveWitNonNullListOfNonNullWrapper(): void
109-
{
110-
/** @var NonNull $type */
111-
$type = $this->resolver->resolve('[Toto!]!');
112-
113-
$this->assertInstanceOf(NonNull::class, $type);
114-
$this->assertInstanceOf(ListOfType::class, $type->getWrappedType());
115-
$this->assertInstanceOf(NonNull::class, $type->getWrappedType()->getWrappedType());
116-
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->getWrappedType()->name);
117-
}
118-
119-
public function testResolveWitListOfListOfWrapper(): void
120-
{
121-
/** @var ListOfType $type */
122-
$type = $this->resolver->resolve('[[Toto]]');
123-
124-
$this->assertInstanceOf(ListOfType::class, $type);
125-
$this->assertInstanceOf(ListOfType::class, $type->getWrappedType());
126-
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->name);
127-
}
128-
12960
public function testAliases(): void
13061
{
13162
$this->assertSame(

0 commit comments

Comments
 (0)