Test Setup Failed
Push — master ( e2ccdd...da0315 )
by Gerrit
09:14
created

GenericEntityInvokeController::invokeEntityMethod()   B

Complexity

Conditions 7
Paths 36

Size

Total Lines 73

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 7.0957

Importance

Changes 0
Metric Value
cc 7
nc 36
nop 1
dl 0
loc 73
ccs 35
cts 40
cp 0.875
crap 7.0957
rs 7.6557
c 0
b 0
f 0

How to fix   Long Method   

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\API;
14
15
use Addiks\SymfonyGenerics\Controllers\ControllerHelperInterface;
16
use Addiks\SymfonyGenerics\Services\ArgumentCompilerInterface;
17
use Webmozart\Assert\Assert;
18
use InvalidArgumentException;
19
use ReflectionObject;
20
use ReflectionMethod;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\Response;
23
use Addiks\SymfonyGenerics\Events\EntityInteractionEvent;
24
25
final class GenericEntityInvokeController
26
{
27
28
    private ControllerHelperInterface $controllerHelper;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
29
30
    private ArgumentCompilerInterface $argumentCompiler;
31
32
    /** @var class-string */
33
    private string $entityClass;
34
35
    private string $entityIdKey;
36
37
    private string $entityIdSource;
38
39
    private string $methodName;
40
41
    private array $arguments;
42
43
    private ?string $denyAccessAttribute;
44
45
    private string $successMessage;
46
47
    private string $successFlashMessage;
48
49
    private ?string $redirectRoute;
50
51
    private array $redirectRouteParameters;
52
53
    private int $redirectStatus;
54
55
    private bool $sendReturnValueInResponse = false;
56
57
    public function __construct(
58
        ControllerHelperInterface $controllerHelper,
59
        ArgumentCompilerInterface $argumentCompiler,
60
        array $options
61
    ) {
62
        Assert::keyExists($options, 'entity-class');
63
        Assert::keyExists($options, 'method');
64
65
        $options = array_merge([
66
            'arguments' => [],
67
            'deny-access-attribute' => null,
68
            'success-message' => "Entity method invoked!",
69
            'success-flash-message' => "",
70 12
            'redirect-route' => null,
71
            'redirect-route-parameters' => [],
72
            'redirect-status' => 301,
73
            'entity-id-key' => 'entityId',
74
            'entity-id-source' => 'request',
75 12
            'send-return-value-in-response' => false,
76 12
        ], $options);
77 11
78
        Assert::classExists($options['entity-class']);
79 10
        Assert::methodExists($options['entity-class'], $options['method']);
80 10
        Assert::isArray($options['arguments'], 'Method-arguments must be array!');
81
        Assert::oneOf($options['entity-id-source'], ['request', 'argument']);
82
83
        $this->controllerHelper = $controllerHelper;
84
        $this->argumentCompiler = $argumentCompiler;
85
        $this->entityClass = $options['entity-class'];
86
        $this->entityIdKey = $options['entity-id-key'];
87
        $this->entityIdSource = $options['entity-id-source'];
88
        $this->methodName = $options['method'];
89
        $this->arguments = $options['arguments'];
90 10
        $this->denyAccessAttribute = $options['deny-access-attribute'];
91
        $this->successMessage = $options['success-message'];
92 10
        $this->successFlashMessage = $options['success-flash-message'];
93 9
        $this->redirectRoute = $options['redirect-route'];
94 8
        $this->redirectStatus = $options['redirect-status'];
95 7
        $this->redirectRouteParameters = $options['redirect-route-parameters'];
96
        $this->sendReturnValueInResponse = $options['send-return-value-in-response'];
97 7
    }
98 7
99 7
    public function __invoke(): Response
100 7
    {
101 7
        /** @var Request $request */
102 7
        $request = $this->controllerHelper->getCurrentRequest();
103 7
104 7
        Assert::isInstanceOf($request, Request::class, "Cannot use controller outside of request-scope!");
105 7
106 7
        /** @var Response $response */
107 7
        $response = null;
108 7
109 7
        if ($this->entityIdSource === 'request') {
110 7
            /** @var string $entityId */
111 7
            $entityId = $request->get($this->entityIdKey);
112
113 2
            $response = $this->invokeEntityMethod($entityId);
114
115
        } elseif ($this->entityIdSource === 'argument') {
116 2
            $response = $this->invokeEntityMethod('');
117
        }
118 2
119
        return $response;
120
121 1
    }
122
123 1
    public function invokeEntityMethod(string $entityId): Response
124
    {
125 1
        /** @var object $entity */
126
        $entity = null;
127 1
128
        if ($this->entityIdSource === 'request') {
129
            $entity = $this->controllerHelper->findEntity($this->entityClass, $entityId);
130
            Assert::object($entity, sprintf("Entity with id '%s' not found!", $entityId));
131
132
        } elseif ($this->entityIdSource === 'argument') {
133 1
            $entity = $this->argumentCompiler->buildArgument($this->entityIdKey);
134
            Assert::object($entity, "Entity not found!");
135
        }
136
137 5
        Assert::isInstanceOf($entity, $this->entityClass, sprintf(
138
            "Found entity is not of expected class '%s', but of class '%s' instead!",
139
            $this->entityClass,
140 5
            get_class($entity)
141
        ));
142 5
143 5
        if (!empty($this->denyAccessAttribute)) {
144 5
            $this->controllerHelper->denyAccessUnlessGranted($this->denyAccessAttribute, $entity);
145
        }
146
147
        $reflectionObject = new ReflectionObject($entity);
148
149
        /** @var ReflectionMethod $reflectionMethod */
150
        $reflectionMethod = $reflectionObject->getMethod($this->methodName);
151 4
152 4
        /** @var array $callArguments */
153 4
        $callArguments = $this->argumentCompiler->buildCallArguments(
154 4
            $reflectionMethod,
155
            $this->arguments
156
        );
157 4
158 1
        $this->controllerHelper->dispatchEvent("symfony_generics.entity_interaction", new EntityInteractionEvent(
159
            $this->entityClass,
160
            $entityId,
161 3
            $entity,
162
            $this->methodName,
163
            $callArguments
164 3
        ));
165
166
        /** @var mixed $result */
167 3
        $result = $reflectionMethod->invokeArgs($entity, $callArguments);
168 3
169 3
        $this->controllerHelper->flushORM();
170
171
        if (!empty($this->successFlashMessage)) {
172 3
            $this->controllerHelper->addFlashMessage($this->successFlashMessage, "success");
173 3
        }
174 3
175 3
        /** @var Response $response */
176 3
        $response = null;
177 3
178
        if ($this->sendReturnValueInResponse) {
179
            return new Response((string)$result);
180
181 3
        } elseif (is_null($this->redirectRoute)) {
182
            $response = new Response($this->successMessage);
183 3
184
        } else {
185 3
            $response = $this->controllerHelper->redirectToRoute(
186
                $this->redirectRoute,
187
                $this->argumentCompiler->buildArguments($this->redirectRouteParameters, [
188
                    'result' => $result
189
                ]),
190 3
                $this->redirectStatus
191
            );
192 3
        }
193
194
        return $response;
195 3
    }
196 2
197
}
198