'Episode', 'description' => 'One of the films in the Star Wars Trilogy', 'values' => [ 'NEWHOPE' => [ 'value' => 4, 'description' => 'Released in 1977.', ], 'EMPIRE' => [ 'value' => 5, 'description' => 'Released in 1980.', ], 'JEDI' => [ 'value' => 6, 'description' => 'Released in 1983.', ], ], ]); $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([ 'name' => 'Character', 'description' => 'A character in the Star Wars Trilogy', 'fields' => static function () use (&$characterInterface, $episodeEnum) { return [ 'id' => [ 'type' => Type::nonNull(Type::string()), 'description' => 'The id of the character.', ], 'name' => [ 'type' => Type::string(), 'description' => 'The name of the character.', ], 'friends' => [ 'type' => Type::listOf($characterInterface), 'description' => 'The friends of the character, or an empty list if they have none.', ], 'appearsIn' => [ 'type' => Type::listOf($episodeEnum), 'description' => 'Which movies they appear in.', ], 'secretBackstory' => [ 'type' => Type::string(), 'description' => 'All secrets about their past.', ], ]; }, 'resolveType' => static function ($obj) use (&$humanType, &$droidType) { return StarWarsData::getHuman($obj['id']) === null ? $droidType : $humanType; }, ]); /** * We define our human type, which implements the character interface. * * This implements the following type system shorthand: * type Human implements Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * secretBackstory: String * } */ $humanType = new ObjectType([ 'name' => 'Human', 'description' => 'A humanoid creature in the Star Wars universe.', 'fields' => [ 'id' => [ 'type' => new NonNull(Type::string()), 'description' => 'The id of the human.', ], 'name' => [ 'type' => Type::string(), 'description' => 'The name of the human.', ], 'friends' => [ 'type' => Type::listOf($characterInterface), 'description' => 'The friends of the human, or an empty list if they have none.', 'resolve' => static function ($human, $args, $context, ResolveInfo $info) { $fieldSelection = $info->getFieldSelection(); $fieldSelection['id'] = true; return array_map( static function ($friend) use ($fieldSelection) { return array_intersect_key($friend, $fieldSelection); }, StarWarsData::getFriends($human) ); }, ], 'appearsIn' => [ 'type' => Type::listOf($episodeEnum), 'description' => 'Which movies they appear in.', ], 'homePlanet' => [ 'type' => Type::string(), 'description' => 'The home planet of the human, or null if unknown.', ], 'secretBackstory' => [ 'type' => Type::string(), 'description' => 'Where are they from and how they came to be who they are.', 'resolve' => static function () { // This is to demonstrate error reporting throw new Exception('secretBackstory is secret.'); }, ], ], 'interfaces' => [$characterInterface], ]); /** * The other type of character in Star Wars is a droid. * * This implements the following type system shorthand: * type Droid implements Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * secretBackstory: String * primaryFunction: String * } */ $droidType = new ObjectType([ 'name' => 'Droid', 'description' => 'A mechanical creature in the Star Wars universe.', 'fields' => [ 'id' => [ 'type' => Type::nonNull(Type::string()), 'description' => 'The id of the droid.', ], 'name' => [ 'type' => Type::string(), 'description' => 'The name of the droid.', ], 'friends' => [ 'type' => Type::listOf($characterInterface), 'description' => 'The friends of the droid, or an empty list if they have none.', 'resolve' => static function ($droid) { return StarWarsData::getFriends($droid); }, ], 'appearsIn' => [ 'type' => Type::listOf($episodeEnum), 'description' => 'Which movies they appear in.', ], 'secretBackstory' => [ 'type' => Type::string(), 'description' => 'Construction date and the name of the designer.', 'resolve' => static function () { // This is to demonstrate error reporting throw new Exception('secretBackstory is secret.'); }, ], 'primaryFunction' => [ 'type' => Type::string(), 'description' => 'The primary function of the droid.', ], ], 'interfaces' => [$characterInterface], ]); /** * 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(episode: Episode): Character * human(id: String!): Human * droid(id: String!): Droid * } */ $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ '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' => static function ($root, $args) { return StarWarsData::getHero($args['episode'] ?? null); }, ], 'human' => [ 'type' => $humanType, 'args' => [ 'id' => [ 'name' => 'id', 'description' => 'id of the human', 'type' => Type::nonNull(Type::string()), ], ], 'resolve' => static function ($root, $args) { $humans = StarWarsData::humans(); return $humans[$args['id']] ?? null; }, ], 'droid' => [ 'type' => $droidType, 'args' => [ 'id' => [ 'name' => 'id', 'description' => 'id of the droid', 'type' => Type::nonNull(Type::string()), ], ], 'resolve' => static function ($root, $args) { $droids = StarWarsData::droids(); return $droids[$args['id']] ?? null; }, ], ], ]); return new Schema(['query' => $queryType]); } }