/** * compile * * @param string $pattern * @param array $requirements * * @return string */ public static function compile($pattern, $requirements = array()) { $pattern = RouteHelper::sanitize($pattern); $regex = static::replaceOptionalSegments($pattern); $regex = static::replaceWildcards($regex); return chr(1) . '^' . static::replaceAllRegex($regex, $requirements) . '$' . chr(1); }
/** * generate * * @param string $pattern * @param array $queries * * @return mixed|string */ public static function generate($pattern, array $queries = array()) { $replace = array(); $pattern = RouteHelper::sanitize($pattern); if (!isset(static::$vars[$pattern])) { TrieCompiler::compile($pattern); static::$vars[$pattern] = (array) TrieCompiler::$vars; } foreach (static::$vars[$pattern] as $key) { $var = isset($queries[$key]) ? $queries[$key] : 'null'; if (is_array($var) || is_object($var)) { $var = implode('/', (array) $var); $key2 = '*' . $key; $replace[$key2] = $var; } else { $key2 = ':' . $key; $replace[$key2] = $var; } if (strpos($pattern, $key2) !== false) { unset($queries[$key]); } } $pattern = strtr($pattern, $replace); $queries = http_build_query($queries); if ($queries) { $pattern = rtrim($pattern, '/') . '/?' . $queries; } return $pattern; }
/** * testGetVariables * * @return void * * @covers Windwalker\Router\RouteHelper::getVariables */ public function testGetVariables() { $array = array(0 => 5, 'id' => 5, 1 => 'foo', 'bar' => 'foo'); $this->assertEquals(array('id' => 5, 'bar' => 'foo'), RouteHelper::getVariables($array)); $vars = array('flower' => 'sakura'); $this->assertEquals(array('flower' => 'sakura', 'id' => 5, 'bar' => 'foo'), RouteHelper::getVariables($array, $vars)); }
/** * Method to test compile(). * * @param string $pattern * @param string $expected * @param int $line * * @return void * * @covers Windwalker\Router\Compiler\BasicCompiler::compile * * @dataProvider regexList */ public function testCompile($pattern, $expected, $route, $expectedMatches, $line) { $regex = TrieCompiler::compile($pattern, array('id' => '\\d+')); $this->assertEquals(chr(1) . '^' . $expected . '$' . chr(1), $regex, 'Fail at: ' . $line); preg_match($regex, $route, $matches); $vars = RouteHelper::getVariables($matches); $this->assertNotEmpty($matches); $this->assertEquals($expectedMatches, $vars); }
/** * Match routes. * * @param string $route * @param Route $routeItem * * @return Route|false */ public function matchRoute($route, Route $routeItem) { $regex = $routeItem->getRegex(); if (!$regex || $this->debug) { $regex = BasicCompiler::compile($routeItem->getPattern(), $routeItem->getRequirements()); $routeItem->setRegex($regex); } $route = RouteHelper::normalise($route); if (preg_match($regex, $route, $matches)) { $variables = RouteHelper::getVariables($matches); $variables['_rawRoute'] = $route; } else { return false; } $routeItem->setVariables(array_merge($routeItem->getVariables(), $variables)); return $routeItem; }
/** * compile * * @param string $pattern * @param array $requirements * * @return string */ public static function compile($pattern, $requirements = array()) { // Sanitize and explode the pattern. $pattern = RouteHelper::sanitize($pattern); $vars = array(); $regex = array(); // Loop on each segment foreach (explode('/', $pattern) as $segment) { if ($segment == '') { // Match root route. $regex[] = ''; } elseif ($segment == '*') { // Match a splat with no variable. $regex[] = '.*'; } elseif ($segment[0] == '*') { // Match a splat and capture the data to a named variable. $vars[] = $segment = substr($segment, 1); $regex[] = '(?P<' . $segment . '>.*)'; } elseif ($segment[0] == '\\' && $segment[1] == '*') { // Match an escaped splat segment. $regex[] = '\\*' . preg_quote(substr($segment, 2)); } elseif ($segment == ':') { // Match an unnamed variable without capture. $regex[] = '[^/]*'; } elseif ($segment[0] == ':') { // Match a named variable and capture the data. $vars[] = $segment = substr($segment, 1); $regex[] = static::requirementPattern($segment, $requirements); } elseif ($segment[0] == '\\' && $segment[1] == ':') { // Match a segment with an escaped variable character prefix. $regex[] = preg_quote(substr($segment, 1)); } else { // Match the standard segment. $regex[] = preg_quote($segment); } } static::$vars = $vars; return chr(1) . '^' . implode('/', $regex) . '$' . chr(1); }
/** * Match routes. * * @param string $route * @param string $method * @param array $options * * @return Route|false */ public function match($route, $method = 'GET', $options = array()) { $route = RouteHelper::normalise($route); $this->count = 0; $this->buildRouteMaps(); $keys = array_keys($this->routeMaps); $left = 0; $right = count($this->routeMaps) - 1; while ($left <= $right) { $middle = round(($left + $right) / 2); $key = $keys[$middle]; $routeItem = $this->routes[$this->routeMaps[$key]]; $this->count++; if ($this->matchOptions($routeItem, $method, $options) && $this->matchRoute($route, $routeItem)) { return $routeItem; } if (strcmp($route, $key) < 0) { $right = $middle - 1; } else { $left = $middle + 1; } } return false; }
/** * buildRoute * * @param string $name * @param array $queries * @param bool $rootSlash * * @return string */ public function build($name, $queries = array(), $rootSlash = false) { if (!array_key_exists($name, $this->routes)) { throw new \OutOfRangeException('Route: ' . $name . ' not found.'); } $route = $this->matcher->build($this->routes[$name], (array) $queries); if ($rootSlash) { return RouteHelper::normalise($route); } return ltrim($route, '/'); }
/** * setPattern * * @param string $pattern * * @return Route Return self to support chaining. */ public function setPattern($pattern) { $this->pattern = RouteHelper::normalise($pattern); return $this; }
/** * matchSegment * * @param array $segments * @param array $node * @param int $level * * @return bool|Route */ protected function matchSegment($segments, $node, $level = 1) { $segment = isset($segments[$level - 1]) ? $segments[$level - 1] : false; if ($segment === false) { return false; } $segment = $segment ?: '/'; foreach ($node as $regex => $child) { $this->count++; // Start with a '(' is a regex if ($regex[0] == '(') { preg_match(chr(1) . $regex . chr(1), $segment, $match); if (!$match) { continue; } RouteHelper::getVariables($match, $this->vars); } else { if ($regex != $segment) { continue; } } $result = false; // Has child, iterate it. if ($child && is_array($child)) { $child = $this->matchSegment($segments, $child, $level + 1); } // If is string, means we get a route index, using this index to find Route from maps. if (is_string($child)) { $child = $this->routes[$this->routeMaps[$child]]; } // Match this Route if ($child instanceof Route) { $result = $this->matchOptions($child, $this->method, $this->options); } // If match fail, continue find next element. if (!$result) { continue; } return $child; } return false; }