Completed
Push — master ( b03604...27d676 )
by Gerrit
03:42
created

executeInnerControllerSafely()   C

Complexity

Conditions 10
Paths 24

Size

Total Lines 78

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 78
ccs 37
cts 37
cp 1
rs 6.6133
c 0
b 0
f 0
cc 10
nc 24
nop 1
crap 10

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 Webmozart\Assert\Assert;
17
use Exception;
18
use Throwable;
19
use Symfony\Component\HttpFoundation\Response;
20
use ErrorException;
21
use Addiks\SymfonyGenerics\Services\ArgumentCompilerInterface;
22
use Symfony\Component\HttpFoundation\Request;
23
use ReflectionMethod;
24
25
final class GenericExceptionResponseController
26
{
27
28
    /**
29
     * @var ControllerHelperInterface
30
     */
31
    private $controllerHelper;
32
33
    /**
34
     * @var ArgumentCompilerInterface
35
     */
36
    private $argumentBuilder;
37
38
    /**
39
     * @var object
40
     */
41
    private $innerController;
42
43
    /**
44
     * @var string
45
     */
46
    private $innerControllerMethod;
47
48
    /**
49
     * @var array
50
     */
51
    private $innerControllerArgumentsConfiguration;
52
53
    /**
54
     * @var string|null
55
     */
56
    private $successResponse;
57
58
    /**
59
     * @var int
60
     */
61
    private $successResponseCode;
62
63
    /**
64
     * @var string|null
65
     */
66
    private $successFlashMessage;
67
68
    /**
69
     * @var array<string, array<string, mixed>>
70
     */
71
    private $exceptionResponses = array();
72
73
    /**
74
     * @param object $innerController
0 ignored issues
show
Bug introduced by
There is no parameter named $innerController. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
75
     */
76 13
    public function __construct(
77
        ControllerHelperInterface $controllerHelper,
78
        ArgumentCompilerInterface $argumentBuilder,
79
        array $options
80
    ) {
81
        /** @var int $defaultResponseCode */
82 13
        $defaultResponseCode = 200;
83
84
        /** @var array<string, mixed> $defaults */
85
        $defaults = array(
86 13
            'arguments' => [],
87
            'exception-responses' => [],
88
            'success-response' => null,
89 13
            'success-response-code' => $defaultResponseCode,
90
            'success-flash-message' => null,
91
        );
92
93
        /** @var mixed $options */
94 13
        $options = array_merge($defaults, $options);
95
96 13
        Assert::null($this->controllerHelper);
97 13
        Assert::true(is_object($options['inner-controller']));
98 12
        Assert::isArray($options['arguments']);
99
100 11
        $this->controllerHelper = $controllerHelper;
101 11
        $this->argumentBuilder = $argumentBuilder;
102 11
        $this->innerController = $options['inner-controller'];
103 11
        $this->innerControllerMethod = $options['inner-controller-method'];
104 11
        $this->innerControllerArgumentsConfiguration = $options['arguments'];
105 11
        $this->successResponse = $options['success-response'];
106 11
        $this->successResponseCode = $options['success-response-code'];
107 11
        $this->successFlashMessage = $options['success-flash-message'];
108
109 11
        foreach ($options['exception-responses'] as $exceptionClass => $responseData) {
110
            /** @var array<string, mixed> $responseData */
111
112 4
            Assert::true(
113 4
                is_subclass_of($exceptionClass, Exception::class) ||
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Exception::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
114 4
                is_subclass_of($exceptionClass, Throwable::class)
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Throwable::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
115
            );
116
117
            /** @var string $responseCode */
118 3
            $responseCode = '500';
119
120 3
            if (isset($responseData['redirect-route'])) {
121 1
                $responseCode = '301';
122
            }
123
124 3
            $responseData = array_merge([
125 3
                'message' => '', # empty => exception message used
126 3
                'code' => $responseCode,
127 3
                'flash-type' => '', # empty => no message triggered
128 3
                'flash-message' => '%s', # empty => exception message used
129
                'redirect-route' => null,
130
                'redirect-route-parameters' => [],
131 3
            ], $responseData);
132
133 3
            $this->exceptionResponses[$exceptionClass] = $responseData;
134
        }
135 10
    }
136
137 9
    public function executeInnerControllerSafely(Request $request): Response
138
    {
139
        /** @var Response|null $response */
140 9
        $response = null;
141
142
        /** @var Response|null $innerResponse */
143 9
        $innerResponse = null;
144
145
        try {
146
            /** @var array<int, mixed> $arguments */
147 9
            $arguments = array();# TODO
148
149 9
            $methodReflection = new ReflectionMethod($this->innerController, $this->innerControllerMethod);
150
151
            /** @var array<int, mixed> $arguments */
152 9
            $arguments = $this->argumentBuilder->buildCallArguments(
153 9
                $methodReflection,
154 9
                $this->innerControllerArgumentsConfiguration,
155 9
                $request
156
            );
157
158 9
            $innerResponse = call_user_func_array([$this->innerController, $this->innerControllerMethod], $arguments);
159
160 5
            Assert::isInstanceOf($innerResponse, Response::class, "Controller did not return an Response object!");
161
162 4
            if (!is_null($this->successFlashMessage)) {
163 1
                $this->controllerHelper->addFlashMessage($this->successFlashMessage, "success");
164
            }
165
166 4
            if (!is_null($this->successResponse)) {
167 2
                $response = new Response($this->successResponse, $this->successResponseCode);
168
169
            } else {
170 4
                $response = $innerResponse;
171
            }
172
173 5
        } catch (Exception $exception) {
174 4
            $this->controllerHelper->handleException($exception);
175
176 4
            foreach ($this->exceptionResponses as $exceptionClass => $responseData) {
177 2
                if (is_a($exception, $exceptionClass)) {
178
                    /** @var string $responseMessage */
179 2
                    $responseMessage = $responseData['message'];
180
181 2
                    if (empty($responseMessage)) {
182 2
                        $responseMessage = $exception->getMessage();
183
                    }
184
185 2
                    if (!empty($responseData['flash-type'])) {
186
                        /** @var string $flashMessage */
187 1
                        $flashMessage = sprintf($responseData['flash-message'], $exception->getMessage());
188
189 1
                        $this->controllerHelper->addFlashMessage($flashMessage, $responseData['flash-type']);
190
                    }
191
192 2
                    if (!empty($responseData['redirect-route'])) {
193 1
                        $response = $this->controllerHelper->redirectToRoute(
194 1
                            $responseData['redirect-route'],
195 1
                            $this->argumentBuilder->buildArguments(
196 1
                                $responseData['redirect-route-parameters'],
197 1
                                $request
198
                            ),
199 1
                            $responseData['code']
200
                        );
201
202
                    } else {
203 2
                        $response = new Response($responseMessage, $responseData['code']);
204
                    }
205
                }
206
            }
207
208 4
            if (is_null($response)) {
209 2
                throw $exception;
210
            }
211
        }
212
213 6
        return $response;
214
    }
215
216
}
217