Completed
Push — 2.0 ( 803ca6...9ea2f8 )
by Vermeulen
02:28
created

Router::addTargetToCtrlRouter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * Class for the router system
4
 * @author Vermeulen Maxime <[email protected]>
5
 * @version 2.0
6
 */
7
8
namespace BfwFastRoute;
9
10
use \Exception;
11
use \FastRoute;
12
13
/**
14
 * Permet de gérer la vue et de savoir vers quel page envoyer
15
 * @package bfw-fastroute
16
 */
17
class Router implements \SplObserver
18
{
19
    /**
20
     * @const ERR_TARGET_NOT_DECLARED : Error code if the target has not
21
     * been declared
22
     */
23
    const ERR_TARGET_NOT_DECLARED = 2001001;
24
    
25
    /**
26
     * @var \BFW\Module $module The bfw module instance for this module
27
     */
28
    protected $module;
29
    
30
    /**
31
     * @var \BFW\Config $config The bfw config instance for this module
32
     */
33
    protected $config;
34
    
35
    /**
36
     * @var \stdClass|null $ctrlRouterInfos The context object passed to
37
     * subject for the action "searchRoute".
38
     */
39
    protected $ctrlRouterInfos;
40
    
41
    /**
42
     * @var \FastRoute\Dispatcher $dispatcher FastRoute dispatcher
43
     */
44
    protected $dispatcher;
45
    
46
    /**
47
     * Constructor
48
     * Get config and linker instance
49
     * Call fastRoute dispatcher
50
     * 
51
     * @param \BFW\Module $module
52
     */
53
    public function __construct(\BFW\Module $module)
54
    {
55
        $this->module = $module;
56
        $this->config = $module->getConfig();
57
        
58
        $this->dispatcher = FastRoute\simpleDispatcher([
59
            $this,
60
            'addRoutesToCollector'
61
        ]);
62
    }
63
    
64
    /**
65
     * Getter accessor for module property
66
     * 
67
     * @return \BFW\Module
68
     */
69
    public function getModule()
70
    {
71
        return $this->module;
72
    }
73
74
    /**
75
     * Getter accessor for config property
76
     * 
77
     * @return \BFW\Config
78
     */
79
    public function getConfig()
80
    {
81
        return $this->config;
82
    }
83
84
    /**
85
     * Getter accessor for ctrlRouterInfos property
86
     * 
87
     * @return \stdClass
88
     */
89
    public function getCtrlRouterInfos()
90
    {
91
        return $this->ctrlRouterInfos;
92
    }
93
94
    /**
95
     * Getter accessor for dispatcher property
96
     * 
97
     * @return \FastRoute\Dispatcher
98
     */
99
    public function getDispatcher()
100
    {
101
        return $this->dispatcher;
102
    }
103
    
104
    /**
105
     * Observer update method
106
     * Call obtainCurrentRoute method on action "apprun_loadAllAppModules".
107
     * 
108
     * @param \SplSubject $subject
109
     * 
110
     * @return void
111
     */
112
    public function update(\SplSubject $subject)
113
    {
114
        if ($subject->getAction() === 'bfw_ctrlRouterLink_subject_added') {
115
            $app = \BFW\Application::getInstance();
116
            $app->getSubjectList()
117
                ->getSubjectForName('ctrlRouterLink')
118
                ->attach($this)
119
            ;
120
        } elseif ($subject->getAction() === 'searchRoute') {
121
            $this->obtainCtrlRouterInfos($subject);
0 ignored issues
show
Documentation introduced by
$subject is of type object<SplSubject>, but the function expects a object<BFW\Subject>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
122
            
123
            if ($this->ctrlRouterInfos->isFound === false) {
124
                $this->searchRoute();
125
            }
126
        }
127
    }
128
    
129
    /**
130
     * Set the property ctrlRouterInfos with the context object obtain linked
131
     * to the subject.
132
     * Allow override to get only some part. And used for unit test.
133
     * 
134
     * @param \BFW\Subject $subject
135
     * 
136
     * @return void
137
     */
138
    protected function obtainCtrlRouterInfos($subject)
139
    {
140
        $this->ctrlRouterInfos = $subject->getContext();
141
    }
142
    
143
    /**
144
     * Call by dispatcher; Add route in config to fastRoute router
145
     * 
146
     * @param FastRoute\RouteCollector $router FastRoute router
147
     * 
148
     * @return void
149
     */
150
    public function addRoutesToCollector(FastRoute\RouteCollector $router)
151
    {
152
        $routes = $this->config->getValue('routes');
153
        
154
        foreach ($routes as $slug => $infos) {
155
            $slug = trim($slug);
156
157
            //Défault method
158
            $method = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'];
159
            
160
            //If method is declared for the route
161
            if (isset($infos['httpMethod'])) {
162
                //Get the method ans remove it from httpMethod array
163
                $method = $infos['httpMethod'];
164
                unset($infos['httpMethod']);
165
            }
166
167
            $router->addRoute($method, $slug, $infos);
168
        }
169
    }
170
    
171
    /**
172
     * Obtain informations about the current route from fastRoute dispatcher
173
     * 
174
     * @return void
175
     */
176
    protected function searchRoute()
177
    {
178
        //Get current request informations
179
        $bfwRequest = \BFW\Request::getInstance();
180
        $request    = $bfwRequest->getRequest()->path;
181
        $method     = $bfwRequest->getMethod();
182
        
183
        //If request is index
184
        if ($request === '') {
185
            $request = '/';
186
        }
187
188
        //Get route information from dispatcher
189
        $routeInfo   = $this->dispatcher->dispatch($method, $request);
190
        $routeStatus = $routeInfo[0];
191
        
192
        //Get and send request http status to the controller/router linker
193
        $httpStatus = $this->checkStatus($routeStatus);
194
        
195
        if ($httpStatus === 404) {
196
            //404 will be declared by \BFW\Application::runCtrlRouterLink()
197
            return;
198
        }
199
        
200
        http_response_code($httpStatus);
201
        $this->addInfosToCtrlRouter();
202
        
203
        if ($httpStatus !== 200) {
204
            return;
205
        }
206
        
207
        //Obtains datas for route from config file and send to linker
208
        $this->addTargetToCtrlRouter($routeInfo[1]);
209
210
        //Add gets datas in route to $_GET var
211
        $this->addDatasToGetVar($routeInfo[1]);
212
        $this->addToSuperglobalVar('GET', $routeInfo[2]);
213
    }
214
    
215
    /**
216
     * Get http status for response from dispatcher
217
     * 
218
     * @param int $routeStatus : Route status send by dispatcher for request
219
     * 
220
     * @return int
221
     */
222
    protected function checkStatus($routeStatus)
223
    {
224
        $httpStatus = 200;
225
        
226
        if ($routeStatus === FastRoute\Dispatcher::METHOD_NOT_ALLOWED) {
227
            $httpStatus = 405;
228
        } elseif ($routeStatus === FastRoute\Dispatcher::NOT_FOUND) {
229
            $httpStatus = 404;
230
        }
231
        
232
        return $httpStatus;
233
    }
234
    
235
    /**
236
     * Update ctrlRouterInfos properties isFound and forWho
237
     * 
238
     * @return void
239
     */
240
    protected function addInfosToCtrlRouter()
241
    {
242
        $app    = \BFW\Application::getInstance();
243
        $forWho = $app->getConfig()->getValue('modules')['controller']['name'];
244
        
245
        $this->ctrlRouterInfos->isFound = true;
246
        $this->ctrlRouterInfos->forWho  = $forWho;
247
    }
248
    
249
    /**
250
     * Obtains route informations from config file and send this informations
251
     * to the controller/router linker
252
     * 
253
     * @param array $routeInfos : Route information from config file
254
     * 
255
     * @return void
256
     * 
257
     * @throws \Exception If target not define in config file
258
     */
259
    protected function addTargetToCtrlRouter(array $routeInfos)
260
    {
261
        if (array_key_exists('target', $routeInfos) === false) {
262
            throw new Exception(
263
                'Router : target not defined',
264
                self::ERR_TARGET_NOT_DECLARED
265
            );
266
        }
267
        
268
        $this->ctrlRouterInfos->target = $routeInfos['target'];
269
    }
270
    
271
    /**
272
     * Add datas into a superglobal var
273
     * 
274
     * @param string $globalVarName : Name of the superglobal var
275
     * @param array $datasToAdd : Datas to add to $_GET var
276
     * 
277
     * @return void
278
     */
279
    protected function addToSuperglobalVar($globalVarName, array $datasToAdd)
280
    {
281
        global ${'_'.$globalVarName};
282
        ${'_'.$globalVarName} = array_merge(${'_'.$globalVarName}, $datasToAdd);
283
    }
284
    
285
    /**
286
     * If property 'get' has been declared into current route config, add
287
     * them into superglobal $_GET .
288
     * 
289
     * @param array $routeInfos route informations declared in config
290
     * 
291
     * @return void
292
     */
293
    protected function addDatasToGetVar(array $routeInfos)
294
    {
295
        if (isset($routeInfos['get'])) {
296
            $this->addToSuperglobalVar('GET', $routeInfos['get']);
297
        }
298
    }
299
}
300