Failed Conditions
Pull Request — master (#360)
by
unknown
04:02
created

KnownDirectives::getDirectiveLocationForASTPath()   D

Complexity

Conditions 27
Paths 27

Size

Total Lines 53
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 45
CRAP Score 27.729

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 53
ccs 45
cts 50
cp 0.9
rs 4.1666
c 0
b 0
f 0
cc 27
nc 27
nop 1
crap 27.729

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\Validator\Rules;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Language\AST\DirectiveDefinitionNode;
9
use GraphQL\Language\AST\DirectiveNode;
10
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
11
use GraphQL\Language\AST\Node;
12
use GraphQL\Language\AST\NodeKind;
13
use GraphQL\Language\AST\NodeList;
14
use GraphQL\Language\DirectiveLocation;
15
use GraphQL\Validator\ValidationContext;
16
use function array_map;
17
use function count;
18
use function in_array;
19
use function sprintf;
20
21
class KnownDirectives extends ValidationRule
22
{
23 113
    public function getVisitor(ValidationContext $context)
24
    {
25 113
        $locationsMap      = [];
26 113
        $schema            = $context->getSchema();
27 113
        $definedDirectives = $schema->getDirectives();
28
29 113
        foreach ($definedDirectives as $directive) {
30 113
            $locationsMap[$directive->name] = $directive->locations;
31
        }
32
33 113
        $astDefinition = $context->getDocument()->definitions;
34
35 113
        foreach ($astDefinition as $def) {
36 113
            if (! ($def instanceof DirectiveDefinitionNode)) {
37 113
                continue;
38
            }
39
40
            $locationsMap[$def->name->value] = array_map(function ($name) {
41
                return $name->value;
42
            }, $def->locations);
43
        }
44
        return [
45
            NodeKind::DIRECTIVE => function (DirectiveNode $node, $key, $parent, $path, $ancestors) use ($context, $locationsMap) {
46 7
                $name      = $node->name->value;
47 7
                $locations = $locationsMap[$name] ?? null;
48
49 7
                if (! $locations) {
50 2
                    $context->reportError(new Error(
51 2
                        self::unknownDirectiveMessage($name),
52 2
                        [$node]
53
                    ));
54 2
                    return;
55
                }
56
57 5
                $candidateLocation = $this->getDirectiveLocationForASTPath($ancestors);
58
59 5
                if (! $candidateLocation || in_array($candidateLocation, $locations)) {
60 3
                    return;
61
                }
62 2
                $context->reportError(
63 2
                    new Error(
64 2
                        self::misplacedDirectiveMessage($name, $candidateLocation),
65 2
                        [$node]
66
                    )
67
                );
68 113
            },
69
        ];
70
    }
71
72 2
    public static function unknownDirectiveMessage($directiveName)
73
    {
74 2
        return sprintf('Unknown directive "%s".', $directiveName);
75
    }
76
77
    /**
78
     * @param Node[]|NodeList[] $ancestors The type is actually (Node|NodeList)[] but this PSR-5 syntax is so far not supported by most of the tools
79
     *
80
     * @return string
81
     */
82 5
    private function getDirectiveLocationForASTPath(array $ancestors)
83
    {
84 5
        $appliedTo = $ancestors[count($ancestors) - 1];
85 5
        switch ($appliedTo->kind) {
86 5
            case NodeKind::OPERATION_DEFINITION:
87 2
                switch ($appliedTo->operation) {
88 2
                    case 'query':
89 2
                        return DirectiveLocation::QUERY;
90 2
                    case 'mutation':
91 2
                        return DirectiveLocation::MUTATION;
92
                    case 'subscription':
93
                        return DirectiveLocation::SUBSCRIPTION;
94
                }
95
                break;
96 5
            case NodeKind::FIELD:
97 3
                return DirectiveLocation::FIELD;
98 4
            case NodeKind::FRAGMENT_SPREAD:
99 2
                return DirectiveLocation::FRAGMENT_SPREAD;
100 2
            case NodeKind::INLINE_FRAGMENT:
101
                return DirectiveLocation::INLINE_FRAGMENT;
102 2
            case NodeKind::FRAGMENT_DEFINITION:
103
                return DirectiveLocation::FRAGMENT_DEFINITION;
104 2
            case NodeKind::SCHEMA_DEFINITION:
105 2
            case NodeKind::SCHEMA_EXTENSION:
106 2
                return DirectiveLocation::SCHEMA;
107 2
            case NodeKind::SCALAR_TYPE_DEFINITION:
108 2
            case NodeKind::SCALAR_TYPE_EXTENSION:
109 2
                return DirectiveLocation::SCALAR;
110 2
            case NodeKind::OBJECT_TYPE_DEFINITION:
111 2
            case NodeKind::OBJECT_TYPE_EXTENSION:
112 2
                return DirectiveLocation::OBJECT;
113 2
            case NodeKind::FIELD_DEFINITION:
114 2
                return DirectiveLocation::FIELD_DEFINITION;
115 2
            case NodeKind::INTERFACE_TYPE_DEFINITION:
116 2
            case NodeKind::INTERFACE_TYPE_EXTENSION:
117 2
                return DirectiveLocation::IFACE;
118 2
            case NodeKind::UNION_TYPE_DEFINITION:
119 2
            case NodeKind::UNION_TYPE_EXTENSION:
120 2
                return DirectiveLocation::UNION;
121 2
            case NodeKind::ENUM_TYPE_DEFINITION:
122 2
            case NodeKind::ENUM_TYPE_EXTENSION:
123 2
                return DirectiveLocation::ENUM;
124 2
            case NodeKind::ENUM_VALUE_DEFINITION:
125 2
                return DirectiveLocation::ENUM_VALUE;
126 2
            case NodeKind::INPUT_OBJECT_TYPE_DEFINITION:
127 2
            case NodeKind::INPUT_OBJECT_TYPE_EXTENSION:
128 2
                return DirectiveLocation::INPUT_OBJECT;
129 2
            case NodeKind::INPUT_VALUE_DEFINITION:
130 2
                $parentNode = $ancestors[count($ancestors) - 3];
131
132 2
                return $parentNode instanceof InputObjectTypeDefinitionNode
133 2
                    ? DirectiveLocation::INPUT_FIELD_DEFINITION
134 2
                    : DirectiveLocation::ARGUMENT_DEFINITION;
135
        }
136
    }
137
138 2
    public static function misplacedDirectiveMessage($directiveName, $location)
139
    {
140 2
        return sprintf('Directive "%s" may not be used on "%s".', $directiveName, $location);
141
    }
142
}
143