HttpRequestHandler::process()   B
last analyzed

Complexity

Conditions 8
Paths 24

Size

Total Lines 74
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 8.0069

Importance

Changes 0
Metric Value
cc 8
eloc 41
nc 24
nop 1
dl 0
loc 74
ccs 40
cts 42
cp 0.9524
crap 8.0069
rs 8.0195
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
namespace ByJG\RestServer;
4
5
use ByJG\RestServer\Exception\ClassNotFoundException;
6
use ByJG\RestServer\Exception\Error404Exception;
7
use ByJG\RestServer\Exception\Error405Exception;
8
use ByJG\RestServer\Exception\Error520Exception;
9
use ByJG\RestServer\Exception\InvalidClassException;
10
use ByJG\RestServer\Middleware\AfterMiddlewareInterface;
11
use ByJG\RestServer\Middleware\BeforeMiddlewareInterface;
12
use ByJG\RestServer\Middleware\MiddlewareManagement;
13
use ByJG\RestServer\Middleware\MiddlewareResult;
14
use ByJG\RestServer\OutputProcessor\BaseOutputProcessor;
15
use ByJG\RestServer\OutputProcessor\OutputProcessorInterface;
16
use ByJG\RestServer\Route\RouteListInterface;
17
use ByJG\RestServer\Writer\HttpWriter;
18
use ByJG\RestServer\Writer\WriterInterface;
19
use Closure;
20
use FastRoute\Dispatcher;
21
use InvalidArgumentException;
22
23
class HttpRequestHandler implements RequestHandler
24
{
25
    const OK = "OK";
26
    const METHOD_NOT_ALLOWED = "NOT_ALLOWED";
27
    const NOT_FOUND = "NOT FOUND";
28
29
    protected $useErrorHandler = true;
30
    protected $detailedErrorHandler = false;
31
32
    protected $defaultOutputProcessor = null;
33
    protected $defaultOutputProcessorArgs = [];
34
35
    protected $afterMiddlewareList = [];
36
    protected $beforeMiddlewareList = [];
37
38
    protected $httpRequest = null;
39
    protected $httpResponse = null;
40
41
    /** @var WriterInterface */
42
    protected $writer;
43
44 16
    public function __construct()
45
    {
46 16
        $this->writer = new HttpWriter();
47
    }
48
49
    /**
50
     * @param RouteListInterface $routeDefinition
51
     * @return bool
52
     * @throws ClassNotFoundException
53
     * @throws Error404Exception
54
     * @throws Error405Exception
55
     * @throws Error520Exception
56
     * @throws InvalidClassException
57
     */
58 12
    protected function process(RouteListInterface $routeDefinition)
59
    {
60
        // Initialize ErrorHandler with default error handler
61 12
        if ($this->useErrorHandler) {
62 12
            ErrorHandler::getInstance()->register();
63
        }
64
65
        // Get the URL parameters
66 12
        $httpMethod = $this->getHttpRequest()->server('REQUEST_METHOD');
67 12
        $uri = parse_url($this->getHttpRequest()->server('REQUEST_URI'), PHP_URL_PATH);
68 12
        $query = parse_url($this->getHttpRequest()->server('REQUEST_URI'), PHP_URL_QUERY);
69 12
        $queryStr = [];
70 12
        if (!empty($query)) {
71
            parse_str($query, $queryStr);
72
        }
73
74
        // Generic Dispatcher for RestServer
75 12
        $dispatcher = $routeDefinition->getDispatcher();
76 12
        $routeInfo = $dispatcher->dispatch($httpMethod, $uri);
77
78
        // Get OutputProcessor
79 12
        $outputProcessor = $this->initializeProcessor();
80
        
81
        // Process Before Middleware
82
        try {
83 12
            $middlewareResult = MiddlewareManagement::processBefore(
84 12
                $this->beforeMiddlewareList,
85 12
                $routeInfo[0],
86 12
                $this->getHttpResponse(),
87 12
                $this->getHttpRequest()
88 12
            );
89 2
        } catch (\Exception $ex) {
90 2
            $outputProcessor->processResponse($this->getHttpResponse());
91 2
            throw $ex;
92
        }
93
        
94 10
        if ($middlewareResult->getStatus() != MiddlewareResult::CONTINUE) {
95 2
            $outputProcessor->processResponse($this->getHttpResponse());
96 2
            return true;
97
        }
98
99
        // Processing
100 8
        switch ($routeInfo[0]) {
101 8
            case Dispatcher::NOT_FOUND:
102 1
                $outputProcessor->processResponse($this->getHttpResponse());
103 1
                throw new Error404Exception("Route '$uri' not found");
104
105 7
            case Dispatcher::METHOD_NOT_ALLOWED:
106 1
                $outputProcessor->processResponse($this->getHttpResponse());
107 1
                throw new Error405Exception('Method not allowed');
108
109 6
            case Dispatcher::FOUND:
110
                // ... 200 Process:
111 6
                $vars = array_merge($routeInfo[2], $queryStr);
112
113
                // Get the Selected Route
114 6
                $selectedRoute = $routeInfo[1];
115
116
                // Class
117 6
                $class = $selectedRoute["class"];
118 6
                $this->getHttpRequest()->appendVars($vars);
119
120
                // Get OutputProcessor
121 6
                $outputProcessor = $this->initializeProcessor(
122 6
                    $selectedRoute["output_processor"]
123 6
                );
124
                
125
                // Execute the request
126 6
                $this->executeRequest($outputProcessor, $class);
127
128 5
                break;
129
130
            default:
131
                throw new Error520Exception('Unknown');
132
        }
133
    }
134
135 12
    protected function initializeProcessor($class = null)
136
    {
137 12
        if (!empty($class)) {
138
            $outputProcessor = BaseOutputProcessor::getFromClassName($class);
139 12
        } elseif (!empty($this->defaultOutputProcessor)) {
140 12
            $outputProcessor = BaseOutputProcessor::getFromClassName($this->defaultOutputProcessor);
141
        } else {
142
            $outputProcessor = BaseOutputProcessor::getFromHttpAccept();
143
        }
144 12
        $outputProcessor->setWriter($this->writer);
145 12
        $outputProcessor->writeContentType();
146 12
        if ($this->detailedErrorHandler) {
147
            ErrorHandler::getInstance()->setHandler($outputProcessor->getDetailedErrorHandler());
148
        } else {
149 12
            ErrorHandler::getInstance()->setHandler($outputProcessor->getErrorHandler());
150
        }
151
152 12
        ErrorHandler::getInstance()->setOutputProcessor($outputProcessor, $this->getHttpResponse());
153
        
154 12
        return $outputProcessor;
155
    }
156
157
    /**
158
     * Undocumented function
159
     *
160
     * @return HttpRequest
161
     */
162 12
    protected function getHttpRequest()
163
    {
164 12
        if (is_null($this->httpRequest)) {
165 12
            $this->httpRequest = new HttpRequest($_GET, $_POST, $_SERVER, isset($_SESSION) ? $_SESSION : [], $_COOKIE);
166
        }
167
168 12
        return $this->httpRequest;
169
    }
170
171
    /**
172
     * Undocumented function
173
     *
174
     * @return HttpResponse
175
     */
176 12
    protected function getHttpResponse()
177
    {
178 12
        if (is_null($this->httpResponse)) {
179 12
            $this->httpResponse = new HttpResponse();
180
        }
181
182 12
        return $this->httpResponse;
183
    }
184
185
    /**
186
     * @param OutputProcessorInterface $outputProcessor
187
     * @param $class
188
     * @throws ClassNotFoundException
189
     * @throws InvalidClassException
190
     */
191 6
    protected function executeRequest(
192
        OutputProcessorInterface $outputProcessor,
193
        $class
194
    )
195
    {
196
        // Process Closure
197 6
        if ($class instanceof Closure) {
198 5
            $class($this->getHttpResponse(), $this->getHttpRequest());
199 5
            $outputProcessor->processResponse($this->getHttpResponse());
200 5
            return;
201
        }
202
203
        // Process Class::Method()
204 1
        $function = $class[1];
205 1
        $class =  $class[0];
206 1
        if (!class_exists($class)) {
207 1
            throw new ClassNotFoundException("Class '$class' defined in the route is not found");
208
        }
209
        $instance = new $class();
210
        if (!method_exists($instance, $function)) {
211
            throw new InvalidClassException("There is no method '$class::$function''");
212
        }
213
        $instance->$function($this->getHttpResponse(), $this->getHttpRequest());
214
215
        MiddlewareManagement::processAfter(
216
            $this->afterMiddlewareList,
217
            $this->getHttpResponse(),
218
            $this->getHttpRequest()
219
        );
220
        
221
        $outputProcessor->processResponse($this->getHttpResponse());
222
    }
223
224
    /**
225
     * Handle the ROUTE (see web/app-dist.php)
226
     *
227
     * @param RouteListInterface $routeDefinition
228
     * @param bool $outputBuffer
229
     * @param bool $session
230
     * @return bool|void
231
     * @throws ClassNotFoundException
232
     * @throws Error404Exception
233
     * @throws Error405Exception
234
     * @throws Error520Exception
235
     * @throws InvalidClassException
236
     */
237 12
    public function handle(RouteListInterface $routeDefinition, $outputBuffer = true, $session = false)
238
    {
239 12
        if ($outputBuffer) {
240 12
            ob_start();
241
        }
242 12
        if ($session) {
243
            session_start();
244
        }
245
246
        // --------------------------------------------------------------------------
247
        // Check if script exists or if is itself
248
        // --------------------------------------------------------------------------
249 12
        return $this->process($routeDefinition);
250
    }
251
252
    public function withErrorHandlerDisabled()
253
    {
254
        $this->useErrorHandler = false;
255
        return $this;
256
    }
257
258
    public function withDetailedErrorHandler()
259
    {
260
        $this->detailedErrorHandler = true;
261
        return $this;
262
    }
263
264 6
    public function withMiddleware($middleware)
265
    {
266 6
        if ($middleware instanceof BeforeMiddlewareInterface) {
267 6
            $this->beforeMiddlewareList[] = $middleware;
268
        }
269 6
        if ($middleware instanceof AfterMiddlewareInterface) {
270
            $this->afterMiddlewareList[] = $middleware;
271
        }
272
273 6
        return $this;
274
    }
275
276 12
    public function withDefaultOutputProcessor($processor, $args = [])
277
    {
278 12
        if (!($processor instanceof \Closure)) {
279 12
            if (!is_string($processor)) {
280
                throw new InvalidArgumentException("Default processor needs to class name of an OutputProcessor");
281
            }
282 12
            if (!is_subclass_of($processor, BaseOutputProcessor::class)) {
283
                throw new InvalidArgumentException("Needs to be a class of " . BaseOutputProcessor::class);
284
            }
285
        }
286
287 12
        $this->defaultOutputProcessor = $processor;
288
289 12
        return $this;
290
    }
291
292 12
    public function withWriter(WriterInterface $writer)
293
    {
294 12
        $this->writer = $writer;
295 12
        return $this;
296
    }
297
}
298