diff --git a/src/Type/Definition/InputObjectType.php b/src/Type/Definition/InputObjectType.php index 8230c72..88de86e 100644 --- a/src/Type/Definition/InputObjectType.php +++ b/src/Type/Definition/InputObjectType.php @@ -1,12 +1,16 @@ */ - private $_fields = []; + private $_fields; + + public $config; public function __construct(array $config) { @@ -21,12 +25,7 @@ class InputObjectType extends Type implements InputType 'description' => Config::STRING ]); - if (!empty($config['fields'])) { - foreach ($config['fields'] as $name => $field) { - $this->_fields[$name] = new InputObjectField($field + ['name' => $name]); - } - } - + $this->config = $config; $this->name = $config['name']; $this->description = isset($config['description']) ? $config['description'] : null; } @@ -36,6 +35,29 @@ class InputObjectType extends Type implements InputType */ 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; + foreach ($fields as $name => $field) { + $this->_fields[$name] = new InputObjectField($field + ['name' => $name]); + } + } + return $this->_fields; } + + /** + * @param string $name + * @return InputObjectField + * @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]; + } } diff --git a/tests/Type/DefinitionTest.php b/tests/Type/DefinitionTest.php index 2e6ea77..9bf3bd5 100644 --- a/tests/Type/DefinitionTest.php +++ b/tests/Type/DefinitionTest.php @@ -402,6 +402,37 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase $this->assertNotNull($blog->getField('owner')); $this->assertSame($user, $blog->getField('owner')->getType()->getWrappedType(true)); + } + public function testInputObjectTypeAllowsRecursiveDefinitions() + { + $called = false; + $inputObject = new InputObjectType([ + 'name' => 'InputObject', + 'fields' => function() use (&$inputObject, &$called) { + $called = true; + return [ + 'value' => ['type' => Type::string()], + 'nested' => ['type' => $inputObject ] + ]; + } + ]); + $someMutation = new ObjectType([ + 'name' => 'SomeMutation', + 'fields' => [ + 'mutateSomething' => [ + 'type' => $this->blogArticle, + 'args' => ['input' => ['type' => $inputObject]] + ] + ] + ]); + + $schema = new Schema($this->blogQuery, $someMutation); + + $this->assertTrue($called); + $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()); } }