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.

Router::handleSegmentsRequest()   A
last analyzed

Complexity

Conditions 6
Paths 8

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 18
nc 8
nop 0
dl 0
loc 30
rs 9.0444
c 0
b 0
f 0
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
use O2System\Kernel\Http\Message\Uri as KernelMessageUri;
19
use O2System\Kernel\Http\Message\Uri\Segments as KernelMessageUriSegments;
20
21
/**
22
 * Class Router
23
 * @package O2System\Kernel\Http
24
 */
25
class Router
26
{
27
    /**
28
     * Router::$uri
29
     *
30
     * @var Message\Uri
31
     */
32
    protected $uri;
33
34
    /**
35
     * Router::$addresses
36
     *
37
     * @var Router\Addresses
38
     */
39
    protected $addresses;
40
41
    // ------------------------------------------------------------------------
42
43
    /**
44
     * Router::getUri
45
     *
46
     * Gets routed Uri.
47
     *
48
     * @return Message\Uri
49
     */
50
    public function getUri()
51
    {
52
        return $this->uri;
53
    }
54
55
    // ------------------------------------------------------------------------
56
57
    /**
58
     * Router::getAddresses
59
     *
60
     * @return \O2System\Kernel\Http\Router\Addresses
61
     */
62
    public function getAddresses()
63
    {
64
        return $this->addresses;
65
    }
66
67
    // ------------------------------------------------------------------------
68
69
    /**
70
     * Router::setAddresses
71
     *
72
     * Sets router addresses.
73
     *
74
     * @param \O2System\Kernel\Http\Router\Addresses $addresses
75
     *
76
     * @return static
77
     */
78
    public function setAddresses(Router\Addresses $addresses)
79
    {
80
        $this->addresses = $addresses;
81
82
        return $this;
83
    }
84
85
    // ------------------------------------------------------------------------
86
87
    /**
88
     * Router::handle
89
     *
90
     * @param \O2System\Kernel\Http\Message\Uri|null $uri
91
     *
92
     * @return bool
93
     * @throws \ReflectionException
94
     * @throws \O2System\Spl\Exceptions\RuntimeException
95
     */
96
    public function handle(Message\Uri $uri = null)
97
    {
98
        $this->uri = is_null($uri) ? new KernelMessageUri() : $uri;
99
100
        // Handle Extension Request
101
        if ($this->uri->segments->count()) {
102
            $this->handleExtensionRequest();
103
        } else {
104
            $uriPath = urldecode(
105
                parse_url($_SERVER[ 'REQUEST_URI' ], PHP_URL_PATH)
106
            );
107
108
            $uriPathParts = explode('public/', $uriPath);
109
            $uriPath = end($uriPathParts);
110
111
            if ($uriPath !== '/') {
112
                $this->uri = $this->uri->withSegments(new KernelMessageUriSegments(
113
                        array_filter(explode('/', $uriPath)))
0 ignored issues
show
Bug introduced by
array_filter(explode('/', $uriPath)) 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

113
                        /** @scrutinizer ignore-type */ array_filter(explode('/', $uriPath)))
Loading history...
114
                );
115
            }
116
117
            unset($uriPathParts, $uriPath);
118
        }
119
120
        // Load app addresses config
121
        $this->addresses = config()->loadFile('addresses', true);
0 ignored issues
show
Bug introduced by
The function config 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

121
        $this->addresses = /** @scrutinizer ignore-call */ config()->loadFile('addresses', true);
Loading history...
122
123
        // Try to translate from uri string
124
        if (false !== ($action = $this->addresses->getTranslation($this->uri->segments->__toString()))) {
125
            if ( ! $action->isValidHttpMethod(input()->server('REQUEST_METHOD')) && ! $action->isAnyHttpMethod()) {
126
                output()->sendError(405);
127
            } else {
128
                // Checks if action closure is an array
129
                if (is_array($closureSegments = $action->getClosure())) {
130
                    $this->uri->segments->exchangeArray($closureSegments);
131
132
                    $this->handleSegmentsRequest();
133
                } else {
134
                    if (false !== ($parseSegments = $action->getParseUriString($this->uri->segments->__toString()))) {
135
                        $uriSegments = $parseSegments;
136
                    } else {
137
                        $uriSegments = [];
138
                    }
139
140
                    $this->uri = $this->uri->withSegments(new KernelMessageUriSegments($uriSegments));
141
142
                    $this->parseAction($action, $uriSegments);
143
                    if ( ! empty(services()->has('controller'))) {
144
                        return true;
145
                    }
146
                }
147
            }
148
        } else {
149
            $this->handleSegmentsRequest();
150
        }
151
152
        // break the loop if the controller has been set
153
        if (services()->has('controller')) {
154
            return true;
155
        }
156
157
        // Let's the app do the rest when there is no controller found
158
        // the app should redirect to PAGE 404
159
    }
160
161
    // ------------------------------------------------------------------------
162
163
    /**
164
     * Router::handleExtensionRequest
165
     */
166
    protected function handleExtensionRequest()
167
    {
168
        $lastSegment = $this->uri->segments->last();
169
170
        if (strpos($lastSegment, '.json') !== false) {
171
            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

171
            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...
172
            $lastSegment = str_replace('.json', '', $lastSegment);
173
            $this->uri->segments->pop();
174
            $this->uri->segments->push($lastSegment);
175
        } elseif (strpos($lastSegment, '.xml') !== false) {
176
            output()->setContentType('application/xml');
177
            $lastSegment = str_replace('.xml', '', $lastSegment);
178
            $this->uri->segments->pop();
179
            $this->uri->segments->push($lastSegment);
180
        } elseif (strpos($lastSegment, '.js') !== false) {
181
            output()->setContentType('application/x-javascript');
182
            $lastSegment = str_replace('.js', '', $lastSegment);
183
            $this->uri->segments->pop();
184
            $this->uri->segments->push($lastSegment);
185
        } elseif (strpos($lastSegment, '.css') !== false) {
186
            output()->setContentType('text/css');
187
            $lastSegment = str_replace('.css', '', $lastSegment);
188
            $this->uri->segments->pop();
189
            $this->uri->segments->push($lastSegment);
190
        }
191
    }
192
193
    // ------------------------------------------------------------------------
194
195
    /**
196
     * Router::handleModuleRequest
197
     */
198
    public function handleSegmentsRequest()
199
    {
200
        // Try to get route from controller
201
        if ($numOfUriSegments = $this->uri->segments->count()) {
202
            $uriSegments = $this->uri->segments->getArrayCopy();
203
204
            $namespaces = [
205
                'App\Controllers\\',
206
                'App\Http\Controllers\\',
207
                'O2System\Reactor\Http\Controllers\\',
208
            ];
209
210
            for ($i = 0; $i <= $numOfUriSegments; $i++) {
211
                $uriRoutedSegments = array_slice($uriSegments, 0, ($numOfUriSegments - $i));
212
213
                foreach ($namespaces as $namespace) {
214
                    $controllerClassName = $namespace . implode('\\',
215
                            array_map('studlycase', $uriRoutedSegments));
216
217
                    if (class_exists($controllerClassName)) {
218
                        $uriSegments = array_diff($uriSegments, $uriRoutedSegments);
219
                        $this->setController(new Router\DataStructures\Controller($controllerClassName),
220
                            $uriSegments);
221
                        break;
222
                    }
223
                }
224
225
                // break the loop if the controller has been set
226
                if (services()->has('controller')) {
227
                    break;
228
                }
229
            }
230
        }
231
    }
232
233
    // ------------------------------------------------------------------------
234
235
    /**
236
     * Router::parseAction
237
     *
238
     * @param \O2System\Kernel\Http\Router\DataStructures\Action $action
239
     * @param array                                              $uriSegments
240
     *
241
     * @throws \O2System\Spl\Exceptions\RuntimeException
242
     * @throws \ReflectionException
243
     */
244
    protected function parseAction(Router\DataStructures\Action $action, array $uriSegments = [])
245
    {
246
        $closure = $action->getClosure();
247
        if (empty($closure)) {
248
            output()->sendError(204);
249
        }
250
251
        if ($closure instanceof Controller) {
252
            $uriSegments = empty($uriSegments)
253
                ? $action->getClosureParameters()
254
                : $uriSegments;
255
            $this->setController(
256
                (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

256
                (new Router\DataStructures\Controller(/** @scrutinizer ignore-type */ $closure))
Loading history...
257
                    ->setRequestMethod('index'),
258
                $uriSegments
259
            );
260
        } elseif ($closure instanceof Router\DataStructures\Controller) {
261
            $this->setController($closure, $action->getClosureParameters());
262
        } elseif (is_array($closure)) {
263
            $this->uri = (new Message\Uri())
264
                ->withSegments(new Message\Uri\Segments(''))
265
                ->withQuery('');
266
            $this->handle($this->uri->addSegments($closure));
267
        } else {
268
            if (class_exists($closure)) {
269
                $this->setController(
270
                    (new Router\DataStructures\Controller($closure))
271
                        ->setRequestMethod('index'),
272
                    $uriSegments
273
                );
274
            } elseif (preg_match("/([a-zA-Z0-9\\\]+)(@)([a-zA-Z0-9\\\]+)/", $closure, $matches)) {
275
                $this->setController(
276
                    (new Router\DataStructures\Controller($matches[ 1 ]))
277
                        ->setRequestMethod($matches[ 3 ]),
278
                    $uriSegments
279
                );
280
            } elseif (is_string($closure) && $closure !== '') {
281
                if (is_json($closure)) {
282
                    output()->setContentType('application/json');
283
                    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

283
                    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...
284
                } else {
285
                    output()->send($closure);
286
                }
287
            } elseif (is_array($closure) || is_object($closure)) {
288
                output()->send($closure);
289
            } elseif (is_numeric($closure)) {
290
                output()->sendError($closure);
291
            } else {
292
                output()->sendError(204);
293
                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...
294
            }
295
        }
296
    }
297
298
    // ------------------------------------------------------------------------
299
300
    /**
301
     * Router::setController
302
     *
303
     * @param \O2System\Kernel\Http\Router\DataStructures\Controller $controller
304
     * @param array                                                  $uriSegments
305
     *
306
     * @throws \ReflectionException
307
     */
308
    protected function setController(
309
        Router\DataStructures\Controller $controller,
310
        array $uriSegments = []
311
    ) {
312
        if ( ! $controller->isValid()) {
313
            output()->sendError(400);
314
        }
315
316
        // Add Controller PSR4 Namespace
317
        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

317
        /** @scrutinizer ignore-call */ 
318
        loader()->addNamespace($controller->getNamespaceName(), $controller->getFileInfo()->getPath());
Loading history...
318
319
        $controllerMethod = $controller->getRequestMethod();
320
        $controllerMethod = empty($controllerMethod) ? reset($uriSegments) : $controllerMethod;
321
        $controllerMethod = camelcase($controllerMethod);
322
323
        // Set default controller method to index
324
        if ( ! $controller->hasMethod($controllerMethod) &&
325
            ! $controller->hasMethod('route')
326
        ) {
327
            $controllerMethod = 'index';
328
        }
329
330
        // has route method, controller method set to index as default
331
        if (empty($controllerMethod)) {
332
            $controllerMethod = 'index';
333
        }
334
335
        if (camelcase(reset($uriSegments)) === $controllerMethod) {
336
            array_shift($uriSegments);
337
        }
338
339
        $controllerMethodParams = $uriSegments;
340
341
        if ($controller->hasMethod('route')) {
342
            $controller->setRequestMethod('route');
343
            $controller->setRequestMethodArgs([
344
                $controllerMethod,
345
                $controllerMethodParams,
346
            ]);
347
        } elseif ($controller->hasMethod($controllerMethod)) {
348
            $method = $controller->getMethod($controllerMethod);
349
350
            // Method doesn't need any parameters
351
            if ($method->getNumberOfParameters() == 0) {
352
                // But there is parameters requested
353
                if (count($controllerMethodParams)) {
354
                    output()->sendError(404);
355
                } else {
356
                    $controller->setRequestMethod($controllerMethod);
357
                }
358
            } else {
359
                $parameters = [];
360
361
                if (count($controllerMethodParams)) {
362
                    if (is_numeric(key($controllerMethodParams))) {
363
                        $parameters = $controllerMethodParams;
364
                    } else {
365
                        foreach ($method->getParameters() as $index => $parameter) {
366
                            if (isset($uriSegments[ $parameter->name ])) {
367
                                $parameters[ $index ] = $controllerMethodParams[ $parameter->name ];
368
                            } else {
369
                                $parameters[ $index ] = null;
370
                            }
371
                        }
372
                    }
373
                }
374
375
                $controller->setRequestMethod($controllerMethod);
376
                $controller->setRequestMethodArgs($parameters);
377
            }
378
        }
379
380
        // Set Controller
381
        services()->add($controller, 'controller');
382
    }
383
}