GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( c64b7f...c8c077 )
by Steeven
03:20
created

Router::handle()   F

Complexity

Conditions 16
Paths 340

Size

Total Lines 88
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 16
eloc 58
c 1
b 1
f 0
nc 340
nop 1
dl 0
loc 88
rs 2.9833

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
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Kernel\Http;
15
16
// ------------------------------------------------------------------------
17
18
/**
19
 * Class Router
20
 * @package O2System\Kernel\Http
21
 */
22
class Router
23
{
24
    /**
25
     * Router::$uri
26
     *
27
     * @var Message\Uri
28
     */
29
    protected $uri;
30
31
    /**
32
     * Router::$addresses
33
     *
34
     * @var Router\Addresses
35
     */
36
    protected $addresses;
37
38
    // ------------------------------------------------------------------------
39
40
    /**
41
     * Router::getUri
42
     *
43
     * Gets routed Uri.
44
     *
45
     * @return Message\Uri
46
     */
47
    public function getUri()
48
    {
49
        return $this->uri;
50
    }
51
52
    // ------------------------------------------------------------------------
53
54
    /**
55
     * Router::getAddresses
56
     *
57
     * @return \O2System\Kernel\Http\Router\Addresses
58
     */
59
    public function getAddresses()
60
    {
61
        return $this->addresses;
62
    }
63
64
    // ------------------------------------------------------------------------
65
66
    /**
67
     * Router::setAddresses
68
     *
69
     * Sets router addresses.
70
     *
71
     * @param \O2System\Kernel\Http\Router\Addresses $addresses
72
     *
73
     * @return static
74
     */
75
    public function setAddresses(Router\Addresses $addresses)
76
    {
77
        $this->addresses = $addresses;
78
79
        return $this;
80
    }
81
82
    // ------------------------------------------------------------------------
83
84
    /**
85
     * Router::handle
86
     *
87
     * @param \O2System\Kernel\Http\Message\Uri|null $uri
88
     *
89
     * @return bool
90
     * @throws \ReflectionException
91
     * @throws \O2System\Spl\Exceptions\RuntimeException
92
     */
93
    public function handle(Message\Uri $uri = null)
94
    {
95
        $this->uri = is_null($uri) ? server_request()->getUri() : $uri;
96
        $uriSegments = $this->uri->segments->getArrayCopy();
97
        $uriString = $this->uri->segments->__toString();
98
99
        if (count($uriSegments)) {
100
            if (strpos(end($uriSegments), '.json') !== false) {
101
                output()->setContentType('application/json');
0 ignored issues
show
Bug introduced by
The method setContentType() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
                output()->/** @scrutinizer ignore-call */ setContentType('application/json');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
102
                $endSegment = str_replace('.json', '', end($uriSegments));
103
                array_pop($uriSegments);
104
                array_push($uriSegments, $endSegment);
105
                $this->uri = $this->uri->withSegments(new Message\Uri\Segments($uriSegments));
106
                $uriString = $this->uri->segments->__toString();
107
            } elseif (strpos(end($uriSegments), '.xml') !== false) {
108
                output()->setContentType('application/xml');
109
                $endSegment = str_replace('.xml', '', end($uriSegments));
110
                array_pop($uriSegments);
111
                array_push($uriSegments, $endSegment);
112
                $this->uri = $this->uri->withSegments(new Message\Uri\Segments($uriSegments));
113
                $uriString = $this->uri->segments->__toString();
114
            }
115
        } else {
116
            $uriPath = urldecode(
117
                parse_url($_SERVER[ 'REQUEST_URI' ], PHP_URL_PATH)
118
            );
119
120
            $uriPathParts = explode('public/', $uriPath);
121
            $uriPath = end($uriPathParts);
122
123
            if ($uriPath !== '/') {
124
                $uriString = $uriPath;
125
                $uriSegments = array_filter(explode('/', $uriString));
126
127
                $this->uri = $this->uri->withSegments(new Message\Uri\Segments($uriSegments));
0 ignored issues
show
Bug introduced by
$uriSegments of type array is incompatible with the type null|string expected by parameter $segments of O2System\Kernel\Http\Mes...Segments::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

127
                $this->uri = $this->uri->withSegments(new Message\Uri\Segments(/** @scrutinizer ignore-type */ $uriSegments));
Loading history...
128
                $uriString = $this->uri->segments->__toString();
129
            }
130
        }
131
132
        // Try to translate from uri string
133
        if (false !== ($action = $this->addresses->getTranslation($uriString))) {
134
            if ( ! $action->isValidHttpMethod(server_request()->getMethod()) && ! $action->isAnyHttpMethod()) {
135
                output()->sendError(405);
136
            } else {
137
                if (false !== ($parseSegments = $action->getParseUriString($uriString))) {
138
                    $uriSegments = $parseSegments;
139
                } else {
140
                    $uriSegments = [];
141
                }
142
143
                $this->uri = $this->uri->withSegments(new Message\Uri\Segments($uriSegments));
0 ignored issues
show
Bug introduced by
$uriSegments of type array|true is incompatible with the type null|string expected by parameter $segments of O2System\Kernel\Http\Mes...Segments::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

143
                $this->uri = $this->uri->withSegments(new Message\Uri\Segments(/** @scrutinizer ignore-type */ $uriSegments));
Loading history...
144
145
                $this->parseAction($action, $uriSegments);
0 ignored issues
show
Bug introduced by
It seems like $uriSegments can also be of type true; however, parameter $uriSegments of O2System\Kernel\Http\Router::parseAction() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
                $this->parseAction($action, /** @scrutinizer ignore-type */ $uriSegments);
Loading history...
Bug introduced by
It seems like $action can also be of type true; however, parameter $action of O2System\Kernel\Http\Router::parseAction() does only seem to accept O2System\Kernel\Http\Router\DataStructures\Action, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
                $this->parseAction(/** @scrutinizer ignore-type */ $action, $uriSegments);
Loading history...
146
147
                if (services()->has('controller')) {
148
                    return true;
149
                }
150
            }
151
        }
152
153
        // Try to get route from controller & page
154
        if ($uriTotalSegments = count($uriSegments)) {
155
            $namespaces = [
156
                'App\Controllers\\',
157
                'App\Http\Controllers\\',
158
                'O2System\Reactor\Http\Controllers\\',
159
            ];
160
161
            for ($i = 0; $i <= $uriTotalSegments; $i++) {
162
                $uriRoutedSegments = array_slice($uriSegments, 0, ($uriTotalSegments - $i));
163
164
                foreach ($namespaces as $namespace) {
165
166
                    $controllerClassName = $namespace . implode('\\',
167
                            array_map('studlycase', $uriRoutedSegments));
168
169
                    if (class_exists($controllerClassName)) {
170
                        $uriSegments = array_diff($uriSegments, $uriRoutedSegments);
171
                        $this->setController(new Router\DataStructures\Controller($controllerClassName),
172
                            $uriSegments);
173
                        break;
174
                    }
175
                }
176
177
                // break the loop if the controller has been set
178
                if (services()->has('controller')) {
179
                    return true;
180
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
181
                }
182
            }
183
        }
184
185
        // Let's the app do the rest when there is no controller found
186
        // the app should redirect to PAGE 404
187
    }
188
189
    // ------------------------------------------------------------------------
190
191
    /**
192
     * Router::parseAction
193
     *
194
     * @param \O2System\Kernel\Http\Router\DataStructures\Action $action
195
     * @param array                                              $uriSegments
196
     *
197
     * @throws \O2System\Spl\Exceptions\RuntimeException
198
     * @throws \ReflectionException
199
     */
200
    protected function parseAction(Router\DataStructures\Action $action, array $uriSegments = [])
201
    {
202
        $closure = $action->getClosure();
203
        if (empty($closure)) {
204
            output()->sendError(204);
205
        }
206
207
        if ($closure instanceof Controller) {
208
            $uriSegments = empty($uriSegments)
209
                ? $action->getClosureParameters()
210
                : $uriSegments;
211
            $this->setController(
212
                (new Router\DataStructures\Controller($closure))
0 ignored issues
show
Bug introduced by
$closure of type O2System\Kernel\Http\Controller is incompatible with the type string expected by parameter $filePath of O2System\Kernel\Http\Rou...ntroller::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

212
                (new Router\DataStructures\Controller(/** @scrutinizer ignore-type */ $closure))
Loading history...
213
                    ->setRequestMethod('index'),
214
                $uriSegments
215
            );
216
        } elseif ($closure instanceof Router\DataStructures\Controller) {
217
            $this->setController($closure, $action->getClosureParameters());
218
        } elseif (is_array($closure)) {
219
            $this->uri = (new Message\Uri())
220
                ->withSegments(new Message\Uri\Segments(''))
221
                ->withQuery('');
222
            $this->handle($this->uri->addSegments($closure));
223
        } else {
224
            if (class_exists($closure)) {
225
                $this->setController(
226
                    (new Router\DataStructures\Controller($closure))
227
                        ->setRequestMethod('index'),
228
                    $uriSegments
229
                );
230
            } elseif (preg_match("/([a-zA-Z0-9\\\]+)(@)([a-zA-Z0-9\\\]+)/", $closure, $matches)) {
231
                $this->setController(
232
                    (new Router\DataStructures\Controller($matches[ 1 ]))
233
                        ->setRequestMethod($matches[ 3 ]),
234
                    $uriSegments
235
                );
236
            } elseif (is_string($closure) && $closure !== '') {
237
                if (is_json($closure)) {
238
                    output()->setContentType('application/json');
239
                    output()->send($closure);
0 ignored issues
show
Bug introduced by
The method send() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

239
                    output()->/** @scrutinizer ignore-call */ send($closure);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
240
                } else {
241
                    output()->send($closure);
242
                }
243
            } elseif (is_array($closure) || is_object($closure)) {
244
                output()->send($closure);
245
            } elseif (is_numeric($closure)) {
246
                output()->sendError($closure);
247
            } else {
248
                output()->sendError(204);
249
                exit(EXIT_ERROR);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
250
            }
251
        }
252
    }
253
254
    // ------------------------------------------------------------------------
255
256
    /**
257
     * Router::setController
258
     *
259
     * @param \O2System\Kernel\Http\Router\DataStructures\Controller $controller
260
     * @param array                                                  $uriSegments
261
     *
262
     * @throws \ReflectionException
263
     */
264
    protected function setController(
265
        Router\DataStructures\Controller $controller,
266
        array $uriSegments = []
267
    ) {
268
        if ( ! $controller->isValid()) {
269
            output()->sendError(400);
270
        }
271
272
        // Add Controller PSR4 Namespace
273
        loader()->addNamespace($controller->getNamespaceName(), $controller->getFileInfo()->getPath());
0 ignored issues
show
Bug introduced by
The function loader was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

273
        /** @scrutinizer ignore-call */ 
274
        loader()->addNamespace($controller->getNamespaceName(), $controller->getFileInfo()->getPath());
Loading history...
274
275
        $controllerMethod = $controller->getRequestMethod();
276
        $controllerMethod = empty($controllerMethod) ? reset($uriSegments) : $controllerMethod;
277
        $controllerMethod = camelcase($controllerMethod);
278
279
        // Set default controller method to index
280
        if ( ! $controller->hasMethod($controllerMethod) &&
281
            ! $controller->hasMethod('route')
282
        ) {
283
            $controllerMethod = 'index';
284
        }
285
286
        // has route method, controller method set to index as default
287
        if (empty($controllerMethod)) {
288
            $controllerMethod = 'index';
289
        }
290
291
        if (camelcase(reset($uriSegments)) === $controllerMethod) {
292
            array_shift($uriSegments);
293
        }
294
295
        $controllerMethodParams = $uriSegments;
296
297
        if ($controller->hasMethod('route')) {
298
            $controller->setRequestMethod('route');
299
            $controller->setRequestMethodArgs([
300
                $controllerMethod,
301
                $controllerMethodParams,
302
            ]);
303
        } elseif ($controller->hasMethod($controllerMethod)) {
304
            $method = $controller->getMethod($controllerMethod);
305
306
            // Method doesn't need any parameters
307
            if ($method->getNumberOfParameters() == 0) {
308
                // But there is parameters requested
309
                if (count($controllerMethodParams)) {
310
                    output()->sendError(404);
311
                } else {
312
                    $controller->setRequestMethod($controllerMethod);
313
                }
314
            } else {
315
                $parameters = [];
316
317
                if (count($controllerMethodParams)) {
318
                    if (is_numeric(key($controllerMethodParams))) {
319
                        $parameters = $controllerMethodParams;
320
                    } else {
321
                        foreach ($method->getParameters() as $index => $parameter) {
322
                            if (isset($uriSegments[ $parameter->name ])) {
323
                                $parameters[ $index ] = $controllerMethodParams[ $parameter->name ];
324
                            } else {
325
                                $parameters[ $index ] = null;
326
                            }
327
                        }
328
                    }
329
                }
330
331
                $controller->setRequestMethod($controllerMethod);
332
                $controller->setRequestMethodArgs($parameters);
333
            }
334
        }
335
336
        // Set Controller
337
        services()->add($controller, 'controller');
338
    }
339
}