Completed
Push — master ( 3ae95d...2e8c19 )
by Rafael
11:16
created

namespaceDefinitions()   C

Complexity

Conditions 12
Paths 54

Size

Total Lines 52
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 14.0509

Importance

Changes 0
Metric Value
dl 0
loc 52
ccs 25
cts 33
cp 0.7576
rs 5.9842
c 0
b 0
f 0
cc 12
eloc 32
nc 54
nop 2
crap 14.0509

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 21
    public function __construct($config = [])
43
    {
44 21
        $this->globalConfig = $config;
45 21
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 21
    public function configure(DefinitionInterface $definition, Endpoint $endpoint, array $config)
51
    {
52 21
        $node = null;
53 21
        $nodeClass = null;
54 21
        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 21
            $node = $definition->getNode();
56
57 21
            if (class_exists($node)) {
58
                $nodeClass = $node;
59
            } else {
60 21
                $nodeClass = $endpoint->getClassForType($node);
61
            }
62
63 21
            if (!is_a($nodeClass, NodeInterface::class, true)) {
64
                return;
65
            }
66
67 21
            if (isset($this->globalConfig['nodes']['aliases'][$node])) {
68
                $node = $this->globalConfig['nodes']['aliases'][$node];
69
            }
70
71 21
            if ($node && in_array($node, $this->globalConfig['nodes']['ignore'])) {
72 21
                $node = null;
73
            }
74
        }
75
76 21
        $bundle = null;
77 21
        if ($this->globalConfig['bundles']['enabled'] ?? false) {
78 21
            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 21
                if ($endpoint->hasType($node) && $nodeClass) {
80 21
                    preg_match_all('/\\\\?(\w+Bundle)\\\\/', $nodeClass, $matches);
81 21
                    if ($matches) {
82 21
                        $bundle = current(array_reverse($matches[1]));
83
                    }
84
85 21
                    if (isset($this->globalConfig['bundles']['aliases'][$bundle])) {
86
                        $bundle = $this->globalConfig['bundles']['aliases'][$bundle];
87
                    }
88
89 21
                    if ($bundle && in_array($bundle, $this->globalConfig['bundles']['ignore'])) {
90 21
                        $bundle = null;
91
                    }
92
93 21
                    if ($bundle) {
94
                        $bundle = preg_replace('/Bundle$/', null, $bundle);
95
                    }
96
                }
97
            }
98
        }
99
100 21
        if ($bundle || $node) {
101 21
            $definition->setMeta('namespace', ['bundle' => $bundle, 'node' => $node]);
102
        }
103 21
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108 21
    public function configureEndpoint(Endpoint $endpoint)
109
    {
110 21
        $groupByBundle = $this->globalConfig['bundles']['enabled'] ?? false;
111 21
        $groupByNode = $this->globalConfig['bundles']['enabled'] ?? false;
112 21
        if ($groupByBundle || $groupByNode) {
113 21
            $endpoint->setQueries($this->namespaceDefinitions($endpoint->allQueries(), $endpoint));
114 21
            $endpoint->setMutations($this->namespaceDefinitions($endpoint->allMutations(), $endpoint));
115
        }
116 21
    }
117
118
    /**
119
     * @param array    $definitions
120
     * @param Endpoint $endpoint
121
     *
122
     * @return array
123
     */
124 21
    private function namespaceDefinitions($definitions, Endpoint $endpoint)
125
    {
126 21
        $namespacedDefinitions = [];
127
        /** @var DefinitionInterface $definition */
128 21
        foreach ($definitions as $definition) {
129 21
            if (!$definition->hasMeta('namespace') || !$definition->getMeta('namespace')) {
130 21
                $namespacedDefinitions[] = $definition;
131 21
                continue;
132
            }
133
134 21
            $root = null;
135 21
            $parent = null;
136 21
            $namespace = $definition->getMeta('namespace');
137 21
            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 21
            if ($nodeName = $namespace['node'] ?? null) {
146 21
                if ($endpoint->hasTypeForClass($nodeName)) {
147
                    $nodeName = $endpoint->getTypeForClass($nodeName);
148
                }
149
150 21
                $name = Inflector::pluralize(lcfirst($nodeName));
151
152 21
                $querySuffix = $this->globalConfig['nodes']['query_suffix'] ?? 'Query';
153 21
                $mutationSuffix = $this->globalConfig['nodes']['mutation_suffix'] ?? 'Mutation';
154
155 21
                $typeName = ucfirst($nodeName).(($definition instanceof MutationDefinition) ? $mutationSuffix : $querySuffix);
156 21
                if (!$root) {
157 21
                    $root = $this->createRootNamespace(get_class($definition), $name, $typeName, $endpoint);
158 21
                    $parent = $endpoint->getType($root->getType());
159
                } elseif ($parent) {
160
                    $parent = $this->createChildNamespace($parent, $name, $typeName, $endpoint);
161
                }
162
163
                //remove node suffix on namespaced definitions
164 21
                $definition->setName(preg_replace(sprintf("/(\w+)%s$/", $nodeName), '$1', $definition->getName()));
165 21
                $definition->setName(preg_replace(sprintf("/(\w+)%s$/", Inflector::pluralize($nodeName)), '$1', $definition->getName()));
166
167
            }
168
169 21
            if ($root && $parent) {
170 21
                $this->addDefinitionToNamespace($parent, $definition);
171 21
                $namespacedDefinitions[] = $root;
172
            }
173
        }
174
175 21
        return $namespacedDefinitions;
176
    }
177
178
    /**
179
     * @param FieldsAwareDefinitionInterface $fieldsAwareDefinition
180
     * @param ExecutableDefinitionInterface  $definition
181
     */
182 21
    private function addDefinitionToNamespace(FieldsAwareDefinitionInterface $fieldsAwareDefinition, ExecutableDefinitionInterface $definition)
183
    {
184 21
        $field = new FieldDefinition();
185 21
        $field->setName($definition->getName());
186 21
        $field->setType($definition->getType());
187 21
        $field->setResolver($definition->getResolver());
188 21
        $field->setArguments($definition->getArguments());
189 21
        $field->setList($definition->isList());
190 21
        $field->setMetas($definition->getMetas());
191 21
        $field->setNode($definition->getNode());
192 21
        $fieldsAwareDefinition->addField($field);
193 21
    }
194
195
    /**
196
     * @param ObjectDefinitionInterface $parent   parent definition to add a child field
197
     * @param string                    $name     name of the field
198
     * @param string                    $typeName name of the type to create
199
     * @param Endpoint                  $endpoint Endpoint instance to extract definitions
200
     *
201
     * @return ObjectDefinition
202
     */
203 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...
204
    {
205
        $child = new FieldDefinition();
206
        $child->setName($name);
207
        $child->setResolver(EmptyObjectResolver::class);
208
209
        $type = new ObjectDefinition();
210
        $type->setName($typeName);
211
        if ($endpoint->hasType($type->getName())) {
212
            $type = $endpoint->getType($type->getName());
213
        } else {
214
            $endpoint->add($type);
215
        }
216
217
        $child->setType($type->getName());
218
        $parent->addField($child);
219
220
        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...
221
    }
222
223
    /**
224
     * @param string   $rootType Class of the root type to create QueryDefinition or MutationDefinition
225
     * @param string   $name     name of the root field
226
     * @param string   $typeName name for the root type
227
     * @param Endpoint $endpoint Endpoint interface to extract existent definitions
228
     *
229
     * @return ExecutableDefinitionInterface
230
     */
231 21 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...
232
    {
233
        /** @var ExecutableDefinitionInterface $rootDefinition */
234 21
        $rootDefinition = new $rootType();
235 21
        $rootDefinition->setName($name);
236 21
        $rootDefinition->setResolver(EmptyObjectResolver::class);
237
238 21
        $type = new ObjectDefinition();
239 21
        $type->setName($typeName);
240 21
        if ($endpoint->hasType($type->getName())) {
241 21
            $type = $endpoint->getType($type->getName());
242
        } else {
243 21
            $endpoint->add($type);
244
        }
245
246 21
        $rootDefinition->setType($type->getName());
247
248 21
        return $rootDefinition;
249
    }
250
}
251