|
37 | 37 | */ |
38 | 38 | abstract class AbstractRoute |
39 | 39 | { |
| 40 | + /** @const string Identifier for catch-all parameters in a route path */ |
40 | 41 | const CATCHALL_IDENTIFIER = '/**'; |
| 42 | + /** @const string Identifier for normal parameters in a route path */ |
41 | 43 | const PARAM_IDENTIFIER = '/*'; |
| 44 | + /** @const string Quoted version of the normal parameter identifier */ |
42 | 45 | const QUOTED_PARAM_IDENTIFIER = '/\*'; |
| 46 | + /** @const string A regular expression that cathes from a / to the end */ |
43 | 47 | const REGEX_CATCHALL = '(/.*)?'; |
| 48 | + /** @const string A regular expression that cathes one parameter */ |
44 | 49 | const REGEX_SINGLE_PARAM = '/([^/]+)'; |
| 50 | + /** @const string A regular expression that cathes one ending parameter */ |
45 | 51 | const REGEX_ENDING_PARAM = '#/\(\[\^/\]\+\)#'; |
| 52 | + /** @const string A regular expression that cathes one optional parameter */ |
46 | 53 | const REGEX_OPTIONAL_PARAM = '(?:/([^/]+))?'; |
| 54 | + /** @const string A regular expression that identifies invalid parameters */ |
47 | 55 | const REGEX_INVALID_OPTIONAL_PARAM = '#\(\?\:/\(\[\^/\]\+\)\)\?/#'; |
48 | 56 |
|
| 57 | + /** @var string The HTTP method for this route (GET, POST, ANY, etc) */ |
49 | 58 | public $method = ''; |
| 59 | + /** @var string The minimalistic pattern for route paths for this route */ |
50 | 60 | public $pattern = ''; |
| 61 | + /** @var string The generated regex for the route pattern */ |
51 | 62 | public $regexForMatch = ''; |
| 63 | + /** @var string The generated regex for creating URIs from parameters */ |
52 | 64 | public $regexForReplace = ''; |
| 65 | + /** @var array A list of routines appended to this route */ |
53 | 66 | public $routines = array(); |
| 67 | + /** @var array A list of side routes to be used */ |
54 | 68 | public $sideRoutes = array(); |
| 69 | + /** @var array A virtualhost applied to this route (deprecated) */ |
55 | 70 | public $virtualHost = null; |
56 | 71 |
|
57 | | - /** Returns the RelfectionFunctionAbstract object for the passed method */ |
| 72 | + /** |
| 73 | + * Returns the RelfectionFunctionAbstract object for the passed method |
| 74 | + * |
| 75 | + * @param string $method The HTTP method (GET, POST, etc) |
| 76 | + */ |
58 | 77 | abstract public function getReflection($method); |
59 | 78 |
|
60 | | - /** Runs the target method/params into this route */ |
| 79 | + /** |
| 80 | + * Runs the target method/params into this route |
| 81 | + * |
| 82 | + * @param string $method The HTTP method (GET, POST, etc) |
| 83 | + * @param array $params A list of params to pass to the target |
| 84 | + */ |
61 | 85 | abstract public function runTarget($method, &$params); |
62 | 86 |
|
| 87 | + /** |
| 88 | + * @param string $method The HTTP method (GET, POST, etc) |
| 89 | + * @param string $pattern The pattern for this route path |
| 90 | + */ |
63 | 91 | public function __construct($method, $pattern) |
64 | 92 | { |
65 | 93 | $this->pattern = $pattern; |
66 | 94 | $this->method = strtoupper($method); |
| 95 | + |
67 | 96 | list($this->regexForMatch, $this->regexForReplace) |
68 | 97 | = $this->createRegexPatterns($pattern); |
69 | 98 | } |
70 | 99 |
|
| 100 | + /** |
| 101 | + * A magic routine builder and composite appender |
| 102 | + * |
| 103 | + * @param string $method The HTTP method (GET, POST, etc) |
| 104 | + * @param array $arguments Arguments to pass to this routine constructor |
| 105 | + * @see Respect\Rest\Routes\AbstractRoute::appendRoutine |
| 106 | + * |
| 107 | + * @return AbstractRoute The route itselt |
| 108 | + */ |
71 | 109 | public function __call($method, $arguments) |
72 | 110 | { |
73 | | - $routineReflection = new ReflectionClass( |
| 111 | + $reflection = new ReflectionClass( |
74 | 112 | 'Respect\\Rest\\Routines\\' . ucfirst($method) |
75 | 113 | ); |
76 | 114 |
|
77 | | - return $this->appendRoutine($routineReflection->newInstanceArgs($arguments)); |
| 115 | + return $this->appendRoutine($reflection->newInstanceArgs($arguments)); |
78 | 116 | } |
79 | 117 |
|
80 | | - /** Appends a pre-built routine to this route */ |
| 118 | + /** |
| 119 | + * Appends a pre-built routine to this route |
| 120 | + * |
| 121 | + * @param Routinable $routine A routine to be appended |
| 122 | + * @see Respect\Rest\Routes\AbstractRoute::__call |
| 123 | + * |
| 124 | + * @return AbstractRoute The route itselt |
| 125 | + */ |
81 | 126 | public function appendRoutine(Routinable $routine) |
82 | 127 | { |
83 | | - $key = $routine instanceof Unique ? get_class($routine) : spl_object_hash($routine); |
| 128 | + $key = $routine instanceof Unique |
| 129 | + ? get_class($routine) |
| 130 | + : spl_object_hash($routine); |
| 131 | + |
84 | 132 | $this->routines[$key] = $routine; |
85 | 133 | return $this; |
86 | 134 | } |
87 | 135 |
|
88 | | - /** Creates an URI for this route with the passed parameters */ |
| 136 | + /** |
| 137 | + * Creates an URI for this route with the passed parameters, replacing |
| 138 | + * them in the declared pattern. /hello/* with ['tom'] returns /hello/tom |
| 139 | + * |
| 140 | + * @param mixed $param1 Some parameter |
| 141 | + * @param mixed $etc This route accepts as many parameters you can pass |
| 142 | + * |
| 143 | + * @return string the created URI |
| 144 | + */ |
89 | 145 | public function createUri($param1=null, $etc=null) |
90 | 146 | { |
91 | 147 | $params = func_get_args(); |
92 | 148 | array_unshift($params, $this->regexForReplace); |
93 | | - return rtrim($this->virtualHost, '/') . call_user_func_array( |
94 | | - 'sprintf', $params |
95 | | - ); |
| 149 | + |
| 150 | + return rtrim($this->virtualHost, '/') . |
| 151 | + call_user_func_array('sprintf', $params); |
96 | 152 | } |
97 | 153 |
|
| 154 | + /** |
| 155 | + * Passes a request through all this routes ProxyableWhen routines |
| 156 | + * |
| 157 | + * @param Request $request The request you want to process |
| 158 | + * @param array $params Parameters for the processed request |
| 159 | + * @see Respect\Rest\Routines\ProxyableWhen |
| 160 | + * |
| 161 | + * @return bool always true \,,/ |
| 162 | + */ |
98 | 163 | public function matchRoutines(Request $request, $params=array()) |
99 | 164 | { |
100 | | - foreach ($this->routines as $routine) |
101 | | - if ($routine instanceof ProxyableWhen |
102 | | - && !$request->routineCall('when', $request->method, $routine, $params)) |
| 165 | + foreach ($this->routines as $routine) { |
| 166 | + if ( |
| 167 | + $routine instanceof ProxyableWhen |
| 168 | + && !$request->routineCall( |
| 169 | + 'when', |
| 170 | + $request->method, |
| 171 | + $routine, |
| 172 | + $params) |
| 173 | + ) { |
103 | 174 | return false; |
| 175 | + } |
| 176 | + } |
104 | 177 |
|
105 | 178 | return true; |
106 | 179 | } |
107 | 180 |
|
108 | | - /** Checks if this route matches a request */ |
| 181 | + /** |
| 182 | + * Checks if a request passes for this route |
| 183 | + * |
| 184 | + * @param Request $request The request you want to process |
| 185 | + * @param array $params Parameters for the processed request |
| 186 | + * |
| 187 | + * @return bool as true as xkcd (always true) |
| 188 | + */ |
109 | 189 | public function match(Request $request, &$params=array()) |
110 | 190 | { |
111 | 191 | $params = array(); |
112 | 192 | $matchUri = $request->uri; |
113 | 193 |
|
114 | | - foreach ($this->routines as $routine) |
115 | | - if ($routine instanceof IgnorableFileExtension) |
116 | | - $matchUri = preg_replace('#(\.[\w\d-_.~\+]+)*$#', '', |
117 | | - $request->uri); |
| 194 | + foreach ($this->routines as $routine) { |
| 195 | + if ($routine instanceof IgnorableFileExtension) { |
| 196 | + $matchUri = preg_replace( |
| 197 | + '#(\.[\w\d-_.~\+]+)*$#', |
| 198 | + '', |
| 199 | + $request->uri |
| 200 | + ); |
| 201 | + } |
| 202 | + } |
118 | 203 |
|
119 | | - if (!preg_match($this->regexForMatch, $matchUri, $params)) |
| 204 | + if (!preg_match($this->regexForMatch, $matchUri, $params)) { |
120 | 205 | return false; |
| 206 | + } |
121 | 207 |
|
122 | 208 | array_shift($params); |
123 | 209 |
|
124 | | - if (false !== stripos($this->pattern, '/**') && false !== stripos(end($params), '/')) { |
| 210 | + if ( |
| 211 | + false !== stripos($this->pattern, '/**') |
| 212 | + && false !== stripos(end($params), '/') |
| 213 | + ) { |
125 | 214 | $lastParam = array_pop($params); |
126 | 215 | $params[] = explode('/', ltrim($lastParam, '/')); |
| 216 | + } elseif ( |
| 217 | + false !== stripos($this->pattern, '/**') && !isset($params[0]) |
| 218 | + ) { |
| 219 | + $params[] = array(); // callback expects a parameter give it |
127 | 220 | } |
128 | | - elseif (false !== stripos($this->pattern, '/**') && !isset($params[0])) |
129 | | - $params[] = array(); // callback expects a parameter give it |
130 | 221 |
|
131 | 222 | return true; |
132 | 223 | } |
133 | 224 |
|
134 | | - /** Creates the regex from the route patterns */ |
| 225 | + /** |
| 226 | + * This creates a regular expression that matches a route pattern and |
| 227 | + * extracts it's parameters |
| 228 | + * |
| 229 | + * @param string $pattern The pattern for the regex creation |
| 230 | + * |
| 231 | + * @return array A matcher regex and a replacer regex for createUri() |
| 232 | + */ |
135 | 233 | protected function createRegexPatterns($pattern) |
136 | 234 | { |
137 | 235 | $pattern = rtrim($pattern, ' /'); |
138 | 236 | $extra = $this->extractCatchAllPattern($pattern); |
139 | 237 | $matchPattern = str_replace( |
140 | | - static::QUOTED_PARAM_IDENTIFIER, static::REGEX_SINGLE_PARAM, preg_quote($pattern), $paramCount |
| 238 | + static::QUOTED_PARAM_IDENTIFIER, |
| 239 | + static::REGEX_SINGLE_PARAM, |
| 240 | + preg_quote($pattern), |
| 241 | + $paramCount |
| 242 | + ); |
| 243 | + $replacePattern = str_replace( |
| 244 | + static::PARAM_IDENTIFIER, |
| 245 | + '/%s', |
| 246 | + $pattern |
141 | 247 | ); |
142 | | - $replacePattern = str_replace(static::PARAM_IDENTIFIER, '/%s', $pattern); |
143 | 248 | $matchPattern = $this->fixOptionalParams($matchPattern); |
144 | 249 | $matchRegex = "#^{$matchPattern}{$extra}$#"; |
145 | 250 | return array($matchRegex, $replacePattern); |
146 | 251 | } |
147 | 252 |
|
148 | | - /** Extracts the catch-all param from a pattern */ |
| 253 | + /** |
| 254 | + * Extracts the catch-all parameter from a pattern and modifies the passed |
| 255 | + * parameter to remove that. Yes, we're modifying by reference. |
| 256 | + * |
| 257 | + * @param string $pattern The pattern for the regex creation |
| 258 | + * |
| 259 | + * @return string The catch-all parameter or empty string |
| 260 | + */ |
149 | 261 | protected function extractCatchAllPattern(&$pattern) |
150 | 262 | { |
151 | 263 | $extra = static::REGEX_CATCHALL; |
152 | 264 |
|
153 | | - if ((strlen($pattern) - strlen(static::CATCHALL_IDENTIFIER)) |
154 | | - === strripos($pattern, static::CATCHALL_IDENTIFIER)) |
| 265 | + if ( |
| 266 | + (strlen($pattern) - strlen(static::CATCHALL_IDENTIFIER)) |
| 267 | + === strripos($pattern, static::CATCHALL_IDENTIFIER) |
| 268 | + ) { |
155 | 269 | $pattern = substr($pattern, 0, -3); |
156 | | - else |
| 270 | + } else { |
157 | 271 | $extra = ''; |
| 272 | + } |
158 | 273 |
|
159 | 274 | $pattern = str_replace( |
160 | | - static::CATCHALL_IDENTIFIER, static::PARAM_IDENTIFIER, $pattern |
| 275 | + static::CATCHALL_IDENTIFIER, |
| 276 | + static::PARAM_IDENTIFIER, |
| 277 | + $pattern |
161 | 278 | ); |
162 | 279 | return $extra; |
163 | 280 | } |
164 | 281 |
|
165 | | - /** Turn sequenced parameters optional */ |
| 282 | + /** |
| 283 | + * Identifies using regular expressions a sequence of parameters in the end |
| 284 | + * of a pattern and make the latest ones optional for the matcher regex |
| 285 | + * |
| 286 | + * @param string $quotedPattern a preg_quoted route pattern |
| 287 | + */ |
166 | 288 | protected function fixOptionalParams($quotedPattern) |
167 | 289 | { |
168 | | - if (strlen($quotedPattern) - strlen(static::REGEX_SINGLE_PARAM) |
169 | | - === strripos($quotedPattern, static::REGEX_SINGLE_PARAM)) |
| 290 | + if ( |
| 291 | + strlen($quotedPattern) - strlen(static::REGEX_SINGLE_PARAM) |
| 292 | + === strripos($quotedPattern, static::REGEX_SINGLE_PARAM) |
| 293 | + ) { |
170 | 294 | $quotedPattern = preg_replace( |
171 | 295 | static::REGEX_ENDING_PARAM, |
172 | 296 | static::REGEX_OPTIONAL_PARAM, |
173 | 297 | $quotedPattern |
174 | 298 | ); |
| 299 | + } |
175 | 300 |
|
176 | 301 | $quotedPattern = preg_replace( |
177 | 302 | static::REGEX_INVALID_OPTIONAL_PARAM, |
|
0 commit comments