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

HttpRequestHandler::process()   B

Complexity

Conditions 7
Paths 20

Size

Total Lines 58
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 7.0145

Importance

Changes 0
Metric Value
cc 7
eloc 30
nc 20
nop 1
dl 0
loc 58
ccs 28
cts 30
cp 0.9333
crap 7.0145
rs 8.5066
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\OutputProcessor\BaseOutputProcessor;
11
use ByJG\RestServer\OutputProcessor\OutputProcessorInterface;
12
use ByJG\RestServer\Route\RouteDefinition;
13
use ByJG\RestServer\Route\RouteDefinitionInterface;
14
use Closure;
15
use FastRoute\Dispatcher;
16
17
class HttpRequestHandler implements RequestHandler
18
{
19
    const OK = "OK";
20
    const METHOD_NOT_ALLOWED = "NOT_ALLOWED";
21
    const NOT_FOUND = "NOT FOUND";
22
23
    protected $useErrorHandler = true;
24
25
    /**
26
     * @param RouteDefinitionInterface $routeDefinition
27
     * @return bool
28
     * @throws ClassNotFoundException
29
     * @throws Error404Exception
30
     * @throws Error405Exception
31
     * @throws Error520Exception
32
     * @throws InvalidClassException
33
     */
34 7
    protected function process(RouteDefinitionInterface $routeDefinition)
35
    {
36
        // Initialize ErrorHandler with default error handler
37 7
        if ($this->useErrorHandler) {
38 7
            ErrorHandler::getInstance()->register();
39
        }
40
41
        // Get HttpRequest
42 7
        $request = $this->getHttpRequest();
43
44
        // Get the URL parameters
45 7
        $httpMethod = $request->server('REQUEST_METHOD');
46 7
        $uri = parse_url($request->server('REQUEST_URI'), PHP_URL_PATH);
47 7
        $query = parse_url($request->server('REQUEST_URI'), PHP_URL_QUERY);
48 7
        $queryStr = [];
49 7
        if (!empty($query)) {
50
            parse_str($query, $queryStr);
51
        }
52
53
        // Generic Dispatcher for RestServer
54 7
        $dispatcher = $routeDefinition->getDispatcher();
55
56 7
        $routeInfo = $dispatcher->dispatch($httpMethod, $uri);
57
58
        // Processing
59 7
        switch ($routeInfo[0]) {
60 7
            case Dispatcher::NOT_FOUND:
61 3
                if ($this->tryDeliveryPhysicalFile() === false) {
62 2
                    $this->prepareToOutput();
63 2
                    throw new Error404Exception("Route '$uri' not found");
64
                }
65 1
                return true;
66
67 4
            case Dispatcher::METHOD_NOT_ALLOWED:
68 1
                $this->prepareToOutput();
69 1
                throw new Error405Exception('Method not allowed');
70
71 3
            case Dispatcher::FOUND:
72
                // ... 200 Process:
73 3
                $vars = array_merge($routeInfo[2], $queryStr);
74
75
                // Get the Selected Route
76 3
                $selectedRoute = $routeInfo[1];
77
78
                // Default Handler for errors and
79 3
                $outputProcessor = $this->prepareToOutput($selectedRoute["output_processor"]);
80
81
                // Class
82 3
                $class = $selectedRoute["class"];
83 3
                $request->appendVars($vars);
84
85
                // Execute the request
86 3
                $this->executeRequest($outputProcessor, $class, $request);
87
88 2
                break;
89
90
            default:
91
                throw new Error520Exception('Unknown');
92
        }
93
    }
94
95 6
    protected function prepareToOutput($class = null)
96
    {
97 6
        if (empty($class)) {
98 3
            $outputProcessor = BaseOutputProcessor::getFromHttpAccept();
99
        } else {
100 3
            $outputProcessor = BaseOutputProcessor::getFromClassName($class);
101
        }
102 6
        $outputProcessor->writeContentType();
103 6
        ErrorHandler::getInstance()->setHandler($outputProcessor->getErrorHandler());
104
105 6
        return $outputProcessor;
106
    }
107
108 7
    protected function getHttpRequest()
109
    {
110 7
        return new HttpRequest($_GET, $_POST, $_SERVER, isset($_SESSION) ? $_SESSION : [], $_COOKIE);
111
    }
112
113
    /**
114
     * @param OutputProcessorInterface $outputProcessor
115
     * @param $class
116
     * @param HttpRequest $request
117
     * @throws ClassNotFoundException
118
     * @throws InvalidClassException
119
     */
120 3
    protected function executeRequest(OutputProcessorInterface $outputProcessor, $class, HttpRequest $request)
121
    {
122
        // Create the Request and Response methods
123 3
        $response = new HttpResponse();
124
125
        // Process Closure
126 3
        if ($class instanceof Closure) {
127 2
            $class($response, $request);
128 2
            $outputProcessor->processResponse($response);
129 2
            return;
130
        }
131
132
        // Process Class::Method()
133 1
        $function = $class[1];
134 1
        $class =  $class[0];
135 1
        if (!class_exists($class)) {
136 1
            throw new ClassNotFoundException("Class '$class' defined in the route is not found");
137
        }
138
        $instance = new $class();
139
        if (!method_exists($instance, $function)) {
140
            throw new InvalidClassException("There is no method '$class::$function''");
141
        }
142
        $instance->$function($response, $request);
143
        $outputProcessor->processResponse($response);
144
    }
145
146
    /**
147
     * Handle the ROUTE (see web/app-dist.php)
148
     *
149
     * @param RouteDefinitionInterface $routeDefinition
150
     * @param bool $outputBuffer
151
     * @param bool $session
152
     * @return bool|void
153
     * @throws ClassNotFoundException
154
     * @throws Error404Exception
155
     * @throws Error405Exception
156
     * @throws Error520Exception
157
     * @throws InvalidClassException
158
     */
159 7
    public function handle(RouteDefinitionInterface $routeDefinition, $outputBuffer = true, $session = false)
160
    {
161 7
        if ($outputBuffer) {
162
            ob_start();
163
        }
164 7
        if ($session) {
165
            session_start();
166
        }
167
168
        // --------------------------------------------------------------------------
169
        // Check if script exists or if is itself
170
        // --------------------------------------------------------------------------
171 7
        return $this->process($routeDefinition);
172
    }
173
174
    /**
175
     * @return bool
176
     * @throws Error404Exception
177
     */
178 3
    protected function tryDeliveryPhysicalFile()
179
    {
180 3
        $file = $_SERVER['SCRIPT_FILENAME'];
181 3
        if (!empty($file) && file_exists($file)) {
182 3
            $mime = $this->mimeContentType($file);
183
184 3
            if ($mime === false) {
0 ignored issues
show
introduced by
The condition $mime === false is always false.
Loading history...
185 2
                return false;
186
            }
187
188 1
            if (!defined("RESTSERVER_TEST")) {
189
                header("Content-Type: $mime");
190
            }
191 1
            echo file_get_contents($file);
192 1
            return true;
193
        }
194
195
        return false;
196
    }
197
198
    /**
199
     * Get the Mime Type based on the filename
200
     *
201
     * @param string $filename
202
     * @return string
203
     * @throws Error404Exception
204
     */
205 7
    protected function mimeContentType($filename)
206
    {
207
        $prohibitedTypes = [
208
            "php",
209
            "vb",
210
            "cs",
211
            "rb",
212
            "py",
213
            "py3",
214
            "lua"
215
        ];
216
217
        $mimeTypes = [
218
            'txt' => 'text/plain',
219
            'htm' => 'text/html',
220
            'html' => 'text/html',
221
            'css' => 'text/css',
222
            'js' => 'application/javascript',
223
            'json' => 'application/json',
224
            'xml' => 'application/xml',
225
            'swf' => 'application/x-shockwave-flash',
226
            'flv' => 'video/x-flv',
227
            // images
228
            'png' => 'image/png',
229
            'jpe' => 'image/jpeg',
230
            'jpeg' => 'image/jpeg',
231
            'jpg' => 'image/jpeg',
232
            'gif' => 'image/gif',
233
            'bmp' => 'image/bmp',
234
            'ico' => 'image/vnd.microsoft.icon',
235
            'tiff' => 'image/tiff',
236
            'tif' => 'image/tiff',
237
            'svg' => 'image/svg+xml',
238
            'svgz' => 'image/svg+xml',
239
            // archives
240
            'zip' => 'application/zip',
241
            'rar' => 'application/x-rar-compressed',
242
            'exe' => 'application/x-msdownload',
243
            'msi' => 'application/x-msdownload',
244
            'cab' => 'application/vnd.ms-cab-compressed',
245
            // audio/video
246
            'mp3' => 'audio/mpeg',
247
            'qt' => 'video/quicktime',
248
            'mov' => 'video/quicktime',
249
            // adobe
250
            'pdf' => 'application/pdf',
251
            'psd' => 'image/vnd.adobe.photoshop',
252
            'ai' => 'application/postscript',
253
            'eps' => 'application/postscript',
254
            'ps' => 'application/postscript',
255
            // ms office
256
            'doc' => 'application/msword',
257
            'rtf' => 'application/rtf',
258
            'xls' => 'application/vnd.ms-excel',
259
            'ppt' => 'application/vnd.ms-powerpoint',
260
            // open office
261
            'odt' => 'application/vnd.oasis.opendocument.text',
262
            'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
263
        ];
264
265 7
        if (!file_exists($filename)) {
266 1
            throw new Error404Exception();
267
        }
268
269 6
        $ext = substr(strrchr($filename, "."), 1);
270 6
        if (!in_array($ext, $prohibitedTypes)) {
271 4
            if (array_key_exists($ext, $mimeTypes)) {
272 4
                return $mimeTypes[$ext];
273
            } elseif (function_exists('finfo_open')) {
274
                $finfo = finfo_open(FILEINFO_MIME);
275
                $mimetype = finfo_file($finfo, $filename);
276
                finfo_close($finfo);
277
                return $mimetype;
278
            }
279
        }
280
281 2
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
282
    }
283
}
284