/** * Coroutine to walk the query and schema in DFS manner (see AbstractQueryVisitor docs for more info) and yield a * tuple of (queryNode, schemaNode, childScore) * * childScore costs are accumulated via values sent into the coroutine. * * Most of the branching in this function is just to handle the different types in a query: Queries, Unions, * Fragments (anonymous and named), and Fields. The core of the function is simple: recurse until we hit the base * case of a Field and yield that back up to the visitor up in `doVisit`. * * @param Query|Field|\Youshido\GraphQL\Parser\Ast\Interfaces\FragmentInterface $queryNode * @param FieldInterface $currentLevelAST * * @return \Generator */ protected function walkQuery($queryNode, FieldInterface $currentLevelAST) { $childrenScore = 0; if (!$queryNode instanceof FieldAst) { foreach ($queryNode->getFields() as $queryField) { if ($queryField instanceof FragmentInterface) { if ($queryField instanceof FragmentReference) { $queryField = $this->executionContext->getRequest()->getFragment($queryField->getName()); } // the next 7 lines are essentially equivalent to `yield from $this->walkQuery(...)` in PHP7. // for backwards compatibility this is equivalent. // This pattern is repeated multiple times in this function, and unfortunately cannot be extracted or // made less verbose. $gen = $this->walkQuery($queryField, $currentLevelAST); $next = $gen->current(); while ($next) { $received = (yield $next); $childrenScore += (int) $received; $next = $gen->send($received); } } else { $fieldType = $currentLevelAST->getType()->getNamedType(); if ($fieldType instanceof AbstractUnionType) { foreach ($fieldType->getTypes() as $unionFieldType) { if ($fieldAst = $unionFieldType->getField($queryField->getName())) { $gen = $this->walkQuery($queryField, $fieldAst); $next = $gen->current(); while ($next) { $received = (yield $next); $childrenScore += (int) $received; $next = $gen->send($received); } } } } elseif ($fieldType instanceof AbstractObjectType && ($fieldAst = $fieldType->getField($queryField->getName()))) { $gen = $this->walkQuery($queryField, $fieldAst); $next = $gen->current(); while ($next) { $received = (yield $next); $childrenScore += (int) $received; $next = $gen->send($received); } } } } } // sanity check. don't yield fragments; they don't contribute to cost if ($queryNode instanceof Query || $queryNode instanceof FieldAst) { // BASE CASE. If we're here we're done recursing - // this node is either a field, or a query that we've finished recursing into. (yield [$queryNode, $currentLevelAST, $childrenScore]); } }
public function getContainer() { return $this->executionContext->getContainer(); }
/** * @inheritdoc */ public function __construct(ExecutionContextInterface $executionContext) { $this->executionContext = $executionContext; parent::__construct($executionContext->getSchema()); }