public function __invoke(ValidationContext $context) { $varDefMap = new \ArrayObject(); $visitedFragmentNames = new \ArrayObject(); return ['visitSpreadFragments' => true, Node::OPERATION_DEFINITION => function () use(&$varDefMap, &$visitedFragmentNames) { $varDefMap = new \ArrayObject(); $visitedFragmentNames = new \ArrayObject(); }, Node::VARIABLE_DEFINITION => function (VariableDefinition $varDefAST) use($varDefMap) { $varDefMap[$varDefAST->variable->name->value] = $varDefAST; }, Node::FRAGMENT_SPREAD => function (FragmentSpread $spreadAST) use($visitedFragmentNames) { // Only visit fragments of a particular name once per operation if (!empty($visitedFragmentNames[$spreadAST->name->value])) { return Visitor::skipNode(); } $visitedFragmentNames[$spreadAST->name->value] = true; }, Node::VARIABLE => function (Variable $variableAST) use($context, $varDefMap) { $varName = $variableAST->name->value; $varDef = isset($varDefMap[$varName]) ? $varDefMap[$varName] : null; $varType = $varDef ? TypeInfo::typeFromAST($context->getSchema(), $varDef->type) : null; $inputType = $context->getInputType(); if ($varType && $inputType && !$this->varTypeAllowedForType($this->effectiveType($varType, $varDef), $inputType)) { return new Error(Messages::badVarPosMessage($varName, $varType, $inputType), [$variableAST]); } }]; }
public function __invoke(ValidationContext $context) { return [Node::DIRECTIVE => function (Directive $node, $key, $parent, $path, $ancestors) use($context) { $directiveDef = null; foreach ($context->getSchema()->getDirectives() as $def) { if ($def->name === $node->name->value) { $directiveDef = $def; break; } } if (!$directiveDef) { return new Error(Messages::unknownDirectiveMessage($node->name->value), [$node]); } $appliedTo = $ancestors[count($ancestors) - 1]; if ($appliedTo instanceof OperationDefinition && !$directiveDef->onOperation) { return new Error(Messages::misplacedDirectiveMessage($node->name->value, 'operation'), [$node]); } if ($appliedTo instanceof Field && !$directiveDef->onField) { return new Error(Messages::misplacedDirectiveMessage($node->name->value, 'field'), [$node]); } $fragmentKind = $appliedTo instanceof FragmentSpread || $appliedTo instanceof InlineFragment || $appliedTo instanceof FragmentDefinition; if ($fragmentKind && !$directiveDef->onFragment) { return new Error(Messages::misplacedDirectiveMessage($node->name->value, 'fragment'), [$node]); } }]; }
public function __invoke(ValidationContext $context) { return [Node::DIRECTIVE => function (Directive $node, $key, $parent, $path, $ancestors) use($context) { $directiveDef = null; foreach ($context->getSchema()->getDirectives() as $def) { if ($def->name === $node->name->value) { $directiveDef = $def; break; } } if (!$directiveDef) { $context->reportError(new Error(self::unknownDirectiveMessage($node->name->value), [$node])); return; } $appliedTo = $ancestors[count($ancestors) - 1]; $candidateLocation = $this->getLocationForAppliedNode($appliedTo); if (!$candidateLocation) { $context->reportError(new Error(self::misplacedDirectiveMessage($node->name->value, $node->type), [$node])); } else { if (!in_array($candidateLocation, $directiveDef->locations)) { $context->reportError(new Error(self::misplacedDirectiveMessage($node->name->value, $candidateLocation), [$node])); } } }]; }
public function __invoke(ValidationContext $context) { return [NodeKind::OPERATION_DEFINITION => ['enter' => function () { $this->varDefMap = []; }, 'leave' => function (OperationDefinitionNode $operation) use($context) { $usages = $context->getRecursiveVariableUsages($operation); foreach ($usages as $usage) { $node = $usage['node']; $type = $usage['type']; $varName = $node->name->value; $varDef = isset($this->varDefMap[$varName]) ? $this->varDefMap[$varName] : null; if ($varDef && $type) { // A var type is allowed if it is the same or more strict (e.g. is // a subtype of) than the expected type. It can be more strict if // the variable type is non-null when the expected type is nullable. // If both are list types, the variable item type can be more strict // than the expected item type (contravariant). $schema = $context->getSchema(); $varType = TypeInfo::typeFromAST($schema, $varDef->type); if ($varType && !TypeInfo::isTypeSubTypeOf($schema, $this->effectiveType($varType, $varDef), $type)) { $context->reportError(new Error(self::badVarPosMessage($varName, $varType, $type), [$varDef, $node])); } } } }], NodeKind::VARIABLE_DEFINITION => function (VariableDefinitionNode $varDefNode) { $this->varDefMap[$varDefNode->variable->name->value] = $varDefNode; }]; }
public function __invoke(ValidationContext $context) { return [Node::INLINE_FRAGMENT => function (InlineFragment $node) use($context) { $typeName = $node->typeCondition->value; $type = $context->getSchema()->getType($typeName); $isCompositeType = $type instanceof CompositeType; if (!$isCompositeType) { return new Error("Fragment cannot condition on non composite type \"{$typeName}\".", [$node->typeCondition]); } }, Node::FRAGMENT_DEFINITION => function (FragmentDefinition $node) use($context) { $typeName = $node->typeCondition->value; $type = $context->getSchema()->getType($typeName); $isCompositeType = $type instanceof CompositeType; if (!$isCompositeType) { return new Error(Messages::fragmentOnNonCompositeErrorMessage($node->name->value, $typeName), [$node->typeCondition]); } }]; }
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])); } }]; }
public function __invoke(ValidationContext $context) { return [Node::VARIABLE_DEFINITION => function (VariableDefinition $node) use($context) { $typeName = $this->getTypeASTName($node->type); $type = $context->getSchema()->getType($typeName); if (!$type instanceof InputType) { $variableName = $node->variable->name->value; return new Error(Messages::nonInputTypeOnVarMessage($variableName, Printer::doPrint($node->type)), [$node->type]); } }]; }
private function buildFieldArguments(FieldNode $node) { $rawVariableValues = $this->getRawVariableValues(); $astFieldInfo = $this->astFieldInfo($node); $fieldDef = $astFieldInfo[1]; $args = []; if ($fieldDef instanceof FieldDefinition) { $variableValues = Values::getVariableValues($this->context->getSchema(), $this->variableDefs, $rawVariableValues); $args = Values::getArgumentValues($fieldDef, $node, $variableValues); } return $args; }
public function __invoke(ValidationContext $context) { return [Node::NAMED_TYPE => function (NamedType $node, $key) use($context) { if ($key === 'type' || $key === 'typeCondition') { $typeName = $node->name->value; $type = $context->getSchema()->getType($typeName); if (!$type) { return new Error(self::unknownTypeMessage($typeName), [$node]); } } }]; }
public function __invoke(ValidationContext $context) { $skip = function () { return Visitor::skipNode(); }; return [Node::OBJECT_TYPE_DEFINITION => $skip, Node::INTERFACE_TYPE_DEFINITION => $skip, Node::UNION_TYPE_DEFINITION => $skip, Node::INPUT_OBJECT_TYPE_DEFINITION => $skip, Node::NAMED_TYPE => function (NamedType $node, $key) use($context) { $typeName = $node->name->value; $type = $context->getSchema()->getType($typeName); if (!$type) { $context->reportError(new Error(self::unknownTypeMessage($typeName), [$node])); } }]; }
public function __invoke(ValidationContext $context) { return [Node::FIELD => function (Field $node) use($context) { $type = $context->getParentType(); if ($type) { $fieldDef = $context->getFieldDef(); if (!$fieldDef) { // This isn't valid. Let's find suggestions, if any. $suggestedTypes = []; if ($type instanceof AbstractType) { $schema = $context->getSchema(); $suggestedTypes = self::getSiblingInterfacesIncludingField($schema, $type, $node->name->value); $suggestedTypes = array_merge($suggestedTypes, self::getImplementationsIncludingField($schema, $type, $node->name->value)); } $context->reportError(new Error(static::undefinedFieldMessage($node->name->value, $type->name, $suggestedTypes), [$node])); } } }]; }
/** * Given a selectionSet, adds all of the fields in that selection to * the passed in map of fields, and returns it at the end. * * Note: This is not the same as execution's collectFields because at static * time we do not know what object type will be used, so we unconditionally * spread in all fragments. * * @param ValidationContext $context * @param mixed $parentType * @param SelectionSetNode $selectionSet * @param \ArrayObject $visitedFragmentNames * @param \ArrayObject $astAndDefs * @return mixed */ private function collectFieldNodesAndDefs(ValidationContext $context, $parentType, SelectionSetNode $selectionSet, \ArrayObject $visitedFragmentNames = null, \ArrayObject $astAndDefs = null) { $_visitedFragmentNames = $visitedFragmentNames ?: new \ArrayObject(); $_astAndDefs = $astAndDefs ?: new \ArrayObject(); for ($i = 0; $i < count($selectionSet->selections); $i++) { $selection = $selectionSet->selections[$i]; switch ($selection->kind) { case NodeKind::FIELD: $fieldName = $selection->name->value; $fieldDef = null; if ($parentType && method_exists($parentType, 'getFields')) { $tmp = $parentType->getFields(); if (isset($tmp[$fieldName])) { $fieldDef = $tmp[$fieldName]; } } $responseName = $selection->alias ? $selection->alias->value : $fieldName; if (!isset($_astAndDefs[$responseName])) { $_astAndDefs[$responseName] = new \ArrayObject(); } $_astAndDefs[$responseName][] = [$parentType, $selection, $fieldDef]; break; case NodeKind::INLINE_FRAGMENT: $typeCondition = $selection->typeCondition; $inlineFragmentType = $typeCondition ? TypeInfo::typeFromAST($context->getSchema(), $typeCondition) : $parentType; $_astAndDefs = $this->collectFieldNodesAndDefs($context, $inlineFragmentType, $selection->selectionSet, $_visitedFragmentNames, $_astAndDefs); break; case NodeKind::FRAGMENT_SPREAD: /** @var FragmentSpreadNode $selection */ $fragName = $selection->name->value; if (!empty($_visitedFragmentNames[$fragName])) { continue; } $_visitedFragmentNames[$fragName] = true; $fragment = $context->getFragment($fragName); if (!$fragment) { continue; } $fragmentType = TypeInfo::typeFromAST($context->getSchema(), $fragment->typeCondition); $_astAndDefs = $this->collectFieldNodesAndDefs($context, $fragmentType, $fragment->selectionSet, $_visitedFragmentNames, $_astAndDefs); break; } } return $_astAndDefs; }
/** * Given a selectionSet, adds all of the fields in that selection to * the passed in map of fields, and returns it at the end. * * Note: This is not the same as execution's collectFields because at static * time we do not know what object type will be used, so we unconditionally * spread in all fragments. * * @see GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged * * @param ValidationContext $context * @param Type|null $parentType * @param SelectionSetNode $selectionSet * @param \ArrayObject $visitedFragmentNames * @param \ArrayObject $astAndDefs * * @return \ArrayObject */ protected function collectFieldASTsAndDefs(ValidationContext $context, $parentType, SelectionSetNode $selectionSet, \ArrayObject $visitedFragmentNames = null, \ArrayObject $astAndDefs = null) { $_visitedFragmentNames = $visitedFragmentNames ?: new \ArrayObject(); $_astAndDefs = $astAndDefs ?: new \ArrayObject(); foreach ($selectionSet->selections as $selection) { switch ($selection->kind) { case NodeKind::FIELD: /* @var FieldNode $selection */ $fieldName = $selection->name->value; $fieldDef = null; if ($parentType && method_exists($parentType, 'getFields')) { $tmp = $parentType->getFields(); $schemaMetaFieldDef = Introspection::schemaMetaFieldDef(); $typeMetaFieldDef = Introspection::typeMetaFieldDef(); $typeNameMetaFieldDef = Introspection::typeNameMetaFieldDef(); if ($fieldName === $schemaMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) { $fieldDef = $schemaMetaFieldDef; } elseif ($fieldName === $typeMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) { $fieldDef = $typeMetaFieldDef; } elseif ($fieldName === $typeNameMetaFieldDef->name) { $fieldDef = $typeNameMetaFieldDef; } elseif (isset($tmp[$fieldName])) { $fieldDef = $tmp[$fieldName]; } } $responseName = $this->getFieldName($selection); if (!isset($_astAndDefs[$responseName])) { $_astAndDefs[$responseName] = new \ArrayObject(); } // create field context $_astAndDefs[$responseName][] = [$selection, $fieldDef]; break; case NodeKind::INLINE_FRAGMENT: /* @var InlineFragmentNode $selection */ $_astAndDefs = $this->collectFieldASTsAndDefs($context, TypeInfo::typeFromAST($context->getSchema(), $selection->typeCondition), $selection->selectionSet, $_visitedFragmentNames, $_astAndDefs); break; case NodeKind::FRAGMENT_SPREAD: /* @var FragmentSpreadNode $selection */ $fragName = $selection->name->value; if (empty($_visitedFragmentNames[$fragName])) { $_visitedFragmentNames[$fragName] = true; $fragment = $context->getFragment($fragName); if ($fragment) { $_astAndDefs = $this->collectFieldASTsAndDefs($context, TypeInfo::typeFromAST($context->getSchema(), $fragment->typeCondition), $fragment->selectionSet, $_visitedFragmentNames, $_astAndDefs); } } break; } } return $_astAndDefs; }
private function getFragmentType(ValidationContext $context, $name) { $frag = $context->getFragment($name); return $frag ? TypeInfo::typeFromAST($context->getSchema(), $frag->typeCondition) : null; }
private function getFragmentType(ValidationContext $context, $name) { $frag = $context->getFragment($name); return $frag ? $context->getSchema()->getType($frag->typeCondition->value) : null; }