summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Pott2013-07-20 17:42:28 (GMT)
committerAlex Pott2013-07-20 17:42:28 (GMT)
commit486f5d0376e5c2fa13fad040624b30e67d6a67af (patch)
tree84c0e6b759b9b74a05bbf6b73b1a8c1a8886b1f5
parent3172ea413cbe0ae8538941bc523f9b72e05bb73c (diff)
Issue #2031353 by pwolanin, dawehner, katbailey: Fixed URLgenerator broken for Drupal installed in a subdirectory - doesn't have a way to get a Drupal path.
-rw-r--r--core/lib/Drupal/Core/Routing/PathBasedGeneratorInterface.php14
-rw-r--r--core/lib/Drupal/Core/Routing/UrlGenerator.php73
-rw-r--r--core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php109
3 files changed, 171 insertions, 25 deletions
diff --git a/core/lib/Drupal/Core/Routing/PathBasedGeneratorInterface.php b/core/lib/Drupal/Core/Routing/PathBasedGeneratorInterface.php
index 5c91e62..79ed373 100644
--- a/core/lib/Drupal/Core/Routing/PathBasedGeneratorInterface.php
+++ b/core/lib/Drupal/Core/Routing/PathBasedGeneratorInterface.php
@@ -30,6 +30,20 @@ interface PathBasedGeneratorInterface {
public function generateFromPath($path = NULL, $options = array());
/**
+ * Gets the internal path of a route.
+ *
+ * @param string $name
+ * The route name.
+ * @param array $parameters
+ * An array of parameters as passed to
+ * \Symfony\Component\Routing\Generator\UrlGeneratorInterface::generate().
+ *
+ * @return string
+ * The internal Drupal path corresponding to the route.
+ */
+ public function getPathFromRoute($name, $parameters = array());
+
+ /**
* Sets the $request property.
*
* @param \Symfony\Component\HttpFoundation\Request $request
diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php
index 972058a..402caa6 100644
--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -105,17 +105,31 @@ class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorI
}
/**
- * Implements Symfony\Component\Routing\Generator\UrlGeneratorInterface::generate().
+ * {@inheritdoc}
*/
- public function generate($name, $parameters = array(), $absolute = FALSE) {
-
- if ($name instanceof SymfonyRoute) {
- $route = $name;
- }
- elseif (NULL === $route = $this->provider->getRouteByName($name, $parameters)) {
- throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
- }
+ public function getPathFromRoute($name, $parameters = array()) {
+ $route = $this->getRoute($name, $parameters);
+ $path = $this->getInternalPathFromRoute($route, $parameters);
+ // Router-based paths may have a querystring on them but Drupal paths may
+ // not have one, so remove any ? and anything after it. For generate() this
+ // is handled in processPath().
+ $path = preg_replace('/\?.*/', '', $path);
+ return trim($path, '/');
+ }
+ /**
+ * Gets the path of a route.
+ *
+ * @param \Symfony\Component\Routing\Route $route
+ * The route object.
+ * @param array $parameters
+ * An array of parameters as passed to
+ * \Symfony\Component\Routing\Generator\UrlGeneratorInterface::generate().
+ *
+ * @return string
+ * The url path corresponding to the route, without the base path.
+ */
+ protected function getInternalPathFromRoute(SymfonyRoute $route, $parameters = array()) {
// The Route has a cache of its own and is not recompiled as long as it does
// not get modified.
$compiledRoute = $route->compile();
@@ -125,10 +139,9 @@ class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorI
// We need to bypass the doGenerate() method's handling of absolute URLs as
// we handle that ourselves after processing the path.
if (isset($route_requirements['_scheme'])) {
- $scheme_req = $route_requirements['_scheme'];
unset($route_requirements['_scheme']);
}
- $path = $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route_requirements, $compiledRoute->getTokens(), $parameters, $name, FALSE, $hostTokens);
+ $path = $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route_requirements, $compiledRoute->getTokens(), $parameters, $route->getPath(), FALSE, $hostTokens);
// The URL returned from doGenerate() will include the base path if there is
// one (i.e., if running in a subdirectory) so we need to strip that off
@@ -137,8 +150,18 @@ class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorI
if (!empty($base_url) && strpos($path, $base_url) === 0) {
$path = substr($path, strlen($base_url));
}
+ return $path;
+ }
+ /**
+ * {@inheritdoc}
+ */
+ public function generate($name, $parameters = array(), $absolute = FALSE) {
+ $route = $this->getRoute($name, $parameters);
+ $path = $this->getInternalPathFromRoute($route, $parameters);
$path = $this->processPath($path);
+
+ $base_url = $this->context->getBaseUrl();
if (!$absolute || !$host = $this->context->getHost()) {
return $base_url . $path;
}
@@ -146,6 +169,7 @@ class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorI
// Prepare an absolute URL by getting the correct scheme, host and port from
// the request context.
$scheme = $this->context->getScheme();
+ $scheme_req = $route->getRequirement('_scheme');
if (isset($scheme_req) && ($req = strtolower($scheme_req)) && $scheme !== $req) {
$scheme = $req;
}
@@ -356,4 +380,31 @@ class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorI
return isset($this->basePath) && isset($this->baseUrl) && isset($this->scriptPath);
}
+ /**
+ * Find the route using the provided route name (and parameters).
+ *
+ * @param string $name
+ * The route name to fetch
+ * @param array $parameters
+ * The parameters as they are passed to the UrlGeneratorInterface::generate
+ * call.
+ *
+ * @return \Symfony\Component\Routing\Route
+ * The found route.
+ *
+ * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
+ * Thrown if there is no route with that name in this repository.
+ *
+ * @see \Drupal\Core\Routing\RouteProviderInterface
+ */
+ protected function getRoute($name, $parameters) {
+ if ($name instanceof SymfonyRoute) {
+ $route = $name;
+ }
+ elseif (NULL === $route = $this->provider->getRouteByName($name, $parameters)) {
+ throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
+ }
+ return $route;
+ }
+
}
diff --git a/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php b/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
index 079213e..d6006ad 100644
--- a/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
@@ -30,6 +30,11 @@ use Drupal\Core\Routing\UrlGenerator;
*/
class UrlGeneratorTest extends UnitTestCase {
+ /**
+ * The url generator to test.
+ *
+ * @var \Drupal\Core\Routing\UrlGenerator
+ */
protected $generator;
protected $aliasManager;
@@ -47,24 +52,50 @@ class UrlGeneratorTest extends UnitTestCase {
$routes = new RouteCollection();
$first_route = new Route('/test/one');
$second_route = new Route('/test/two/{narf}');
+ $third_route = new Route('/test/two/');
+ $fourth_route = new Route('/test/four', array(), array('_scheme' => 'https'));
$routes->add('test_1', $first_route);
$routes->add('test_2', $second_route);
+ $routes->add('test_3', $third_route);
+ $routes->add('test_4', $fourth_route);
// Create a route provider stub.
$provider = $this->getMockBuilder('Drupal\Core\Routing\RouteProvider')
->disableOriginalConstructor()
->getMock();
- $route_name_return_map = array(
- array('test_1', array(), $first_route),
- array('test_2', array('narf' => '5'), $second_route),
+ // We need to set up return value maps for both the getRouteByName() and the
+ // getRoutesByNames() method calls on the route provider. The parameters
+ // passed in will be slightly different but based on the same information.
+ $route_name_return_map = $routes_names_return_map = array();
+ $return_map_values = array(
+ array(
+ 'route_name' => 'test_1',
+ 'parameters' => array(),
+ 'return' => $first_route,
+ ),
+ array(
+ 'route_name' => 'test_2',
+ 'parameters' => array('narf' => '5'),
+ 'return' => $second_route,
+ ),
+ array(
+ 'route_name' => 'test_3',
+ 'parameters' => array(),
+ 'return' => $third_route,
+ ),
+ array(
+ 'route_name' => 'test_4',
+ 'parameters' => array(),
+ 'return' => $fourth_route,
+ ),
);
+ foreach ($return_map_values as $values) {
+ $route_name_return_map[] = array($values['route_name'], $values['parameters'], $values['return']);
+ $routes_names_return_map[] = array(array($values['route_name']), $values['parameters'], $values['return']);
+ }
$provider->expects($this->any())
->method('getRouteByName')
->will($this->returnValueMap($route_name_return_map));
- $routes_names_return_map = array(
- array(array('test_1'), array(), array($first_route)),
- array(array('test_2'), array('narf' => '5'), array($second_route)),
- );
$provider->expects($this->any())
->method('getRoutesByNames')
->will($this->returnValueMap($routes_names_return_map));
@@ -73,14 +104,10 @@ class UrlGeneratorTest extends UnitTestCase {
$alias_manager = $this->getMockBuilder('Drupal\Core\Path\AliasManager')
->disableOriginalConstructor()
->getMock();
- $alias_map = array(
- array('test/one', NULL, 'hello/world'),
- array('test/two/5', NULL, 'goodbye/cruel/world'),
- array('node/123', NULL, 'node/123'),
- );
+
$alias_manager->expects($this->any())
->method('getPathAlias')
- ->will($this->returnValueMap($alias_map));
+ ->will($this->returnCallback(array($this, 'aliasManagerCallback')));
$this->aliasManager = $alias_manager;
@@ -100,11 +127,47 @@ class UrlGeneratorTest extends UnitTestCase {
}
/**
+ * Return value callback for the getPathAlias() method on the mock alias manager.
+ *
+ * Ensures that by default the call to getPathAlias() will return the first argument
+ * that was passed in. We special-case the paths for which we wish it to return an
+ * actual alias.
+ *
+ * @return string
+ */
+ public function aliasManagerCallback() {
+ $args = func_get_args();
+ switch($args[0]) {
+ case 'test/one':
+ return 'hello/world';
+ case 'test/two/5':
+ return 'goodbye/cruel/world';
+ case '<front>':
+ return '';
+ default:
+ return $args[0];
+ }
+ }
+
+ /**
* Confirms that generated routes will have aliased paths.
*/
public function testAliasGeneration() {
$url = $this->generator->generate('test_1');
$this->assertEquals('/hello/world', $url);
+
+ $path = $this->generator->getPathFromRoute('test_1');
+ $this->assertEquals('test/one', $path);
+ }
+
+ /**
+ * Tests URL generation in a subdirectory.
+ */
+ public function testGetPathFromRouteWithSubdirectory() {
+ $this->generator->setBasePath('/test-base-path');
+
+ $path = $this->generator->getPathFromRoute('test_1');
+ $this->assertEquals('test/one', $path);
}
/**
@@ -113,6 +176,17 @@ class UrlGeneratorTest extends UnitTestCase {
public function testAliasGenerationWithParameters() {
$url = $this->generator->generate('test_2', array('narf' => '5'));
$this->assertEquals('/goodbye/cruel/world', $url, 'Correct URL generated including alias and parameters.');
+
+ $path = $this->generator->getPathFromRoute('test_2', array('narf' => '5'));
+ $this->assertEquals('test/two/5', $path);
+ }
+
+ /**
+ * Tests URL generation from route with trailing start and end slashes.
+ */
+ public function testGetPathFromRouteTrailing() {
+ $path = $this->generator->getPathFromRoute('test_3');
+ $this->assertEquals($path, 'test/two');
}
/**
@@ -124,6 +198,14 @@ class UrlGeneratorTest extends UnitTestCase {
}
/**
+ * Test that the 'scheme' route requirement is respected during url generation.
+ */
+ public function testUrlGenerationWithHttpsRequirement() {
+ $url = $this->generator->generate('test_4', array(), TRUE);
+ $this->assertEquals('https://localhost/test/four', $url);
+ }
+
+ /**
* Tests path-based URL generation.
*/
public function testPathBasedURLGeneration() {
@@ -136,7 +218,6 @@ class UrlGeneratorTest extends UnitTestCase {
foreach (array(FALSE, TRUE) as $absolute) {
// Get the expected start of the path string.
$base = ($absolute ? $base_url . '/' : $base_path . '/') . $script_path;
- $absolute_string = $absolute ? 'absolute' : NULL;
$url = $base . 'node/123';
$result = $this->generator->generateFromPath('node/123', array('absolute' => $absolute));
$this->assertEquals($url, $result, "$url == $result");