Example #1
0
 /**
  * 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.
  *
  * @return FieldDefinition
  */
 private static function _getFieldDef(Schema $schema, Type $parentType, Field $fieldAST)
 {
     $name = $fieldAST->name->value;
     $schemaMeta = Introspection::schemaMetaFieldDef();
     if ($name === $schemaMeta->name && $schema->getQueryType() === $parentType) {
         return $schemaMeta;
     }
     $typeMeta = Introspection::typeMetaFieldDef();
     if ($name === $typeMeta->name && $schema->getQueryType() === $parentType) {
         return $typeMeta;
     }
     $typeNameMeta = Introspection::typeNameMetaFieldDef();
     if ($name === $typeNameMeta->name && ($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;
 }
Example #2
0
 /**
  * Go through all of the implementations of type, and find other interaces
  * that they implement. If those interfaces include `field` as a valid field,
  * return them, sorted by how often the implementations include the other
  * interface.
  */
 static function getSiblingInterfacesIncludingField(Schema $schema, AbstractType $type, $fieldName)
 {
     $types = $schema->getPossibleTypes($type);
     $suggestedInterfaces = array_reduce($types, function ($acc, $t) use($fieldName) {
         foreach ($t->getInterfaces() as $i) {
             if (empty($i->getFields()[$fieldName])) {
                 continue;
             }
             if (!isset($acc[$i->name])) {
                 $acc[$i->name] = 0;
             }
             $acc[$i->name] += 1;
         }
         return $acc;
     }, []);
     $suggestedInterfaceNames = array_keys($suggestedInterfaces);
     usort($suggestedInterfaceNames, function ($a, $b) use($suggestedInterfaces) {
         return $suggestedInterfaces[$b] - $suggestedInterfaces[$a];
     });
     return $suggestedInterfaceNames;
 }
Example #3
0
 /**
  * This method looks up the field on the given type defintion.
  * It has special casing for the two introspection fields, __schema
  * and __typename. __typename is special because it can always be
  * queried as a field, even in situations where no other fields
  * are allowed, like on a Union. __schema could get automatically
  * added to the query type, but that would require mutating type
  * definitions, which would cause issues.
  *
  * @param Schema $schema
  * @param ObjectType $parentType
  * @param $fieldName
  *
  * @return FieldDefinition
  */
 private static function getFieldDef(Schema $schema, ObjectType $parentType, $fieldName)
 {
     static $schemaMetaFieldDef, $typeMetaFieldDef, $typeNameMetaFieldDef;
     $schemaMetaFieldDef = $schemaMetaFieldDef ?: Introspection::schemaMetaFieldDef();
     $typeMetaFieldDef = $typeMetaFieldDef ?: Introspection::typeMetaFieldDef();
     $typeNameMetaFieldDef = $typeNameMetaFieldDef ?: Introspection::typeNameMetaFieldDef();
     if ($fieldName === $schemaMetaFieldDef->name && $schema->getQueryType() === $parentType) {
         return $schemaMetaFieldDef;
     } else {
         if ($fieldName === $typeMetaFieldDef->name && $schema->getQueryType() === $parentType) {
             return $typeMetaFieldDef;
         } else {
             if ($fieldName === $typeNameMetaFieldDef->name) {
                 return $typeNameMetaFieldDef;
             }
         }
     }
     $tmp = $parentType->getFields();
     return isset($tmp[$fieldName]) ? $tmp[$fieldName] : null;
 }
Example #4
0
 public function testIncludesInterfaceSubtypesInTheTypeMap()
 {
     $someInterface = new InterfaceType(['name' => 'SomeInterface', 'fields' => []]);
     $someSubtype = new ObjectType(['name' => 'SomeSubtype', 'fields' => [], 'interfaces' => [$someInterface]]);
     $schema = new Schema($someInterface);
     $this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
 }
Example #5
0
 public function testIncludesInterfacesThunkSubtypesInTheTypeMap()
 {
     // includes interfaces' thunk subtypes in the type map
     $someInterface = new InterfaceType(['name' => 'SomeInterface', 'fields' => ['f' => ['type' => Type::int()]]]);
     $someSubtype = new ObjectType(['name' => 'SomeSubtype', 'fields' => ['f' => ['type' => Type::int()]], 'interfaces' => function () use($someInterface) {
         return [$someInterface];
     }, 'isTypeOf' => function () {
         return true;
     }]);
     $schema = new Schema(new ObjectType(['name' => 'Query', 'fields' => ['iface' => ['type' => $someInterface]]]));
     $this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
 }
 public function testRejectsWhenAnImplementationIsNotAPossibleType()
 {
     // rejects when an implementation is not a possible type
     $interfaceType = new InterfaceType(['name' => 'InterfaceType', 'fields' => []]);
     $subType = new ObjectType(['name' => 'SubType', 'fields' => [], 'interfaces' => []]);
     $tmp = new \ReflectionObject($subType);
     $prop = $tmp->getProperty('_interfaces');
     $prop->setAccessible(true);
     $prop->setValue($subType, [$interfaceType]);
     // Sanity check the test.
     $this->assertEquals([$interfaceType], $subType->getInterfaces());
     $this->assertSame(false, $interfaceType->isPossibleType($subType));
     // Need to make sure SubType is in the schema! We rely on
     // possibleTypes to be able to see it unless it's explicitly used.
     $schema = new Schema($interfaceType, $subType);
     // Another sanity check.
     $this->assertSame($subType, $schema->getType('SubType'));
     $validationResult = SchemaValidator::validate($schema, [SchemaValidator::typesInterfacesMustShowThemAsPossibleRule()]);
     $this->assertSame(false, $validationResult->isValid);
     $this->assertSame(1, count($validationResult->errors));
     $this->assertSame('SubType implements interface InterfaceType, but InterfaceType does ' . 'not list it as possible!', $validationResult->errors[0]->message);
     /*
     
        var validationResult = validateSchema(
          schema,
          [TypesInterfacesMustShowThemAsPossible]
        );
        expect(validationResult.isValid).to.equal(false);
        expect(validationResult.errors.length).to.equal(1);
        expect(validationResult.errors[0].message).to.equal(
          'SubType implements interface InterfaceType, but InterfaceType does ' +
          'not list it as possible!'
        );
     */
 }
Example #7
0
 public function testAllowsShorthandFieldDefinition()
 {
     $interface = new InterfaceType(['name' => 'SomeInterface', 'fields' => function () use(&$interface) {
         return ['value' => Type::string(), 'nested' => $interface, 'withArg' => ['type' => Type::string(), 'args' => ['arg1' => Type::int()]]];
     }]);
     $query = new ObjectType(['name' => 'Query', 'fields' => ['test' => $interface]]);
     $schema = new Schema(['query' => $query]);
     $valueField = $schema->getType('SomeInterface')->getField('value');
     $nestedField = $schema->getType('SomeInterface')->getField('nested');
     $this->assertEquals(Type::string(), $valueField->getType());
     $this->assertEquals($interface, $nestedField->getType());
     $withArg = $schema->getType('SomeInterface')->getField('withArg');
     $this->assertEquals(Type::string(), $withArg->getType());
     $this->assertEquals('arg1', $withArg->args[0]->name);
     $this->assertEquals(Type::int(), $withArg->args[0]->getType());
     $testField = $schema->getType('Query')->getField('test');
     $this->assertEquals($interface, $testField->getType());
     $this->assertEquals('test', $testField->name);
 }