Passed
Branch master (11fee5)
by Henri
01:26
created

Router::setOnRoute()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 4
nop 2
dl 0
loc 18
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace HnrAzevedo\Router;
4
5
use Exception;
6
7
class Router{
8
    use Helper, CheckTrait, CheckWhere, DefinitionsTrait;
9
10
    private static $instance = null;
11
    private array $routers = [];
12
    private ?string $prefix = null;
13
    private ?string $group = null;
14
    private $lastReturn = null;
15
    private bool $instanced = false;
16
17
    public function __construct()
18
    {
19
        return $this;
20
    }
21
22
    public static function create(): Router
23
    {
24
        if(!self::getInstance()->instanced){
25
            self::getInstance()->checkConfig();
26
            self::getInstance()->import(ROUTER_CONFIG['path']);
27
            self::getInstance()->instanced = true;
28
        }
29
        
30
        return self::getInstance();
31
    }
32
33
    public static function getInstance(): Router
34
    {
35
        self::$instance = (is_null(self::$instance)) ? new self() : self::$instance;
36
        return self::$instance;
37
    }
38
39
    public function set($url ,$walking , string $protocol): Router
40
    {
41
        $this->lastReturn = null;
42
        
43
		$url = (substr($url,0,1) !=='/' and strlen($url) > 0) ? "/{$url}" : $url;
44
45
    	foreach($this->routers as $key => $value){
46
    		if( md5($this->prefix . $value['url'] . $value['protocol'] ) === md5( $url . $protocol ) ){
47
                throw new Exception("There is already a route with the url {$url} and with the {$protocol} protocol configured.");
48
            }
49
        }
50
        
51
        $this->checkTypeRole($walking);
52
53
		$route = [
54
			'url' => $this->prefix.$url,
55
			'role' => $walking,
56
			'protocol' => $protocol,
57
            'filters' => null,
58
            'where' => null,
59
            'before' => null,
60
            'after' => null,
61
            'group' => self::getInstance()->group
62
		];
63
64
		$this->routers[] = $route;		
65
        
66
        return self::getInstance();
67
    }
68
69
    public static function group(string $prefix,$callback): Router
70
    {
71
        self::getInstance()->prefix = (substr($prefix,0,1) !== '/') ? "/{$prefix}" : $prefix;
72
        self::getInstance()->group = sha1(date('d/m/Y h:m:i'));
73
        $callback();
74
        self::getInstance()->group = null;
75
        self::getInstance()->prefix = null;
76
        self::getInstance()->lastReturn = true;
77
        return self::getInstance();
78
    }
79
80
    public static function where(): Router
81
    {
82
        if(self::getInstance()->lastReturn){
83
            throw new Exception("It is not possible to define parameter tests for groups of routes.");
84
        }
85
86
        self::getInstance()->callWhereAdd(func_get_args());
87
88
        return self::getInstance();
89
    }
90
91
    public static function name(string $name): Router
92
    {
93
        if(self::getInstance()->lastReturn){
94
            throw new Exception("There is no reason to call a {$name} route group.");
95
        }
96
97
        $currentRoute = end(self::getInstance()->routers);
98
99
        foreach(self::getInstance()->routers as $key => $value){
100
            if(array_key_exists($name, self::getInstance()->routers)){
101
                throw new Exception("There is already a route with the name {$name} configured.");
102
            }
103
        }
104
105
        $currentRoute['name'] = $name;
106
107
        self::getInstance()->routers[count(self::getInstance()->routers)-1] = $currentRoute;
108
109
        return self::getInstance();
110
    }
111
112
    private function byName(?string $routName)
113
    {
114
        if(!is_null($routName)){
115
            $currentProtocol = $this->getProtocol();
116
117
            $this->checkName($routName);
118
    
119
            $route = $this->routers[$routName];
120
    
121
            if(!$this->checkProtocol($route['protocol'], $currentProtocol)){
122
                throw new Exception('Page not found.',404);
123
            }
124
    
125
            $this->checkFiltering($route);
126
    
127
            $this->toHiking($route['role']);
128
            throw true;
129
        }
130
    }
131
132
    public static function dispatch(?string $routeName = null): bool
133
    {
134
        $instance = self::create();
135
136
        $instance->getInstance()->byName($routeName);
137
138
		$currentProtocol = $instance->getInstance()->getProtocol();
139
140
        foreach(array_reverse($instance->getInstance()->routers) as $r => $route){
141
142
            $instance->getInstance()->currentRoute = $route;
143
144
            if(!$instance->getInstance()->checkProtocol($route['protocol'], $currentProtocol)){
145
                continue;
146
            }
147
148
            $instance->getInstance()->hasProtocol($route, $currentProtocol);
149
150
            $_SERVER['REQUEST_URI'] = (array_key_exists('REQUEST_URI', $_SERVER)) ? $_SERVER['REQUEST_URI'] : '';
151
152
153
            $routs = $instance->getInstance()->explodeRoutes(
154
                (substr($route['url'],strlen($route['url'])-1,1) === '/') , $route['url'],
155
                (substr($_SERVER['REQUEST_URI'],strlen($_SERVER['REQUEST_URI'])-1,1) === '/') , $_SERVER['REQUEST_URI']
156
            );
157
158
            if(!$instance->getInstance()->checkToHiking($route, $routs['routeRequest'], $routs['routeLoop'])){
159
                continue;
160
            }
161
162
            $instance->getInstance()->checkFiltering($route);
163
164
            $instance->getInstance()->toHiking($route);
165
            return true;
166
            
167
        }
168
        
169
        $instance->getInstance()->currentRoute = null;
170
171
	    throw new Exception('Page not found.',404);
172
    }
173
174
    public function filter($filters): Router
175
    {
176
        if($this->lastReturn !== null){
177
            $currentGroup = end($this->routers)['group'];
178
179
            foreach ($this->routers as $key => $value) {
180
181
                if($value['group'] === $currentGroup){
182
                    $currentRoute = $this->addFilter($this->routers[$key],$filters);
183
                    $this->routers[$key] = $currentRoute;
184
                }
185
186
            }
187
            
188
            return $this;
189
        }
190
        
191
        $this->routers[count($this->routers)-1] = $this->addFilter(end($this->routers),$filters);
192
        return $this;
193
    }
194
 
195
    public function before($walking): Router
196
    {
197
        return $this->setOnRoute($walking,'before');
198
    }
199
200
    public function after($walking): Router
201
    {
202
        return $this->setOnRoute($walking,'after');
203
    }
204
205
    private function setOnRoute($walking, string $state): Router
206
    {
207
        if($this->lastReturn !== null){
208
            $currentGroup = end($this->routers)['group'];
209
210
            foreach ($this->routers as $key => $value) {
211
212
                if($value['group'] === $currentGroup){
213
                    $this->routers[$key][$state] = $walking;
214
                }
215
216
            }
217
            
218
            return $this;
219
        }
220
        
221
        $this->routers[count($this->routers)-1][$state] = $walking;
222
        return $this;
223
    }
224
225
226
227
    public static function addFilter(array $route, $filter): array
228
    {
229
        if(is_null($route['filters'])){
230
            $route['filters'] = $filter;
231
            return $route;
232
        }
233
234
        $filters = (is_array($filter)) ? $filter : [0 => $filter];
235
236
        if(is_array($route['filters'])){
237
            foreach ($route['filters'] as $key => $value) {
238
                $filters[] = $value;
239
            }
240
        }else{
241
            $filters[] = $route['filters'];
242
        }
243
244
        $route['filters'] = $filters;
245
        return $route;
246
    }
247
248
}
249