/** * @return Schema */ protected function getDefaultSchema() { $Being = new InterfaceType(['name' => 'Being', 'fields' => ['name' => ['type' => Type::string()]]]); $Pet = new InterfaceType(['name' => 'Pet', 'fields' => ['name' => ['type' => Type::string()]]]); $DogCommand = new EnumType(['name' => 'DogCommand', 'values' => ['SIT' => ['value' => 0], 'HEEL' => ['value' => 1], 'DOWN' => ['value' => 3]]]); $Dog = new ObjectType(['name' => 'Dog', 'fields' => ['name' => ['type' => Type::string()], 'nickname' => ['type' => Type::string()], 'barkVolume' => ['type' => Type::int()], 'barks' => ['type' => Type::boolean()], 'doesKnowCommand' => ['type' => Type::boolean(), 'args' => ['dogCommand' => ['type' => $DogCommand]]], 'isHousetrained' => ['type' => Type::boolean(), 'args' => ['atOtherHomes' => ['type' => Type::boolean(), 'defaultValue' => true]]], 'isAtLocation' => ['type' => Type::boolean(), 'args' => ['x' => ['type' => Type::int()], 'y' => ['type' => Type::int()]]]], 'interfaces' => [$Being, $Pet]]); $FurColor = new EnumType(['name' => 'FurColor', 'values' => ['BROWN' => ['value' => 0], 'BLACK' => ['value' => 1], 'TAN' => ['value' => 2], 'SPOTTED' => ['value' => 3]]]); $Cat = new ObjectType(['name' => 'Cat', 'fields' => ['name' => ['type' => Type::string()], 'nickname' => ['type' => Type::string()], 'meows' => ['type' => Type::boolean()], 'meowVolume' => ['type' => Type::int()], 'furColor' => ['type' => $FurColor]], 'interfaces' => [$Being, $Pet]]); $CatOrDog = new UnionType(['name' => 'CatOrDog', 'types' => [$Dog, $Cat], 'resolveType' => function ($value) { // not used for validation return null; }]); $Intelligent = new InterfaceType(['name' => 'Intelligent', 'fields' => ['iq' => ['type' => Type::int()]]]); $Human = $this->humanType = new ObjectType(['name' => 'Human', 'interfaces' => [$Being, $Intelligent], 'fields' => ['name' => ['args' => ['surname' => ['type' => Type::boolean()]], 'type' => Type::string()], 'pets' => ['type' => Type::listOf($Pet)], 'relatives' => ['type' => function () { return Type::listOf($this->humanType); }]]]); $Alien = new ObjectType(['name' => 'Alien', 'interfaces' => [$Being, $Intelligent], 'fields' => ['iq' => ['type' => Type::int()], 'numEyes' => ['type' => Type::int()]]]); $DogOrHuman = new UnionType(['name' => 'DogOrHuman', 'types' => [$Dog, $Human], 'resolveType' => function () { // not used for validation return null; }]); $HumanOrAlien = new UnionType(['name' => 'HumanOrAlien', 'types' => [$Human, $Alien], 'resolveType' => function () { // not used for validation return null; }]); $ComplexInput = new InputObjectType(['name' => 'ComplexInput', 'fields' => ['requiredField' => ['type' => Type::nonNull(Type::boolean())], 'intField' => ['type' => Type::int()], 'stringField' => ['type' => Type::string()], 'booleanField' => ['type' => Type::boolean()], 'stringListField' => ['type' => Type::listOf(Type::string())]]]); $ComplicatedArgs = new ObjectType(['name' => 'ComplicatedArgs', 'fields' => ['intArgField' => ['type' => Type::string(), 'args' => ['intArg' => ['type' => Type::int()]]], 'nonNullIntArgField' => ['type' => Type::string(), 'args' => ['nonNullIntArg' => ['type' => Type::nonNull(Type::int())]]], 'stringArgField' => ['type' => Type::string(), 'args' => ['stringArg' => ['type' => Type::string()]]], 'booleanArgField' => ['type' => Type::string(), 'args' => ['booleanArg' => ['type' => Type::boolean()]]], 'enumArgField' => ['type' => Type::string(), 'args' => ['enumArg' => ['type' => $FurColor]]], 'floatArgField' => ['type' => Type::string(), 'args' => ['floatArg' => ['type' => Type::float()]]], 'idArgField' => ['type' => Type::string(), 'args' => ['idArg' => ['type' => Type::id()]]], 'stringListArgField' => ['type' => Type::string(), 'args' => ['stringListArg' => ['type' => Type::listOf(Type::string())]]], 'complexArgField' => ['type' => Type::string(), 'args' => ['complexArg' => ['type' => $ComplexInput]]], 'multipleReqs' => ['type' => Type::string(), 'args' => ['req1' => ['type' => Type::nonNull(Type::int())], 'req2' => ['type' => Type::nonNull(Type::int())]]], 'multipleOpts' => ['type' => Type::string(), 'args' => ['opt1' => ['type' => Type::int(), 'defaultValue' => 0], 'opt2' => ['type' => Type::int(), 'defaultValue' => 0]]], 'multipleOptAndReq' => ['type' => Type::string(), 'args' => ['req1' => ['type' => Type::nonNull(Type::int())], 'req2' => ['type' => Type::nonNull(Type::int())], 'opt1' => ['type' => Type::int(), 'defaultValue' => 0], 'opt2' => ['type' => Type::int(), 'defaultValue' => 0]]]]]); $queryRoot = new ObjectType(['name' => 'QueryRoot', 'fields' => ['human' => ['args' => ['id' => ['type' => Type::id()]], 'type' => $Human], 'alien' => ['type' => $Alien], 'dog' => ['type' => $Dog], 'cat' => ['type' => $Cat], 'pet' => ['type' => $Pet], 'catOrDog' => ['type' => $CatOrDog], 'dogOrHuman' => ['type' => $DogOrHuman], 'humanOrAlien' => ['type' => $HumanOrAlien], 'complicatedArgs' => ['type' => $ComplicatedArgs]]]); $defaultSchema = new Schema($queryRoot); return $defaultSchema; }
/** * @param string $name * @return Type */ public function resolveType($name) { if (preg_match('#^(.+)\\!$#', $name, $regs)) { return Type::nonNull($this->resolveType($regs[1])); } if (preg_match('#^\\[(.+)\\]$#', $name, $regs)) { return Type::listOf($this->resolveType($regs[1])); } switch ($name) { case Type::INT: return Type::int(); case Type::STRING: return Type::string(); case Type::BOOLEAN: return Type::boolean(); case Type::FLOAT: return Type::float(); case Type::ID: return Type::id(); default: if (!isset($this->types[$name])) { throw new \InvalidArgumentException(sprintf('Type "%s" is not defined', $name)); } return $this->types[$name]; } }
public function setUp() { $NamedType = new InterfaceType(['name' => 'Named', 'fields' => ['name' => ['type' => Type::string()]]]); $DogType = new ObjectType(['name' => 'Dog', 'interfaces' => [$NamedType], 'fields' => ['name' => ['type' => Type::string()], 'barks' => ['type' => Type::boolean()]], 'isTypeOf' => function ($value) { return $value instanceof Dog; }]); $CatType = new ObjectType(['name' => 'Cat', 'interfaces' => [$NamedType], 'fields' => ['name' => ['type' => Type::string()], 'meows' => ['type' => Type::boolean()]], 'isTypeOf' => function ($value) { return $value instanceof Cat; }]); $PetType = new UnionType(['name' => 'Pet', 'types' => [$DogType, $CatType], 'resolveType' => function ($value) use($DogType, $CatType) { if ($value instanceof Dog) { return $DogType; } if ($value instanceof Cat) { return $CatType; } }]); $PersonType = new ObjectType(['name' => 'Person', 'interfaces' => [$NamedType], 'fields' => ['name' => ['type' => Type::string()], 'pets' => ['type' => Type::listOf($PetType)], 'friends' => ['type' => Type::listOf($NamedType)]], 'isTypeOf' => 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]); }
public function testFieldSelection() { $image = new ObjectType(['name' => 'Image', 'fields' => ['url' => ['type' => Type::string()], 'width' => ['type' => Type::int()], 'height' => ['type' => Type::int()]]]); $article = null; $author = new ObjectType(['name' => 'Author', 'fields' => function () use($image, &$article) { return ['id' => ['type' => Type::string()], 'name' => ['type' => Type::string()], 'pic' => ['type' => $image, 'args' => ['width' => ['type' => Type::int()], 'height' => ['type' => Type::int()]]], 'recentArticle' => ['type' => $article]]; }]); $reply = new ObjectType(['name' => 'Reply', 'fields' => ['author' => ['type' => $author], 'body' => ['type' => Type::string()]]]); $article = new ObjectType(['name' => 'Article', 'fields' => ['id' => ['type' => Type::string()], 'isPublished' => ['type' => Type::boolean()], 'author' => ['type' => $author], 'title' => ['type' => Type::string()], 'body' => ['type' => Type::string()], 'image' => ['type' => $image], 'replies' => ['type' => Type::listOf($reply)]]]); $doc = ' query Test { article { author { name pic { url width } } image { width height } replies { body author { id name pic { url width } recentArticle { id title body } } } } } '; $expectedDefaultSelection = ['author' => true, 'image' => true, 'replies' => true]; $expectedDeepSelection = ['author' => ['name' => true, 'pic' => ['url' => true, 'width' => true]], 'image' => ['width' => true, 'height' => true], 'replies' => ['body' => true, 'author' => ['id' => true, 'name' => true, 'pic' => ['url' => true, 'width' => true], 'recentArticle' => ['id' => true, 'title' => true, 'body' => true]]]]; $hasCalled = false; $actualDefaultSelection = null; $actualDeepSelection = null; $blogQuery = new ObjectType(['name' => 'Query', 'fields' => ['article' => ['type' => $article, 'resolve' => function ($value, $args, $context, ResolveInfo $info) use(&$hasCalled, &$actualDefaultSelection, &$actualDeepSelection) { $hasCalled = true; $actualDefaultSelection = $info->getFieldSelection(); $actualDeepSelection = $info->getFieldSelection(5); return null; }]]]); $schema = new Schema(['query' => $blogQuery]); $result = GraphQL::execute($schema, $doc); $this->assertTrue($hasCalled); $this->assertEquals(['data' => ['article' => null]], $result); $this->assertEquals($expectedDefaultSelection, $actualDefaultSelection); $this->assertEquals($expectedDeepSelection, $actualDeepSelection); }
public function getType() { if (null === $this->resolvedType) { $this->resolvedType = Type::resolve($this->type); } return $this->resolvedType; }
public function setup() { $this->allUsers = [['name' => 'Dan', 'friends' => [1, 2, 3, 4]], ['name' => 'Nick', 'friends' => [0, 2, 3, 4]], ['name' => 'Lee', 'friends' => [0, 1, 3, 4]], ['name' => 'Joe', 'friends' => [0, 1, 2, 4]], ['name' => 'Tim', 'friends' => [0, 1, 2, 3]]]; $this->userType = new ObjectType(['name' => 'User', 'fields' => function () { return ['name' => ['type' => Type::string()], 'friends' => ['type' => $this->friendConnection, 'args' => Connection::connectionArgs(), 'resolve' => function ($user, $args) { return ArrayConnection::connectionFromArray($user['friends'], $args); }], 'friendsForward' => ['type' => $this->userConnection, 'args' => Connection::forwardConnectionArgs(), 'resolve' => function ($user, $args) { return ArrayConnection::connectionFromArray($user['friends'], $args); }], 'friendsBackward' => ['type' => $this->userConnection, 'args' => Connection::backwardConnectionArgs(), 'resolve' => function ($user, $args) { return ArrayConnection::connectionFromArray($user['friends'], $args); }]]; }]); $this->friendEdge = Connection::createEdgeType(['name' => 'Friend', 'nodeType' => $this->userType, 'resolveNode' => function ($edge) { return $this->allUsers[$edge['node']]; }, 'edgeFields' => function () { return ['friendshipTime' => ['type' => Type::string(), 'resolve' => function () { return 'Yesterday'; }]]; }]); $this->friendConnection = Connection::createConnectionType(['name' => 'Friend', 'nodeType' => $this->userType, 'edgeType' => $this->friendEdge, 'connectionFields' => function () { return ['totalCount' => ['type' => Type::int(), 'resolve' => function () { return count($this->allUsers) - 1; }]]; }]); $this->userEdge = Connection::createEdgeType(['nodeType' => $this->userType, 'resolveNode' => function ($edge) { return $this->allUsers[$edge['node']]; }]); $this->userConnection = Connection::createConnectionType(['nodeType' => $this->userType, 'edgeType' => $this->userEdge]); $this->queryType = new ObjectType(['name' => 'Query', 'fields' => function () { return ['user' => ['type' => $this->userType, 'resolve' => function () { return $this->allUsers[0]; }]]; }]); $this->schema = new Schema(['query' => $this->queryType]); }
public function setUp() { $this->syncError = new Error('sync'); $this->nonNullSyncError = new Error('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(['name' => 'DataType', 'fields' => ['sync' => ['type' => Type::string()], 'nonNullSync' => ['type' => Type::nonNull(Type::string())], 'nest' => ['type' => function () use(&$dataType) { return $dataType; }], 'nonNullNest' => ['type' => function () use(&$dataType) { return Type::nonNull($dataType); }]]]); $this->schema = new Schema($dataType); }
/** * Type fields. * * @return array */ public function fields() { return ['name' => ['type' => Type::string(), 'description' => 'Name of the user.'], 'email' => ['type' => Type::string(), 'description' => 'Email of the user.'], 'tasks' => GraphQL::connection('task')->args(['order' => ['type' => Type::string(), 'description' => 'Sort order of tasks.']])->resolve(function ($parent, array $args) { return $parent->tasks->transform(function ($task) { return array_merge($task->toArray(), ['title' => 'foo']); }); })->field()]; }
public static function buildDogType() { if (null !== self::$dogType) { return self::$dogType; } self::$dogType = new ObjectType(['name' => 'Dog', 'fields' => ['name' => ['type' => Type::nonNull(Type::string())], 'master' => ['type' => self::buildHumanType()]]]); return self::$dogType; }
public function __construct() { $config = ['name' => 'Query', 'fields' => ['user' => ['type' => Types::user(), 'description' => 'Returns user by id (in range of 1-5)', 'args' => ['id' => Types::nonNull(Types::id())]], 'viewer' => ['type' => Types::user(), 'description' => 'Represents currently logged-in user (for the sake of example - simply returns user with id == 1)'], 'stories' => ['type' => Types::listOf(Types::story()), 'description' => 'Returns subset of stories posted for this blog', 'args' => ['after' => ['type' => Types::id(), 'description' => 'Fetch stories listed after the story with this ID'], 'limit' => ['type' => Types::int(), 'description' => 'Number of stories to be returned', 'defaultValue' => 10]]], 'lastStoryPosted' => ['type' => Types::story(), 'description' => 'Returns last story posted for this blog'], 'deprecatedField' => ['type' => Types::string(), 'deprecationReason' => 'This field is deprecated!'], 'fieldWithException' => ['type' => Types::string(), 'resolve' => function () { throw new \Exception("Exception message thrown in field resolver"); }], 'hello' => Type::string()], 'resolveField' => function ($val, $args, $context, ResolveInfo $info) { return $this->{$info->fieldName}($val, $args, $context, $info); }]; parent::__construct($config); }
/** * Returns the test ObjectType * @return ObjectType */ protected function getTestObjectType() { if (!$this->testObject) { $this->testObject = new ObjectType(['name' => 'TestObject', 'fields' => ['name' => ['type' => Type::string(), 'resolve' => function () { return 'testname'; }]], 'interfaces' => [$this->getLazyInterfaceType()]]); } return $this->testObject; }
public function setUp() { $ColorType = new EnumType(['name' => 'Color', 'values' => ['RED' => ['value' => 0], 'GREEN' => ['value' => 1], 'BLUE' => ['value' => 2]]]); $simpleEnum = new EnumType(['name' => 'SimpleEnum', 'values' => ['ONE', 'TWO', 'THREE']]); $Complex1 = ['someRandomFunction' => function () { }]; $Complex2 = new \ArrayObject(['someRandomValue' => 123]); $ComplexEnum = new EnumType(['name' => 'Complex', 'values' => ['ONE' => ['value' => $Complex1], 'TWO' => ['value' => $Complex2]]]); $QueryType = new ObjectType(['name' => 'Query', 'fields' => ['colorEnum' => ['type' => $ColorType, 'args' => ['fromEnum' => ['type' => $ColorType], 'fromInt' => ['type' => Type::int()], 'fromString' => ['type' => Type::string()]], 'resolve' => function ($value, $args) { if (isset($args['fromInt'])) { return $args['fromInt']; } if (isset($args['fromString'])) { return $args['fromString']; } if (isset($args['fromEnum'])) { return $args['fromEnum']; } }], 'simpleEnum' => ['type' => $simpleEnum, 'args' => ['fromName' => ['type' => Type::string()], 'fromValue' => ['type' => Type::string()]], 'resolve' => function ($value, $args) { if (isset($args['fromName'])) { return $args['fromName']; } if (isset($args['fromValue'])) { return $args['fromValue']; } }], 'colorInt' => ['type' => Type::int(), 'args' => ['fromEnum' => ['type' => $ColorType], 'fromInt' => ['type' => Type::int()]], 'resolve' => function ($value, $args) { if (isset($args['fromInt'])) { return $args['fromInt']; } if (isset($args['fromEnum'])) { return $args['fromEnum']; } }], 'complexEnum' => ['type' => $ComplexEnum, 'args' => ['fromEnum' => ['type' => $ComplexEnum, 'defaultValue' => $Complex1], 'provideGoodValue' => ['type' => Type::boolean()], 'provideBadValue' => ['type' => Type::boolean()]], 'resolve' => function ($value, $args) use($Complex1, $Complex2) { if (!empty($args['provideGoodValue'])) { // Note: this is one of the references of the internal values which // ComplexEnum allows. return $Complex2; } if (!empty($args['provideBadValue'])) { // Note: similar shape, but not the same *reference* // as Complex2 above. Enum internal values require === equality. return new \ArrayObject(['someRandomValue' => 123]); } return $args['fromEnum']; }]]]); $MutationType = new ObjectType(['name' => 'Mutation', 'fields' => ['favoriteEnum' => ['type' => $ColorType, 'args' => ['color' => ['type' => $ColorType]], 'resolve' => function ($value, $args) { return isset($args['color']) ? $args['color'] : null; }]]]); $SubscriptionType = new ObjectType(['name' => 'Subscription', 'fields' => ['subscribeToEnum' => ['type' => $ColorType, 'args' => ['color' => ['type' => $ColorType]], 'resolve' => function ($value, $args) { return isset($args['color']) ? $args['color'] : null; }]]]); $this->Complex1 = $Complex1; $this->Complex2 = $Complex2; $this->ComplexEnum = $ComplexEnum; $this->schema = new Schema(['query' => $QueryType, 'mutation' => $MutationType, 'subscription' => $SubscriptionType]); }
/** * @describe [T!]! */ public function testHandlesNonNullListOfNonNulls() { $type = Type::nonNull(Type::listOf(Type::nonNull(Type::int()))); // Contains values $this->check($type, [1, 2], ['data' => ['nest' => ['test' => [1, 2]]]]); // Contains null $this->check($type, [1, null, 2], ['data' => ['nest' => null], 'errors' => [FormattedError::create('Cannot return null for non-nullable field DataType.test.', [new SourceLocation(1, 10)])]]); // Returns null $this->check($type, null, ['data' => ['nest' => null], 'errors' => [FormattedError::create('Cannot return null for non-nullable field DataType.test.', [new SourceLocation(1, 10)])]]); }
/** * @it uses provided resolve function */ public function testUsesProvidedResolveFunction() { $schema = $this->buildSchema(['type' => Type::string(), 'args' => ['aStr' => ['type' => Type::string()], 'aInt' => ['type' => Type::int()]], 'resolve' => function ($source, $args) { return json_encode([$source, $args]); }]); $this->assertEquals(['data' => ['test' => '[null,[]]']], GraphQL::execute($schema, '{ test }')); $this->assertEquals(['data' => ['test' => '["Source!",[]]']], GraphQL::execute($schema, '{ test }', 'Source!')); $this->assertEquals(['data' => ['test' => '["Source!",{"aStr":"String!"}]']], GraphQL::execute($schema, '{ test(aStr: "String!") }', 'Source!')); $this->assertEquals(['data' => ['test' => '["Source!",{"aStr":"String!","aInt":-123}]']], GraphQL::execute($schema, '{ test(aInt: -123, aStr: "String!") }', 'Source!')); }
public function getTypeMap() { if (null === $this->_typeMap) { $map = []; foreach ([$this->getQueryType(), $this->getMutationType(), Introspection::_schema()] as $type) { $this->_extractTypes($type, $map); } $this->_typeMap = $map + Type::getInternalTypes(); } return $this->_typeMap; }
public function testCoercesOutputBoolean() { $boolType = Type::boolean(); $this->assertSame(true, $boolType->coerce('string')); $this->assertSame(false, $boolType->coerce('')); $this->assertSame(true, $boolType->coerce(1)); $this->assertSame(false, $boolType->coerce(0)); $this->assertSame(true, $boolType->coerce(true)); $this->assertSame(false, $boolType->coerce(false)); // TODO: how should it behaive on '0'? }
public function __invoke(ValidationContext $context) { return [NodeKind::VARIABLE_DEFINITION => function (VariableDefinitionNode $node) use($context) { $type = Utils\TypeInfo::typeFromAST($context->getSchema(), $node->type); // If the variable type is not an input type, return an error. if ($type && !Type::isInputType($type)) { $variableName = $node->variable->name->value; $context->reportError(new Error(self::nonInputTypeOnVarMessage($variableName, Printer::doPrint($node->type)), [$node->type])); } }]; }
protected static function getSchema() { $userType = new ObjectType(['name' => 'User', 'fields' => function () { return ['username' => ['type' => Type::string()], 'url' => ['type' => Type::string()]]; }]); $queryType = new ObjectType(['name' => 'Query', 'fields' => function () use($userType) { return ['usernames' => Plural::pluralIdentifyingRootField(['argName' => 'usernames', 'description' => 'Map from a username to the user', 'inputType' => Type::string(), 'outputType' => $userType, 'resolveSingleInput' => function ($userName, $context, $info) { return ['username' => $userName, 'url' => 'www.facebook.com/' . $userName . '?lang=' . $info->rootValue['lang']]; }])]; }]); return new Schema(['query' => $queryType]); }
/** * Returns configuration for Plural identifying root field * * type PluralIdentifyingRootFieldConfig = { * argName: string, * inputType: GraphQLInputType, * outputType: GraphQLOutputType, * resolveSingleInput: (input: any, info: GraphQLResolveInfo) => ?any, * description?: ?string, * }; * * @param array $config * @return array */ public static function pluralIdentifyingRootField(array $config) { $inputArgs = []; $argName = self::getArrayValue($config, 'argName'); $inputArgs[$argName] = ['type' => Type::nonNull(Type::listOf(Type::nonNull(self::getArrayValue($config, 'inputType'))))]; return ['description' => isset($config['description']) ? $config['description'] : null, 'type' => Type::listOf(self::getArrayValue($config, 'outputType')), 'args' => $inputArgs, 'resolve' => function ($obj, $args, $context, ResolveInfo $info) use($argName, $config) { $inputs = $args[$argName]; return array_map(function ($input) use($config, $context, $info) { return call_user_func(self::getArrayValue($config, 'resolveSingleInput'), $input, $context, $info); }, $inputs); }]; }
public function testExecutesUsingASchema() { $BlogArticle = null; $BlogImage = new ObjectType(['name' => 'Image', 'fields' => ['url' => ['type' => Type::string()], 'width' => ['type' => Type::int()], 'height' => ['type' => Type::int()]]]); $BlogAuthor = new ObjectType(['name' => 'Author', 'fields' => ['id' => ['type' => Type::string()], 'name' => ['type' => Type::string()], 'pic' => ['args' => ['width' => ['type' => Type::int()], 'height' => ['type' => Type::int()]], 'type' => $BlogImage, 'resolve' => function ($obj, $args) { return $obj['pic']($args['width'], $args['height']); }], 'recentArticle' => ['type' => function () use(&$BlogArticle) { return $BlogArticle; }]]]); $BlogArticle = new ObjectType(['name' => 'Article', 'fields' => ['id' => ['type' => Type::nonNull(Type::string())], 'isPublished' => ['type' => Type::boolean()], 'author' => ['type' => $BlogAuthor], 'title' => ['type' => Type::string()], 'body' => ['type' => Type::string()], 'keywords' => ['type' => Type::listOf(Type::string())]]]); $BlogQuery = new ObjectType(['name' => 'Query', 'fields' => ['article' => ['type' => $BlogArticle, 'args' => ['id' => ['type' => Type::id()]], 'resolve' => function ($_, $args) { return $this->article($args['id']); }], 'feed' => ['type' => Type::listOf($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]]]]]]; $this->assertEquals($expected, Executor::execute($BlogSchema, Parser::parse($request))->toArray()); }
/** * Fields that exist on every connection. * * @return array */ public function fields() { return ['node' => ['type' => $this->type, 'description' => 'The item at the end of the edge.', 'resolve' => function ($edge) { return $edge; }], 'cursor' => ['type' => Type::nonNull(Type::string()), 'description' => 'A cursor for use in pagination.', 'resolve' => function ($edge) { if (is_array($edge) && isset($edge['relayCursor'])) { return $edge['relayCursor']; } elseif (is_array($edge->attributes)) { return $edge->attributes['relayCursor']; } return $edge->relayCursor; }]]; }
/** * Fields available on PageInfo. * * @return array */ public function fields() { return ['hasNextPage' => ['type' => Type::nonNull(Type::boolean()), 'description' => 'When paginating forwards, are there more items?', 'resolve' => function ($collection, $test) { if ($collection['total'] - $collection['first'] * $collection['currentPage'] > 0) { return true; } return false; }], 'hasPreviousPage' => ['type' => Type::nonNull(Type::boolean()), 'description' => 'When paginating backwards, are there more items?', 'resolve' => function ($collection) { if ($collection['currentPage'] > 1) { return true; } return false; }]]; }
private function schema() { $numberHolderType = new ObjectType(['fields' => ['theNumber' => ['type' => Type::int()]], 'name' => 'NumberHolder']); $schema = new Schema(['query' => new ObjectType(['fields' => ['numberHolder' => ['type' => $numberHolderType]], 'name' => 'Query']), 'mutation' => new ObjectType(['fields' => ['immediatelyChangeTheNumber' => ['type' => $numberHolderType, 'args' => ['newNumber' => ['type' => Type::int()]], 'resolve' => function (Root $obj, $args) { return $obj->immediatelyChangeTheNumber($args['newNumber']); }], 'promiseToChangeTheNumber' => ['type' => $numberHolderType, 'args' => ['newNumber' => ['type' => Type::int()]], 'resolve' => function (Root $obj, $args) { return $obj->promiseToChangeTheNumber($args['newNumber']); }], 'failToChangeTheNumber' => ['type' => $numberHolderType, 'args' => ['newNumber' => ['type' => Type::int()]], 'resolve' => function (Root $obj, $args) { return $obj->failToChangeTheNumber($args['newNumber']); }], 'promiseAndFailToChangeTheNumber' => ['type' => $numberHolderType, 'args' => ['newNumber' => ['type' => Type::int()]], 'resolve' => function (Root $obj, $args) { return $obj->promiseAndFailToChangeTheNumber($args['newNumber']); }]], 'name' => 'Mutation'])]); return $schema; }
public function __invoke(ValidationContext $context) { return [Node::INLINE_FRAGMENT => function (InlineFragment $node) use($context) { $type = $context->getType(); if ($node->typeCondition && $type && !Type::isCompositeType($type)) { $context->reportError(new Error(static::inlineFragmentOnNonCompositeErrorMessage($type), [$node->typeCondition])); } }, Node::FRAGMENT_DEFINITION => function (FragmentDefinition $node) use($context) { $type = $context->getType(); if ($type && !Type::isCompositeType($type)) { $context->reportError(new Error(static::fragmentOnNonCompositeErrorMessage($node->name->value, Printer::doPrint($node->typeCondition)), [$node->typeCondition])); } }]; }
/** * @return ObjectType[] */ public function getTypes() { 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($types), 'Option "types" of union "%s" is expected to return array of types (or closure returning array of types)', $this->name); $this->types = []; foreach ($types as $type) { $this->types[] = Type::resolve($type); } } return $this->types; }
public function __invoke(ValidationContext $context) { return [Node::FIELD => function (Field $node) use($context) { $type = $context->getType(); if ($type) { if (Type::isLeafType($type)) { if ($node->selectionSet) { return new Error(Messages::noSubselectionAllowedMessage($node->name->value, $type), [$node->selectionSet]); } } else { if (!$node->selectionSet) { return new Error(Messages::requiredSubselectionMessage($node->name->value, $type), [$node]); } } } }]; }
public function __invoke(ValidationContext $context) { return [Node::INLINE_FRAGMENT => function (InlineFragment $node) use($context) { $fragType = Type::getUnmodifiedType($context->getType()); $parentType = $context->getParentType(); if ($fragType && $parentType && !$this->doTypesOverlap($fragType, $parentType)) { return new Error(Messages::typeIncompatibleAnonSpreadMessage($parentType, $fragType), [$node]); } }, Node::FRAGMENT_SPREAD => function (FragmentSpread $node) use($context) { $fragName = $node->name->value; $fragType = Type::getUnmodifiedType($this->getFragmentType($context, $fragName)); $parentType = $context->getParentType(); if ($fragType && $parentType && !$this->doTypesOverlap($fragType, $parentType)) { return new Error(Messages::typeIncompatibleSpreadMessage($fragName, $parentType, $fragType), [$node]); } }]; }
function getConfig($config) { return array_replace_recursive(['description' => 'Items in a navigation menu', 'fields' => ['id' => ['type' => Type::string(), 'description' => 'Unique id for menu item', 'resolve' => function ($item) { return $item->object_id; }], 'caption' => ['type' => Type::string(), 'description' => 'File caption', 'resolve' => function ($item) { return $item->caption; }], 'title' => ['type' => Type::string(), 'description' => 'File title', 'resolve' => function ($item) { return $item->title; }], 'target' => ['type' => Type::string(), 'description' => 'Link target', 'resolve' => function ($item) { return $item->target; }], 'url' => ['type' => Type::string(), 'description' => 'Menu url', 'resolve' => function ($item) { return $item->url; }], 'description' => ['type' => Type::string(), 'description' => 'Link description', 'resolve' => function ($item) { return $item->description; }], 'classes' => ['type' => new ListOfType(Type::string()), 'description' => 'CSS class names for this item', 'resolve' => function ($item) { return $item->classes; }]]], $config); }
/** * Fields available on PageInfo. * * @return array */ public function fields() { return ['hasNextPage' => ['type' => Type::nonNull(Type::boolean()), 'description' => 'When paginating forwards, are there more items?', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $collection->hasMorePages(); } return false; }], 'hasPreviousPage' => ['type' => Type::nonNull(Type::boolean()), 'description' => 'When paginating backwards, are there more items?', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $collection->currentPage() > 1; } return false; }], 'startCursor' => ['type' => Type::string(), 'description' => 'When paginating backwards, the cursor to continue.', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $this->encodeGlobalId('arrayconnection', $collection->firstItem() * $collection->currentPage()); } return null; }], 'endCursor' => ['type' => Type::string(), 'description' => 'When paginating forwards, the cursor to continue.', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $this->encodeGlobalId('arrayconnection', $collection->lastItem() * $collection->currentPage()); } return null; }], 'total' => ['type' => Type::int(), 'description' => 'Total number of node in connection.', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $collection->total(); } return null; }], 'count' => ['type' => Type::int(), 'description' => 'Count of nodes in current request.', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $collection->count(); } return null; }], 'currentPage' => ['type' => Type::int(), 'description' => 'Current page of request.', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $collection->currentPage(); } return null; }], 'lastPage' => ['type' => Type::int(), 'description' => 'Last page in connection.', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $collection->lastPage(); } return null; }]]; }
function getConfig($config) { return array_replace_recursive(['description' => 'An image from the ACF plugin', 'fields' => ['caption' => ['description' => 'Image caption'], 'title' => ['description' => 'Image title'], 'url' => ['description' => 'Image path', 'args' => ['size' => ['description' => 'size of the image', 'type' => Type::string()]], 'resolve' => function ($field, $args) { $args += ['size' => 'medium']; $size = $args['size']; if ($size == 'full') { return $field['url']; } return $field['sizes'][$size]; }], 'width' => ['type' => Type::int(), 'description' => 'Image width', 'args' => ['size' => ['description' => 'size of the image', 'type' => Type::string()]], 'resolve' => function ($field) { $args += ['size' => 'medium']; $size = $args['size']; return $field['sizes'][$size . '-width']; }], 'height' => ['type' => Type::int(), 'description' => 'Image width', 'args' => ['size' => ['description' => 'size of the image', 'type' => Type::string()]], 'resolve' => function ($post) { $args += ['size' => 'medium']; $size = $args['size']; return $field['sizes'][$size . '-height']; }]]], parent::getConfig($config)); }