Completed
Push — master ( c00bbf...06e52a )
by Pavel
17:08 queued 22s
created

CrudsEntitiesConfigurator   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 364
Duplicated Lines 4.4 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 96.7%

Importance

Changes 0
Metric Value
wmc 25
lcom 1
cbo 4
dl 16
loc 364
ccs 205
cts 212
cp 0.967
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getEvm() 0 4 1
A __construct() 0 4 1
B processEntityConfiguration() 16 55 7
B registerCreateAction() 0 52 4
B registerReadAction() 0 26 1
B registerDeleteAction() 0 29 1
A registerSearchAction() 0 74 3
A filterReference() 0 4 1
A generateControllerId() 0 4 1
A normalize() 0 4 1
B registerRoute() 0 27 1
A getLoaderDefinition() 0 4 1
B registerUpdateAction() 0 34 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace ScayTrase\Api\Cruds\DependencyInjection;
4
5
use Doctrine\Common\Persistence\ObjectManager;
6
use Doctrine\ORM\EntityRepository;
7
use ScayTrase\Api\Cruds\Controller\CountController;
8
use ScayTrase\Api\Cruds\Controller\CreateController;
9
use ScayTrase\Api\Cruds\Controller\DeleteController;
10
use ScayTrase\Api\Cruds\Controller\ReadController;
11
use ScayTrase\Api\Cruds\Controller\SearchController;
12
use ScayTrase\Api\Cruds\Controller\UpdateController;
13
use ScayTrase\Api\Cruds\Criteria\NestedCriteriaConfigurator;
14
use Symfony\Component\DependencyInjection\ChildDefinition;
15
use Symfony\Component\DependencyInjection\ContainerBuilder;
16
use Symfony\Component\DependencyInjection\Definition;
17
use Symfony\Component\DependencyInjection\DefinitionDecorator;
18
use Symfony\Component\DependencyInjection\Reference;
19
20
final class CrudsEntitiesConfigurator
21
{
22
    /** @var  ContainerBuilder */
23
    private $container;
24
25
    /**
26
     * CrudsEntitiesConfigurator constructor.
27
     *
28
     * @param ContainerBuilder $container
29
     */
30 30
    public function __construct(ContainerBuilder $container)
31
    {
32 30
        $this->container = $container;
33 30
    }
34
35 30
    public function processEntityConfiguration($name, $config)
36
    {
37 30
        $class      = $config['class'];
38 30
        $actions    = $config['actions'];
39 30
        $prefix     = $config['prefix'];
40 30
        $manager    = $config['manager'];
41 30
        $repository = $config['repository'];
42 30
        $mount      = $config['mount'];
43
44 30 View Code Duplication
        if (null === $manager) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
45 30
            $manager    = $this->normalize('cruds.class_' . $class . '.object_manager');
46 30
            $managerDef = new Definition(ObjectManager::class);
47 30
            $managerDef->setPublic(false);
48 30
            $managerDef->setFactory([new Reference('doctrine'), 'getManagerForClass']);
49 30
            $managerDef->setArguments([$class]);
50 30
            $this->container->setDefinition($manager, $managerDef);
51
        }
52 30
        $manager = new Reference($this->filterReference($manager));
53
54 30 View Code Duplication
        if (null === $repository) {
55 30
            $repository    = $this->normalize('cruds.class_' . $class . '.entity_repository');
56 30
            $repositoryDef = new Definition(EntityRepository::class);
57 30
            $repositoryDef->setPublic(false);
58 30
            $repositoryDef->setFactory([$manager, 'getRepository']);
59 30
            $repositoryDef->setArguments([$class]);
60 30
            $this->container->setDefinition($repository, $repositoryDef);
61
        }
62
63 30
        $repository = new Reference($this->filterReference($repository));
64
65 30
        foreach ($actions as $action => $actionConfig) {
66 30
            if (!$actionConfig['enabled']) {
67
                continue;
68
            }
69
70 30
            $actionConfig['name']       = $name;
71 30
            $actionConfig['class']      = $class;
72 30
            $actionConfig['mount']      = $mount;
73 30
            $actionConfig['repository'] = $repository;
74 30
            $actionConfig['path']       = $prefix . $actionConfig['path'];
75 30
            $actionConfig['manager']    = $manager;
76 30
            $actionConfig['prefix']     = $prefix;
77 30
            $function                   = new \ReflectionMethod($this, 'register' . ucfirst($action) . 'Action');
78 30
            $args                       = [];
79
80 30
            foreach ($function->getParameters() as $parameter) {
81 30
                if (array_key_exists($parameter->getName(), $actionConfig)) {
82 30
                    $args[] = $actionConfig[$parameter->getName()];
83
                } else {
84 30
                    $args[] = $parameter->getDefaultValue();
85
                }
86
            }
87 30
            $function->invokeArgs($this, $args);
88
        }
89 30
    }
90
91 30
    public function registerCreateAction($mount, $name, $class, $factory, $processor, $path, $manager)
92
    {
93 30
        $actionName   = 'create';
94 30
        $controllerId = $this->generateControllerId($name, $actionName);
95
96 30
        if (null === $factory) {
97 30
            $factory = $controllerId . '.entity_factory';
98
99 30
            if (class_exists(ChildDefinition::class)) {
100 30
                $factoryDef = new ChildDefinition('cruds.factory.reflection');
101
            } else {
102
                $factoryDef = new DefinitionDecorator('cruds.factory.reflection');
103
            }
104
105 30
            $factoryDef->setArguments([$class, []]);
106 30
            $factoryDef->setPublic(false);
107 30
            $this->container->setDefinition($factory, $factoryDef);
108
        }
109
110 30
        $factory = new Reference($this->filterReference($factory));
111
112 30
        if (null === $processor) {
113 30
            $processor = 'cruds.processor.property_access';
114
        }
115
116 30
        $processor = new Reference($this->filterReference($processor));
117
118 30
        $definition = new Definition(CreateController::class);
119 30
        $definition->setPublic(true);
120 30
        $definition->setArguments(
121
            [
122 30
                $processor,
123 30
                $manager,
124 30
                $factory,
125 30
                $this->getEvm(),
126
            ]
127
        );
128 30
        $definition->setPublic(true);
129
130 30
        $this->container->setDefinition($controllerId, $definition);
131
132 30
        $action = $controllerId . ':' . CreateController::ACTION;
133 30
        $this->registerRoute(
134 30
            $mount,
135 30
            $name,
136 30
            $actionName,
137 30
            $path,
138 30
            $action,
139 30
            ['POST'],
140 30
            ['class' => $class, 'arguments' => ['data']]
141
        );
142 30
    }
143
144 30
    public function registerReadAction($mount, $name, $path, $repository, $class)
145
    {
146 30
        $definition = new Definition(ReadController::class);
147 30
        $definition->setPublic(true);
148 30
        $definition->setArguments(
149
            [
150 30
                $repository,
151 30
                $this->getEvm(),
152
            ]
153
        );
154
155 30
        $actionName   = 'read';
156 30
        $controllerId = $this->generateControllerId($name, $actionName);
157 30
        $this->container->setDefinition($controllerId, $definition);
158
159 30
        $action = $controllerId . ':' . ReadController::ACTION;
160 30
        $this->registerRoute(
161 30
            $mount,
162 30
            $name,
163 30
            $actionName,
164 30
            $path,
165 30
            $action,
166 30
            ['GET', 'POST'],
167 30
            ['class' => $class, 'arguments' => ['identifier']]
168
        );
169 30
    }
170
171 30
    public function registerUpdateAction($mount, $name, $path, $repository, $processor, $manager, $class)
172
    {
173 30
        if (null === $processor) {
174 15
            $processor = new Reference('cruds.processor.property_access');
175
        } else {
176 15
            $processor = new Reference($this->filterReference($processor));
177
        }
178
179 30
        $definition = new Definition(UpdateController::class);
180 30
        $definition->setPublic(true);
181 30
        $definition->setArguments(
182
            [
183 30
                $repository,
184 30
                $processor,
185 30
                $manager,
186 30
                $this->getEvm(),
187
            ]
188
        );
189
190 30
        $actionName   = 'update';
191 30
        $controllerId = $this->generateControllerId($name, $actionName);
192 30
        $this->container->setDefinition($controllerId, $definition);
193
194 30
        $action = $controllerId . ':' . UpdateController::ACTION;
195 30
        $this->registerRoute(
196 30
            $mount,
197 30
            $name,
198 30
            $actionName,
199 30
            $path,
200 30
            $action,
201 30
            ['POST', 'PATCH'],
202 30
            ['class' => $class, 'arguments' => ['identifier', 'data']]
203
        );
204 30
    }
205
206 30
    public function registerDeleteAction($mount, $name, $path, $repository, $manager, $class)
207
    {
208 30
        $definition = new Definition(DeleteController::class);
209 30
        $definition->setPublic(true);
210 30
        $definition->setPublic(true);
211 30
        $definition->setArguments(
212
            [
213 30
                $repository,
214 30
                $manager,
215 30
                $this->getEvm(),
216
            ]
217
        );
218
219 30
        $actionName   = 'delete';
220 30
        $controllerId = $controllerId = $this->generateControllerId($name, $actionName);
221 30
        $this->container->setDefinition($controllerId, $definition);
222
223 30
        $action = $controllerId . ':' . DeleteController::ACTION;
224 30
        $definition->setPublic(true);
225 30
        $this->registerRoute(
226 30
            $mount,
227 30
            $name,
228 30
            $actionName,
229 30
            $path,
230 30
            $action,
231 30
            ['POST', 'DELETE'],
232 30
            ['class' => $class, 'arguments' => ['identifier']]
233
        );
234 30
    }
235
236 30
    public function registerSearchAction(
237
        string $mount,
238
        string $name,
239
        string $path,
240
        string $class,
241
        Reference $repository,
242
        $criteria,
243
        string $count_path,
244
        string $prefix
245
    ) {
246
247 30
        if (is_array($criteria)) {
248
            $filterArray = [];
249
            foreach ($criteria as $filter => $reference) {
250
                $filterArray[$filter] = new Reference($this->filterReference($reference));
251
            }
252
            $criteriaConfigurator = new Definition(NestedCriteriaConfigurator::class);
253
            $criteriaConfigurator->setArguments([$filterArray]);
254
        } else {
255 30
            $criteriaConfigurator = new Reference($this->filterReference($criteria));
256
        }
257
258 30
        $definition = new Definition(SearchController::class);
259 30
        $definition->setPublic(true);
260 30
        $definition->setArguments(
261
            [
262 30
                $class,
263 30
                $repository,
264 30
                $criteriaConfigurator,
265 30
                $this->getEvm(),
266
            ]
267
        );
268
269 30
        $actionName   = 'search';
270 30
        $controllerId = $this->generateControllerId($name, $actionName);
271 30
        $this->container->setDefinition($controllerId, $definition);
272
273 30
        $action = $controllerId . ':' . SearchController::ACTION;
274 30
        $this->registerRoute(
275 30
            $mount,
276 30
            $name,
277 30
            $actionName,
278 30
            $path,
279 30
            $action,
280 30
            ['GET', 'POST'],
281 30
            ['class' => $class, 'arguments' => ['criteria', 'order', 'limit', 'offset']]
282
        );
283
284 30
        $definition = new Definition(CountController::class);
285 30
        $definition->setPublic(true);
286 30
        $definition->setArguments(
287
            [
288 30
                $class,
289 30
                $repository,
290 30
                $criteriaConfigurator,
291 30
                $this->getEvm(),
292
            ]
293
        );
294
295 30
        $actionName   = 'count';
296 30
        $controllerId = $this->generateControllerId($name, $actionName);
297 30
        $this->container->setDefinition($controllerId, $definition);
298
299 30
        $action = $controllerId . ':' . CountController::ACTION;
300 30
        $this->registerRoute(
301 30
            $mount,
302 30
            $name,
303 30
            $actionName,
304 30
            $prefix . $count_path,
305 30
            $action,
306 30
            ['GET', 'POST'],
307 30
            ['class' => $class, 'arguments' => ['criteria']]
308
        );
309 30
    }
310
311 30
    private function filterReference(string $reference): string
312
    {
313 30
        return ltrim($reference, '@');
314
    }
315
316
    /**
317
     * @return Reference
318
     */
319 30
    private function getEvm(): Reference
320
    {
321 30
        return new Reference('event_dispatcher');
322
    }
323
324 30
    private function generateControllerId(string $name, string $actionName): string
325
    {
326 30
        return $this->normalize('cruds.generated_controller.' . $name . '.' . $actionName);
327
    }
328
329
    /**
330
     * @param string $name
331
     *
332
     * @return string
333
     */
334 30
    private function normalize(string $name): string
335
    {
336 30
        return str_replace(['-', ':'], '_', $name);
337
    }
338
339
    /**
340
     * @param string $mount
341
     * @param string $name
342
     * @param string $actionName
343
     * @param string $path
344
     * @param string $action
345
     * @param array  $methods
346
     * @param array  $options
347
     *
348
     * @return Definition
349
     * @throws \InvalidArgumentException
350
     */
351 30
    private function registerRoute(
352
        string $mount,
353
        string $name,
354
        string $actionName,
355
        string $path,
356
        string $action,
357
        array $methods,
358
        array $options = []
359
    ): Definition {
360 30
        return $this->getLoaderDefinition()->addMethodCall(
361 30
            'addRoute',
362
            [
363 30
                $mount,
364 30
                $this->normalize('cruds.routing.' . $name . '.' . $actionName),
365 30
                $path,
366 30
                $action,
367 30
                $methods,
368 30
                array_replace(
369
                    [
370 30
                        'action' => $actionName,
371 30
                        'mount'  => $mount,
372
                    ],
373 30
                    $options
374
                ),
375
            ]
376
        );
377
    }
378
379 30
    private function getLoaderDefinition(): Definition
380
    {
381 30
        return $this->container->getDefinition('cruds.api.router_loader');
382
    }
383
}
384