protected function setUp() { $namedType = new InterfaceType('Named', ['name' => ['type' => Type::stringType()]]); $dogType = new ObjectType('Dog', ['name' => ['type' => Type::stringType()], 'barks' => ['type' => Type::booleanType()]], [$namedType], function ($value) { return $value instanceof Dog; }); $catType = new ObjectType('Cat', ['name' => ['type' => Type::stringType()], 'meows' => ['type' => Type::booleanType()]], [$namedType], function ($value) { return $value instanceof Cat; }); $petType = new UnionType('Pet', [$dogType, $catType], function ($value) use($dogType, $catType) { if ($value instanceof Dog) { return $dogType; } if ($value instanceof Cat) { return $catType; } return NULL; }); $personType = new ObjectType('Person', ['name' => ['type' => Type::stringType()], 'pets' => ['type' => new ListModifier($petType)], 'friends' => ['type' => new ListModifier($namedType)]], [$namedType], function ($value) { return $value instanceof Person; }); $this->schema = new Schema($personType); $this->garfield = new Cat('Garfield', FALSE); $this->odie = new Dog('Odie', TRUE); $this->liz = new Person('Liz'); $this->john = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]); }
/** * {@inheritdoc} */ public function getType() { if (!isset($this->type)) { $this->type = new NonNullModifier(Type::booleanType()); } return $this->type; }
protected function setUp() { $this->syncError = new \Exception('sync'); $this->nonNullSyncError = new \Exception('nonNullSync'); $this->throwingData = ['sync' => function () { throw $this->syncError; }, 'nonNullSync' => function () { throw $this->nonNullSyncError; }, 'nest' => function () { return $this->throwingData; }, 'nonNullNest' => function () { return $this->throwingData; }]; $this->NULLingData = ['sync' => function () { return NULL; }, 'nonNullSync' => function () { return NULL; }, 'nest' => function () { return $this->NULLingData; }, 'nonNullNest' => function () { return $this->NULLingData; }]; $dataType = new ObjectType('DataType', ['sync' => ['type' => Type::stringType()], 'nonNullSync' => ['type' => new NonNullModifier(Type::stringType())], 'nest' => ['type' => function () use(&$dataType) { return $dataType; }], 'nonNullNest' => ['type' => function () use(&$dataType) { return new NonNullModifier($dataType); }]]); $this->schema = new Schema($dataType); }
/** * Constructor. * * @param string $name * @param array $fields * @param \Fubhy\GraphQL\Type\Definition\Types\InterfaceType[] $interfaces * @param callable|null $isTypeOf * @param string|null $description */ public function __construct($name, array $fields = [], array $interfaces = [], callable $isTypeOf = NULL, $description = NULL) { parent::__construct($name, $description); $this->fields = $fields; $this->interfaces = $interfaces; $this->isTypeOf = $isTypeOf; foreach ($this->interfaces as $interface) { $interface->addPossibleType($this); } }
public function testExecutesUsingASchema() { $blogArticle = NULL; $blogImage = new ObjectType('Image', ['url' => ['type' => Type::stringType()], 'width' => ['type' => Type::intType()], 'height' => ['type' => Type::intType()]]); $blogAuthor = new ObjectType('Author', ['id' => ['type' => Type::stringType()], 'name' => ['type' => Type::stringType()], 'pic' => ['args' => ['width' => ['type' => Type::intType()], 'height' => ['type' => Type::intType()]], 'type' => $blogImage, 'resolve' => function ($obj, $args) { return $obj['pic']($args['width'], $args['height']); }], 'recentArticle' => ['type' => function () use(&$blogArticle) { return $blogArticle; }]]); $blogArticle = new ObjectType('Article', ['id' => ['type' => new NonNullModifier(Type::stringType())], 'isPublished' => ['type' => Type::booleanType()], 'author' => ['type' => $blogAuthor], 'title' => ['type' => Type::stringType()], 'body' => ['type' => Type::stringType()], 'keywords' => ['type' => new ListModifier(Type::stringType())]]); $blogQuery = new ObjectType('Query', ['article' => ['type' => $blogArticle, 'args' => ['id' => ['type' => Type::idType()]], 'resolve' => function ($_, $args) { return $this->article($args['id']); }], 'feed' => ['type' => new ListModifier($blogArticle), 'resolve' => function () { return [$this->article(1), $this->article(2), $this->article(3), $this->article(4), $this->article(5), $this->article(6), $this->article(7), $this->article(8), $this->article(9), $this->article(10)]; }]]); $blogSchema = new Schema($blogQuery); $request = ' { feed { id, title }, article(id: "1") { ...articleFields, author { id, name, pic(width: 640, height: 480) { url, width, height }, recentArticle { ...articleFields, keywords } } } } fragment articleFields on Article { id, isPublished, title, body, hidden, notdefined } '; $expected = ['data' => ['feed' => [['id' => '1', 'title' => 'My Article 1'], ['id' => '2', 'title' => 'My Article 2'], ['id' => '3', 'title' => 'My Article 3'], ['id' => '4', 'title' => 'My Article 4'], ['id' => '5', 'title' => 'My Article 5'], ['id' => '6', 'title' => 'My Article 6'], ['id' => '7', 'title' => 'My Article 7'], ['id' => '8', 'title' => 'My Article 8'], ['id' => '9', 'title' => 'My Article 9'], ['id' => '10', 'title' => 'My Article 10']], 'article' => ['id' => '1', 'isPublished' => TRUE, 'title' => 'My Article 1', 'body' => 'This is a post', 'author' => ['id' => '123', 'name' => 'John Smith', 'pic' => ['url' => 'cdn://123', 'width' => 640, 'height' => 480], 'recentArticle' => ['id' => '1', 'isPublished' => TRUE, 'title' => 'My Article 1', 'body' => 'This is a post', 'keywords' => ['foo', 'bar', '1', 'true', NULL]]]]]]; $parser = new Parser(); $this->assertEquals($expected, Executor::execute($blogSchema, NULL, $parser->parse(new Source($request)), '', [])); }
/** * Not exactly the same as the executor's definition of getFieldDef, in this * statically evaluated environment we do not always have an Object type, * and need to handle Interface and Union types. * * @param Schema $schema * @param Type $parentType * @param Field $fieldAST * * @return FieldDefinition */ protected static function getFieldDefinition(Schema $schema, Type $parentType, Field $fieldAST) { $name = $fieldAST->get('name')->get('value'); $schemaMeta = Introspection::schemaMetaFieldDefinition(); if ($name === $schemaMeta->getName() && $schema->getQueryType() === $parentType) { return $schemaMeta; } $typeMeta = Introspection::typeMetaFieldDefinition(); if ($name === $typeMeta->getName() && $schema->getQueryType() === $parentType) { return $typeMeta; } $typeNameMeta = Introspection::typeNameMetaFieldDefinition(); if ($name === $typeNameMeta->getName() && ($parentType instanceof ObjectType || $parentType instanceof InterfaceType || $parentType instanceof UnionType)) { return $typeNameMeta; } if ($parentType instanceof ObjectType || $parentType instanceof InterfaceType) { $fields = $parentType->getFields(); return isset($fields[$name]) ? $fields[$name] : NULL; } return NULL; }
/** * @dataProvider coercesOutputBooleanProvider * * @param mixed $input * @param float|null $expected */ public function testCoercesOutputBoolean($input, $expected) { $this->assertSame($expected, Type::booleanType()->coerce($input)); }
public function prohibitsPuttingNonObjcetTypesInUnionsProvider() { return [[Type::intType()], [new NonNullModifier(Type::intType())], [new ListModifier(Type::intType())], [new InterfaceType('Interface')], [new UnionType('Union')], [new EnumType('Enum')], [new InputObjectType('InputObject')]]; }
public function testRespectsTheIncludeDeprecatedParameterForFields() { $testType = new ObjectType('TestType', ['nonDeprecated' => ['type' => Type::stringType()], 'deprecated' => ['type' => Type::stringType(), 'deprecationReason' => 'Removed in 1.0']]); $schema = new Schema($testType); $request = ' { __type(name: "TestType") { name trueFields: fields(includeDeprecated: true) { name } falseFields: fields(includeDeprecated: false) { name } omittedFields: fields { name } } } '; $expected = ['data' => ['__type' => ['name' => 'TestType', 'trueFields' => [['name' => 'nonDeprecated'], ['name' => 'deprecated']], 'falseFields' => [['name' => 'nonDeprecated']], 'omittedFields' => [['name' => 'nonDeprecated']]]]]; $this->assertEquals($expected, GraphQL::execute($schema, $request)); }
protected function getSchema() { $testInputObject = new InputObjectType('TestInputObject', ['a' => ['type' => Type::stringType()], 'b' => ['type' => new ListModifier(Type::stringType())], 'c' => ['type' => new NonNullModifier(Type::stringType())]]); $testType = new ObjectType('TestType', ['fieldWithObjectInput' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => $testInputObject]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'fieldWithNullableStringInput' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => Type::stringType()]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'fieldWithNonNullableStringInput' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new NonNullModifier(Type::stringType())]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'list' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new ListModifier(Type::stringType())]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'nnList' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new NonNullModifier(new ListModifier(Type::stringType()))]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'listNN' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new ListModifier(new NonNullModifier(Type::stringType()))]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'nnListNN' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new NonNullModifier(new ListModifier(new NonNullModifier(Type::stringType())))]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }]]); $schema = new Schema($testType); return $schema; }
protected function executeTestQuery($document) { $data = ['a' => function () { return 'a'; }, 'b' => function () { return 'b'; }]; $schema = new Schema(new ObjectType('TestType', ['a' => ['type' => Type::stringType()], 'b' => ['type' => Type::stringType()]])); $parser = new Parser(); return Executor::execute($schema, $data, $parser->parse(new Source($document))); }
/** * @return \Fubhy\GraphQL\Type\Definition\FieldDefinition */ public static function typeNameMetaFieldDefinition() { if (!isset(static::$typeNameMetaFieldDefinition)) { static::$typeNameMetaFieldDefinition = new FieldDefinition(['name' => '__typename', 'type' => new NonNullModifier(Type::stringType()), 'description' => 'The name of the current Object type at runtime.', 'args' => [], 'resolve' => [__CLASS__, 'resolveTypeNameMetaField']]); } return static::$typeNameMetaFieldDefinition; }
/** * Constructor. * * @param string $name * @param array $fields * @param string|null $description */ public function __construct($name, array $fields = [], $description = NULL) { parent::__construct($name, $description); $this->fields = $fields; }
protected function getSchema() { $dataType = new ObjectType('DataType', ['list' => ['type' => new ListModifier(Type::intType())], 'listOfNonNull' => ['type' => new ListModifier(new NonNullModifier(Type::intType()))], 'nonNullList' => ['type' => new NonNullModifier(new ListModifier(Type::intType()))], 'nonNullListOfNonNull' => ['type' => new NonNullModifier(new ListModifier(new NonNullModifier(Type::intType())))], 'listContainsNull' => ['type' => new ListModifier(Type::intType())], 'listOfNonNullContainsNull' => ['type' => new ListModifier(new NonNullModifier(Type::intType()))], 'nonNullListContainsNull' => ['type' => new NonNullModifier(new ListModifier(Type::intType()))], 'nonNullListOfNonNullContainsNull' => ['type' => new NonNullModifier(new ListModifier(new NonNullModifier(Type::intType())))], 'listReturnsNull' => ['type' => new ListModifier(Type::intType())], 'listOfNonNullReturnsNull' => ['type' => new ListModifier(new NonNullModifier(Type::intType()))], 'nonNullListReturnsNull' => ['type' => new NonNullModifier(new ListModifier(Type::intType()))], 'nonNullListOfNonNullReturnsNull' => ['type' => new NonNullModifier(new ListModifier(new NonNullModifier(Type::intType())))], 'nest' => ['type' => function () use(&$dataType) { return $dataType; }]]); $schema = new Schema($dataType); return $schema; }
protected function getStarWarsSchema() { /** * The original trilogy consists of three movies. * * This implements the following type system shorthand: * enum Episode { NEWHOPE, EMPIRE, JEDI } */ $episodeEnum = new EnumType('Episode', ['NEWHOPE' => ['value' => 4, 'description' => 'Released in 1977.'], 'EMPIRE' => ['value' => 5, 'description' => 'Released in 1980.'], 'JEDI' => ['value' => 6, 'description' => 'Released in 1983.']], 'One of the films in the Star Wars Trilogy'); $humanType = NULL; $droidType = NULL; /** * Characters in the Star Wars trilogy are either humans or droids. * * This implements the following type system shorthand: * interface Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * } */ $characterInterface = new InterfaceType('Character', ['id' => ['type' => new NonNullModifier(Type::stringType()), 'description' => 'The id of the character.'], 'name' => ['type' => Type::stringType(), 'description' => 'The name of the character.'], 'friends' => ['type' => function () use(&$characterInterface) { return new ListModifier($characterInterface); }, 'description' => 'The friends of the character, or an empty list if they have none.'], 'appearsIn' => ['type' => new ListModifier($episodeEnum), 'description' => 'Which movies they appear in.']], function ($obj) use(&$humanType, &$droidType) { $humans = $this->getHumans(); if (isset($humans[$obj['id']])) { return $humanType; } $droids = $this->getDroids(); if (isset($droids[$obj['id']])) { return $droidType; } return NULL; }, 'A character in the Star Wars Trilogy'); /** * We define our human type, which implements the character interface. * * This implements the following type system shorthand: * type Human : Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * } */ $humanType = new ObjectType('Human', ['id' => ['type' => new NonNullModifier(Type::stringType()), 'description' => 'The id of the human.'], 'name' => ['type' => Type::stringType(), 'description' => 'The name of the human.'], 'friends' => ['type' => new ListModifier($characterInterface), 'description' => 'The friends of the human, or an empty list if they have none.', 'resolve' => function ($human) { return $this->getStarWarsFriends($human); }], 'appearsIn' => ['type' => new ListModifier($episodeEnum), 'description' => 'Which movies they appear in.'], 'homePlanet' => ['type' => Type::stringType(), 'description' => 'The home planet of the human, or null if unknown.']], [$characterInterface], NULL, 'A humanoid creature in the Star Wars universe.'); /** * The other type of character in Star Wars is a droid. * * This implements the following type system shorthand: * type Droid : Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * primaryFunction: String * } */ $droidType = new ObjectType('Droid', ['id' => ['type' => new NonNullModifier(Type::stringType()), 'description' => 'The id of the droid.'], 'name' => ['type' => Type::stringType(), 'description' => 'The name of the droid.'], 'friends' => ['type' => new ListModifier($characterInterface), 'description' => 'The friends of the droid, or an empty list if they have none.', 'resolve' => function ($droid) { return $this->getStarWarsFriends($droid); }], 'appearsIn' => ['type' => new ListModifier($episodeEnum), 'description' => 'Which movies they appear in.'], 'primaryFunction' => ['type' => Type::stringType(), 'description' => 'The primary function of the droid.']], [$characterInterface], NULL, 'A mechanical creature in the Star Wars universe.'); /** * This is the type that will be the root of our query, and the * entry point into our schema. It gives us the ability to fetch * objects by their IDs, as well as to fetch the undisputed hero * of the Star Wars trilogy, R2-D2, directly. * * This implements the following type system shorthand: * type Query { * hero: Character * human(id: String!): Human * droid(id: String!): Droid * } * */ $queryType = new ObjectType('Query', ['hero' => ['type' => $characterInterface, 'args' => ['episode' => ['description' => 'If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.', 'type' => $episodeEnum]], 'resolve' => function () { return $this->getArtoo(); }], 'human' => ['type' => $humanType, 'args' => ['id' => ['name' => 'id', 'description' => 'The id of the human.', 'type' => new NonNullModifier(Type::stringType())]], 'resolve' => function ($root, array $args) { $humans = $this->getHumans(); return isset($humans[$args['id']]) ? $humans[$args['id']] : NULL; }], 'droid' => ['type' => $droidType, 'args' => ['id' => ['name' => 'id', 'description' => 'The id of the droid.', 'type' => new NonNullModifier(Type::stringType())]], 'resolve' => function ($root, array $args) { $droids = $this->getDroids(); return isset($droids[$args['id']]) ? $droids[$args['id']] : NULL; }]]); return new Schema($queryType); }
/** * Constructor. * * @param string $name * @param array $values * @param string|null $description */ public function __construct($name, array $values = [], $description = NULL) { parent::__construct($name, $description); $this->values = $values; }
/** * Re-populate static properties when de-serializing. */ public function __wakeup() { Type::intType(); Type::booleanType(); Type::floatType(); Type::idType(); Type::stringType(); }
public function testDoesNotIncludeIllegalFieldsInOutput() { $document = ' mutation M { thisIsIllegalDontIncludeMe } '; $parser = new Parser(); $ast = $parser->parse(new Source($document)); $schema = new Schema(new ObjectType('Q', ['a' => ['type' => Type::stringType()]]), new ObjectType('M', ['c' => ['type' => Type::stringType()]])); $result = Executor::execute($schema, NULL, $ast); $this->assertEquals(['data' => []], $result); }