/
RouteCollection.php
146 lines (132 loc) · 3.58 KB
/
RouteCollection.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<?php
namespace Cake\Routing;
use Cake\Routing\Route\Route;
class RouteCollection {
protected $_routes = array();
protected $_routeTable = array();
/**
* Add a route to the collection.
*
* Appends the route to the list of routes, and the route hashtable.
* @param Cake\Routing\Route\Route $route The route to add
* @return void
*/
public function add(Route $route) {
$this->_routes[] = $route;
$name = $route->getName();
if (!isset($this->_routeTable[$name])) {
$this->_routeTable[$name] = array();
}
$this->_routeTable[$name][] = $route;
}
/**
* Reverse route or match a $url array with the defined routes.
* Returns either the string URL generate by the route, or false on failure.
*
* @param array $url The url to match.
* @param array $params The current request parameters, used for persistent parameters.
* @return void
* @TODO Remove persistent params? Are they even useful?
*/
public function match($url, $params = null) {
$names = $this->_getNames($url);
foreach ($names as $name) {
if (isset($this->_routeTable[$name])) {
$routes = $this->_routeTable[$name];
return $this->_matchRoutes($routes, $url, $params);
}
}
return $this->_matchRoutes($this->_routes, $url, $params);
}
protected function _matchRoutes($routes, $url, $params) {
$output = false;
for ($i = 0, $len = count($routes); $i < $len; $i++) {
$originalUrl = $url;
$route =& $routes[$i];
if (isset($route->options['persist'], $params)) {
$url = $route->persistParams($url, $params);
}
if ($match = $route->match($url)) {
$output = trim($match, '/');
break;
}
$url = $originalUrl;
}
return $output;
}
/**
* Get the set of names from the $url. Accepts both older style array urls,
* and newer style urls containing '_name'
*
* @param array $url The url to match.
* @return string The name of the url
*/
protected function _getNames($url) {
$name = false;
if (isset($url['_name'])) {
$name = $url['_name'];
}
$plugin = false;
if (isset($url['plugin'])) {
$plugin = $url['plugin'];
}
$fallbacks = array(
'%2s::%3s',
'%2s::_action',
'_controller::_action'
);
if ($plugin) {
$fallbacks = array(
'%1s.%2s::%3s',
'%1s.%2s::_action',
'_controller::_action'
);
}
foreach ($fallbacks as $i => $template) {
$fallbacks[$i] = sprintf($template, $plugin, $url['controller'], $url['action']);
}
if ($name) {
array_unshift($fallbacks, $name);
}
return $fallbacks;
}
/**
* Takes the URL string and iterates the routes until one is able to parse the route.
*
* @param string $url Url to parse.
* @return array An array of request parameters parsed from the url.
*/
public function parse($url) {
$out = array();
for ($i = 0, $len = count($this->_routes); $i < $len; $i++) {
$route = $this->_routes[$i];
if (($r = $route->parse($url)) !== false) {
$out = $r;
break;
}
}
return $out;
}
/**
* Promote a route (by default, the last one added) to the beginning of the list.
* Does not modify route ordering stored in the hashtable lookups.
*
* @param integer $which A zero-based array index representing
* the route to move. For example,
* if 3 routes have been added, the last route would be 2.
* @return boolean Returns false if no route exists at the position
* specified by $which.
*/
public function promote($which) {
if ($which === null) {
$which = count($this->_routes) - 1;
}
if (!isset($this->_routes[$which])) {
return false;
}
$route =& $this->_routes[$which];
unset($this->_routes[$which]);
array_unshift($this->_routes, $route);
return true;
}
}