Creates a new visitor instance which maintains a provided TypeInfo instance
along with visiting visitor.
static public visitWithTypeInfo ( |
||
$typeInfo |
/** * @it maintains type info during edit */ public function testMaintainsTypeInfoDuringEdit() { $visited = []; $typeInfo = new TypeInfo(TestCase::getDefaultSchema()); $ast = Parser::parse('{ human(id: 4) { name, pets }, alien }'); $editedAst = Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, ['enter' => function ($node) use($typeInfo, &$visited) { $parentType = $typeInfo->getParentType(); $type = $typeInfo->getType(); $inputType = $typeInfo->getInputType(); $visited[] = ['enter', $node->kind, $node->kind === 'Name' ? $node->value : null, $parentType ? (string) $parentType : null, $type ? (string) $type : null, $inputType ? (string) $inputType : null]; // Make a query valid by adding missing selection sets. if ($node->kind === 'Field' && !$node->selectionSet && Type::isCompositeType(Type::getNamedType($type))) { return new FieldNode(['alias' => $node->alias, 'name' => $node->name, 'arguments' => $node->arguments, 'directives' => $node->directives, 'selectionSet' => new SelectionSetNode(['kind' => 'SelectionSet', 'selections' => [new FieldNode(['name' => new NameNode(['value' => '__typename'])])]])]); } }, 'leave' => function ($node) use($typeInfo, &$visited) { $parentType = $typeInfo->getParentType(); $type = $typeInfo->getType(); $inputType = $typeInfo->getInputType(); $visited[] = ['leave', $node->kind, $node->kind === 'Name' ? $node->value : null, $parentType ? (string) $parentType : null, $type ? (string) $type : null, $inputType ? (string) $inputType : null]; }])); $this->assertEquals(Printer::doPrint(Parser::parse('{ human(id: 4) { name, pets }, alien }')), Printer::doPrint($ast)); $this->assertEquals(Printer::doPrint(Parser::parse('{ human(id: 4) { name, pets { __typename } }, alien { __typename } }')), Printer::doPrint($editedAst)); $this->assertEquals([['enter', 'Document', null, null, null, null], ['enter', 'OperationDefinition', null, null, 'QueryRoot', null], ['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null], ['enter', 'Field', null, 'QueryRoot', 'Human', null], ['enter', 'Name', 'human', 'QueryRoot', 'Human', null], ['leave', 'Name', 'human', 'QueryRoot', 'Human', null], ['enter', 'Argument', null, 'QueryRoot', 'Human', 'ID'], ['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'], ['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'], ['enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID'], ['leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID'], ['leave', 'Argument', null, 'QueryRoot', 'Human', 'ID'], ['enter', 'SelectionSet', null, 'Human', 'Human', null], ['enter', 'Field', null, 'Human', 'String', null], ['enter', 'Name', 'name', 'Human', 'String', null], ['leave', 'Name', 'name', 'Human', 'String', null], ['leave', 'Field', null, 'Human', 'String', null], ['enter', 'Field', null, 'Human', '[Pet]', null], ['enter', 'Name', 'pets', 'Human', '[Pet]', null], ['leave', 'Name', 'pets', 'Human', '[Pet]', null], ['enter', 'SelectionSet', null, 'Pet', '[Pet]', null], ['enter', 'Field', null, 'Pet', 'String!', null], ['enter', 'Name', '__typename', 'Pet', 'String!', null], ['leave', 'Name', '__typename', 'Pet', 'String!', null], ['leave', 'Field', null, 'Pet', 'String!', null], ['leave', 'SelectionSet', null, 'Pet', '[Pet]', null], ['leave', 'Field', null, 'Human', '[Pet]', null], ['leave', 'SelectionSet', null, 'Human', 'Human', null], ['leave', 'Field', null, 'QueryRoot', 'Human', null], ['enter', 'Field', null, 'QueryRoot', 'Alien', null], ['enter', 'Name', 'alien', 'QueryRoot', 'Alien', null], ['leave', 'Name', 'alien', 'QueryRoot', 'Alien', null], ['enter', 'SelectionSet', null, 'Alien', 'Alien', null], ['enter', 'Field', null, 'Alien', 'String!', null], ['enter', 'Name', '__typename', 'Alien', 'String!', null], ['leave', 'Name', '__typename', 'Alien', 'String!', null], ['leave', 'Field', null, 'Alien', 'String!', null], ['leave', 'SelectionSet', null, 'Alien', 'Alien', null], ['leave', 'Field', null, 'QueryRoot', 'Alien', null], ['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null], ['leave', 'OperationDefinition', null, null, 'QueryRoot', null], ['leave', 'Document', null, null, null, null]], $visited); }
/** * This uses a specialized visitor which runs multiple visitors in parallel, * while maintaining the visitor skip and break API. * * @param Schema $schema * @param TypeInfo $typeInfo * @param DocumentNode $documentNode * @param array $rules * @return array */ public static function visitUsingRules(Schema $schema, TypeInfo $typeInfo, DocumentNode $documentNode, array $rules) { $context = new ValidationContext($schema, $documentNode, $typeInfo); $visitors = []; foreach ($rules as $rule) { $visitors[] = $rule($context); } Visitor::visit($documentNode, Visitor::visitWithTypeInfo($typeInfo, Visitor::visitInParallel($visitors))); return $context->getErrors(); }
/** * @param HasSelectionSet $node * @return array List of ['node' => Variable, 'type' => ?InputObjectType] */ function getVariableUsages(HasSelectionSet $node) { $usages = isset($this->variableUsages[$node]) ? $this->variableUsages[$node] : null; if (!$usages) { $newUsages = []; $typeInfo = new TypeInfo($this->schema); Visitor::visit($node, Visitor::visitWithTypeInfo($typeInfo, [Node::VARIABLE_DEFINITION => function () { return false; }, Node::VARIABLE => function (Variable $variable) use(&$newUsages, $typeInfo) { $newUsages[] = ['node' => $variable, 'type' => $typeInfo->getInputType()]; }])); $usages = $newUsages; $this->variableUsages[$node] = $usages; } return $usages; }