Commit 435f4842 authored by Crell's avatar Crell

Add an alias-capable UrlGenerator and use that in Drupal.

parent 229dde1d
......@@ -153,8 +153,9 @@ public function build(ContainerBuilder $container) {
$container->register('router.matcher', 'Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher')
->addArgument(new Reference('router.route_provider'))
->addMethodCall('setFinalMatcher', array(new Reference('router.matcher.final_matcher')));
$container->register('router.generator', 'Symfony\Cmf\Component\Routing\ProviderBasedGenerator')
->addArgument(new Reference('router.route_provider'));
$container->register('router.generator', 'Drupal\Core\Routing\UrlGenerator')
->addArgument(new Reference('router.route_provider'))
->addArgument(new Reference('path.alias_manager.cached'));
$container->register('router.dynamic', 'Symfony\Cmf\Component\Routing\DynamicRouter')
->addArgument(new Reference('router.request_context'))
->addArgument(new Reference('router.matcher'))
......
......@@ -33,6 +33,13 @@ class RouteProvider implements RouteProviderInterface {
*/
protected $tableName;
/**
* A cache of already-loaded routes, keyed by route name.
*
* @var array
*/
protected $routes;
/**
* Constructs a new PathMatcher.
*
......@@ -68,6 +75,8 @@ public function __construct(Connection $connection, $table = 'router') {
* @return \Symfony\Component\Routing\RouteCollection with all urls that
* could potentially match $request. Empty collection if nothing can
* match.
*
* @todo Should this method's found routes also be included in the cache?
*/
public function getRouteCollectionForRequest(Request $request) {
......@@ -151,15 +160,19 @@ public function getRouteByName($name, $parameters = array()) {
* the names of the $names argument.
*/
public function getRoutesByNames($names, $parameters = array()) {
$result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN :names', array(':names' => $names));
$routes_to_load = array_diff($names, array_keys($this->routes));
$result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN :names', array(':names' => $routes_to_load));
$routes = $result->fetchAllKeyed();
$return = array();
foreach ($routes as $name => $route) {
$return[$name] = unserialize($route);
$this->routes[$name] = unserialize($route);
}
return $return;
return array_intersect_key($this->routes, $names);
}
/**
......
<?php
/**
* @file
* Contains of Drupal\Core\Routing\UrlGenerator.
*/
namespace Drupal\Core\Routing;
use Symfony\Cmf\Component\Routing\ProviderBasedGenerator;
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
use Drupal\Core\Path\AliasManagerInterface;
/**
* Description of UrlGenerator
*/
class UrlGenerator extends ProviderBasedGenerator {
/**
* The alias manager that will be used to alias generated URLs.
*
* @var AliasManagerInterface
*/
protected $aliasManager;
public function __construct(RouteProviderInterface $provider, AliasManagerInterface $alias_manager, LoggerInterface $logger = NULL) {
parent::__construct($provider, $logger);
$this->aliasManager = $alias_manager;
}
public function generate($name, $parameters = array(), $absolute = FALSE) {
$path = parent::generate($name, $parameters, $absolute);
// This method is expected to return a path with a leading /, whereas
// the alias manager has no leading /.
$path = '/' . $this->aliasManager->getPathAlias(trim($path, '/'));
return $path;
}
}
<?php
/**
* @file
* Contains of Drupal\system\Tests\Routing\MockAliasManager.
*/
namespace Drupal\system\Tests\Routing;
use Drupal\Core\Path\AliasManagerInterface;
/**
* An easily configurable mock alias manager.
*/
class MockAliasManager implements AliasManagerInterface {
/**
* Array of mocked aliases. Keys are system paths, followed by language.
*
* @var type
*/
protected $aliases = array();
protected $systemPaths = array();
protected $lookedUp = array();
public $defaultLanguage = 'en';
public function addAlias($path, $alias, $path_language = NULL) {
$language = $path_language ?: $this->defaultLanguage;
$this->aliases[$path][$language] = $alias;
$this->systemPaths[$alias][$language] = $path;
}
public function getSystemPath($path, $path_language = NULL) {
$language = $path_language ?: $this->defaultLanguage;
return $this->systemPaths[$path][$language];
}
public function getPathAlias($path, $path_language = NULL) {
$language = $path_language ?: $this->defaultLanguage;
$this->lookedUp[$path] = 1;
return $this->aliases[$path][$language];
}
public function getPathLookups() {
return array_keys($this->lookedUp);
}
public function preloadPathLookups(array $path_list) {
// Not needed.
}
}
<?php
/**
* @file
* Contains of Drupal\system\Tests\Routing\MockRouteProvider.
*/
namespace Drupal\system\Tests\Routing;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
/**
* Easily configurable mock route provider.
*
*/
class MockRouteProvider implements RouteProviderInterface {
/**
*
* @var RouteCollection
*/
protected $routes;
public function __construct(RouteCollection $routes) {
$this->routes = $routes;
}
public function getRouteCollectionForRequest(Request $request) {
}
public function getRouteByName($name, $parameters = array()) {
$routes = $this->getRoutesByNames(array($name), $parameters);
if (empty($routes)) {
throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
}
return reset($routes);
}
public function getRoutesByNames($names, $parameters = array()) {
$routes = array();
foreach ($names as $name) {
$routes[] = $this->routes->get($name);
}
return $routes;
}
}
<?php
/**
* @file
* Contains of Drupal\system\Tests\Routing\UrlGeneratorTest.
*/
namespace Drupal\system\Tests\Routing;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RequestContext;
use Drupal\simpletest\UnitTestBase;
use Drupal\Core\Routing\UrlGenerator;
/**
* Basic tests for the Route.
*/
class UrlGeneratorTest extends UnitTestBase {
protected $generator;
protected $aliasManager;
public static function getInfo() {
return array(
'name' => 'UrlGenerator',
'description' => 'Confirm that the UrlGenerator is functioning properly.',
'group' => 'Routing',
);
}
function setUp() {
parent::setUp();
$routes = new RouteCollection();
$routes->add('test_1', new Route('/test/one'));
$routes->add('test_2', new Route('/test/two/{narf}'));
$provider = new MockRouteProvider($routes);
$this->aliasManager = new MockAliasManager();
$this->aliasManager->addAlias('test/one', 'hello/world');
$context = new RequestContext();
$context->fromRequest(Request::create('/some/path'));
$generator = new UrlGenerator($provider, $this->aliasManager);
$generator->setContext($context);
$this->generator = $generator;
}
/**
* Confirms that generated routes will have aliased paths.
*/
public function testAliasGeneration() {
$url = $this->generator->generate('test_1');
$this->assertEqual($url, '/hello/world', 'Correct URL generated including alias.');
}
/**
* Confirms that generated routes will have aliased paths.
*/
public function testAliasGenerationWithParameters() {
$this->aliasManager->addAlias('test/two/5', 'goodbye/cruel/world');
$url = $this->generator->generate('test_2', array('narf' => '5'));
$this->assertEqual($url, '/goodbye/cruel/world', 'Correct URL generated including alias and parameters.');
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment