This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Date: 07.11.16 |
||
4 | * |
||
5 | * @author Portey Vasil <[email protected]> |
||
6 | */ |
||
7 | |||
8 | namespace Youshido\GraphQL\Execution; |
||
9 | |||
10 | |||
11 | use Youshido\GraphQL\Execution\Context\ExecutionContextInterface; |
||
12 | use Youshido\GraphQL\Execution\Visitor\AbstractQueryVisitor; |
||
13 | use Youshido\GraphQL\Field\Field; |
||
14 | use Youshido\GraphQL\Field\FieldInterface; |
||
15 | use Youshido\GraphQL\Parser\Ast\Field as FieldAst; |
||
16 | use Youshido\GraphQL\Parser\Ast\FragmentReference; |
||
17 | use Youshido\GraphQL\Parser\Ast\Interfaces\FragmentInterface; |
||
18 | use Youshido\GraphQL\Parser\Ast\Mutation; |
||
19 | use Youshido\GraphQL\Parser\Ast\Query; |
||
20 | use Youshido\GraphQL\Type\AbstractType; |
||
21 | use Youshido\GraphQL\Type\Object\AbstractObjectType; |
||
22 | use Youshido\GraphQL\Type\Union\AbstractUnionType; |
||
23 | |||
24 | class Reducer |
||
25 | { |
||
26 | |||
27 | /** @var ExecutionContextInterface */ |
||
28 | private $executionContext; |
||
29 | |||
30 | /** |
||
31 | * Apply all of $reducers to this query. Example reducer operations: checking for maximum query complexity, |
||
32 | * performing look-ahead query planning, etc. |
||
33 | * |
||
34 | * @param ExecutionContextInterface $executionContext |
||
35 | * @param AbstractQueryVisitor[] $reducers |
||
36 | */ |
||
37 | 2 | public function reduceQuery(ExecutionContextInterface $executionContext, array $reducers) |
|
38 | { |
||
39 | 2 | $this->executionContext = $executionContext; |
|
40 | 2 | $schema = $executionContext->getSchema(); |
|
41 | |||
42 | 2 | foreach ($reducers as $reducer) { |
|
43 | 2 | foreach ($executionContext->getRequest()->getAllOperations() as $operation) { |
|
44 | 2 | $this->doVisit($operation, $operation instanceof Mutation ? $schema->getMutationType() : $schema->getQueryType(), $reducer); |
|
45 | 2 | } |
|
46 | 2 | } |
|
47 | 2 | } |
|
48 | |||
49 | /** |
||
50 | * Entry point for the `walkQuery` routine. Execution bounces between here, where the reducer's ->visit() method |
||
51 | * is invoked, and `walkQuery` where we send in the scores from the `visit` call. |
||
52 | * |
||
53 | * @param Query $query |
||
54 | * @param AbstractType $currentLevelSchema |
||
55 | * @param AbstractQueryVisitor $reducer |
||
56 | */ |
||
57 | 2 | protected function doVisit(Query $query, $currentLevelSchema, $reducer) |
|
58 | { |
||
59 | 2 | if (!($currentLevelSchema instanceof AbstractObjectType) || !$currentLevelSchema->hasField($query->getName())) { |
|
60 | return; |
||
61 | } |
||
62 | |||
63 | 2 | if ($operationField = $currentLevelSchema->getField($query->getName())) { |
|
64 | |||
65 | 2 | $coroutine = $this->walkQuery($query, $operationField); |
|
66 | |||
67 | 2 | if ($results = $coroutine->current()) { |
|
68 | 2 | $queryCost = 0; |
|
69 | 2 | while ($results) { |
|
70 | // initial values come from advancing the generator via ->current, subsequent values come from ->send() |
||
71 | 2 | list($queryField, $astField, $childCost) = $results; |
|
72 | |||
73 | /** |
||
74 | * @var Query|FieldAst $queryField |
||
75 | * @var Field $astField |
||
76 | */ |
||
77 | 2 | $cost = $reducer->visit($queryField->getKeyValueArguments(), $astField->getConfig(), $childCost); |
|
78 | 2 | $queryCost += $cost; |
|
79 | 2 | $results = $coroutine->send($cost); |
|
80 | 2 | } |
|
81 | 2 | } |
|
82 | 2 | } |
|
83 | 2 | } |
|
84 | |||
85 | /** |
||
86 | * Coroutine to walk the query and schema in DFS manner (see AbstractQueryVisitor docs for more info) and yield a |
||
87 | * tuple of (queryNode, schemaNode, childScore) |
||
88 | * |
||
89 | * childScore costs are accumulated via values sent into the coroutine. |
||
90 | * |
||
91 | * Most of the branching in this function is just to handle the different types in a query: Queries, Unions, |
||
92 | * Fragments (anonymous and named), and Fields. The core of the function is simple: recurse until we hit the base |
||
93 | * case of a Field and yield that back up to the visitor up in `doVisit`. |
||
94 | * |
||
95 | * @param Query|Field|\Youshido\GraphQL\Parser\Ast\Interfaces\FragmentInterface $queryNode |
||
96 | * @param FieldInterface $currentLevelAST |
||
97 | * |
||
98 | * @return \Generator |
||
99 | */ |
||
100 | 2 | protected function walkQuery($queryNode, FieldInterface $currentLevelAST) |
|
101 | { |
||
102 | 2 | $childrenScore = 0; |
|
103 | 2 | if (!($queryNode instanceof FieldAst)) { |
|
104 | 2 | foreach ($queryNode->getFields() as $queryField) { |
|
0 ignored issues
–
show
|
|||
105 | 2 | if ($queryField instanceof FragmentInterface) { |
|
106 | 1 | if ($queryField instanceof FragmentReference) { |
|
107 | $queryField = $this->executionContext->getRequest()->getFragment($queryField->getName()); |
||
108 | } |
||
109 | // the next 7 lines are essentially equivalent to `yield from $this->walkQuery(...)` in PHP7. |
||
110 | // for backwards compatibility this is equivalent. |
||
111 | // This pattern is repeated multiple times in this function, and unfortunately cannot be extracted or |
||
112 | // made less verbose. |
||
113 | 1 | $gen = $this->walkQuery($queryField, $currentLevelAST); |
|
0 ignored issues
–
show
It seems like
$queryField defined by $this->executionContext-...$queryField->getName()) on line 107 can also be of type null or object<Youshido\GraphQL\Parser\Ast\Fragment> ; however, Youshido\GraphQL\Execution\Reducer::walkQuery() does only seem to accept object<Youshido\GraphQL\...aces\FragmentInterface> , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
114 | 1 | $next = $gen->current(); |
|
115 | 1 | while ($next) { |
|
116 | 1 | $received = (yield $next); |
|
117 | 1 | $childrenScore += (int)$received; |
|
118 | 1 | $next = $gen->send($received); |
|
119 | 1 | } |
|
120 | 1 | } else { |
|
121 | 2 | $fieldType = $currentLevelAST->getType()->getNamedType(); |
|
122 | 2 | if ($fieldType instanceof AbstractUnionType) { |
|
123 | 1 | foreach ($fieldType->getTypes() as $unionFieldType) { |
|
124 | 1 | View Code Duplication | if ($fieldAst = $unionFieldType->getField($queryField->getName())) { |
0 ignored issues
–
show
The method
getField does only exist in Youshido\GraphQL\Type\Object\AbstractObjectType , but not in Youshido\GraphQL\Type\Scalar\AbstractScalarType .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
125 | 1 | $gen = $this->walkQuery($queryField, $fieldAst); |
|
126 | 1 | $next = $gen->current(); |
|
127 | 1 | while ($next) { |
|
128 | 1 | $received = (yield $next); |
|
129 | 1 | $childrenScore += (int)$received; |
|
130 | 1 | $next = $gen->send($received); |
|
131 | 1 | } |
|
132 | 1 | } |
|
133 | 1 | } |
|
134 | 2 | View Code Duplication | } elseif ($fieldType instanceof AbstractObjectType && $fieldAst = $fieldType->getField($queryField->getName())) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
135 | 1 | $gen = $this->walkQuery($queryField, $fieldAst); |
|
136 | 1 | $next = $gen->current(); |
|
137 | 1 | while ($next) { |
|
138 | 1 | $received = (yield $next); |
|
139 | 1 | $childrenScore += (int)$received; |
|
140 | 1 | $next = $gen->send($received); |
|
141 | 1 | } |
|
142 | 1 | } |
|
143 | } |
||
144 | 2 | } |
|
145 | 2 | } |
|
146 | // sanity check. don't yield fragments; they don't contribute to cost |
||
147 | 2 | if ($queryNode instanceof Query || $queryNode instanceof FieldAst) { |
|
148 | // BASE CASE. If we're here we're done recursing - |
||
149 | // this node is either a field, or a query that we've finished recursing into. |
||
150 | 2 | yield [$queryNode, $currentLevelAST, $childrenScore]; |
|
151 | 2 | } |
|
152 | 2 | } |
|
153 | |||
154 | } |
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: