Completed
Push — master ( c6433c...a8c688 )
by Gerrit
38:24
created

GenericEntityCreateController::createEntity()   C

Complexity

Conditions 10
Paths 56

Size

Total Lines 92

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 10.1466

Importance

Changes 0
Metric Value
dl 0
loc 92
c 0
b 0
f 0
ccs 39
cts 44
cp 0.8864
rs 6.3078
cc 10
nc 56
nop 1
crap 10.1466

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
 * Copyright (C) 2018 Gerrit Addiks.
4
 * This package (including this file) was released under the terms of the GPL-3.0.
5
 * You should have received a copy of the GNU General Public License along with this program.
6
 * If not, see <http://www.gnu.org/licenses/> or send me a mail so i can send you a copy.
7
 *
8
 * @license GPL-3.0
9
 *
10
 * @author Gerrit Addiks <[email protected]>
11
 */
12
13
namespace Addiks\SymfonyGenerics\Controllers;
14
15
use Addiks\SymfonyGenerics\Controllers\ControllerHelperInterface;
16
use Addiks\SymfonyGenerics\Services\ArgumentCompilerInterface;
17
use Symfony\Component\HttpFoundation\Response;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\Serializer\SerializerInterface;
20
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
21
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
22
use Webmozart\Assert\Assert;
23
use XSLTProcessor;
24
use DOMDocument;
25
use ReflectionClass;
26
use ReflectionMethod;
27
use ReflectionParameter;
28
use Psr\Container\ContainerInterface;
29
use ErrorException;
30
31
final class GenericEntityCreateController
32
{
33
34
    /**
35
     * @var ControllerHelperInterface
36
     */
37
    private $controllerHelper;
38
39
    /**
40
     * @var ContainerInterface
41
     */
42
    private $container;
43
44
    /**
45
     * @var string
46
     */
47
    private $entityClass;
48
49
    /**
50
     * @var array<string, array<string, mixed>>
51
     */
52
    private $calls = array();
53
54
    /**
55
     * @var string|null
56
     */
57
    private $factory = null;
58
59
    /**
60
     * @var array<string, mixed>|null
61
     */
62
    private $constructArguments;
63
64
    /**
65
     * @var ArgumentCompilerInterface
66
     */
67
    private $argumentBuilder;
68
69
    /**
70
     * @var string
71
     */
72
    private $successResponse;
73
74
    /**
75
     * @var string|null
76
     */
77
    private $authorizationAttribute;
78
79 16
    public function __construct(
80
        ControllerHelperInterface $controllerHelper,
81
        ArgumentCompilerInterface $argumentBuilder,
82
        ContainerInterface $container,
83
        array $options
84
    ) {
85 16
        Assert::null($this->controllerHelper);
86 16
        Assert::keyExists($options, 'entity-class');
87 15
        Assert::true(class_exists($options['entity-class']));
88
89 14
        $options = array_merge([
90 14
            'calls' => [],
91
            'success-response' => "object created",
92
            'factory' => null,
93
            'authorization-attribute' => null,
94 14
        ], $options);
95
96 14
        $this->controllerHelper = $controllerHelper;
97 14
        $this->argumentBuilder = $argumentBuilder;
98 14
        $this->container = $container;
99 14
        $this->entityClass = $options['entity-class'];
100 14
        $this->successResponse = $options['success-response'];
101 14
        $this->factory = $options['factory'];
102 14
        $this->authorizationAttribute = $options['authorization-attribute'];
103
104 14
        foreach ($options['calls'] as $methodName => $arguments) {
105
            /** @var array $arguments */
106
107 5
            Assert::isArray($arguments);
108
109 4
            if ($methodName === 'construct') {
110 1
                $this->constructArguments = $arguments;
111
112
            } else {
113 3
                Assert::true(method_exists($this->entityClass, $methodName));
114
115 2
                $this->calls[$methodName] = $arguments;
116
            }
117
        }
118 11
    }
119
120 10
    public function createEntity(Request $request): Response
121
    {
122 10
        $classReflection = new ReflectionClass($this->entityClass);
123
124
        /** @var ReflectionMethod $constructorReflection */
125 10
        $constructorReflection = $classReflection->getConstructor();
126
127
        /** @var array<int, mixed> $constructArguments */
128 10
        $constructArguments = array();
129
130 10
        if (!empty($this->constructArguments)) {
131 1
            $constructArguments = $this->argumentBuilder->buildCallArguments(
132 1
                $constructorReflection,
133 1
                $this->constructArguments,
134 1
                $request
135
            );
136
        }
137
138
        /** @var object|null $entity */
139 10
        $entity = null;
140
141 10
        if (!empty($this->factory)) {
142 7
            if (is_int(strpos($this->factory, '::'))) {
143 7
                [$factoryClass, $factoryMethod] = explode('::', $this->factory, 2);
0 ignored issues
show
Bug introduced by
The variable $factoryClass does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $factoryMethod does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
144
145 7
                if (!empty($factoryClass)) {
146 6
                    if ($factoryClass[0] == '@') {
147
                        /** @var string $factoryServiceId */
148 6
                        $factoryServiceId = substr($factoryClass, 1);
149
150
                        /** @var object|null $factoryObject */
151 6
                        $factoryObject = $this->container->get($factoryServiceId);
152
153 6
                        Assert::methodExists($factoryObject, $factoryMethod, sprintf(
154 6
                            "Did not find service with id '%s' that has a method '%s' to use as factory for '%s'!",
155 6
                            $factoryServiceId,
156 6
                            $factoryMethod,
157 6
                            $this->entityClass
158
                        ));
159
160
                        # Create by factory-service-object
161 3
                        $entity = call_user_func_array([$factoryObject, $factoryMethod], $constructArguments);
162
163
                    } else {
164
                        # Create by static factory-method of other class
165 4
                        $entity = call_user_func_array($this->factory, $constructArguments);
166
                    }
167
                }
168
169
            } elseif (method_exists($this->entityClass, $this->factory)) {
170
                # Create by static factory method on entity class
171
                $entity = call_user_func_array(
172
                    sprintf("%s::%s", $this->entityClass, $this->factory),
173
                    $constructArguments
174
                );
175
176
            } elseif (function_exists($this->factory)) {
177
                # Create by factory function
178 4
                $entity = call_user_func_array($this->factory, $constructArguments);
179
            }
180
181
        } else {
182
            # Create by calling the constructor directly
183 3
            $entity = $classReflection->newInstanceArgs($constructArguments);
184
        }
185
186 7
        Assert::isInstanceOf($entity, $this->entityClass);
187
188 5
        foreach ($this->calls as $methodName => $callArgumentConfiguration) {
189
            /** @var array $callArgumentConfiguration */
190
191
            /** @var ReflectionMethod $methodReflection */
192 1
            $methodReflection = $classReflection->getMethod($methodName);
193
194 1
            $callArguments = $this->argumentBuilder->buildCallArguments(
195 1
                $methodReflection,
196 1
                $callArgumentConfiguration,
197 1
                $request
198
            );
199
200 1
            $methodReflection->invoke($entity, $callArguments);
201
        }
202
203 5
        if (!empty($this->authorizationAttribute)) {
204 1
            $this->controllerHelper->denyAccessUnlessGranted($this->authorizationAttribute, $entity);
205
        }
206
207 4
        $this->controllerHelper->persistEntity($entity);
208 4
        $this->controllerHelper->flushORM();
209
210 4
        return new Response($this->successResponse, 200);
211
    }
212
213
}
214