diff --git a/src/Type/Definition/InterfaceType.php b/src/Type/Definition/InterfaceType.php index 5192149..4ef8b54 100644 --- a/src/Type/Definition/InterfaceType.php +++ b/src/Type/Definition/InterfaceType.php @@ -49,6 +49,10 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT } } + /** + * InterfaceType constructor. + * @param array $config + */ public function __construct(array $config) { Config::validate($config, [ @@ -63,7 +67,6 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT $this->name = $config['name']; $this->description = isset($config['description']) ? $config['description'] : null; - $this->_fields = !empty($config['fields']) ? FieldDefinition::createMap($config['fields']) : []; $this->_resolveTypeFn = isset($config['resolveType']) ? $config['resolveType'] : null; $this->config = $config; } @@ -73,11 +76,25 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT */ public function getFields() { + if (null === $this->_fields) { + $this->_fields = []; + $fields = isset($this->config['fields']) ? $this->config['fields'] : []; + $fields = is_callable($fields) ? call_user_func($fields) : $fields; + $this->_fields = FieldDefinition::createMap($fields); + } return $this->_fields; } + /** + * @param $name + * @return FieldDefinition + * @throws \Exception + */ public function getField($name) { + if (null === $this->_fields) { + $this->getFields(); + } Utils::invariant(isset($this->_fields[$name]), 'Field "%s" is not defined for type "%s"', $name, $this->name); return $this->_fields[$name]; } @@ -90,6 +107,10 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT return $this->_implementations; } + /** + * @param Type $type + * @return bool + */ public function isPossibleType(Type $type) { $possibleTypeNames = $this->_possibleTypeNames; diff --git a/tests/Type/DefinitionTest.php b/tests/Type/DefinitionTest.php index 9bf3bd5..7a94f5b 100644 --- a/tests/Type/DefinitionTest.php +++ b/tests/Type/DefinitionTest.php @@ -433,6 +433,35 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase $this->assertSame($inputObject, $schema->getType('InputObject')); $this->assertEquals(count($inputObject->getFields()), 2); $this->assertSame($inputObject->getField('nested')->getType(), $inputObject); - $this->assertSame($inputObject->getField('value')->getType(), Type::string()); + } + + public function testInterfaceTypeAllowsRecursiveDefinitions() + { + $called = false; + $interface = new InterfaceType([ + 'name' => 'SomeInterface', + 'fields' => function() use (&$interface, &$called) { + $called = true; + return [ + 'value' => ['type' => Type::string()], + 'nested' => ['type' => $interface ] + ]; + } + ]); + + $query = new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'test' => ['type' => $interface] + ] + ]); + + $schema = new Schema($query); + + $this->assertTrue($called); + $this->assertSame($interface, $schema->getType('SomeInterface')); + $this->assertEquals(count($interface->getFields()), 2); + $this->assertSame($interface->getField('nested')->getType(), $interface); + $this->assertSame($interface->getField('value')->getType(), Type::string()); } }