Completed
Pull Request — master (#74)
by Quang
02:06
created

ValuesResolver   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 18
dl 0
loc 163
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B coerceValueForVariableNode() 0 29 5
A coerceValueForASTNode() 0 21 2
A getDirectiveValues() 0 15 3
C coerceArgumentValues() 0 49 8
1
<?php
2
3
namespace Digia\GraphQL\Execution;
4
5
use Digia\GraphQL\Error\ExecutionException;
6
use Digia\GraphQL\Error\InvalidTypeException;
7
use Digia\GraphQL\Error\InvariantException;
8
use Digia\GraphQL\Language\Node\ArgumentNode;
9
use Digia\GraphQL\Language\Node\DirectivesTrait;
10
use Digia\GraphQL\Language\Node\FieldNode;
11
use Digia\GraphQL\Language\Node\NamedTypeNode;
12
use Digia\GraphQL\Language\Node\NodeInterface;
13
use Digia\GraphQL\Language\Node\VariableNode;
14
use Digia\GraphQL\Type\Definition\DirectiveInterface;
15
use Digia\GraphQL\Type\Definition\Field;
16
use Digia\GraphQL\Type\Definition\NonNullType;
17
use Digia\GraphQL\Type\Definition\TypeInterface;
18
use function Digia\GraphQL\Language\valueFromAST;
19
use function Digia\GraphQL\Util\find;
20
use function Digia\GraphQL\Util\keyMap;
21
22
/**
23
 * Class ValuesResolver
24
 * @package Digia\GraphQL\Execution
25
 */
26
class ValuesResolver
27
{
28
    /**
29
     * @see http://facebook.github.io/graphql/October2016/#CoerceArgumentValues()
30
     *
31
     * @param Field|DirectiveInterface $objectType
32
     * @param FieldNode                $field
33
     * @param array                    $variableValues
34
     * @return array
35
     * @throws ExecutionException
36
     * @throws InvalidTypeException
37
     * @throws InvariantException
38
     */
39
    public function coerceArgumentValues($objectType, $field, array $variableValues = []): array
40
    {
41
        $coercedValues       = [];
42
        $argumentDefinitions = $objectType->getArguments();
43
        $argumentNodes       = $field->getArguments();
44
45
        if (empty($argumentDefinitions) || empty($argumentNodes)) {
46
            return $coercedValues;
47
        }
48
49
        $argumentNodeMap = keyMap($argumentNodes, function (ArgumentNode $value) {
50
            return $value->getNameValue();
51
        });
52
53
        foreach ($argumentDefinitions as $argumentDefinition) {
54
            $argumentName = $argumentDefinition->getName();
55
            $argumentType = $argumentDefinition->getType();
56
            /** @var ArgumentNode $argumentNode */
57
            $argumentNode = $argumentNodeMap[$argumentName];
58
            $defaultValue = $argumentDefinition->getDefaultValue();
59
60
            if (null === $argumentNode) {
61
                if (null === $defaultValue) {
62
                    $coercedValues[$argumentName] = $defaultValue;
63
                } elseif (!$argumentType instanceof NonNullType) {
64
                    throw new ExecutionException(
65
                        sprintf('Argument "%s" of required type "%s" was not provided.', $argumentName, $argumentType),
66
                        [$field]
67
                    );
68
                }
69
            } elseif ($argumentNode instanceof VariableNode) {
70
                $coercedValues[$argumentName] = $this->coerceValueForVariableNode(
71
                    $argumentNode,
72
                    $argumentType,
73
                    $argumentName,
74
                    $variableValues,
75
                    $defaultValue
76
                );
77
            } else {
78
                $coercedValues[$argumentName] = $this->coerceValueForASTNode(
79
                    $argumentNode,
80
                    $argumentType,
81
                    $argumentName,
82
                    $variableValues
83
                );
84
            }
85
        }
86
87
        return $coercedValues;
88
    }
89
90
    /**
91
     * @param NodeInterface $argumentNode
92
     * @param TypeInterface $argumentType
93
     * @param string        $argumentName
94
     * @param               $variableValues
95
     * @return mixed|null
96
     * @throws ExecutionException
97
     * @throws InvalidTypeException
98
     * @throws InvariantException
99
     */
100
    protected function coerceValueForASTNode(
101
        NodeInterface $argumentNode,
102
        TypeInterface $argumentType,
103
        string $argumentName,
104
        $variableValues
105
    ) {
106
        $valueNode = $argumentNode->getValue();
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on Digia\GraphQL\Language\Node\NodeInterface. It seems like you code against a sub-type of Digia\GraphQL\Language\Node\NodeInterface such as Digia\GraphQL\Language\Node\NameNode or Digia\GraphQL\Language\Node\ArgumentNode or Digia\GraphQL\Language\Node\ObjectFieldNode or Digia\GraphQL\Language\Node\BooleanValueNode or Digia\GraphQL\Language\Node\EnumValueNode or Digia\GraphQL\Language\Node\StringValueNode or Digia\GraphQL\Language\Node\FloatValueNode or Digia\GraphQL\Language\Node\IntValueNode. ( Ignorable by Annotation )

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

106
        /** @scrutinizer ignore-call */ 
107
        $valueNode = $argumentNode->getValue();
Loading history...
107
108
        $coercedValue = valueFromAST($valueNode, $argumentType, $variableValues);
109
110
        if (null === $coercedValue) {
111
            // Note: ValuesOfCorrectType validation should catch this before
112
            // execution. This is a runtime check to ensure execution does not
113
            // continue with an invalid argument value.
114
            throw new ExecutionException(
115
                sprintf('Argument "%s" has invalid value %s.', $argumentName, $valueNode),
116
                [$argumentNode->getValue()]
117
            );
118
        }
119
120
        return $coercedValue;
121
    }
122
123
    /**
124
     * @param VariableNode  $variableNode
125
     * @param TypeInterface $argumentType
126
     * @param string        $argumentName
127
     * @param array         $variableValues
128
     * @param               $defaultValue
129
     * @return mixed
130
     * @throws ExecutionException
131
     */
132
    protected function coerceValueForVariableNode(
133
        VariableNode $variableNode,
134
        TypeInterface $argumentType,
135
        string $argumentName,
136
        array $variableValues,
137
        $defaultValue
138
    ) {
139
        $variableName = $variableNode->getNameValue();
140
141
        if (!empty($variableValues) && isset($variableValues[$variableName])) {
142
            // Note: this does not check that this variable value is correct.
143
            // This assumes that this query has been validated and the variable
144
            // usage here is of the correct type.
145
            return $variableValues[$variableName];
146
        }
147
148
        if (null !== $defaultValue) {
149
            return $defaultValue;
150
        }
151
152
        if ($argumentType instanceof NonNullType) {
153
            throw new ExecutionException(
154
                sprintf(
155
                    'Argument "%s" of required type "%s" was provided the variable "%s" which was not provided a runtime value.',
156
                    $argumentName,
157
                    $argumentType,
158
                    $variableName
159
                ),
160
                [$variableNode->getValue()]
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on Digia\GraphQL\Language\Node\VariableNode. ( Ignorable by Annotation )

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

160
                [$variableNode->/** @scrutinizer ignore-call */ getValue()]

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
            );
162
        }
163
    }
164
165
    /**
166
     * @param DirectiveInterface            $directive
167
     * @param NodeInterface|DirectivesTrait $node
168
     * @param array                         $variableValues
169
     * @return array|null
170
     * @throws ExecutionException
171
     * @throws InvalidTypeException
172
     * @throws InvariantException
173
     */
174
    public function getDirectiveValues(
175
        DirectiveInterface $directive,
176
        NodeInterface $node, array
177
        $variableValues = []
178
    ): ?array {
179
        $directiveNode = $node->hasDirectives()
0 ignored issues
show
Bug introduced by
The method hasDirectives() does not exist on Digia\GraphQL\Language\Node\NodeInterface. It seems like you code against a sub-type of Digia\GraphQL\Language\Node\NodeInterface such as Digia\GraphQL\Language\Node\FragmentSpreadNode or Digia\GraphQL\Language\Node\InlineFragmentNode or Digia\GraphQL\Language\Node\FieldNode or Digia\GraphQL\Language\Node\EnumTypeDefinitionNode or Digia\GraphQL\Language\N...EnumValueDefinitionNode or Digia\GraphQL\Language\N...nputValueDefinitionNode or Digia\GraphQL\Language\Node\FieldDefinitionNode or Digia\GraphQL\Language\Node\FragmentDefinitionNode or Digia\GraphQL\Language\N...OperationDefinitionNode or Digia\GraphQL\Language\Node\SchemaDefinitionNode or Digia\GraphQL\Language\N...bjectTypeDefinitionNode or Digia\GraphQL\Language\N...calarTypeDefinitionNode or Digia\GraphQL\Language\N...bjectTypeDefinitionNode or Digia\GraphQL\Language\N...rfaceTypeDefinitionNode or Digia\GraphQL\Language\N...UnionTypeDefinitionNode or Digia\GraphQL\Language\N...ObjectTypeExtensionNode or Digia\GraphQL\Language\N...ScalarTypeExtensionNode or Digia\GraphQL\Language\Node\EnumTypeExtensionNode or Digia\GraphQL\Language\N...ObjectTypeExtensionNode or Digia\GraphQL\Language\N...erfaceTypeExtensionNode or Digia\GraphQL\Language\Node\UnionTypeExtensionNode. ( Ignorable by Annotation )

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

179
        $directiveNode = $node->/** @scrutinizer ignore-call */ hasDirectives()
Loading history...
180
            ? find($node->getDirectives(), function (NamedTypeNode $value) use ($directive) {
0 ignored issues
show
Bug introduced by
The method getDirectives() does not exist on Digia\GraphQL\Language\Node\NodeInterface. It seems like you code against a sub-type of Digia\GraphQL\Language\Node\NodeInterface such as Digia\GraphQL\Language\Node\FragmentSpreadNode or Digia\GraphQL\Language\Node\InlineFragmentNode or Digia\GraphQL\Language\Node\FieldNode or Digia\GraphQL\Language\Node\EnumTypeDefinitionNode or Digia\GraphQL\Language\N...EnumValueDefinitionNode or Digia\GraphQL\Language\N...nputValueDefinitionNode or Digia\GraphQL\Language\Node\FieldDefinitionNode or Digia\GraphQL\Language\Node\FragmentDefinitionNode or Digia\GraphQL\Language\N...OperationDefinitionNode or Digia\GraphQL\Language\Node\SchemaDefinitionNode or Digia\GraphQL\Language\N...bjectTypeDefinitionNode or Digia\GraphQL\Language\N...calarTypeDefinitionNode or Digia\GraphQL\Language\N...bjectTypeDefinitionNode or Digia\GraphQL\Language\N...rfaceTypeDefinitionNode or Digia\GraphQL\Language\N...UnionTypeDefinitionNode or Digia\GraphQL\Language\N...ObjectTypeExtensionNode or Digia\GraphQL\Language\N...ScalarTypeExtensionNode or Digia\GraphQL\Language\Node\EnumTypeExtensionNode or Digia\GraphQL\Language\N...ObjectTypeExtensionNode or Digia\GraphQL\Language\N...erfaceTypeExtensionNode or Digia\GraphQL\Language\Node\UnionTypeExtensionNode. ( Ignorable by Annotation )

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

180
            ? find($node->/** @scrutinizer ignore-call */ getDirectives(), function (NamedTypeNode $value) use ($directive) {
Loading history...
181
                return $value->getNameValue() === $directive->getName();
182
            }) : null;
183
184
        if (null !== $directiveNode) {
185
            return $this->coerceArgumentValues($directive, $directiveNode, $variableValues);
186
        }
187
188
        return null;
189
    }
190
}