Passed
Push — master ( 40eec0...6215ec )
by Darío
02:02
created

Router::setBasePath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * DronePHP (http://www.dronephp.com)
4
 *
5
 * @link      http://github.com/Pleets/DronePHP
6
 * @copyright Copyright (c) 2016-2018 Pleets. (http://www.pleets.org)
7
 * @license   http://www.dronephp.com/license
8
 * @author    Darío Rivera <[email protected]>
9
 */
10
11
namespace Drone\Mvc;
12
13
use Drone\Mvc\Exception;
14
15
/**
16
 * Router class
17
 *
18
 * This class build the route and calls to specific application controller
19
 */
20
class Router
21
{
22
    /**
23
     * List of routes
24
     *
25
     * @var array
26
     */
27
    private $routes = [];
28
29
    /**
30
     * The Identifiers builds the route
31
     *
32
     * @var array
33
     */
34
    private $identifiers;
35
36
    /**
37
     * Controller instance
38
     *
39
     * @var AbstractController
40
     */
41
    private $controller;
42
43
    /**
44
     * Indicates how the class name could be matched
45
     *
46
     * @var callable
47
     */
48
    private $classNameBuilder;
49
50
    /**
51
     * Zend\Router implementation
52
     *
53
     * @var \Zend\Router\SimpleRouteStack
54
     */
55
    private $zendRouter;
56
57
    /**
58
     * Returns all routes built
59
     *
60
     * @return array
61
     */
62
    public function getRoutes()
63
    {
64
        return $this->routes;
65
    }
66
67
    /**
68
     * Returns all identifiers
69
     *
70
     * @return array
71
     */
72
    public function getIdentifiers()
73
    {
74
        return $this->identifiers;
75
    }
76
77
    /**
78
     * Returns the controller instance
79
     *
80
     * @throws \RuntimeException
81
     *
82
     * @return AbstractController
83
     */
84
    public function getController()
85
    {
86
        if (is_null($this->controller))
87
            throw new \RuntimeException("No controller matched, try to match first.");
88
89
        return $this->controller;
90
    }
91
92
    /**
93
     * Returns the class name builder function
94
     *
95
     * @return callable
96
     */
97
    public function getClassNameBuilder()
98
    {
99
        return $this->classNameBuilder;
100
    }
101
102
    /**
103
     * Returns the Zend\Router\SimpleRouteStack object
104
     *
105
     * @return \Zend\Router\SimpleRouteStack
106
     */
107
    public function getZendRouter()
108
    {
109
        return $this->zendRouter;
110
    }
111
112
    /**
113
     * Sets identifiers
114
     *
115
     * @param string $module
116
     * @param string $controller
117
     * @param string $view
118
     *
119
     * @return null
120
     */
121
    public function setIdentifiers($module, $controller, $view)
122
    {
123
        $this->identifiers = [
124
            "module"     => $module,
125
            "controller" => $controller,
126
            "view"       => $view
127
        ];
128
    }
129
130
    /**
131
     * Sets the class name builder function
132
     *
133
     * @param callable $builder
134
     *
135
     * @return null
136
     */
137
    public function setClassNameBuilder(callable $builder)
138
    {
139
        $this->classNameBuilder = $builder;
140
    }
141
142
    /**
143
     * Constructor
144
     *
145
     * @param array $routes
146
     */
147
    public function __construct(Array $routes = [])
148
    {
149
        if (count($routes))
150
        {
151
            foreach ($routes as $route)
152
            {
153
                $this->addRoute($route);
154
            }
155
        }
156
157
        # default class name builder
158
        $this->setClassNameBuilder(function($module, $class) {
159
            return "\\$module\\$class";
160
        });
161
162
        $this->zendRouter = new \Zend\Router\SimpleRouteStack();
163
    }
164
165
    /**
166
     * Builds the current route and calls the controller
167
     *
168
     * @throws Exception\PageNotFoundException
169
     * @throws \LogicException
170
     *
171
     * @return  null
172
     */
173
    public function match()
174
    {
175
        if (!is_callable($this->classNameBuilder))
176
            throw \LogicException("No class name builder found");
0 ignored issues
show
Bug introduced by
The function LogicException was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

176
            throw /** @scrutinizer ignore-call */ \LogicException("No class name builder found");
Loading history...
177
178
        /*
179
         *  Key value pairs builder:
180
         *  Searches for the pattern /var1/value1/var2/value2 and converts it to  var1 => value1, var2 => value2
181
         */
182
        if (array_key_exists('params', $_GET))
183
        {
184
            $keypairs = $this->parseRequestParameters($_GET["params"]);
0 ignored issues
show
Bug introduced by
The method parseRequestParameters() does not exist on Drone\Mvc\Router. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

184
            /** @scrutinizer ignore-call */ 
185
            $keypairs = $this->parseRequestParameters($_GET["params"]);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
185
            unset($_GET["params"]);
186
            $_GET = array_merge($_GET, $keypairs);
187
        }
188
189
        /*
190
         *  Route builder:
191
         *  The route is built by default from the URL as follow
192
         *  www.example.com/module/controller/view
193
         */
194
195
        $module = (is_null($this->identifiers["module"]) || empty($this->identifiers["module"]))
196
                    ? $this->routes["defaults"]["module"] : $this->identifiers["module"];
197
198
        if (!array_key_exists($module, $this->routes))
199
            throw new Exception\ModuleNotFoundException("The key '$module' does not exists in routes!");
200
201
        $controller = (is_null($this->identifiers["controller"]) || empty($this->identifiers["controller"]))
202
                    ? $this->routes[$module]["controller"] : $this->identifiers["controller"];
203
204
        $view = (is_null($this->identifiers["view"]) || empty($this->identifiers["view"]))
205
                    ? $this->routes[$module]["view"] : $this->identifiers["view"];
206
207
        $fqn_controller = call_user_func($this->classNameBuilder, $module, $controller);
208
209
        if (class_exists($fqn_controller))
210
        {
211
            try {
212
                $this->controller = new $fqn_controller;
213
            }
214
            # change context, in terms of Router MethodNotFoundException or
215
            # PrivateMethodExecutionException is a PageNotfoundException
216
            catch (Exception\MethodNotFoundException $e)
217
            {
218
                throw new Exception\PageNotFoundException($e->getMessage(), $e->getCode(), $e);
219
            }
220
            catch (Exception\PrivateMethodExecutionException $e)
221
            {
222
                throw new Exception\PageNotFoundException($e->getMessage(), $e->getCode(), $e);
223
            }
224
225
            # in controller terms, a view is a method
226
            $this->controller->setMethod($view);
227
        }
228
        else
229
            throw new Exception\ControllerNotFoundException("The control class '$fqn_controller' does not exists!");
230
    }
231
232
    /**
233
     * Execute the method matched in the controller
234
     *
235
     * @return  null
236
     */
237
    public function run()
238
    {
239
        $this->controller->execute();
240
    }
241
242
    /**
243
     * Adds a new route to router
244
     *
245
     * @param Array $route
246
     *
247
     * @throws LogicException
248
     *
249
     * @return null
250
     */
251
    public function addRoute(array $route)
252
    {
253
        $key = array_keys($route);
254
        $key = array_shift($key);
255
256
        if (array_key_exists($key, $this->routes))
257
            throw new \LogicException("The key '$key' was already defined as route");
258
259
        $this->routes = array_merge($this->routes, $route);
260
    }
261
262
    /**
263
     * Adds a new route to router
264
     *
265
     * @param string $name
266
     * @param Zend\Router\Http\RouteInterface $route
0 ignored issues
show
Bug introduced by
The type Drone\Mvc\Zend\Router\Http\RouteInterface was not found. Did you mean Zend\Router\Http\RouteInterface? If so, make sure to prefix the type with \.
Loading history...
267
     *
268
     * @throws LogicException
269
     *
270
     * @return null
271
     */
272
    public function addZendRoute($name, \Zend\Router\Http\RouteInterface $route)
273
    {
274
        $this->zendRouter->addRoute($name, $route);
275
    }
276
277
    /**
278
     * Parse key value pairs from a string
279
     *
280
     * Searches for the pattern /var1/value1/var2/value2 and converts it to
281
     *
282
     * var1 => value1
283
     * var2 => value2
284
     *
285
     * @param string $unparsed
286
     *
287
     * @return array
288
     */
289
    private function parseKeyValuePairsFrom($unparsed)
0 ignored issues
show
Unused Code introduced by
The method parseKeyValuePairsFrom() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
290
    {
291
        $params = explode("/", $unparsed);
292
293
        $vars = $values = [];
294
295
        $i = 1;
296
        foreach ($params as $item)
297
        {
298
            if ($i % 2 != 0)
299
                $vars[] = $item;
300
            else
301
                $values[] = $item;
302
            $i++;
303
        }
304
305
        $vars_count = count($vars);
306
307
        $result = [];
308
309
        for ($i = 0; $i < $vars_count; $i++)
310
        {
311
            if (array_key_exists($i, $values))
312
                $result[$vars[$i]] = $values[$i];
313
            else
314
                $result[$vars[$i]] = '';
315
        }
316
317
        return $result;
318
    }
319
}