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.
Completed
Push — master ( 666d58...4a7ff2 )
by やかみ
04:05
created

Route::dispatch()   F

Complexity

Conditions 18
Paths 261

Size

Total Lines 109
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 13
Bugs 0 Features 0
Metric Value
cc 18
eloc 63
nc 261
nop 0
dl 0
loc 109
ccs 0
cts 61
cp 0
crap 342
rs 3.6714
c 13
b 0
f 0

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
 * Kotori.php
4
 *
5
 * A Tiny Model-View-Controller PHP Framework
6
 *
7
 * This content is released under the Apache 2 License
8
 *
9
 * Copyright (c) 2015-2017 Kotori Technology. All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
24
/**
25
 * Route class
26
 *
27
 * Parses URIs and determines routing
28
 *
29
 * @package     Kotori
30
 * @subpackage  Http
31
 * @author      Kokororin
32
 * @link        https://kotori.love
33
 */
34
namespace Kotori\Http;
35
36
use Kotori\Core\Container;
37
use Kotori\Core\Helper;
38
use Kotori\Core\Middleware;
39
use Kotori\Debug\Hook;
40
use Kotori\Exception\ConfigException;
41
use Kotori\Exception\NotFoundException;
42
use Kotori\Exception\RouteNotFoundException;
43
use ReflectionClass;
44
use Symfony\Component\Finder\Finder;
45
use zpt\anno\Annotations;
46
47
class Route
48
{
49
    /**
50
     * Controllers Array
51
     *
52
     * @var array
53
     */
54
    protected $controllers = [];
55
56
    /**
57
     * Current controller
58
     *
59
     * @var string
60
     */
61
    protected $controller;
62
63
    /**
64
     * Current action
65
     *
66
     * @var string
67
     */
68
    protected $action;
69
70
    /**
71
     * Current URI string
72
     *
73
     * @var mixed
74
     */
75
    protected $uri = '';
76
77
    /**
78
     * Parsed URI Array
79
     *
80
     * @var array
81
     */
82
    protected $uris = [];
83
84
    /**
85
     * Parsed params
86
     *
87
     * @var array
88
     */
89
    protected $params = [];
90
91
    /**
92
     * Parsed routes
93
     *
94
     * @var array
95
     */
96
    protected $routes = [];
97
98
    /**
99
     * Class constructor
100
     *
101
     * Initialize route class.
102
     *
103
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
104
     */
105 1
    public function __construct()
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
106
    {
107 1
        if (Container::get('request')->isCli()) {
108 1
            $this->uri = $this->parseArgv();
109
        } else {
110
            if (isset($_GET['_i'])) {
111
                $_SERVER['PATH_INFO'] = $_GET['_i'];
112
            }
113
114
            $_SERVER['PATH_INFO'] = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO']
115
            : (isset($_SERVER['ORIG_PATH_INFO']) ? $_SERVER['ORIG_PATH_INFO']
116
                : (isset($_SERVER['REDIRECT_PATH_INFO']) ? $_SERVER['REDIRECT_PATH_INFO'] : ''));
117
118
            $this->uri = $_SERVER['PATH_INFO'];
119
        }
120
121 1
        if (substr($this->uri, 0, 1) == '/') {
122
            $this->uri = ltrim($this->uri, '/');
123
        }
124
125 1
        if (trim($this->uri, '/') == '') {
126
            $this->uri = '/';
127
        }
128
129 1
        Hook::listen(__CLASS__);
130 1
    }
131
132
    /**
133
     * Map URL to controller and action
134
     *
135
     * @return void
136
     *
137
     * @throws \Kotori\Exception\RouteNotFoundException
138
     * @throws \Kotori\Exception\NotFoundException
139
     */
140
    public function dispatch()
0 ignored issues
show
Coding Style introduced by
dispatch uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
dispatch uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
dispatch uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
dispatch uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
dispatch uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
141
    {
142
        if (strtolower(Container::get('config')->get('url_mode')) == 'query_string') {
143
            $this->uri = explode('?', $this->uri, 2);
144
            $_SERVER['QUERY_STRING'] = isset($this->uri[1]) ? $this->uri[1] : '';
145
            $this->uri = $this->uri[0];
146
            parse_str($_SERVER['QUERY_STRING'], $_GET);
147
        }
148
149
        if ($this->uri == 'favicon.ico') {
150
            return Container::get('response')->setStatus(404);
151
        }
152
153
        Middleware::register('before_route');
154
        $parsedRoute = $this->parseRoutes($this->uri);
155
        Middleware::register('after_route');
156
157
        if ($parsedRoute) {
158
            $this->uri = $parsedRoute;
159
        } else {
160
            if (Container::get('request')->isOptions()) {
161
                Container::get('response')->setStatus(204);
162
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method dispatch() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
163
            }
164
165
            throw new RouteNotFoundException('Request URI ' . $this->uri . ' is not Matched by any route.');
166
        }
167
168
        $this->uris = ($this->uri != '') ? explode('/', trim($this->uri, '/')) : [];
169
170
        // Clean uris
171
        foreach ($this->uris as $key => $value) {
172
            if ($value == '') {
173
                unset($this->uris[$key]);
174
            }
175
        }
176
177
        $this->uris = array_merge($this->uris);
178
179
        $this->controller = $this->getController();
180
        $this->action = $this->getAction();
181
182
        // If is already initialized
183
        $prefix = Container::get('config')->get('namespace_prefix');
184
185
        $controllerClassName = $prefix . 'controllers\\' . $this->controller;
186
187
        Middleware::register('before_controller');
188
189
        if (isset($this->controllers[$this->controller])) {
190
            $class = $this->controllers[$this->controller];
191
        } else {
192
            $class = new $controllerClassName();
193
            $this->controllers[$this->controller] = $class;
194
        }
195
196
        Middleware::register('after_controller');
197
198
        if (!class_exists($controllerClassName)) {
199
            throw new NotFoundException('Request Controller ' . $this->controller . ' is not Found.');
200
        }
201
202
        if (!method_exists($class, $this->action)) {
203
            throw new NotFoundException('Request Action ' . $this->action . ' is not Found.');
204
        }
205
206
        $callback = [$class, $this->action];
207
        if (!is_callable($callback)) {
208
            throw new NotFoundException($controllerClassName . '::' . $this->action . '() is not callable');
209
        }
210
211
        // Parse params from uri
212
        $this->params = $this->getParams();
213
214
        // Do some final cleaning of the params
215
        $_GET = array_merge($this->params, $_GET);
216
        $_REQUEST = array_merge($_POST, $_GET, $_COOKIE);
217
218
        if (Container::get('config')->get('app_debug')) {
219
            Container::get('response')->setHeader('X-Kotori-Hash', call_user_func(function () {
220
                $lockFile = Helper::getComposerVendorPath() . '/../composer.lock';
221
                if (!Helper::isFile($lockFile)) {
222
                    return 'unknown';
223
                } else {
224
                    $lockData = file_get_contents($lockFile);
225
                    $lockData = json_decode($lockData, true);
226
                    foreach ($lockData['packages'] as $package) {
227
                        if ($package['name'] == 'kokororin/kotori-php') {
228
                            return substr($package['source']['reference'], 0, 6);
229
                        }
230
                    }
231
                }
232
233
                return 'unknown';
234
            }));
235
        }
236
237
        Middleware::register('before_action');
238
        // Call the requested method
239
240
        $methodInstances = $this->getMethodInstances($callback[0], $callback[1]);
241
        if (!$methodInstances) {
242
            call_user_func_array($callback, $this->params);
243
        } else {
244
            call_user_func_array($callback, $methodInstances);
245
        }
246
247
        Middleware::register('after_action');
248
    }
249
250
    /**
251
     * Returns the controller name
252
     *
253
     * @return      string
254
     *
255
     * @throws \Kotori\Exception\NotFoundException
256
     */
257
    public function getController()
258
    {
259
        if (isset($this->uris[0]) && '' !== $this->uris[0]) {
260
            $_controller = $this->uris[0];
261
        } else {
262
            throw new NotFoundException('Cannot dispatch controller name.');
263
        }
264
265
        return strip_tags($_controller);
266
    }
267
268
    /**
269
     * Returns the action name
270
     *
271
     * @return      string
272
     *
273
     * @throws \Kotori\Exception\NotFoundException
274
     */
275
    public function getAction()
276
    {
277
        if (isset($this->uris[1])) {
278
            $_action = $this->uris[1];
279
        } else {
280
            throw new NotFoundException('Cannot dispatch action name.');
281
        }
282
283
        return strip_tags($_action);
284
    }
285
286
    /**
287
     * Returns the request params
288
     *
289
     * @return array
290
     */
291
    public function getParams()
292
    {
293
        $params = $this->uris;
294
        unset($params[0], $params[1]);
295
        return array_merge($params);
296
    }
297
298
    /**
299
     * Returns the request params instances
300
     *
301
     * @param  string $className
302
     * @param  string $methodName
303
     * @return mixed
304
     *
305
     * @throws \Kotori\Exception\NotFoundException
306
     */
307
    private function getMethodInstances($className, $methodName = '__construct')
308
    {
309
        $reflectClass = new ReflectionClass($className);
310
        $instances = [];
311
312
        if ($reflectClass->hasMethod($methodName)) {
313
            $reflectMethod = $reflectClass->getMethod($methodName);
314
315
            $params = $reflectMethod->getParameters();
316
317
            $hasDI = false;
318
319
            if (count($params) > 0) {
320
                foreach ($params as $param) {
321
                    $paramClass = $param->getClass();
322
                    if ($paramClass) {
323
                        $paramClassName = $paramClass->getName();
324
                        array_push($instances, Container::getByClassName($paramClassName));
325
                        $hasDI = true;
326
                    } elseif ($hasDI) {
327
                        throw new NotFoundException('Dependency Injection cannot work with normal params');
328
                    }
329
                }
330
            }
331
        }
332
333
        if ($hasDI) {
0 ignored issues
show
Bug introduced by
The variable $hasDI does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
334
            return $instances;
335
        }
336
337
        return false;
338
    }
339
340
    /**
341
     * Returns the URI
342
     *
343
     * @return string
344
     */
345
    public function getUri()
346
    {
347
        return $this->uri;
348
    }
349
350
    /**
351
     * Returns routes
352
     *
353
     * @return array
354
     */
355
    public function getRoutes()
356
    {
357
        return $this->routes;
358
    }
359
360
    /**
361
     * Parse Routes
362
     *
363
     * Matches any routes that may exist in URL_ROUTE array
364
     * against the URI to determine if the class/method need to be remapped.
365
     *
366
     * @param  string $uri
367
     * @return string
368
     */
369
    protected function parseRoutes($uri)
0 ignored issues
show
Coding Style introduced by
parseRoutes uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
370
    {
371
        if (Container::get('config')->get('url_route_annotation')) {
372
            $finder = new Finder();
373
            $finder
374
                ->in(Container::get('config')->get('app_full_path') . '/controllers')
375
                ->name('*.php');
376
            $controllerNamespaces = [];
377
            foreach ($finder as $file) {
378
                array_push($controllerNamespaces, '\\' . Container::get('config')->get('namespace_prefix') . 'controllers\\' . $file->getBasename('.' . $file->getExtension()));
379
            }
380
381
            foreach ($controllerNamespaces as $namespace) {
382
                $classReflector = new ReflectionClass($namespace);
383
                $classAnnotations = new Annotations($classReflector);
0 ignored issues
show
Unused Code introduced by
$classAnnotations is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
384
385
                foreach ($classReflector->getMethods() as $methodReflector) {
386
                    $methodAnnotations = new Annotations($methodReflector);
387
                    if (!isset($methodAnnotations['route'])) {
388
                        continue;
389
                    } else {
390
                        $routeAnnotations = $methodAnnotations['route'];
391
                        if (!isset($routeAnnotations['uri'])) {
392
                            throw new ConfigException('Route annotations error');
393
                        }
394
395
                        $controllerName = $classReflector->getShortName();
396
                        $actionName = $methodReflector->getName();
0 ignored issues
show
Bug introduced by
Consider using $methodReflector->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
397
                        $route = $controllerName . '/' . $actionName;
398
                        if (isset($routeAnnotations['params'])) {
399
                            $route .= '/' . $routeAnnotations['params'];
400
                        }
401
402
                        if (!isset($routeAnnotations['method'])) {
403
                            $this->routes[$routeAnnotations['uri']] = $route;
404
                        } else {
405
                            $this->routes[$routeAnnotations['uri']][$routeAnnotations['method']] = $route;
406
                        }
407
408
                        unset($route);
409
                    }
410
                }
411
            }
412
        } else {
413
            $this->routes = Container::get('config')->get('url_route');
414
        }
415
416
        $hostName = Container::get('request')->getHostName();
417
418
        if (isset($this->routes[$hostName])) {
419
            $this->routes = $this->routes[$hostName];
420
        }
421
422
        // Get HTTP verb
423
        $httpVerb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';
424
425
        if (null != $this->routes) {
426
            foreach ($this->routes as $key => $val) {
427
                // Check if route format is using HTTP verbs
428
                if (is_array($val)) {
429
                    $val = array_change_key_case($val, CASE_LOWER);
430
                    if (isset($val[$httpVerb])) {
431
                        $val = $val[$httpVerb];
432
                    } else {
433
                        continue;
434
                    }
435
                }
436
437
                // Does the RegEx match?
438
                if (preg_match('#^' . $key . '$#', $uri, $matches)) {
439
                    // Are we using callbacks to process back-references?
440
                    if (!is_string($val) && is_callable($val)) {
441
                        // Remove the original string from the matches array.
442
                        array_shift($matches);
443
444
                        // Execute the callback using the values in matches as its parameters.
445
                        $val = call_user_func_array($val, $matches);
446
                    }
447
                    // Are we using the default routing method for back-references?
448
                    elseif (strpos($val, '$') !== false && strpos($key, '(') !== false) {
449
                        $val = preg_replace('#^' . $key . '$#', $val, $uri);
450
                    }
451
452
                    return $val;
453
                }
454
            }
455
        }
456
457
    }
458
459
    /**
460
     * Parse CLI arguments
461
     *
462
     * Take each command line argument and assume it is a URI segment.
463
     *
464
     * @return  string
465
     */
466 1
    protected function parseArgv()
0 ignored issues
show
Coding Style introduced by
parseArgv uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
467
    {
468 1
        $args = array_slice($_SERVER['argv'], 1);
469 1
        return $args ? implode('/', $args) : '';
470
    }
471
472
    /**
473
     * Build Full URL
474
     *
475
     * @param  string $uri
476
     * @param  string $module
477
     * @return string
478
     *
479
     * @throws \Kotori\Exception\ConfigException
480
     */
481
    public function url($uri = '', $module = null)
482
    {
483
        if ($module != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $module of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
484
            $appNames = Container::get('config')->get('app_name');
485
            if (is_array($appNames)) {
486
                foreach ($appNames as &$appName) {
487
                    $appName = str_replace('./', '', $appName);
488
                }
489
490
                $appNames = array_flip($appNames);
491
                $baseUrl = $appNames[$module];
492
                $baseUrl = '//' . $baseUrl . '/';
493
            }
494
        } else {
495
            $baseUrl = Container::get('request')->getBaseUrl();
496
        }
497
498
        $uri = is_array($uri) ? implode('/', $uri) : trim($uri, '/');
499
        $prefix = $baseUrl . 'index.php?_i=';
0 ignored issues
show
Bug introduced by
The variable $baseUrl does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
500
501
        switch (strtolower(Container::get('config')->get('url_mode'))) {
502
            case 'path_info':
503
                return $uri == '' ? rtrim($baseUrl, '/') : $baseUrl . $uri;
504
            case 'query_string':
505
                return $uri == '' ? rtrim($baseUrl, '/') : $prefix . $uri;
506
            default:
507
                throw new ConfigException('`url_mode` Config ERROR');
508
        }
509
510
    }
511
512
}
513