RouteManager::saveRoutes()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/*
3
 * The MIT License (MIT)
4
 *
5
 * Copyright (c) 2015 zepi
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 *
25
 */
26
27
/**
28
 * The RouteManager registers and manages all routes. The
29
 * routes are saved in an object backend.
30
 * 
31
 * @package Zepi\Turbo\Manager
32
 * @author Matthias Zobrist <[email protected]>
33
 * @copyright Copyright (c) 2015 zepi
34
 */
35
36
namespace Zepi\Turbo\Manager;
37
38
use \Zepi\Turbo\Framework;
39
use \Zepi\Turbo\Backend\ObjectBackendAbstract;
40
use \Zepi\Turbo\Request\RequestAbstract;
41
42
/**
43
 * The RouteManager registers and manages all routes. The
44
 * routes are saved in an object backend.
45
 * 
46
 * @author Matthias Zobrist <[email protected]>
47
 * @copyright Copyright (c) 2015 zepi
48
 */
49
class RouteManager
50
{
51
    /**
52
     * @access protected
53
     * @var Framework
54
     */
55
    protected $framework;
56
    
57
    /**
58
     * @access protected
59
     * @var ObjectBackendAbstract
60
     */
61
    protected $routeObjectBackend;
62
    
63
    /**
64
     * @access protected
65
     * @var array
66
     */
67
    protected $routes = array();
68
    
69
    /**
70
     * Constructs the object
71
     * 
72
     * @access public
73
     * @param \Zepi\Turbo\Framework $framework
74
     * @param \Zepi\Turbo\Backend\ObjectBackendAbstract $routeObjectBackend
75
     */
76 27
    public function __construct(Framework $framework, ObjectBackendAbstract $routeObjectBackend)
77
    {
78 27
        $this->framework = $framework;
79 27
        $this->routeObjectBackend = $routeObjectBackend;
80 27
    }
81
    
82
    /**
83
     * Initializes the routing table. The function loads
84
     * the saved routes from the object backend.
85
     * 
86
     * @access public
87
     */
88 27
    public function initializeRoutingTable()
89
    {
90 27
        $routes = $this->routeObjectBackend->loadObject();
91 27
        if (!is_array($routes)) {
92 27
            $routes = array();
93
        }
94
        
95 27
        $this->routes = $routes;
96 27
    }
97
    
98
    /**
99
     * Adds an event handler for the given event.
100
     * 
101
     * @access public
102
     * @param string $route
103
     * @param string $eventName
104
     * @param integer $priority
105
     * @return boolean
106
     */
107 9
    public function addRoute($route, $eventName, $priority = 50)
108
    {
109
        // If the priority isn't existing we add the priority as 
110
        // a new array.
111 9
        if (!isset($this->routes[$priority])) {
112 9
            $this->routes[$priority] = array();
113 9
            ksort($this->routes);
114
        }
115
        
116
        // If we had the route already registred, return at this point
117 9
        if (isset($this->routes[$priority][$route])) {
118 1
            return true;
119
        }
120
        
121
        // Add the route and save the new routes array
122 9
        $this->routes[$priority][$route] = $eventName;
123 9
        $this->saveRoutes();
124
        
125 9
        return true;
126
    }
127
    
128
    /**
129
     * Removes a route for the given priority.
130
     * 
131
     * @access public
132
     * @param string $route
133
     * @param integer $priority
134
     * @return boolean
135
     */
136 3
    public function removeRoute($route, $priority = 50)
137
    {
138
        // If the priority isn't existing we return at this point
139 3
        if (!isset($this->routes[$priority])) {
140 1
            return true;
141
        }
142
        
143
        // If the route isn't registred we return with true.
144 2
        if (!isset($this->routes[$priority][$route])) {
145 1
            return true;
146
        }
147
        
148
        // Remove the route from the array
149 2
        unset($this->routes[$priority][$route]);
150 2
        $this->saveRoutes();
151
        
152 2
        return true;
153
    }
154
    
155
    /**
156
     * Clears the route cache and reactivates the modules
157
     * to rebuild the cache.
158
     * 
159
     * @access public
160
     * @param boolean $reactivateModules
161
     */
162 1
    public function clearCache($reactivateModules = true)
163
    {
164 1
        $this->routes = array();
165
        
166 1
        if ($reactivateModules) {
167 1
            $this->framework->getModuleManager()->reactivateModules();
168
        }
169 1
    }
170
    
171
    /**
172
     * Saves the routes in the object backend
173
     * 
174
     * @access protected
175
     */
176 9
    protected function saveRoutes()
177
    {
178 9
        $this->routeObjectBackend->saveObject($this->routes);
179 9
    }
180
    
181
    /**
182
     * Returns the event name for the given request. The function uses
183
     * the first possible match. The routes are sorted by the priority.
184
     * 
185
     * @access public
186
     * @param \Zepi\Turbo\Request\RequestAbstract $request
187
     * @return false|string
188
     */
189 11
    public function getEventNameForRoute(RequestAbstract $request)
190
    {
191
        // Loop trough the priorities
192 11
        foreach ($this->routes as $priority => $routes) {
193
            // Loop trough the routes for each priority
194 9
            foreach ($routes as $route => $eventName) {
195 9
                $result = $this->compareRoute($route, $request);
196
                
197 9
                if ($result) {
198
                    // The routes are equal - we have an event name
199 9
                    return $eventName;
200
                }
201
            }
202
        }
203
        
204 6
        return false;
205
    }
206
    
207
    /**
208
     * Compares the target route with the found route in the routing table.
209
     * 
210
     * @access protected
211
     * @param string $route
212
     * @param \Zepi\Turbo\Request\RequestAbstract $request
213
     * @return boolean
214
     */
215 9
    protected function compareRoute($route, RequestAbstract $request)
216
    {
217
        // Replace the normal route delimiter with the request route delimiter
218 9
        $route = str_replace('|', $request->getRouteDelimiter(), $route);
219
        
220
        // Split the two routes into parts
221 9
        $routeParts = explode($request->getRouteDelimiter(), $route);
222 9
        $targetRouteParts = explode($request->getRouteDelimiter(), trim($request->getRoute(), $request->getRouteDelimiter()));
223 9
        $numberOfTargetRouteParts = count($targetRouteParts);
224
        
225
        // If we have different number of parts between the two routes
226
        // there are not equal so we have no equal route.
227 9
        if (count($routeParts) != $numberOfTargetRouteParts) {
228 1
            return false;
229
        }
230
        
231
        // Define the data types
232 8
        $routeParams = array();
233 8
        $routeIndex = 0;
234
        
235
        // Loop through the route parts and compare each part
236 8
        for ($pos = 0; $pos < $numberOfTargetRouteParts; $pos++) {
237 8
            $part = $routeParts[$pos];
238 8
            $targetPart = $targetRouteParts[$pos];
239
240 8
            if ($targetPart != '' && preg_match('/\[(d|s)(?:\:([0-9a-zA-Z]*))?\]/', $part)) {
241 2
                list($key, $value) = $this->parseRouteParam($part, $targetPart);
242
                
243 2
                $routeParams[$routeIndex] = $value;
244 2
                $routeIndex++;
245
                
246 2
                if ($key !== '') {
247 2
                    $routeParams[$key] = $value;
248
                }
249 8
            } else if ($part !== $targetPart) {
250
                // The part isn't equal == the route can't be equal
251 1
                return false;
252
            }
253
        }
254
255
        // Save the route parameters in the request
256 7
        $request->setRouteParams($routeParams);
257
        
258 7
        return true;
259
    }
260
    
261
    /**
262
     * Parses the route param data to the correct format
263
     * 
264
     * @access protected
265
     * @param string $part
266
     * @param string $targetPart
267
     * @return array
268
     */
269 2
    protected function parseRouteParam($part, $targetPart)
270
    {
271 2
        preg_match('/\[(d|s)(?:\:([0-9a-zA-Z]*))?\]/', $part, $matches);
272
273 2
        $value = null;
274
        
275
        // If the part is a data type we need this route parameter
276 2
        if ($matches[1] === 'd' && is_numeric($targetPart)) {
277
            // Transform the value into the correct data type
278 2
            $value = $targetPart * 1;
279 2
        } else if ($matches[1] === 's' && is_string($targetPart)) {
280 2
            $value = $targetPart;
281
        }
282
        
283 2
        $key = '';
284 2
        if (isset($matches[2])) {
285 1
            $key = $matches[2];
286
        }
287
        
288 2
        return [$key, $value];
289
    }
290
}
291