Passed
Pull Request — master (#11)
by Joao
01:52
created

HttpRequestHandler::process()   B

Complexity

Conditions 8
Paths 24

Size

Total Lines 74
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 8.0079

Importance

Changes 0
Metric Value
cc 8
eloc 41
c 0
b 0
f 0
nc 24
nop 1
dl 0
loc 74
ccs 38
cts 40
cp 0.95
crap 8.0079
rs 8.0195

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
            );
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
                );
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