Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Pull Request — master (#277)
by Jérémiah
22:38 queued 19:05
created

GraphQLParser::typeDefinitionToConfig()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 44
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 44
ccs 27
cts 27
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 32
nc 7
nop 1
crap 7
1
<?php
2
3
namespace Overblog\GraphQLBundle\Config\Parser;
4
5
use GraphQL\Language\AST\FieldDefinitionNode;
6
use GraphQL\Language\AST\InputValueDefinitionNode;
7
use GraphQL\Language\AST\Node;
8
use GraphQL\Language\AST\NodeKind;
9
use GraphQL\Language\AST\TypeNode;
10
use GraphQL\Language\AST\ValueNode;
11
use GraphQL\Language\Parser;
12
use Symfony\Component\Config\Resource\FileResource;
13
use Symfony\Component\DependencyInjection\ContainerBuilder;
14
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
15
16
class GraphQLParser implements ParserInterface
17
{
18
    /** @var self */
19
    private static $parser;
20
21
    const DEFINITION_TYPE_MAPPING = [
22
        NodeKind::OBJECT_TYPE_DEFINITION => 'object',
23
        NodeKind::INTERFACE_TYPE_DEFINITION => 'interface',
24
        NodeKind::ENUM_TYPE_DEFINITION => 'enum',
25
        NodeKind::UNION_TYPE_DEFINITION => 'union',
26
        NodeKind::INPUT_OBJECT_TYPE_DEFINITION => 'input-object',
27
        NodeKind::SCALAR_TYPE_DEFINITION => 'custom-scalar',
28
    ];
29
30
    /**
31
     * {@inheritdoc}
32
     */
33 5
    public static function parse(\SplFileInfo $file, ContainerBuilder $container)
34
    {
35 5
        $container->addResource(new FileResource($file->getRealPath()));
36 5
        $content = trim(file_get_contents($file->getPathname()));
37 5
        $typesConfig = [];
38
39
        // allow empty files
40 5
        if (empty($content)) {
41 1
            return [];
42
        }
43 4
        if (!self::$parser) {
44 1
            self::$parser = new static();
45
        }
46
        try {
47 4
            $ast = Parser::parse($content);
48 1
        } catch (\Exception $e) {
49 1
            throw new InvalidArgumentException(sprintf('An error occurred while parsing the file "%s".', $file), $e->getCode(), $e);
50
        }
51
52
        /** @var Node $typeDef */
53 3
        foreach ($ast->definitions as $typeDef) {
54 3
            $typeConfig = self::$parser->typeDefinitionToConfig($typeDef);
0 ignored issues
show
Documentation introduced by
$typeDef is of type object<GraphQL\Language\AST\DefinitionNode>, but the function expects a object<GraphQL\Language\AST\Node>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
55 2
            $typesConfig[$typeDef->name->value] = $typeConfig;
0 ignored issues
show
Bug introduced by
Accessing name on the interface GraphQL\Language\AST\DefinitionNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
56
        }
57
58 2
        return $typesConfig;
59
    }
60
61 1
    public static function mustOverrideConfig()
62
    {
63 1
        throw new \RuntimeException('Config entry must be override with ResolverMap to be used.');
64
    }
65
66 3
    protected function typeDefinitionToConfig(Node $typeDef)
67
    {
68 3
        switch ($typeDef->kind) {
69 3
            case NodeKind::OBJECT_TYPE_DEFINITION:
70 3
            case NodeKind::INTERFACE_TYPE_DEFINITION:
71 3
            case NodeKind::INPUT_OBJECT_TYPE_DEFINITION:
72 3
            case NodeKind::ENUM_TYPE_DEFINITION:
73 3
            case NodeKind::UNION_TYPE_DEFINITION:
74 2
                $config = [];
75 2
                $this->addTypeFields($typeDef, $config);
76 2
                $this->addDescription($typeDef, $config);
77 2
                $this->addInterfaces($typeDef, $config);
78 2
                $this->addTypes($typeDef, $config);
79 2
                $this->addValues($typeDef, $config);
80
81
                return [
82 2
                    'type' => self::DEFINITION_TYPE_MAPPING[$typeDef->kind],
83 2
                    'config' => $config,
84
                ];
85
86 3
            case NodeKind::SCALAR_TYPE_DEFINITION:
87 2
                $mustOverride = [__CLASS__, 'mustOverrideConfig'];
88
                $config = [
89 2
                    'serialize' => $mustOverride,
90 2
                    'parseValue' => $mustOverride,
91 2
                    'parseLiteral' => $mustOverride,
92
                ];
93 2
                $this->addDescription($typeDef, $config);
94
95
                return [
96 2
                    'type' => self::DEFINITION_TYPE_MAPPING[$typeDef->kind],
97 2
                    'config' => $config,
98
                ];
99
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
100
101
            default:
102 1
                throw new InvalidArgumentException(
103 1
                    sprintf(
104 1
                        '%s definition is not supported right now.',
105 1
                        preg_replace('@Definition$@', '', $typeDef->kind)
106
                    )
107
                );
108
        }
109
    }
110
111
    /**
112
     * @param Node  $typeDef
113
     * @param array $config
114
     */
115 2
    private function addTypeFields(Node $typeDef, array &$config)
116
    {
117 2
        if (!empty($typeDef->fields)) {
118 2
            $fields = [];
119
            /** @var FieldDefinitionNode|InputValueDefinitionNode $fieldDef */
120 2
            foreach ($typeDef->fields as $fieldDef) {
0 ignored issues
show
Bug introduced by
The property fields does not seem to exist in GraphQL\Language\AST\Node.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
121 2
                $fieldName = $fieldDef->name->value;
122 2
                $fields[$fieldName] = [];
123 2
                $this->addType($fieldDef, $fields[$fieldName]);
124 2
                $this->addDescription($fieldDef, $fields[$fieldName]);
125 2
                $this->addDefaultValue($fieldDef, $fields[$fieldName]);
126 2
                $this->addFieldArguments($fieldDef, $fields[$fieldName]);
127
            }
128 2
            $config['fields'] = $fields;
129
        }
130 2
    }
131
132
    /**
133
     * @param Node  $fieldDef
134
     * @param array $fieldConf
135
     */
136 2
    private function addFieldArguments(Node $fieldDef, array &$fieldConf)
137
    {
138 2
        if (!empty($fieldDef->arguments)) {
139 2
            $arguments = [];
140
            /** @var InputValueDefinitionNode $definition */
141 2
            foreach ($fieldDef->arguments as $definition) {
0 ignored issues
show
Bug introduced by
The property arguments does not seem to exist in GraphQL\Language\AST\Node.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
142 2
                $name = $definition->name->value;
143 2
                $arguments[$name] = [];
144 2
                $this->addType($definition, $arguments[$name]);
145 2
                $this->addDescription($definition, $arguments[$name]);
146 2
                $this->addDefaultValue($definition, $arguments[$name]);
147
            }
148 2
            $fieldConf['args'] = $arguments;
149
        }
150 2
    }
151
152
    /**
153
     * @param Node  $typeDef
154
     * @param array $config
155
     */
156 2 View Code Duplication
    private function addInterfaces(Node $typeDef, array &$config)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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.

Loading history...
157
    {
158 2
        if (!empty($typeDef->interfaces)) {
159 2
            $interfaces = [];
160 2
            foreach ($typeDef->interfaces as $interface) {
0 ignored issues
show
Bug introduced by
The property interfaces does not seem to exist in GraphQL\Language\AST\Node.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
161 2
                $interfaces[] = $this->astTypeNodeToString($interface);
162
            }
163 2
            $config['interfaces'] = $interfaces;
164
        }
165 2
    }
166
167
    /**
168
     * @param Node  $typeDef
169
     * @param array $config
170
     */
171 2 View Code Duplication
    private function addTypes(Node $typeDef, array &$config)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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.

Loading history...
172
    {
173 2
        if (!empty($typeDef->types)) {
174 1
            $types = [];
175 1
            foreach ($typeDef->types as $type) {
0 ignored issues
show
Bug introduced by
The property types does not seem to exist in GraphQL\Language\AST\Node.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
176 1
                $types[] = $this->astTypeNodeToString($type);
177
            }
178 1
            $config['types'] = $types;
179
        }
180 2
    }
181
182
    /**
183
     * @param Node  $typeDef
184
     * @param array $config
185
     */
186 2
    private function addValues(Node $typeDef, array &$config)
187
    {
188 2
        if (!empty($typeDef->values)) {
189 2
            $values = [];
190 2
            foreach ($typeDef->values as $value) {
0 ignored issues
show
Bug introduced by
The property values does not seem to exist in GraphQL\Language\AST\Node.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
191 2
                $values[$value->name->value] = ['value' => $value->name->value];
192 2
                $this->addDescription($value, $values[$value->name->value]);
193
            }
194 2
            $config['values'] = $values;
195
        }
196 2
    }
197
198
    /**
199
     * @param Node  $definition
200
     * @param array $config
201
     */
202 2
    private function addType(Node $definition, array &$config)
203
    {
204 2
        if (!empty($definition->type)) {
205 2
            $config['type'] = $this->astTypeNodeToString($definition->type);
0 ignored issues
show
Bug introduced by
The property type does not seem to exist in GraphQL\Language\AST\Node.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
206
        }
207 2
    }
208
209
    /**
210
     * @param Node  $definition
211
     * @param array $config
212
     */
213 2
    private function addDescription(Node $definition, array &$config)
214
    {
215
        if (
216 2
            !empty($definition->description)
0 ignored issues
show
Bug introduced by
The property description does not seem to exist in GraphQL\Language\AST\Node.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
217 2
            && $description = $this->cleanAstDescription($definition->description)
218
        ) {
219 1
            $config['description'] = $description;
220
        }
221 2
    }
222
223
    /**
224
     * @param InputValueDefinitionNode|FieldDefinitionNode $definition
225
     * @param array                                        $config
226
     */
227 2
    private function addDefaultValue($definition, array &$config)
228
    {
229 2
        if (!empty($definition->defaultValue)) {
230 1
            $config['defaultValue'] = $this->astValueNodeToConfig($definition->defaultValue);
231
        }
232 2
    }
233
234 2
    private function astTypeNodeToString(TypeNode $typeNode)
235
    {
236 2
        $type = '';
237 2
        switch ($typeNode->kind) {
0 ignored issues
show
Bug introduced by
Accessing kind on the interface GraphQL\Language\AST\TypeNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
238 2
            case NodeKind::NAMED_TYPE:
239 2
                $type = $typeNode->name->value;
0 ignored issues
show
Bug introduced by
Accessing name on the interface GraphQL\Language\AST\TypeNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
240 2
                break;
241
242 2
            case NodeKind::NON_NULL_TYPE:
243 2
                $type = $this->astTypeNodeToString($typeNode->type).'!';
0 ignored issues
show
Bug introduced by
Accessing type on the interface GraphQL\Language\AST\TypeNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
244 2
                break;
245
246 2
            case NodeKind::LIST_TYPE:
247 2
                $type = '['.$this->astTypeNodeToString($typeNode->type).']';
0 ignored issues
show
Bug introduced by
Accessing type on the interface GraphQL\Language\AST\TypeNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
248 2
                break;
249
        }
250
251 2
        return $type;
252
    }
253
254 1
    private function astValueNodeToConfig(ValueNode $valueNode)
255
    {
256 1
        $config = null;
257 1
        switch ($valueNode->kind) {
0 ignored issues
show
Bug introduced by
Accessing kind on the interface GraphQL\Language\AST\ValueNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
258 1
            case NodeKind::INT:
259 1
            case NodeKind::FLOAT:
260 1
            case NodeKind::STRING:
261 1
            case NodeKind::BOOLEAN:
262 1
            case NodeKind::ENUM:
263 1
                $config = $valueNode->value;
0 ignored issues
show
Bug introduced by
Accessing value on the interface GraphQL\Language\AST\ValueNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
264 1
                break;
265
266 1
            case NodeKind::LST:
267 1
                $config = [];
268 1
                foreach ($valueNode->values as $node) {
0 ignored issues
show
Bug introduced by
Accessing values on the interface GraphQL\Language\AST\ValueNode suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
269 1
                    $config[] = $this->astValueNodeToConfig($node);
270
                }
271 1
                break;
272
273 1
            case NodeKind::NULL:
274 1
                $config = null;
275 1
                break;
276
        }
277
278 1
        return $config;
279
    }
280
281 1
    private function cleanAstDescription($description)
282
    {
283 1
        $description = trim($description);
284
285 1
        return empty($description) ? null : $description;
286
    }
287
}
288