First thing first, a simple route addition:
# The order is as-is in my environment
Route::PATTERN('/^\/style\/(.*?)\/$/', 'style/[0].css');
Route::PATTERN('/^\/style\/(.*?)\/image-storage\/(.*?)\/$/', 'transformed/images/[1]');
Route::SIMPLE('/blog', 'parts/blog');
The routes are not sorted by priorities for now (that’s an option if nothing else can be done, but I’d like to avoid it), and active route is determined, routine is performed after a scan (foreach loop through routes added above in the same order):
foreach(self::$routes as $route){
// lookup active route
switch($route->type){
case self::TYPE_SIMPLE:
if($route->lookup === $_SERVER['REQUEST_URI']) self::$active = $route;
break;
case self::TYPE_PATTERN:
if(preg_match_all($route->lookup, $_SERVER['REQUEST_URI'], $found)){
// find all replaceable entries of route
preg_match_all('/((?<=\[)\d(?=\]))/', $route->location, $replace);
// remove first results
$lookup = array_shift($found);
$location = array_shift($replace);
// make the actual location out of both
foreach($replace[0] as $value)
if(isset($found[$value]))
$route->location = str_replace('[' . $value . ']', $found[$value][0], $route->location);
// this is active, cache it
self::$active = $route;
}
break;
}
}
// I have left out the active route and routine parsing, because the problem is here at the
// case self::TYPE_PATTERN part
The thing here is that the second pattern route is matched by the first one. I could prevent this with a lookahead, but the routes will later become dynamic and nested, therefore unpredictable- lookaheads could/would fail.
I had an idea about length comparison of requests and lookups (the patterns), but that’s pretty darn unpredictable also.
So, the question, how could I avoid this collision?
Move the less general route to the top, above the other. Then only if that fails to match will the more general one be attempted: