Router   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 4
Bugs 1 Features 1
Metric Value
wmc 23
c 4
b 1
f 1
lcom 1
cbo 6
dl 0
loc 182
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getInstance() 0 8 2
A prefix() 0 11 2
A add() 0 4 1
A get() 0 4 1
A post() 0 4 1
A put() 0 4 1
B setMethod() 0 23 4
B getParams() 0 24 3
A includeRoutes() 0 8 2
A init() 0 10 2
A getCollection() 0 4 1
A group() 0 7 2
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 14 and the first side effect is on line 197.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
namespace Core;
4
5
use Core\Exceptions\ExceptionHandler;
6
use Exception;
7
use Symfony\Component\HttpFoundation\Request;
8
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
9
use Symfony\Component\Routing\Matcher\UrlMatcher;
10
use Symfony\Component\Routing\RequestContext;
11
use Symfony\Component\Routing\Route;
12
use Symfony\Component\Routing\RouteCollection;
13
14
class Router
15
{
16
    public $routeColletion;
17
    private $prefix = '';
18
    private static $instance = null;
19
    private $middlewares = [];
20
21
    private function __construct()
22
    {
23
        $this->routeColletion = new RouteCollection();
24
    }
25
26
    public static function getInstance()
27
    {
28
        if (!self::$instance instanceof self) {
29
            self::$instance = new self();
30
        }
31
32
        return self::$instance;
33
    }
34
35
    /**
36
     * @param $prefixParam
37
     * @param $callable
38
     *
39
     * @throws \ErrorException
40
     */
41
    public function prefix($prefixParam, $callable)
42
    {
43
        if (!is_callable($callable)) {
44
            throw new \ErrorException('O segundo parâmetro não é executável');
45
        }
46
47
        $oldPrefix = $this->prefix;
48
        $this->prefix .= $prefixParam;
49
        $callable($this);
50
        $this->prefix = $oldPrefix;
51
    }
52
53
    /**
54
     * @param       $path
55
     * @param       $controller
56
     * @param array $params
57
     */
58
    public function add($path, $controller, $params = [])
59
    {
60
        $this->setMethod(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'PATCH'], $path, $controller, $params);
61
    }
62
63
    /**
64
     * @param       $path
65
     * @param       $controller
66
     * @param array $params
67
     */
68
    public function get($path, $controller, $params = [])
69
    {
70
        $this->setMethod('GET', $path, $controller, $params);
71
    }
72
73
    /**
74
     * @param       $path
75
     * @param       $controller
76
     * @param array $params
77
     */
78
    public function post($path, $controller, $params = [])
79
    {
80
        $this->setMethod('POST', $path, $controller, $params);
81
    }
82
83
    /**
84
     * @param       $path
85
     * @param       $controller
86
     * @param array $params
87
     */
88
    public function put($path, $controller, $params = [])
89
    {
90
        $this->setMethod('PUT', $path, $controller, $params);
91
    }
92
93
    /**
94
     * @param       $httpMethod
95
     * @param       $path
96
     * @param       $controller
97
     * @param array $params
98
     */
99
    private function setMethod($httpMethod, $path, $controller, $params = [])
100
    {
101
        if (!is_array($httpMethod)) {
102
            $httpMethod = [$httpMethod];
103
        }
104
105
        list($controller, $method) = explode('::', $controller);
106
        $prefixedPath = $this->prefix.$path;
107
108
        $configsParams = array_merge([
109
            '_path'       => $path,
110
            '_controller' => $controller,
111
            '_method'     => $method,
112
        ], $params);
113
114
        if (is_array($this->middlewares) && count($this->middlewares) > 0) {
115
            $configsParams['_middleware'] = $this->middlewares;
116
        }
117
118
        $route = new Route($prefixedPath, $configsParams);
119
        $route->setMethods($httpMethod);
120
        $this->routeColletion->add(implode('', $httpMethod).$prefixedPath, $route);
121
    }
122
123
    /**
124
     * @return array
125
     */
126
    public static function getParams()
0 ignored issues
show
Coding Style introduced by
getParams 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...
127
    {
128
        static::includeRoutes();
0 ignored issues
show
Bug introduced by
Since includeRoutes() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of includeRoutes() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
129
130
        $parameters = null;
131
        $context = new RequestContext();
132
        $context->fromRequest(Request::createFromGlobals());
133
        $matcher = new UrlMatcher(self::getInstance()->routeColletion, $context);
134
135
        try {
136
            $parameters = $matcher->match(Request::createFromGlobals()->getPathInfo());
137
        } catch (ResourceNotFoundException $e) {
138
            $parameters = [
139
                '_path'       => $_SERVER['REQUEST_URI'],
140
                '_controller' => 'HomeController',
141
                '_method'     => '_404',
142
                '_route'      => 'GETPOSTPUTPATCHDELETEPATCH/',
143
            ];
144
        } catch (Exception $e) {
145
            new ExceptionHandler($e);
146
        }
147
148
        return $parameters;
149
    }
150
151
    private static function includeRoutes()
152
    {
153
        static $included = false;
154
        if (!$included) {
155
            require ROOT_APP.'routes.php';
156
            $included = true;
157
        }
158
    }
159
160
    /**
161
     * @return bool
162
     */
163
    public static function init()
164
    {
165
        static $init = false;
166
        if (!$init) {
167
            self::includeRoutes();
168
            $init = true;
169
        }
170
171
        return $init;
172
    }
173
174
    /**
175
     * Return router collection.
176
     *
177
     * @return RouteCollection
178
     */
179
    public function getCollection()
180
    {
181
        return $this->routeColletion;
182
    }
183
184
    /**
185
     * @param $params
186
     * @param $closure
187
     */
188
    public function group($params, $closure)
189
    {
190
        $oldMiddlewares = $this->middlewares;
191
        $this->middlewares = array_merge($this->middlewares, isset($params['middleware']) ? $params['middleware'] : []);
192
        $closure($this);
193
        $this->middlewares = $oldMiddlewares;
194
    }
195
}
196
197
Router::init();
198