Completed
Push — master ( 465cbd...e0d13e )
by Marco
06:44 queued 11s
created

Table::updateRoute()   B

Complexity

Conditions 7
Paths 64

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 13
c 0
b 0
f 0
ccs 10
cts 10
cp 1
rs 8.2222
cc 7
eloc 9
nc 64
nop 4
crap 7
1
<?php namespace Comodojo\Dispatcher\Router;
2
3
use \Comodojo\Foundation\Base\Configuration;
4
use \Comodojo\Dispatcher\Components\AbstractModel;
5
use \Comodojo\Dispatcher\Cache\RouterCache;
6
use \Comodojo\Dispatcher\Request\Model as Request;
7
use \Comodojo\Dispatcher\Router\Parser;
8
use \Comodojo\Dispatcher\Router\Route;
9
use \Comodojo\Dispatcher\Router\Model as Router;
10
use \Comodojo\SimpleCache\Manager as SimpleCacheManager;
11
use \Comodojo\Exception\DispatcherException;
12
use \Psr\Log\LoggerInterface;
13
use \Countable;
14
use \Exception;
15
16
/**
17
 * @package     Comodojo Dispatcher
18
 * @author      Marco Giovinazzi <[email protected]>
19
 * @author      Marco Castiello <[email protected]>
20
 * @license     MIT
21
 *
22
 * LICENSE:
23
 *
24
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
 * THE SOFTWARE.
31
 */
32
33
class Table extends AbstractModel implements Countable {
34
35
    /**
36
     * Types of route that this table will accept
37
     * @var array
38
     */
39
    const ALLOWED_ROUTES = [ "ROUTE", "REDIRECT", "ERROR" ];
40
41
    /**
42
     * Current repository of routes
43
     * @var array
44
     */
45
    protected $routes = [];
46
47
    /**
48
     * @var Parser
49
     */
50
    protected $parser;
51
52
    /**
53
     * @var RouterCache
54
     */
55
    protected $cache;
56
57
    /**
58
     * Table constructor
59
     *
60
     * @param Configuration $configuration
61
     * @param LoggerInterface $logger
62
     * @param SimpleCacheManager $cache
63
     */
64 1
    public function __construct(
65
        Configuration $configuration,
66
        LoggerInterface $logger,
67
        SimpleCacheManager $cache
68
    ) {
69
70 1
        parent::__construct($configuration, $logger);
71
72 1
        $this->parser = new Parser($logger);
73 1
        $this->cache = new RouterCache($cache);
74
75 1
        $this->readCache();
76
77 1
    }
78
79 1
    public function add(
80
        $route,
81
        $type,
82
        $class = null,
83
        array $parameters = []
84
    ) {
85
86 1
        $type = strtoupper($type);
87
88 1
        if ( !in_array($type, self::ALLOWED_ROUTES) ) {
89
90
            $this->getLogger()->error("Invalid route definition - unknown type $type for route $route)");
91
92 1
        } else if ( $type == 'ROUTE' && empty($class) ) {
93
94
            $this->getLogger()->error("Invalid route definition - missing class for route $route)");
95
96
        } else {
97
98 1
            $routeData = $this->get($route);
99
100 1
            if ( !is_null($routeData) ) {
101
102
                $this->updateRoute($routeData, $type, $class, $parameters);
103
104
            } else {
105
106 1
                $folders = explode("/", $route);
107
108 1
                $this->registerRoute($folders, $type, $class, $parameters);
109
110
            }
111
112
        }
113
114 1
        return $this;
115
116
    }
117
118
    /**
119
     * Get registered routes count
120
     *
121
     * @return int
122
     */
123
    public function count() {
124
125
        return count($this->routes);
126
127
    }
128
129 1
    public function getRoutes() {
130
131 1
        return $this->routes;
132
133
    }
134
135 1
    public function get($route) {
136
137 1
        $regex = $this->regex($route);
138
139 1
        if (isset($this->routes[$regex])) {
140 1
            return $this->routes[$regex];
141
        }
142
143 1
        return null;
144
145
    }
146
147 1
    public function regex($route) {
148
149 1
        $folders = explode("/", $route);
150
151 1
        return $this->parser->read($folders);
152
153
    }
154
155 1
    public function remove($route) {
156
157 1
        $regex = $this->regex($route);
158
159 1
        $routes = $this->routes;
160
161 1
        if (isset($routes[$regex])) {
162
163 1
            unset($routes[$regex]);
164
165 1
            $this->routes = $routes;
166
167 1
            return true;
168
169
        }
170
171
        return false;
172
173
    }
174
175
    public function defaultRoute() {
176
177
        return $this->get('/');
178
179
    }
180
181
    public function load(array $routes) {
182
183
        if (!empty($routes)) {
184
185
            foreach ($routes as $name => $route) {
186
187
                $this->add(
188
                    $route['route'],
189
                    $route['type'],
190
                    empty($route['class']) ? null : $route['class'],
191
                    empty($route['parameters']) ? [] : $route['parameters']
192
                );
193
194
            }
195
196
        }
197
198
        $count = $this->count();
199
        $this->logger->debug("$count routes loaded in routing table");
200
201
        $this->dumpCache();
202
203
    }
204
205
    // This method add a route to the supported list
206 1
    private function registerRoute($folders, $type, $class = null, array $parameters = []) {
207
208
        // The values associated with a route are as follows:
209
        // $route = new Route($this->router);
210 1
        $route = new Route();
211
212 1
        $this->updateRoute($route, $type, $class, $parameters);
213
214
        // $route->setType($type) // Type of route
215
        //     ->setClassName($class) // Class to be invoked
216
        //     ->setParameters($parameters); // Parameters passed via the composer.json configuration (cache, ttl, etc...)
217
218 1
        $this->logger->debug("Route table - route: ".implode("/", $folders));
219
220
        // This method generate a global regular expression which will be able to match all the URI supported by the route
221 1
        $regex = $this->parser->read($folders, $route);
222
223 1
        $this->logger->debug("Route table - route regex: $regex");
224
225 1
        $this->routes = array_merge($this->routes, [$regex => $route]);
226
227 1
    }
228
229 1
    private function updateRoute(Route $route, $type, $class = null, array $parameters = []) {
230
231 1
        $route->setType($type)
232 1
            ->setClassName($class)
233 1
            ->setParameters($parameters);
234
235 1
        if ( !empty($parameters['redirect-code']) ) $route->setRedirectCode($parameters['redirect-code']);
236 1
        if ( !empty($parameters['redirect-location']) ) $route->setRedirectLocation($parameters['redirect-location']);
237 1
        if ( !empty($parameters['redirect-message']) ) $route->setRedirectLocation($parameters['redirect-message']);
238 1
        if ( !empty($parameters['redirect-type']) ) $route->setRedirectType($parameters['redirect-type']);
239
240 1
        if ( !empty($parameters['error-code']) ) $route->setErrorCode($parameters['error-code']);
241 1
        if ( !empty($parameters['error-message']) ) $route->setErrorMessage($parameters['error-message']);
242
243 1
    }
244
245 1
    private function readCache() {
246
247 1
        if ($this->configuration->get('routing-table-cache') !== true) return;
248
249
        $data = $this->cache->read();
250
251
        if (is_null($data)) {
252
253
            $this->routes = [];
254
255
            return;
256
257
        }
258
259
        $this->routes = $data;
260
261
        $this->logger->debug("Routing table loaded from cache");
262
263
    }
264
265
    private function dumpCache() {
266
267
        if ($this->configuration->get('routing-table-cache') !== true) return;
268
269
        $ttl = $this->configuration->get('routing-table-ttl');
270
271
        if ($this->cache->dump($this->routes, $ttl)) {
272
            $this->logger->debug("Routing table saved to cache");
273
        } else {
274
            $this->logger->warning("Cannot save routing table to cache");
275
        }
276
277
    }
278
279
}
280