diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index 5418f64..1052841 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -19,6 +19,7 @@ use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\ScalarType; use GraphQL\Type\Definition\Type; +use GraphQL\Type\DefinitionContainer; use GraphQL\Type\Introspection; use GraphQL\Utils; @@ -744,6 +745,10 @@ class Executor $runtimeType = $exeContext->schema->getType($runtimeType); } + if ($runtimeType instanceof DefinitionContainer) { + $runtimeType = $runtimeType->getDefinition(); + } + if (!($runtimeType instanceof ObjectType)) { throw new Error( "Abstract type {$returnType} must resolve to an Object type at runtime " . diff --git a/src/Schema.php b/src/Schema.php index c9996ca..4002902 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -9,6 +9,7 @@ use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\UnionType; use GraphQL\Type\Definition\WrappingType; +use GraphQL\Type\DefinitionContainer; use GraphQL\Type\Introspection; /** @@ -113,6 +114,18 @@ class Schema 'validate' => true ]; + if ($config['query'] instanceof DefinitionContainer) { + $config['query'] = $config['query']->getDefinition(); + } + + if ($config['mutation'] instanceof DefinitionContainer) { + $config['mutation'] = $config['mutation']->getDefinition(); + } + + if ($config['subscription'] instanceof DefinitionContainer) { + $config['subscription'] = $config['subscription']->getDefinition(); + } + Utils::invariant( $config['query'] instanceof ObjectType, "Schema query must be Object Type but got: " . Utils::getVariableType($config['query']) @@ -299,6 +312,9 @@ class Schema if (!$type) { return $this->typeMap; } + if ($type instanceof DefinitionContainer) { + $type = $type->getDefinition(); + } if ($type instanceof WrappingType) { return $this->extractTypes($type->getWrappedType(true)); diff --git a/src/Type/Definition/Config.php b/src/Type/Definition/Config.php index a561549..815b8c6 100644 --- a/src/Type/Definition/Config.php +++ b/src/Type/Definition/Config.php @@ -2,6 +2,7 @@ namespace GraphQL\Type\Definition; use GraphQL\Error\InvariantViolation; +use GraphQL\Type\DefinitionContainer; use GraphQL\Utils; /** @@ -188,6 +189,10 @@ class Config $err = 'Error in "'.$typeName.'" type definition: ' . "Each entry at '$pathStr' must be an array, but '%s' is '%s'"; foreach ($value as $arrKey => $arrValue) { + if ($arrValue instanceof DefinitionContainer) { + $arrValue = $arrValue->getDefinition(); + } + if (is_array($def->definition)) { if ($def->flags & self::MAYBE_TYPE && $arrValue instanceof Type) { $arrValue = ['type' => $arrValue]; @@ -220,6 +225,10 @@ class Config return ; // Allow nulls for non-required fields } + if ($value instanceof DefinitionContainer) { + $value = $value->getDefinition(); + } + switch (true) { case $def & self::ANY: break; diff --git a/src/Type/Definition/InterfaceType.php b/src/Type/Definition/InterfaceType.php index a34da04..11f110a 100644 --- a/src/Type/Definition/InterfaceType.php +++ b/src/Type/Definition/InterfaceType.php @@ -52,7 +52,7 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT } /** - * @return array + * @return FieldDefinition[] */ public function getFields() { diff --git a/src/Type/Definition/ListOfType.php b/src/Type/Definition/ListOfType.php index b59ba74..3e37a54 100644 --- a/src/Type/Definition/ListOfType.php +++ b/src/Type/Definition/ListOfType.php @@ -1,6 +1,7 @@ interfaces) { $interfaces = isset($this->config['interfaces']) ? $this->config['interfaces'] : []; $interfaces = is_callable($interfaces) ? call_user_func($interfaces) : $interfaces; + + // TODO: Return some sort of generator to avoid multiple loops + $interfaces = Utils::map($interfaces, function($iface) { + return $iface instanceof DefinitionContainer ? $iface->getDefinition() : $iface; + }); + $this->interfaces = $interfaces; } return $this->interfaces; diff --git a/src/Type/Definition/Type.php b/src/Type/Definition/Type.php index f4a1467..cfe96e0 100644 --- a/src/Type/Definition/Type.php +++ b/src/Type/Definition/Type.php @@ -2,6 +2,7 @@ namespace GraphQL\Type\Definition; use GraphQL\Error\InvariantViolation; +use GraphQL\Type\DefinitionContainer; use GraphQL\Utils; /* @@ -198,6 +199,9 @@ abstract class Type ); $type = $type(); } + if ($type instanceof DefinitionContainer) { + $type = $type->getDefinition(); + } if (!$type instanceof Type) { throw new InvariantViolation(sprintf( diff --git a/src/Type/Definition/UnionType.php b/src/Type/Definition/UnionType.php index 876e3bb..90d26c0 100644 --- a/src/Type/Definition/UnionType.php +++ b/src/Type/Definition/UnionType.php @@ -1,6 +1,7 @@ Config::STRING ]); - Utils::invariant(!empty($config['types']), ""); - /** * Optionally provide a custom type resolver function. If one is not provided, * the default implemenation will call `isTypeOf` on each implementing @@ -51,7 +50,6 @@ class UnionType extends Type implements AbstractType, OutputType, CompositeType */ $this->name = $config['name']; $this->description = isset($config['description']) ? $config['description'] : null; - $this->types = $config['types']; $this->resolveTypeFn = isset($config['resolveType']) ? $config['resolveType'] : null; $this->config = $config; } @@ -70,13 +68,23 @@ class UnionType extends Type implements AbstractType, OutputType, CompositeType */ public function getTypes() { - if ($this->types instanceof \Closure) { - $this->types = call_user_func($this->types); + if (null === $this->types) { + if ($this->config['types'] instanceof \Closure) { + $types = call_user_func($this->config['types']); + } else { + $types = $this->config['types']; + } + Utils::invariant( - is_array($this->types), - 'Closure for option "types" of union "%s" is expected to return array of types', + is_array($types), + 'Option "types" of union "%s" is expected to return array of types (or closure returning array of types)', $this->name ); + + // TODO: Return some sort of generator to avoid multiple loops + $this->types = Utils::map($types, function($type) { + return $type instanceof DefinitionContainer ? $type->getDefinition() : $type; + }); } return $this->types; } diff --git a/src/Type/DefinitionContainer.php b/src/Type/DefinitionContainer.php new file mode 100644 index 0000000..6cabc5e --- /dev/null +++ b/src/Type/DefinitionContainer.php @@ -0,0 +1,15 @@ +