Passed
Branch master (814b1f)
by Henri
06:44 queued 05:22
created

Router::load()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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