diff --git a/core/includes/router.inc b/core/includes/router.inc index b8a08f8f7ea1ebc3c30fa5b4352d2da4e62a195b..8c3973c175fc038998007a0e283f7d9fdf2f5b55 100644 --- a/core/includes/router.inc +++ b/core/includes/router.inc @@ -5,7 +5,7 @@ use Symfony\Component\Routing; use Symfony\Component\HttpKernel; use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\Routing\Matcher\UrlMatcher as SymfonyUrlMatcher; +use Drupal\Core\UrlMatcher; /** @@ -20,17 +20,13 @@ * the result to the caller (FALSE). */ function router_execute_active_handler($request) { - // Do some hand waving to setup the routing. - $routes = router_get_routes($request); try { // Resolve a routing context(path, etc) using the routes object to a - // Set a /routing/ context to translate - // @todo probably write our own route object and UrlMatcher to handle - // converting Drupal's db driven backend. + // Set a routing context to translate. $context = new Routing\RequestContext(); $context->fromRequest($request); - $matcher = new SymfonyUrlMatcher($routes, $context); + $matcher = new UrlMatcher($context); // Push path paramaters into attributes. $request->attributes->add($matcher->match($request->getPathInfo())); @@ -53,84 +49,3 @@ function router_execute_active_handler($request) { return $response; } - -/** - * Get a RouteCollection for resolving a request. - * - * Ok, so... we need a routing collection that's not this "dumb". Symfony's just - * is just a trivial implementation. It probably means we need our own - * DrupalRouteCollection which would actually wrap this logic, our menu router - * table, translating between it, and caching. - */ -function router_get_routes($request) { - - // Rebuild if we know it's needed, or if the menu masks are missing which - // occurs rarely, likely due to a race condition of multiple rebuilds. - if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) { - menu_rebuild(); - } - - - $routes = new Routing\RouteCollection(); - $foo = db_query('SELECT path, page_callback, page_arguments FROM {menu_router}'); - while ($router_item = $foo->fetchAssoc()) { - $route = array( - 'path' => $router_item['path'], - '_controller' => $router_item['page_callback'], - ); - if (0 !== strpos($route['path'], '/')) { - $route['path'] = '/' . $route['path']; - } - - // Place argument defaults on the route. - foreach (unserialize($router_item['page_arguments']) as $k => $v) { - $route[$k] = $v; - } - - $routes->add(hash('sha256', $route['path']), new Routing\Route($route['path'], $route)); - } - - return $routes; - - // Since there is no limit to the length of $path, use a hash to keep it - // short yet unique. - $cid = 'menu_item:' . hash('sha256', $path); - if ($cached = cache('menu')->get($cid)) { - $router_item = $cached->data; - } - else { - $parts = array_slice($original_map, 0, MENU_MAX_PARTS); - $ancestors = menu_get_ancestors($parts); - $router_item = db_query_range('SELECT * FROM {menu_router} WHERE path IN (:ancestors) ORDER BY fit DESC', 0, 1, array(':ancestors' => $ancestors))->fetchAssoc(); - cache('menu')->set($cid, $router_item); - } - - $routes = new Routing\RouteCollection(); - foreach (module_list() as $module) { - $items = module_invoke($module, 'menu'); - - foreach ($items as $path => $item) { - // Drupal doesn't prefix but if someone did we wouldn't want to double up. - if (0 !== strpos($path, '/')) { - $path = '/' . $path; - } - - // Set base route array. - $route = array( - // A page callback could be a router. I'm not sure if the controller - // should actually be a thin layer on top or work like this yet. - '_controller' => $item['page callback'], - ); - - // Place argument defaults on the route. - foreach ($item['page arguments'] as $k => $v) { - $route[$k] = $v; - } - // @todo put other "menu" information somewhere. - - $routes->add(hash('sha256', $path), new Routing\Route($path, $route)); - } - } - - return $routes; -} diff --git a/core/lib/Drupal/Core/UrlMatcher.php b/core/lib/Drupal/Core/UrlMatcher.php new file mode 100644 index 0000000000000000000000000000000000000000..f56b13a389226efd4fe92fc6815a6e40b9596de4 --- /dev/null +++ b/core/lib/Drupal/Core/UrlMatcher.php @@ -0,0 +1,85 @@ +context = $context; + } + + /** + * {@inheritDoc} + * + * @api + */ + public function match($pathinfo) { + + $this->allow = array(); + + // Symfony uses a prefixing / but we don't yet. + $dpathinfo = ltrim($pathinfo, '/'); + + // Do our fancy frontpage logic. + if (empty($dpathinfo)) { + $dpathinfo = variable_get('site_frontpage', 'user'); + } + + if ($router_item = $this->matchDrupalItem($dpathinfo)) { + + $routes = new RouteCollection(); + $routes->add(hash('sha256', $router_item['path']), $this->convertDrupalItem($router_item)); + + if ($ret = $this->matchCollection($pathinfo, $routes)) { + return $ret; + } + } + + throw 0 < count($this->allow) + ? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow))) + : new ResourceNotFoundException(); + } + + /** + * Get a drupal menu item. + * + * @param string $path + * The path being looked up by + */ + protected function matchDrupalItem($path) { + // For now we can just proxy our procedural method. At some point this will + // become more complicated because we'll need to get back candidates for a + // path and them resolve them based on things like method and scheme which + // we currently can't do. + return menu_get_item($path); + } + + protected function convertDrupalItem($router_item) { + $route = array( + '_controller' => $router_item['page_callback'] + ); + // Place argument defaults on the route. + foreach ($router_item['page_arguments'] as $k => $v) { + $route[$k] = $v; + } + return new Route($router_item['path'], $route); + } +}