public function __invoke(ValidationContext $context)
{
$operation = null;
$visitedFragmentNames = [];
$definedVariableNames = [];
return ['visitSpreadFragments' => true, Node::OPERATION_DEFINITION => function (OperationDefinition $node, $key, $parent, $path, $ancestors) use(&$operation, &$visitedFragmentNames, &$definedVariableNames) {
$operation = $node;
$visitedFragmentNames = [];
$definedVariableNames = [];
}, Node::VARIABLE_DEFINITION => function (VariableDefinition $def) use(&$definedVariableNames) {
$definedVariableNames[$def->variable->name->value] = true;
}, Node::VARIABLE => function (Variable $variable, $key, $parent, $path, $ancestors) use(&$definedVariableNames, &$visitedFragmentNames, &$operation) {
$varName = $variable->name->value;
if (empty($definedVariableNames[$varName])) {
$withinFragment = false;
foreach ($ancestors as $ancestor) {
if ($ancestor instanceof FragmentDefinition) {
$withinFragment = true;
break;
}
}
if ($withinFragment && $operation && $operation->name) {
return new Error(Messages::undefinedVarByOpMessage($varName, $operation->name->value), [$variable, $operation]);
}
return new Error(Messages::undefinedVarMessage($varName), [$variable]);
}
}, 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;
}];
}