Passed
Pull Request — master (#21)
by Pavel
06:33
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 0%

Importance

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

13 Methods

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

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
    public function __construct(ContainerBuilder $container)
31
    {
32
        $this->container = $container;
33
    }
34
35
    public function processEntityConfiguration($name, $config)
36
    {
37
        $class      = $config['class'];
38
        $actions    = $config['actions'];
39
        $prefix     = $config['prefix'];
40
        $manager    = $config['manager'];
41
        $repository = $config['repository'];
42
        $mount      = $config['mount'];
43
44 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
            $manager    = $this->normalize('cruds.class_' . $class . '.object_manager');
46
            $managerDef = new Definition(ObjectManager::class);
47
            $managerDef->setPublic(false);
48
            $managerDef->setFactory([new Reference('doctrine'), 'getManagerForClass']);
49
            $managerDef->setArguments([$class]);
50
            $this->container->setDefinition($manager, $managerDef);
51
        }
52
        $manager = new Reference($this->filterReference($manager));
53
54 View Code Duplication
        if (null === $repository) {
55
            $repository    = $this->normalize('cruds.class_' . $class . '.entity_repository');
56
            $repositoryDef = new Definition(EntityRepository::class);
57
            $repositoryDef->setPublic(false);
58
            $repositoryDef->setFactory([$manager, 'getRepository']);
59
            $repositoryDef->setArguments([$class]);
60
            $this->container->setDefinition($repository, $repositoryDef);
61
        }
62
63
        $repository = new Reference($this->filterReference($repository));
64
65
        foreach ($actions as $action => $actionConfig) {
66
            if (!$actionConfig['enabled']) {
67
                continue;
68
            }
69
70
            $actionConfig['name']       = $name;
71
            $actionConfig['class']      = $class;
72
            $actionConfig['mount']      = $mount;
73
            $actionConfig['repository'] = $repository;
74
            $actionConfig['path']       = $prefix . $actionConfig['path'];
75
            $actionConfig['manager']    = $manager;
76
            $actionConfig['prefix']     = $prefix;
77
            $function                   = new \ReflectionMethod($this, 'register' . ucfirst($action) . 'Action');
78
            $args                       = [];
79
80
            foreach ($function->getParameters() as $parameter) {
81
                if (array_key_exists($parameter->getName(), $actionConfig)) {
82
                    $args[] = $actionConfig[$parameter->getName()];
83
                } else {
84
                    $args[] = $parameter->getDefaultValue();
85
                }
86
            }
87
            $function->invokeArgs($this, $args);
88
        }
89
    }
90
91
    public function registerCreateAction($mount, $name, $class, $factory, $processor, $path, $manager)
92
    {
93
        $actionName   = 'create';
94
        $controllerId = $this->generateControllerId($name, $actionName);
95
96
        if (null === $factory) {
97
            $factory = $controllerId . '.entity_factory';
98
99
            if (class_exists(ChildDefinition::class)) {
100
                $factoryDef = new ChildDefinition('cruds.factory.reflection');
101
            } else {
102
                $factoryDef = new DefinitionDecorator('cruds.factory.reflection');
103
            }
104
105
            $factoryDef->setArguments([$class, []]);
106
            $factoryDef->setPublic(false);
107
            $this->container->setDefinition($factory, $factoryDef);
108
        }
109
110
        $factory = new Reference($this->filterReference($factory));
111
112
        if (null === $processor) {
113
            $processor = 'cruds.processor.property_access';
114
        }
115
116
        $processor = new Reference($this->filterReference($processor));
117
118
        $definition = new Definition(CreateController::class);
119
        $definition->setPublic(true);
120
        $definition->setArguments(
121
            [
122
                $processor,
123
                $manager,
124
                $factory,
125
                $this->getEvm(),
126
            ]
127
        );
128
        $definition->setPublic(true);
129
130
        $this->container->setDefinition($controllerId, $definition);
131
132
        $action = $controllerId . ':' . CreateController::ACTION;
133
        $this->registerRoute(
134
            $mount,
135
            $name,
136
            $actionName,
137
            $path,
138
            $action,
139
            ['POST'],
140
            ['class' => $class, 'arguments' => ['data']]
141
        );
142
    }
143
144
    public function registerReadAction($mount, $name, $path, $repository, $class)
145
    {
146
        $definition = new Definition(ReadController::class);
147
        $definition->setPublic(true);
148
        $definition->setArguments(
149
            [
150
                $repository,
151
                $this->getEvm(),
152
            ]
153
        );
154
155
        $actionName   = 'read';
156
        $controllerId = $this->generateControllerId($name, $actionName);
157
        $this->container->setDefinition($controllerId, $definition);
158
159
        $action = $controllerId . ':' . ReadController::ACTION;
160
        $this->registerRoute(
161
            $mount,
162
            $name,
163
            $actionName,
164
            $path,
165
            $action,
166
            ['GET', 'POST'],
167
            ['class' => $class, 'arguments' => ['identifier']]
168
        );
169
    }
170
171
    public function registerUpdateAction($mount, $name, $path, $repository, $processor, $manager, $class)
172
    {
173
        if (null === $processor) {
174
            $processor = new Reference('cruds.processor.property_access');
175
        } else {
176
            $processor = new Reference($this->filterReference($processor));
177
        }
178
179
        $definition = new Definition(UpdateController::class);
180
        $definition->setPublic(true);
181
        $definition->setArguments(
182
            [
183
                $repository,
184
                $processor,
185
                $manager,
186
                $this->getEvm(),
187
            ]
188
        );
189
190
        $actionName   = 'update';
191
        $controllerId = $this->generateControllerId($name, $actionName);
192
        $this->container->setDefinition($controllerId, $definition);
193
194
        $action = $controllerId . ':' . UpdateController::ACTION;
195
        $this->registerRoute(
196
            $mount,
197
            $name,
198
            $actionName,
199
            $path,
200
            $action,
201
            ['POST', 'PATCH'],
202
            ['class' => $class, 'arguments' => ['identifier', 'data']]
203
        );
204
    }
205
206
    public function registerDeleteAction($mount, $name, $path, $repository, $manager, $class)
207
    {
208
        $definition = new Definition(DeleteController::class);
209
        $definition->setPublic(true);
210
        $definition->setPublic(true);
211
        $definition->setArguments(
212
            [
213
                $repository,
214
                $manager,
215
                $this->getEvm(),
216
            ]
217
        );
218
219
        $actionName   = 'delete';
220
        $controllerId = $controllerId = $this->generateControllerId($name, $actionName);
221
        $this->container->setDefinition($controllerId, $definition);
222
223
        $action = $controllerId . ':' . DeleteController::ACTION;
224
        $definition->setPublic(true);
225
        $this->registerRoute(
226
            $mount,
227
            $name,
228
            $actionName,
229
            $path,
230
            $action,
231
            ['POST', 'DELETE'],
232
            ['class' => $class, 'arguments' => ['identifier']]
233
        );
234
    }
235
236
    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
        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
            $criteriaConfigurator = new Reference($this->filterReference($criteria));
256
        }
257
258
        $definition = new Definition(SearchController::class);
259
        $definition->setPublic(true);
260
        $definition->setArguments(
261
            [
262
                $class,
263
                $repository,
264
                $criteriaConfigurator,
265
                $this->getEvm(),
266
            ]
267
        );
268
269
        $actionName   = 'search';
270
        $controllerId = $this->generateControllerId($name, $actionName);
271
        $this->container->setDefinition($controllerId, $definition);
272
273
        $action = $controllerId . ':' . SearchController::ACTION;
274
        $this->registerRoute(
275
            $mount,
276
            $name,
277
            $actionName,
278
            $path,
279
            $action,
280
            ['GET', 'POST'],
281
            ['class' => $class, 'arguments' => ['criteria', 'order', 'limit', 'offset']]
282
        );
283
284
        $definition = new Definition(CountController::class);
285
        $definition->setPublic(true);
286
        $definition->setArguments(
287
            [
288
                $class,
289
                $repository,
290
                $criteriaConfigurator,
291
                $this->getEvm(),
292
            ]
293
        );
294
295
        $actionName   = 'count';
296
        $controllerId = $this->generateControllerId($name, $actionName);
297
        $this->container->setDefinition($controllerId, $definition);
298
299
        $action = $controllerId . ':' . CountController::ACTION;
300
        $this->registerRoute(
301
            $mount,
302
            $name,
303
            $actionName,
304
            $prefix . $count_path,
305
            $action,
306
            ['GET', 'POST'],
307
            ['class' => $class, 'arguments' => ['criteria']]
308
        );
309
    }
310
311
    private function filterReference(string $reference): string
312
    {
313
        return ltrim($reference, '@');
314
    }
315
316
    /**
317
     * @return Reference
318
     */
319
    private function getEvm(): Reference
320
    {
321
        return new Reference('event_dispatcher');
322
    }
323
324
    private function generateControllerId(string $name, string $actionName): string
325
    {
326
        return $this->normalize('cruds.generated_controller.' . $name . '.' . $actionName);
327
    }
328
329
    /**
330
     * @param string $name
331
     *
332
     * @return string
333
     */
334
    private function normalize(string $name): string
335
    {
336
        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
    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
        return $this->getLoaderDefinition()->addMethodCall(
361
            'addRoute',
362
            [
363
                $mount,
364
                $this->normalize('cruds.routing.' . $name . '.' . $actionName),
365
                $path,
366
                $action,
367
                $methods,
368
                array_replace(
369
                    [
370
                        'action' => $actionName,
371
                        'mount'  => $mount,
372
                    ],
373
                    $options
374
                ),
375
            ]
376
        );
377
    }
378
379
    private function getLoaderDefinition(): Definition
380
    {
381
        return $this->container->getDefinition('cruds.api.router_loader');
382
    }
383
}
384