Skip to content

Update generated types #780

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions src/Generator/TypeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,22 +144,32 @@ public function build(array $config, string $type): PhpFile

/**
* Converts a native GraphQL type string into the `webonyx/graphql-php`
* type literal.
* type literal. References to user-defined types are converted into
* TypeResovler method call and wrapped into a closure.
*
* Render examples:
*
* - "String" -> Type::string()
* - "String!" -> Type::nonNull(Type::string())
* - "[String!] -> Type::listOf(Type::nonNull(Type::string()))
* - "[Post]" -> Type::listOf($globalVariables->get('typeResolver')->resolve('Post'))
* - "[Post]" -> fn() => Type::listOf($globalVariables->get('typeResolver')->resolve('Post'))
*
* @return GeneratorInterface|string
*/
protected function buildType(string $typeDefinition)
{
$typeNode = Parser::parseType($typeDefinition);

return $this->wrapTypeRecursive($typeNode);
$isReference = false;
$type = $this->wrapTypeRecursive($typeNode, $isReference);

if ($isReference) {
// References to other types should be wrapped in a closure
// for performance reasons
return ArrowFunction::new($type);
}

return $type;
}

/**
Expand All @@ -169,27 +179,28 @@ protected function buildType(string $typeDefinition)
*
* @return DependencyAwareGenerator|string
*/
protected function wrapTypeRecursive($typeNode)
protected function wrapTypeRecursive($typeNode, bool &$isReference)
{
switch ($typeNode->kind) {
case NodeKind::NON_NULL_TYPE:
$innerType = $this->wrapTypeRecursive($typeNode->type);
$innerType = $this->wrapTypeRecursive($typeNode->type, $isReference);
$type = Literal::new("Type::nonNull($innerType)");
$this->file->addUse(Type::class);
break;
case NodeKind::LIST_TYPE:
$innerType = $this->wrapTypeRecursive($typeNode->type);
$innerType = $this->wrapTypeRecursive($typeNode->type, $isReference);
$type = Literal::new("Type::listOf($innerType)");
$this->file->addUse(Type::class);
break;
default:
default: // NodeKind::NAMED_TYPE
if (in_array($typeNode->name->value, static::BUILT_IN_TYPES)) {
$name = strtolower($typeNode->name->value);
$type = Literal::new("Type::$name()");
$this->file->addUse(Type::class);
} else {
$name = $typeNode->name->value;
$type = "$this->globalVars->get('typeResolver')->resolve('$name')";
$isReference = true;
}
break;
}
Expand Down
48 changes: 1 addition & 47 deletions src/Resolver/TypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@

namespace Overblog\GraphQLBundle\Resolver;

use GraphQL\Type\Definition\NullableType;
use GraphQL\Type\Definition\Type;
use Overblog\GraphQLBundle\Event\Events;
use Overblog\GraphQLBundle\Event\TypeLoadedEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use function json_encode;
use function sprintf;
use function strlen;
use function substr;

class TypeResolver extends AbstractResolver
{
Expand Down Expand Up @@ -53,22 +49,13 @@ public function resolve($alias): ?Type
}

if (!isset($this->cache[$alias])) {
$type = $this->string2Type($alias);
$type = $this->baseType($alias);
$this->cache[$alias] = $type;
}

return $this->cache[$alias];
}

private function string2Type(string $alias): Type
{
if (null !== ($type = $this->wrapTypeIfNeeded($alias))) {
return $type;
}

return $this->baseType($alias);
}

private function baseType(string $alias): Type
{
$type = $this->getSolution($alias);
Expand All @@ -81,39 +68,6 @@ private function baseType(string $alias): Type
return $type;
}

private function wrapTypeIfNeeded(string $alias): ?Type
{
// Non-Null
if ('!' === $alias[strlen($alias) - 1]) {
/** @var NullableType $type */
$type = $this->string2Type(substr($alias, 0, -1));

return Type::nonNull($type);
}
// List
if ($this->hasNeedListOfWrapper($alias)) {
return Type::listOf($this->string2Type(substr($alias, 1, -1)));
}

return null;
}

private function hasNeedListOfWrapper(string $alias): bool
{
if ('[' === $alias[0]) {
$got = $alias[strlen($alias) - 1];
if (']' !== $got) {
throw new UnresolvableException(
sprintf('Malformed ListOf wrapper type "%s" expected "]" but got "%s".', $alias, json_encode($got))
);
}

return true;
}

return false;
}

protected function supportedSolutionClass(): ?string
{
return Type::class;
Expand Down
69 changes: 0 additions & 69 deletions tests/Resolver/TypeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@

namespace Overblog\GraphQLBundle\Tests\Resolver;

use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\WrappingType;
use Overblog\GraphQLBundle\Resolver\TypeResolver;
use Overblog\GraphQLBundle\Resolver\UnresolvableException;
use Overblog\GraphQLBundle\Resolver\UnsupportedResolverException;
Expand Down Expand Up @@ -60,72 +57,6 @@ public function testResolveUnknownType(): void
$this->resolver->resolve('Fake');
}

public function testWrongListOfWrappingType(): void
{
$this->expectException(UnresolvableException::class);
$this->expectExceptionMessage('Malformed ListOf wrapper type "[Tata" expected "]" but got ""a"".');
$this->resolver->resolve('[Tata');
}

public function testResolveWithListOfWrapper(): void
{
/** @var WrappingType $type */
$type = $this->resolver->resolve('[Tata]');

$this->assertInstanceOf(ListOfType::class, $type);
$this->assertSame('Tata', $type->getWrappedType()->name);
}

public function testResolveWithNonNullWrapper(): void
{
/** @var WrappingType $type */
$type = $this->resolver->resolve('Toto!');

$this->assertInstanceOf(NonNull::class, $type);
$this->assertSame('Toto', $type->getWrappedType()->name);
}

public function testResolveWithNonNullListOfWrapper(): void
{
/** @var NonNull $type */
$type = $this->resolver->resolve('[Toto]!');

$this->assertInstanceOf(NonNull::class, $type);
$this->assertInstanceOf(ListOfType::class, $type->getWrappedType());
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->name);
}

public function testResolveWitListOfNonNullWrapper(): void
{
/** @var ListOfType $type */
$type = $this->resolver->resolve('[Toto!]');

$this->assertInstanceOf(ListOfType::class, $type);
$this->assertInstanceOf(NonNull::class, $type->getWrappedType());
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->name);
}

public function testResolveWitNonNullListOfNonNullWrapper(): void
{
/** @var NonNull $type */
$type = $this->resolver->resolve('[Toto!]!');

$this->assertInstanceOf(NonNull::class, $type);
$this->assertInstanceOf(ListOfType::class, $type->getWrappedType());
$this->assertInstanceOf(NonNull::class, $type->getWrappedType()->getWrappedType());
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->getWrappedType()->name);
}

public function testResolveWitListOfListOfWrapper(): void
{
/** @var ListOfType $type */
$type = $this->resolver->resolve('[[Toto]]');

$this->assertInstanceOf(ListOfType::class, $type);
$this->assertInstanceOf(ListOfType::class, $type->getWrappedType());
$this->assertSame('Toto', $type->getWrappedType()->getWrappedType()->name);
}

public function testAliases(): void
{
$this->assertSame(
Expand Down