Passed
Pull Request — master (#314)
by Jakub
08:46 queued 02:41
created

Values::getArgumentValuesForMap()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 55
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 11

Importance

Changes 0
Metric Value
eloc 35
dl 0
loc 55
ccs 35
cts 35
cp 1
rs 7.3166
c 0
b 0
f 0
cc 11
nc 10
nop 4
crap 11

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Executor;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Language\AST\ArgumentNode;
9
use GraphQL\Language\AST\DirectiveNode;
10
use GraphQL\Language\AST\EnumValueDefinitionNode;
11
use GraphQL\Language\AST\FieldDefinitionNode;
12
use GraphQL\Language\AST\FieldNode;
13
use GraphQL\Language\AST\FragmentSpreadNode;
14
use GraphQL\Language\AST\InlineFragmentNode;
15
use GraphQL\Language\AST\Node;
16
use GraphQL\Language\AST\NodeList;
17
use GraphQL\Language\AST\ValueNode;
18
use GraphQL\Language\AST\VariableDefinitionNode;
19
use GraphQL\Language\AST\VariableNode;
20
use GraphQL\Language\Printer;
21
use GraphQL\Type\Definition\Directive;
22
use GraphQL\Type\Definition\FieldDefinition;
23
use GraphQL\Type\Definition\InputType;
24
use GraphQL\Type\Definition\NonNull;
25
use GraphQL\Type\Definition\Type;
26
use GraphQL\Type\Schema;
27
use GraphQL\Utils\AST;
28
use GraphQL\Utils\TypeInfo;
29
use GraphQL\Utils\Utils;
30
use GraphQL\Utils\Value;
31
use stdClass;
32
use Throwable;
33
use function array_key_exists;
34
use function array_map;
35
use function sprintf;
36
37
class Values
38
{
39
    /**
40
     * Prepares an object map of variables of the correct type based on the provided
41
     * variable definitions and arbitrary input. If the input cannot be coerced
42
     * to match the variable definitions, a Error will be thrown.
43
     *
44
     * @param VariableDefinitionNode[] $varDefNodes
45
     * @param mixed[]                  $inputs
46
     *
47
     * @return mixed[]
48
     */
49 235
    public static function getVariableValues(Schema $schema, $varDefNodes, array $inputs)
50
    {
51 235
        $errors        = [];
52 235
        $coercedValues = [];
53 235
        foreach ($varDefNodes as $varDefNode) {
54 54
            $varName = $varDefNode->variable->name->value;
55
            /** @var InputType|Type $varType */
56 54
            $varType = TypeInfo::typeFromAST($schema, $varDefNode->type);
57
58 54
            if (Type::isInputType($varType)) {
59 52
                if (array_key_exists($varName, $inputs)) {
60 47
                    $value   = $inputs[$varName];
61 47
                    $coerced = Value::coerceValue($value, $varType, $varDefNode);
0 ignored issues
show
Bug introduced by
$varType of type GraphQL\Type\Definition\Type is incompatible with the type GraphQL\Type\Definition\InputType expected by parameter $type of GraphQL\Utils\Value::coerceValue(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

61
                    $coerced = Value::coerceValue($value, /** @scrutinizer ignore-type */ $varType, $varDefNode);
Loading history...
62
                    /** @var Error[] $coercionErrors */
63 47
                    $coercionErrors = $coerced['errors'];
64 47
                    if (empty($coercionErrors)) {
65 32
                        $coercedValues[$varName] = $coerced['value'];
66
                    } else {
67 16
                        $messagePrelude = sprintf(
68 16
                            'Variable "$%s" got invalid value %s; ',
69 16
                            $varName,
70 16
                            Utils::printSafeJson($value)
71
                        );
72
73 16
                        foreach ($coercionErrors as $error) {
74 16
                            $errors[] = new Error(
75 16
                                $messagePrelude . $error->getMessage(),
76 16
                                $error->getNodes(),
77 16
                                $error->getSource(),
78 16
                                $error->getPositions(),
79 16
                                $error->getPath(),
80 16
                                $error,
81 47
                                $error->getExtensions()
82
                            );
83
                        }
84
                    }
85
                } else {
86 19
                    if ($varType instanceof NonNull) {
87 1
                        $errors[] = new Error(
88 1
                            sprintf(
89 1
                                'Variable "$%s" of required type "%s" was not provided.',
90 1
                                $varName,
91 1
                                $varType
92
                            ),
93 1
                            [$varDefNode]
94
                        );
95 18
                    } elseif ($varDefNode->defaultValue) {
96 52
                        $coercedValues[$varName] = AST::valueFromAST($varDefNode->defaultValue, $varType);
0 ignored issues
show
Bug introduced by
$varType of type GraphQL\Type\Definition\Type is incompatible with the type GraphQL\Type\Definition\InputType expected by parameter $type of GraphQL\Utils\AST::valueFromAST(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

96
                        $coercedValues[$varName] = AST::valueFromAST($varDefNode->defaultValue, /** @scrutinizer ignore-type */ $varType);
Loading history...
97
                    }
98
                }
99
            } else {
100 2
                $errors[] = new Error(
101 2
                    sprintf(
102 2
                        'Variable "$%s" expected value of type "%s" which cannot be used as an input type.',
103 2
                        $varName,
104 2
                        Printer::doPrint($varDefNode->type)
105
                    ),
106 54
                    [$varDefNode->type]
107
                );
108
            }
109
        }
110
111 235
        if (! empty($errors)) {
112 19
            return [$errors, null];
113
        }
114
115 217
        return [null, $coercedValues];
116
    }
117
118
    /**
119
     * Prepares an object map of argument values given a directive definition
120
     * and a AST node which may contain directives. Optionally also accepts a map
121
     * of variable values.
122
     *
123
     * If the directive does not exist on the node, returns undefined.
124
     *
125
     * @param FragmentSpreadNode|FieldNode|InlineFragmentNode|EnumValueDefinitionNode|FieldDefinitionNode $node
126
     * @param mixed[]|null                                                                                $variableValues
127
     *
128
     * @return mixed[]|null
129
     */
130 318
    public static function getDirectiveValues(Directive $directiveDef, $node, $variableValues = null)
131
    {
132 318
        if (isset($node->directives) && $node->directives instanceof NodeList) {
133 318
            $directiveNode = Utils::find(
134 318
                $node->directives,
135
                static function (DirectiveNode $directive) use ($directiveDef) {
136 9
                    return $directive->name->value === $directiveDef->name;
137 318
                }
138
            );
139
140 318
            if ($directiveNode !== null) {
141 9
                return self::getArgumentValues($directiveDef, $directiveNode, $variableValues);
142
            }
143
        }
144
145 315
        return null;
146
    }
147
148
    /**
149
     * Prepares an object map of argument values given a list of argument
150
     * definitions and list of argument AST nodes.
151
     *
152
     * @param FieldDefinition|Directive $def
153
     * @param FieldNode|DirectiveNode   $node
154
     * @param mixed[]                   $variableValues
155
     *
156
     * @return mixed[]
157
     *
158
     * @throws Error
159
     */
160 211
    public static function getArgumentValues($def, $node, $variableValues = null)
161
    {
162 211
        if (empty($def->args)) {
163 162
            return [];
164
        }
165
166 104
        $argumentNodes = $node->arguments;
167 104
        if (empty($argumentNodes)) {
168
            return [];
169
        }
170
171 104
        $argumentValueMap = [];
172 104
        foreach ($argumentNodes as $argumentNode) {
173 89
            $argumentValueMap[$argumentNode->name->value] = $argumentNode->value;
174
        }
175
176 104
        return static::getArgumentValuesForMap($def, $argumentValueMap, $variableValues, $node);
177
    }
178
179
    /**
180
     * @param FieldDefinition|Directive $fieldDefinition
181
     * @param ArgumentNode[]            $argumentValueMap
182
     * @param mixed[]                   $variableValues
183
     * @param Node|null                 $referenceNode
184
     *
185
     * @return mixed[]
186
     *
187
     * @throws Error
188
     */
189 104
    public static function getArgumentValuesForMap($fieldDefinition, $argumentValueMap, $variableValues = null, $referenceNode = null)
190
    {
191 104
        $argumentDefinitions = $fieldDefinition->args;
192 104
        $coercedValues       = [];
193
194 104
        foreach ($argumentDefinitions as $argumentDefinition) {
195 104
            $name              = $argumentDefinition->name;
196 104
            $argType           = $argumentDefinition->getType();
197 104
            $argumentValueNode = $argumentValueMap[$name] ?? null;
198
199 104
            if (! $argumentValueNode) {
200 41
                if ($argumentDefinition->defaultValueExists()) {
201 12
                    $coercedValues[$name] = $argumentDefinition->defaultValue;
202 31
                } elseif ($argType instanceof NonNull) {
203 1
                    throw new Error(
204 1
                        'Argument "' . $name . '" of required type ' .
205 1
                        '"' . Utils::printSafe($argType) . '" was not provided.',
206 41
                        $referenceNode
207
                    );
208
                }
209 89
            } elseif ($argumentValueNode instanceof VariableNode) {
210 32
                $variableName = $argumentValueNode->name->value;
211
212 32
                if ($variableValues && array_key_exists($variableName, $variableValues)) {
213
                    // Note: this does not check that this variable value is correct.
214
                    // This assumes that this query has been validated and the variable
215
                    // usage here is of the correct type.
216 27
                    $coercedValues[$name] = $variableValues[$variableName];
217 5
                } elseif ($argumentDefinition->defaultValueExists()) {
218 1
                    $coercedValues[$name] = $argumentDefinition->defaultValue;
219 4
                } elseif ($argType instanceof NonNull) {
220 1
                    throw new Error(
221 1
                        'Argument "' . $name . '" of required type "' . Utils::printSafe($argType) . '" was ' .
222 1
                        'provided the variable "$' . $variableName . '" which was not provided ' .
223 1
                        'a runtime value.',
224 32
                        [$argumentValueNode]
225
                    );
226
                }
227
            } else {
228 60
                $valueNode    = $argumentValueNode;
229 60
                $coercedValue = AST::valueFromAST($valueNode, $argType, $variableValues);
0 ignored issues
show
Bug introduced by
$valueNode of type GraphQL\Language\AST\ArgumentNode is incompatible with the type GraphQL\Language\AST\ValueNode|null expected by parameter $valueNode of GraphQL\Utils\AST::valueFromAST(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

229
                $coercedValue = AST::valueFromAST(/** @scrutinizer ignore-type */ $valueNode, $argType, $variableValues);
Loading history...
230 60
                if (Utils::isInvalid($coercedValue)) {
231
                    // Note: ValuesOfCorrectType validation should catch this before
232
                    // execution. This is a runtime check to ensure execution does not
233
                    // continue with an invalid argument value.
234 3
                    throw new Error(
235 3
                        'Argument "' . $name . '" has invalid value ' . Printer::doPrint($valueNode) . '.',
236 3
                        [$argumentValueNode]
237
                    );
238
                }
239 101
                $coercedValues[$name] = $coercedValue;
240
            }
241
        }
242
243 101
        return $coercedValues;
244
    }
245
246
    /**
247
     * @deprecated as of 8.0 (Moved to \GraphQL\Utils\AST::valueFromAST)
248
     *
249
     * @param ValueNode    $valueNode
250
     * @param mixed[]|null $variables
251
     *
252
     * @return mixed[]|stdClass|null
253
     */
254
    public static function valueFromAST($valueNode, InputType $type, ?array $variables = null)
255
    {
256
        return AST::valueFromAST($valueNode, $type, $variables);
257
    }
258
259
    /**
260
     * @deprecated as of 0.12 (Use coerceValue() directly for richer information)
261
     *
262
     * @param mixed[] $value
263
     *
264
     * @return string[]
265
     */
266
    public static function isValidPHPValue($value, InputType $type)
267
    {
268
        $errors = Value::coerceValue($value, $type)['errors'];
269
270
        return $errors
271
            ? array_map(
272
                static function (Throwable $error) {
273
                    return $error->getMessage();
274
                },
275
                $errors
276
            ) : [];
277
    }
278
}
279