Passed
Push — master ( c39fb6...9e9a0d )
by Rafael
04:42
created

NamespaceDefinitionExtension::configure()   D

Complexity

Conditions 18
Paths 190

Size

Total Lines 41
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 18.7184

Importance

Changes 0
Metric Value
cc 18
eloc 22
nc 190
nop 3
dl 0
loc 41
ccs 20
cts 23
cp 0.8696
crap 18.7184
rs 4.6734
c 0
b 0
f 0

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