Completed
Push — master ( 620fe4...c35a3d )
by Derek Stephen
02:47
created

Router::parseRoute()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2.004

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 9
cts 10
cp 0.9
rs 8.9713
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 0
crap 2.004
1
<?php
2
3
namespace Bone\Mvc;
4
5
use Bone\Mvc\Router\Route;
6
use Bone\Regex;
7
use Psr\Http\Message\RequestInterface;
8
9
class Router
10
{
11
    private $request;
12
    private $uri;
13
    private $controller;
14
    private $action;
15
    private $params;
16
    private $routes;
17
18
19
    /**
20
     *  We be needin' t' look at th' map
21
     *  @param Request $request
22
     */
23 16
    public function __construct(RequestInterface $request)
24 16
    {
25 16
        $this->request = $request;
26 16
        $this->uri = $request->getURI();
27 16
        $this->controller = 'index';
28 16
        $this->action = 'index';
29 16
        $this->params = array();
30 16
        $this->routes = array();
31
32
        // get th' path 'n' query string from url
33 16
        $parse = parse_url($this->uri);
34 16
        $this->uri = $parse['path'];
35
36 16
    }
37
38
39
40
41
42
    /**
43
     *  @return bool
44
     */
45 15
    private function matchCustomRoute()
46 15
    {
47
        /** @var \Bone\Mvc\Router\Route $route */
48 15
        foreach($this->routes as $route)
49
        {
50
            // if the regex ain't for the home page an' it matches our route
51 15
            $strings = $route->getRegexStrings();
52 15
            if($strings[0] != '\/' && $matches = $route->checkRoute($this->uri))
53
            {
54
                // Garrr me hearties! It be a custom route from th' configgeration!
55
                $this->controller = $route->getControllerName();
56
                $this->action = $route->getActionName();
57
                $this->params = $route->getParams();
58 15
                return true;
59
            }
60
        }
61 15
        return false;
62
    }
63
64
65
66
67
68 15
    private function regexMatch($regex_string)
69 15
    {
70 15
        $regex = new Regex($regex_string);
71 15
        return $regex->getMatches($this->uri);
72
    }
73
74
75
76
77
    /**
78
     * @param array $matches
79
     */
80
    private function setController(array $matches)
81
    {
82
        $this->action = $matches['controller'];
83
    }
84
85
86
87
88
    /**
89
     * @param array $matches
90
     */
91
    private function setAction(array $matches)
92
    {
93
        $this->action = $matches['action'];
94
    }
95
96
97
98
99
100
    /**
101
     * @param array $matches
102
     */
103
    private function setVarValPairs(array $matches)
104
    {
105
        $ex = explode('/',$matches['varvalpairs']);
106
        for($x = 0; $x <= count($ex)-1 ; $x += 2)
107
        {
108
            if(isset($ex[$x+1]))
109
            {
110
                $this->params[$ex[$x]] = $ex[$x+1];
111
            }
112
        }
113
    }
114
115
116
117
118
119
120
    /**
121
     *  @return bool
122
     */
123 15
    private function matchControllerActionParamsRoute()
124 15
    {
125 15
         return $this->regexMatch(Regex\Url::CONTROLLER_ACTION_VARS);
126
    }
127
128
129
130
131
132
    /**
133
     *  @return array|null
134
     */
135 15
    private function matchControllerActionRoute()
136 15
    {
137 15
        return $this->regexMatch(Regex\Url::CONTROLLER_ACTION);
138
    }
139
140
141
142
143
144
    /**
145
     *  @return bool
146
     */
147 15
    private function matchControllerRoute()
148 15
    {
149 15
        return $this->regexMatch(Regex\Url::CONTROLLER);
150
    }
151
152
153
154
155
    /**
156
     *  gets custom routes from config
157
     */
158 15
    private function setCustomRoutesFromConfig()
159 15
    {
160
        // we be checkin' our instruction fer configgered routes
161 15
        $configgeration = Registry::ahoy()->get('routes');
162
163
        // stick some voodoo pins in the map
164 15
        foreach($configgeration as $route => $options)
165
        {
166
            // add the route t' the map
167 15
            $this->routes[] = new Route($route,$options);
168
        }
169 15
    }
170
171
172
173
174
175
    /**
176
     *  Merges params from config
177
     */
178 15
    private function setParams()
179 15
    {
180
        // be addin' the $_GET an' $_POST t' th' params!
181 15
        $method = $this->request->getMethod();
182 15
        if($method == "POST")
183
        {
184
            $this->params = array_merge($this->params, $this->request->getServerParams());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\RequestInterface as the method getServerParams() does only exist in the following implementations of said interface: GuzzleHttp\Psr7\ServerRequest, Zend\Diactoros\ServerRequest.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
185
        }
186 15
        $this->params = array_merge($this->params, $this->request->getQueryParams());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\RequestInterface as the method getQueryParams() does only exist in the following implementations of said interface: GuzzleHttp\Psr7\ServerRequest, Zend\Diactoros\ServerRequest.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
187 15
    }
188
189
190
191
192
193
    /**
194
     *  Tells the Navigator to go to the / route
195
     */
196 15
    private function matchRoute()
197 15
    {
198
        // we be startin' off assumin' th' voyage will be a disaster
199 15
        $this->controller = 'error';
200 15
        $this->action = 'not-found';
201
202
        // Get th' navigator!
203 15
        if($this->matchCustomRoute())
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
204
        {
205
            // gaaarrrr, we're set to go!
206
        }
207 15
        elseif($matches = $this->matchControllerActionParamsRoute())
208
        {
209
            // we have a controller action var val match Cap'n!
210
            $this->setController($matches);
211
            $this->setAction($matches);
212
            $this->setVarValPairs($matches);
213
        }
214 15
        elseif($matches = $this->matchControllerActionRoute())
215
        {
216
            // we have a controller action match Cap'n!
217
            $this->setController($matches);
218
            $this->setAction($matches);
219
        }
220 15
        elseif($matches = $this->matchControllerRoute())
221
        {
222
            // we have a controller action match Cap'n!
223
            // settin' the destination controller and action and params
224
            $this->setController($matches);
225
            $this->action = 'index';
226
        }
227 15
    }
228
229
    /**
230
     *  Tells the Navigator to go to the / route
231
     */
232 15
    private function sailHome()
233 15
    {
234 15
        $routes = Registry::ahoy()->get('routes');
235 15
        $home_page = $routes['/'];
236 15
        $this->controller = $home_page['controller'];
237 15
        $this->action = $home_page['action'];
238 15
        $this->params = $home_page['params'];
239 15
    }
240
241
242
243
    /**
244
     *  Figger out where we be goin'
245
     */
246 15
    public function parseRoute()
247 15
    {
248
249
        // start at the home page
250 15
        $this->sailHome();
251
252
        // which way be we goin' ?
253 15
        $path = $this->uri;
254
255
        // Has th' route been set?
256 15
        if ($path != '/')
257
        {
258
            // Set the routes configgerd in th' config.php
259 15
            $this->setCustomRoutesFromConfig();
260
261
            // Match the feckin' route ya blubberin' seadog!
262 15
            $this->matchRoute();
263
264
            // Merge th' GET POST and config params
265 15
            $this->setParams();
266
267 15
            return;
268
        }
269
    }
270
271 16
    public function getController()
272 16
    {
273 16
        return $this->controller;
274
    }
275
276 11
    public function getAction()
277 11
    {
278 11
        return $this->action;
279
    }
280
281
    public function getParams()
282
    {
283
        return $this->params;
284
    }
285
}