/** * Matches the URI against the Routes Mapping Table. * Taking static, dynamic and regexp routings into account. * In other words, it "map matches the URI". * * @return TargetRoute|null */ public function match() { // do we have some routes now? if (0 === count($this->routes)) { throw new \OutOfBoundsException('The routes lookup table is empty. Define some routes.'); } /* * Detects if Mod_Rewrite engine is active and * calls the proper URL Parser/Segmentizer method for the extraction of uri segments. */ if ($this->isRewriteEngineOn() or isset($_ENV['FORCE_MOD_REWRITE_ON']) and true === empty($_GET['mod']) and true === empty($_GET['ctrl'])) { $this->uriSegments = $this->parseUrlRewrite($this->uri); } else { $this->uriSegments = $this->parseUrlNoRewrite($this->uri); $this->uriSegments = self::fixNoRewriteShorthands($this->uriSegments); $targetRoute = TargetRoute::setSegmentsToTargetRoute($this->uriSegments); if ($targetRoute::dispatchable()) { return $targetRoute; } } /* * Reduce the map lookup table, by dropping all routes * with more segments than the current requested uri. */ if (count($this->routes) > 1 and count($this->uriSegments) >= 1) { self::reduceRoutesToSegmentCount(); } /* * Process: Static Route * * Do we have a direct match ? * This matches "static routes". Without any preg_match overhead. * * Example: * The request URI "/news/index" relates 1:1 to $routes['/news/index']. * The request URI "/login" relates 1:1 to $routes['/login'] */ if (isset($this->routes[$this->uri])) { // we have a direct match $found_route = $this->routes[$this->uri]; // return the TargetRoute object return TargetRoute::setSegmentsToTargetRoute($found_route); } else { /* * No, there wasn't a 1:1 match. * Now we have to check the uri segments. * * Let's loop over the remaining routes and try to map match the uri_segments. */ foreach ($this->routes as $route_pattern => $route_values) { unset($route_pattern); $matches = ''; /** * Process: Dynamic Regular Expression Parameters. * * Example: * URI: /news * Rule /:controller * Regexp: "#(?P<controller>[a-z0-9_-]+)\/?#" * Matches: $matches['controller'] = 'news'; */ if (1 === preg_match($route_values['regexp'], $this->uri, $matches)) { // matches[0] contains $this->uri unset($matches[0]); // remove duplicate values // e.g. [controller] = news // [1] = news $matches = array_unique($matches); # @todo # fetch key and its position from $route_values['requirements'] if (count($route_values['requirements']) > 0) { foreach ($route_values['requirements'] as $array_position => $key_name) { // insert a new key // with name from requirements array // and value from matches array // ([id] => 42) $pos = $array_position + 1; $matches[$key_name] = $matches[$pos]; // remove the old not-named key ([2] => 42) unset($matches[$pos]); } } // insert $matches[<controller>] etc TargetRoute::setSegmentsToTargetRoute($matches); } if (TargetRoute::dispatchable()) { // route found, stop foreach break; } else { TargetRoute::reset(); continue; } } } return TargetRoute::instantiate(); }