Completed
Push — master ( fcf75e...aa8db4 )
by Rafael
03:53
created

NamespaceDefinitionExtension::configure()   D

Complexity

Conditions 21
Paths 344

Size

Total Lines 52
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 23.2596

Importance

Changes 0
Metric Value
dl 0
loc 52
ccs 24
cts 29
cp 0.8276
rs 4.3925
c 0
b 0
f 0
cc 21
eloc 29
nc 344
nop 3
crap 23.2596

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
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Definition\Extension;
12
13
use Doctrine\Common\Util\Inflector;
14
use Ynlo\GraphQLBundle\Definition\DefinitionInterface;
15
use Ynlo\GraphQLBundle\Definition\ExecutableDefinitionInterface;
16
use Ynlo\GraphQLBundle\Definition\FieldDefinition;
17
use Ynlo\GraphQLBundle\Definition\FieldsAwareDefinitionInterface;
18
use Ynlo\GraphQLBundle\Definition\MutationDefinition;
19
use Ynlo\GraphQLBundle\Definition\NodeAwareDefinitionInterface;
20
use Ynlo\GraphQLBundle\Definition\ObjectDefinition;
21
use Ynlo\GraphQLBundle\Definition\ObjectDefinitionInterface;
22
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
23
use Ynlo\GraphQLBundle\Model\NodeInterface;
24
use Ynlo\GraphQLBundle\Resolver\EmptyObjectResolver;
25
26
/**
27
 * This extension configure namespace in definitions
28
 * using definition node and bundle in the node
29
 */
30
class NamespaceDefinitionExtension extends AbstractDefinitionExtension
31
{
32
    /**
33
     * @var array
34
     */
35
    protected $globalConfig = [];
36
37
    /**
38
     * PaginationDefinitionExtension constructor.
39
     *
40
     * @param array $config
41
     */
42 1
    public function __construct($config = [])
43
    {
44 1
        $this->globalConfig = $config;
45 1
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 1
    public function configure(DefinitionInterface $definition, Endpoint $endpoint, array $config)
51
    {
52 1
        $node = null;
53 1
        $nodeClass = null;
54 1
        if (($this->globalConfig['nodes']['enabled'] ?? false) && $definition instanceof NodeAwareDefinitionInterface && $definition->getNode()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $definition->getNode() of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
55 1
            $node = $definition->getNode();
56
57 1
            if (class_exists($node)) {
58
                $nodeClass = $node;
59
            } else {
60 1
                $nodeClass = $endpoint->getClassForType($node);
61
            }
62
63 1
            if (!is_a($nodeClass, NodeInterface::class, true)) {
64
                return;
65
            }
66
67 1
            if (isset($this->globalConfig['nodes']['aliases'][$node])) {
68
                $node = $this->globalConfig['nodes']['aliases'][$node];
69
            }
70
71 1
            if ($node && in_array($node, $this->globalConfig['nodes']['ignore'])) {
72 1
                $node = null;
73
            }
74
        }
75
76 1
        $bundle = null;
77 1
        if ($this->globalConfig['bundles']['enabled'] ?? false) {
78 1
            if ($node && $nodeClass) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nodeClass of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
79 1
                if ($endpoint->hasType($node) && $nodeClass) {
80 1
                    preg_match_all('/\\\\(\w+Bundle)\\\\/', $nodeClass, $matches);
81 1
                    if ($matches) {
82 1
                        $bundle = current(array_reverse($matches[1]));
83
                    }
84
85 1
                    if (isset($this->globalConfig['bundles']['aliases'][$bundle])) {
86
                        $bundle = $this->globalConfig['bundles']['aliases'][$bundle];
87
                    }
88
89 1
                    if ($bundle && in_array($bundle, $this->globalConfig['bundles']['ignore'])) {
90 1
                        $bundle = null;
91
                    }
92
93 1
                    if ($bundle) {
94
                        $bundle = preg_replace('/Bundle$/', null, $bundle);
95
                    }
96
                }
97
            }
98
        }
99
100 1
        if ($bundle || $node) {
101 1
            $definition->setMeta('namespace', ['bundle' => $bundle, 'node' => $node]);
102
        }
103 1
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108 1
    public function configureEndpoint(Endpoint $endpoint)
109
    {
110 1
        $groupByBundle = $this->globalConfig['bundles']['enabled'] ?? false;
111 1
        $groupByNode = $this->globalConfig['bundles']['enabled'] ?? false;
112 1
        if ($groupByBundle || $groupByNode) {
113 1
            $endpoint->setQueries($this->namespaceDefinitions($endpoint->allQueries(), $endpoint));
114 1
            $endpoint->setMutations($this->namespaceDefinitions($endpoint->allMutations(), $endpoint));
115
        }
116 1
    }
117
118
    /**
119
     * @param array    $definitions
120
     * @param Endpoint $endpoint
121
     *
122
     * @return array
123
     */
124 1
    private function namespaceDefinitions($definitions, Endpoint $endpoint)
125
    {
126 1
        $namespacedDefinitions = [];
127
        /** @var DefinitionInterface $definition */
128 1
        foreach ($definitions as $definition) {
129 1
            if (!$definition->hasMeta('namespace') || !$definition->getMeta('namespace')) {
130 1
                $namespacedDefinitions[] = $definition;
131 1
                continue;
132
            }
133
134 1
            $root = null;
135 1
            $parent = null;
136 1
            $namespace = $definition->getMeta('namespace');
137 1
            if ($bundle = $namespace['bundle'] ?? null) {
138
                $bundleSuffix = $this->globalConfig['bundles']['suffix'] ?? 'Bundle';
139
                $name = lcfirst($bundle);
140
                $typeName = ucfirst($name).$bundleSuffix;
141
                $root = $this->createRootNamespace(get_class($definition), $name, $typeName, $endpoint);
142
                $parent = $endpoint->getType($root->getType());
143
            }
144
145 1
            if ($nodeName = $namespace['node'] ?? null) {
146 1
                $name = Inflector::pluralize(lcfirst($nodeName));
147
148 1
                $querySuffix = $this->globalConfig['nodes']['query_suffix'] ?? 'Query';
149 1
                $mutationSuffix = $this->globalConfig['nodes']['mutation_suffix'] ?? 'Mutation';
150
151 1
                $typeName = ucfirst($nodeName).(($definition instanceof MutationDefinition) ? $mutationSuffix : $querySuffix);
152 1
                if (!$root) {
153 1
                    $root = $this->createRootNamespace(get_class($definition), $name, $typeName, $endpoint);
154 1
                    $parent = $endpoint->getType($root->getType());
155
                } elseif ($parent) {
156
                    $parent = $this->createChildNamespace($parent, $name, $typeName, $endpoint);
157
                }
158
159
                //remove node suffix on namespaced definitions
160 1
                $definition->setName(preg_replace(sprintf("/(\w+)%s$/", $nodeName), '$1', $definition->getName()));
161 1
                $definition->setName(preg_replace(sprintf("/(\w+)%s$/", Inflector::pluralize($nodeName)), '$1', $definition->getName()));
162
163
            }
164
165 1
            if ($root && $parent) {
166 1
                $this->addDefinitionToNamespace($parent, $definition);
167 1
                $namespacedDefinitions[] = $root;
168
            }
169
        }
170
171 1
        return $namespacedDefinitions;
172
    }
173
174
    /**
175
     * @param FieldsAwareDefinitionInterface $fieldsAwareDefinition
176
     * @param ExecutableDefinitionInterface  $definition
177
     */
178 1
    private function addDefinitionToNamespace(FieldsAwareDefinitionInterface $fieldsAwareDefinition, ExecutableDefinitionInterface $definition)
179
    {
180 1
        $field = new FieldDefinition();
181 1
        $field->setName($definition->getName());
182 1
        $field->setType($definition->getType());
183 1
        $field->setResolver($definition->getResolver());
184 1
        $field->setArguments($definition->getArguments());
185 1
        $field->setList($definition->isList());
186 1
        $field->setMetas($definition->getMetas());
187 1
        $field->setNode($definition->getNode());
188 1
        $fieldsAwareDefinition->addField($field);
189 1
    }
190
191
    /**
192
     * @param ObjectDefinitionInterface $parent   parent definition to add a child field
193
     * @param string                    $name     name of the field
194
     * @param string                    $typeName name of the type to create
195
     * @param Endpoint                  $endpoint Endpoint instance to extract definitions
196
     *
197
     * @return ObjectDefinition
198
     */
199 View Code Duplication
    private function createChildNamespace(ObjectDefinitionInterface $parent, $name, $typeName, Endpoint $endpoint): ObjectDefinition
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...
200
    {
201
        $child = new FieldDefinition();
202
        $child->setName($name);
203
        $child->setResolver(EmptyObjectResolver::class);
204
205
        $type = new ObjectDefinition();
206
        $type->setName($typeName);
207
        if ($endpoint->hasType($type->getName())) {
208
            $type = $endpoint->getType($type->getName());
209
        } else {
210
            $endpoint->add($type);
211
        }
212
213
        $child->setType($type->getName());
214
        $parent->addField($child);
215
216
        return $type;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $type could return the type Ynlo\GraphQLBundle\Definition\DefinitionInterface which includes types incompatible with the type-hinted return Ynlo\GraphQLBundle\Definition\ObjectDefinition. Consider adding an additional type-check to rule them out.
Loading history...
217
    }
218
219
    /**
220
     * @param string   $rootType Class of the root type to create QueryDefinition or MutationDefinition
221
     * @param string   $name     name of the root field
222
     * @param string   $typeName name for the root type
223
     * @param Endpoint $endpoint Endpoint interface to extract existent definitions
224
     *
225
     * @return ExecutableDefinitionInterface
226
     */
227 1 View Code Duplication
    private function createRootNamespace($rootType, $name, $typeName, Endpoint $endpoint): ExecutableDefinitionInterface
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...
228
    {
229
        /** @var ExecutableDefinitionInterface $rootDefinition */
230 1
        $rootDefinition = new $rootType();
231 1
        $rootDefinition->setName($name);
232 1
        $rootDefinition->setResolver(EmptyObjectResolver::class);
233
234 1
        $type = new ObjectDefinition();
235 1
        $type->setName($typeName);
236 1
        if ($endpoint->hasType($type->getName())) {
237 1
            $type = $endpoint->getType($type->getName());
238
        } else {
239 1
            $endpoint->add($type);
240
        }
241
242 1
        $rootDefinition->setType($type->getName());
243
244 1
        return $rootDefinition;
245
    }
246
}
247