namespace Ice\Mvc\Route\Parser;
use Ice\Exception;
use Ice\Mvc\Route\Parser\ParserInterface;
/**
* Parses route strings of the following form:
*
* "/user/{name}[/{id:[0-9]+}]"
*/
class Std implements ParserInterface
{
const VARIABLE_REGEX = "\\{ \\s* ([a-zA-Z_][a-zA-Z0-9_-]*) \\s* (?: : \\s* ([^{}]*(?:\\{(?-1)\\}[^{}]*)*) )? \\}";
const DEFAULT_DISPATCH_REGEX = "[^/]+";
public function parse(route)
{
var routeWithoutClosingOptionals, numOptionals, segments, currentRoute, routeDatas, n, segment;
let routeWithoutClosingOptionals = rtrim(route, "]"),
numOptionals = strlen(route) - strlen(routeWithoutClosingOptionals);
// Split on [ while skipping placeholders
let segments = preg_split("~" . self::VARIABLE_REGEX . "(*SKIP)(*F) | \\[~x", routeWithoutClosingOptionals);
if numOptionals !== count(segments) - 1 {
// If there are any ] in the middle of the route, throw a more specific error message
if preg_match("~" . self::VARIABLE_REGEX . "(*SKIP)(*F) | \\]~x", routeWithoutClosingOptionals) {
throw new Exception("Optional segments can only occur at the end of a route");
}
throw new Exception("Number of opening '[' and closing ']' does not match");
}
let currentRoute = "",
routeDatas = [];
for n, segment in segments {
if segment === "" && n !== 0 {
throw new Exception("Empty optional part");
}
let currentRoute .= segment,
routeDatas[] = this->parsePlaceholders(currentRoute);
}
return routeDatas;
}
/**
* Parses a route string that does not contain optional segments.
*/
private function parsePlaceholders(route)
{
var matches, routeData, value, offset;
let matches = null;
if !preg_match_all("~" . self::VARIABLE_REGEX . "~x", route, matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER) {
return [route];
}
let offset = 0,
routeData = [];
for value in matches {
if value[0][1] > offset {
let routeData[] = substr(route, offset, value[0][1] - offset);
}
let routeData[] = [
value[1][0],
isset(value[2]) ? trim(value[2][0]) : self::DEFAULT_DISPATCH_REGEX
];
let offset = value[0][1] + strlen(value[0][0]);
}
if offset != strlen(route) {
let routeData[] = substr(route, offset);
}
return routeData;
}
}