diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index f98d607..3b006e8 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -5,7 +5,7 @@ * Contains Drupal. */ -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Symfony\Component\DependencyInjection\ContainerInterface; /** diff --git a/core/lib/Drupal/Component/Utility/Url.php b/core/lib/Drupal/Component/Utility/Url.php index c7eff3e..be27e52 100644 --- a/core/lib/Drupal/Component/Utility/Url.php +++ b/core/lib/Drupal/Component/Utility/Url.php @@ -9,6 +9,8 @@ /** * Helper class URL based methods. + * + * @todo Consider renaming to UrlHelper to not clash with \Drupal\Core\Url. */ class Url { diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php index 5c14953..bd9a386 100644 --- a/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/core/lib/Drupal/Core/Form/FormBuilder.php @@ -10,7 +10,7 @@ use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\Unicode; -use Drupal\Component\Utility\Url as UrlUtility; +use Drupal\Component\Utility\Url as UrlHelper; use Drupal\Core\Access\CsrfTokenGenerator; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\HttpKernel; @@ -18,7 +18,7 @@ use Drupal\Core\Render\Element; use Drupal\Core\Routing\UrlGeneratorInterface; use Drupal\Core\StringTranslation\TranslationInterface; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -848,7 +848,7 @@ public function validateForm($form_id, &$form, &$form_state) { if (isset($form['#token'])) { if (!$this->csrfToken->validate($form_state['values']['form_token'], $form['#token'])) { $path = $this->request->attributes->get('_system_path'); - $query = UrlUtility::filterQueryParameters($this->request->query->all()); + $query = UrlHelper::filterQueryParameters($this->request->query->all()); $url = $this->urlGenerator->generateFromPath($path, array('query' => $query)); // Setting this error will cause the form to fail validation. @@ -1323,7 +1323,7 @@ public function doBuildForm($form_id, &$element, &$form_state) { // Special handling if we're on the top level form element. if (isset($element['#type']) && $element['#type'] == 'form') { if (!empty($element['#https']) && settings()->get('mixed_mode_sessions', FALSE) && - !UrlUtility::isExternal($element['#action'])) { + !UrlHelper::isExternal($element['#action'])) { global $base_root; // Not an external URL so ensure that it is secure. diff --git a/core/lib/Drupal/Core/Routing/ExternalUrl.php b/core/lib/Drupal/Core/Routing/ExternalUrl.php new file mode 100644 index 0000000..638b64c --- /dev/null +++ b/core/lib/Drupal/Core/Routing/ExternalUrl.php @@ -0,0 +1,100 @@ +path = $path; + $this->options = $options; + } + + /** + * {@inheritdoc} + */ + public static function createFromPath($path) { + if (!UrlHelper::isExternal($path)) { + return Url::createFromPath($path); + } + + return new static($path); + } + + /** + * {@inheritdoc} + */ + public static function createFromRequest(Request $request) { + throw new \Exception('External URLs cannot be built from a request.'); + } + + /** + * {@inheritdoc} + */ + public function getRouteName() { + throw new \Exception('External URLs do not have route names.'); + } + + /** + * {@inheritdoc} + */ + public function getRouteParameters() { + throw new \Exception('External URLs do not have route parameters.'); + } + + /** + * {@inheritdoc} + */ + public function setRouteParameters($parameters) { + throw new \Exception('External URLs do not have route parameters.'); + } + + /** + * {@inheritdoc} + */ + public function setRouteParameter($key, $value) { + throw new \Exception('External URLs do not have route parameters.'); + } + + /** + * {@inheritdoc} + */ + public function toString() { + return $this->urlGenerator()->generateFromPath($this->path, $this->getOptions()); + } + + /** + * {@inheritdoc} + */ + public function toArray() { + throw new \Exception('External URLs do not have route metadata.'); + } + + /** + * {@inheritdoc} + */ + public function getInternalPath() { + throw new \Exception('External URLs do not have internal representations.'); + } + +} diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Routing/Url.php similarity index 82% rename from core/lib/Drupal/Core/Url.php rename to core/lib/Drupal/Core/Routing/Url.php index 4a55f55..19bf368 100644 --- a/core/lib/Drupal/Core/Url.php +++ b/core/lib/Drupal/Core/Routing/Url.php @@ -5,9 +5,10 @@ * Contains \Drupal\Core\Url. */ -namespace Drupal\Core; +namespace Drupal\Core\Routing; -use Drupal\Core\Routing\UrlGeneratorInterface; +use Symfony\Cmf\Component\Routing\RouteObjectInterface; +use Symfony\Component\HttpFoundation\Request; /** * Defines an object that holds information about an internal route. @@ -40,7 +41,7 @@ class Url { * * @var array */ - protected $routeOptions = array(); + protected $options = array(); /** * Constructs a new Url object. @@ -49,7 +50,7 @@ class Url { * The name of the route * @param array $route_parameters * (optional) An associative array of parameter names and values. - * @param array $route_options + * @param array $options * (optional) An associative array of additional options, with the following * elements: * - 'query': An array of query key/value-pairs (without any URL-encoding) @@ -67,10 +68,10 @@ class Url { * respectively. if mixed mode sessions are permitted, TRUE enforces HTTPS * and FALSE enforces HTTP. */ - public function __construct($route_name, $route_parameters = array(), $route_options = array()) { + public function __construct($route_name, $route_parameters = array(), $options = array()) { $this->routeName = $route_name; $this->routeParameters = $route_parameters; - $this->routeOptions = $route_options; + $this->options = $options; } /** @@ -91,6 +92,21 @@ public static function createFromPath($path) { } /** + * Returns the Url object matching a request + * + * @param \Symfony\Component\HttpFoundation\Request $request + * A request object. + * + * @return static + * An Url object. + */ + public static function createFromRequest(Request $request) { + $route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME); + $route_parameters = $request->attributes->get('_raw_variables')->all(); + return new static($route_name, $route_parameters); + } + + /** * Returns the route name. * * @return string @@ -137,29 +153,29 @@ public function setRouteParameter($key, $value) { } /** - * Returns the route options. + * Returns the URL options. * * @return array */ - public function getRouteOptions() { - return $this->routeOptions; + public function getOptions() { + return $this->options; } /** - * Sets the route options. + * Sets the URL options. * * @param array $options * The array of options. * * @return $this */ - public function setRouteOptions($options) { - $this->routeOptions = $options; + public function setOptions($options) { + $this->options = $options; return $this; } /** - * Sets a specific route option. + * Sets a specific option. * * @param string $name * The name of the option. @@ -168,8 +184,8 @@ public function setRouteOptions($options) { * * @return $this */ - public function setRouteOption($name, $value) { - $this->routeOptions[$name] = $value; + public function setOption($name, $value) { + $this->options[$name] = $value; return $this; } @@ -182,7 +198,7 @@ public function setRouteOption($name, $value) { * @return $this */ public function setAbsolute($absolute = TRUE) { - $this->routeOptions['absolute'] = $absolute; + $this->options['absolute'] = $absolute; return $this; } @@ -190,7 +206,7 @@ public function setAbsolute($absolute = TRUE) { * Generates the path for this Url object. */ public function toString() { - return $this->urlGenerator()->generateFromRoute($this->getRouteName(), $this->getRouteParameters(), $this->getRouteOptions()); + return $this->urlGenerator()->generateFromRoute($this->getRouteName(), $this->getRouteParameters(), $this->getOptions()); } /** @@ -203,7 +219,7 @@ public function toArray() { return array( 'route_name' => $this->getRouteName(), 'route_parameters' => $this->getRouteParameters(), - 'options' => $this->getRouteOptions(), + 'options' => $this->getOptions(), ); } diff --git a/core/lib/Drupal/Core/Utility/LinkGenerator.php b/core/lib/Drupal/Core/Utility/LinkGenerator.php index bea2f0d..7d8644c 100644 --- a/core/lib/Drupal/Core/Utility/LinkGenerator.php +++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php @@ -15,7 +15,7 @@ use Drupal\Core\Path\AliasManagerInterface; use Drupal\Core\Template\Attribute; use Drupal\Core\Routing\UrlGeneratorInterface; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -105,7 +105,7 @@ public function generateFromUrl($text, Url $url) { $text = is_array($text) ? drupal_render($text) : $text; // Merge in default options. - $options = $url->getRouteOptions(); + $options = $url->getOptions(); $options += array( 'attributes' => array(), 'query' => array(), @@ -145,7 +145,7 @@ public function generateFromUrl($text, Url $url) { } // Update the options before allowing altering. - $url->setRouteOptions($options); + $url->setOptions($options); // Allow other modules to modify the structure of the link. $this->moduleHandler->alter('link', $text, $url); @@ -153,7 +153,7 @@ public function generateFromUrl($text, Url $url) { // Move attributes out of options. generateFromRoute(() doesn't need them. $attributes = new Attribute($options['attributes']); unset($options['attributes']); - $url->setRouteOptions($options); + $url->setOptions($options); // The result of the url generator is a plain-text URL. Because we are using // it here in an HTML argument context, we need to encode it properly. diff --git a/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php b/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php index 851100d..fb4700f 100644 --- a/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php +++ b/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Utility; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; /** * Defines an interface for generating links from route names and parameters. @@ -84,7 +84,7 @@ public function generate($text, $route_name, array $parameters = array(), array * * @param string $text * The link text for the anchor tag as a translated string. - * @param \Drupal\Core\Url $url + * @param \Drupal\Core\Routing\Url $url * The URL object used for the link. * * @return string diff --git a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php index 83ab609..fa7ee21 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php @@ -11,7 +11,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Routing\UrlMatcher; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Drupal\menu_link\MenuLinkInterface; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Route; diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php b/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php index 6784bd0..8052554 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php @@ -11,7 +11,7 @@ use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Routing\UrlMatcher; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Drupal\shortcut\ShortcutInterface; use Symfony\Component\Routing\Exception\ResourceNotFoundException; diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index d5f4774..13330c8 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -5,7 +5,7 @@ * Allows users to manage customizable lists of shortcut links. */ -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Drupal\shortcut\ShortcutSetInterface; use Symfony\Component\HttpFoundation\Request; diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index ce889f1..53daaba 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -5,7 +5,7 @@ * Hooks provided by Drupal core and the System module. */ -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Drupal\Core\Utility\UpdateException; /** @@ -3094,7 +3094,7 @@ function hook_filetransfer_info_alter(&$filetransfer_info) { * * @param string $text * The link text for the anchor tag as a translated string. - * @param \Drupal\Core\Url $url + * @param \Drupal\Core\Routing\Url $url * The URL object used for the link. Url::getRouteOptions() can contain many * keys, but the following are guaranteed to exist: * - query: An array of query key/value-pairs (without any URL-encoding) to diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php index 2bf6b69..3d6f3a3 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php @@ -11,7 +11,7 @@ use Drupal\Core\Ajax\HtmlCommand; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Drupal\user\TempStoreFactory; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\DependencyInjection\ContainerInterface; diff --git a/core/tests/Drupal/Tests/Core/DrupalTest.php b/core/tests/Drupal/Tests/Core/DrupalTest.php index 2a9e764..75474a4 100644 --- a/core/tests/Drupal/Tests/Core/DrupalTest.php +++ b/core/tests/Drupal/Tests/Core/DrupalTest.php @@ -7,7 +7,7 @@ namespace Drupal\Tests\Core; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Drupal\Tests\UnitTestCase; /** diff --git a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php index 4537b6e..7b55764 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php @@ -10,7 +10,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Form\FormInterface; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; diff --git a/core/tests/Drupal/Tests/Core/Routing/ExternalUrlTest.php b/core/tests/Drupal/Tests/Core/Routing/ExternalUrlTest.php new file mode 100644 index 0000000..46a4055 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Routing/ExternalUrlTest.php @@ -0,0 +1,183 @@ + 'External Url object', + 'description' => 'Tests the \Drupal\Core\Routing\ExternalUrl class.', + 'group' => 'Routing', + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'); + $this->urlGenerator->expects($this->any()) + ->method('generateFromPath') + ->will($this->returnCallback(function ($path, $options) { + return $path; + })); + + $this->router = $this->getMock('Symfony\Component\Routing\RouterInterface'); + $container = new ContainerBuilder(); + $container->set('router', $this->router); + $container->set('url_generator', $this->urlGenerator); + \Drupal::setContainer($container); + } + + /** + * Tests the createFromPath method. + * + * @covers ::createFromPath() + */ + public function testCreateFromPath() { + $url = ExternalUrl::createFromPath($this->path); + $this->assertInstanceOf('Drupal\Core\Routing\ExternalUrl', $url); + return $url; + } + + /** + * Tests that an internal path will not return an ExternalUrl object. + * + * @covers ::createFromPath() + */ + public function testCreateFromPathInternal() { + $this->router->expects($this->once()) + ->method('match') + ->with('/some/path') + ->will($this->returnValue(array( + RouteObjectInterface::ROUTE_NAME => 'some.route', + '_raw_variables' => new ParameterBag(), + ))); + + $url = ExternalUrl::createFromPath('some/path'); + $this->assertNotInstanceOf('Drupal\Core\Routing\ExternalUrl', $url); + $this->assertInstanceOf('Drupal\Core\Routing\Url', $url); + } + + /** + * Tests the createFromRequest method. + * + * @covers ::createFromRequest() + * + * @expectedException \Exception + */ + public function testCreateFromRequest() { + $request = new Request(); + $url = ExternalUrl::createFromRequest($request); + $this->assertNull($url); + } + + /** + * Tests the toString() method. + * + * @depends testCreateFromPath + * + * @covers ::toString() + */ + public function testToString(ExternalUrl $url) { + $this->assertSame($this->path, $url->toString()); + } + + /** + * Tests the toArray() method. + * + * @depends testCreateFromPath + * + * @covers ::toArray() + * + * @expectedException \Exception + */ + public function testToArray(ExternalUrl $url) { + $this->assertNull($url->toArray()); + } + + /** + * Tests the getRouteName() method. + * + * @depends testCreateFromPath + * + * @covers ::getRouteName() + * + * @expectedException \Exception + */ + public function testGetRouteName(ExternalUrl $url) { + $this->assertNull($url->getRouteName()); + } + + /** + * Tests the getRouteParameters() method. + * + * @depends testCreateFromPath + * + * @covers ::getRouteParameters() + * + * @expectedException \Exception + */ + public function testGetRouteParameters(ExternalUrl $url) { + $this->assertNull($url->getRouteParameters()); + } + + /** + * Tests the getOptions() method. + * + * @depends testCreateFromPath + * + * @covers ::getOptions() + */ + public function testGetOptions(ExternalUrl $url) { + $this->assertInternalType('array', $url->getOptions()); + } + +} diff --git a/core/tests/Drupal/Tests/Core/Routing/UrlTest.php b/core/tests/Drupal/Tests/Core/Routing/UrlTest.php index 35af9d4..723c96c 100644 --- a/core/tests/Drupal/Tests/Core/Routing/UrlTest.php +++ b/core/tests/Drupal/Tests/Core/Routing/UrlTest.php @@ -8,19 +8,20 @@ namespace Drupal\Tests\Core\Routing; use Drupal\Core\DependencyInjection\ContainerBuilder; -use Drupal\Core\Url; +use Drupal\Core\Routing\Url; use Drupal\Tests\UnitTestCase; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\ParameterBag; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Exception\ResourceNotFoundException; /** - * Tests the \Drupal\Core\Url class. + * Tests the \Drupal\Core\Routing\Url class. * * @group Drupal * @group Routing * - * @coversDefaultClass \Drupal\Core\Url + * @coversDefaultClass \Drupal\Core\Routing\Url */ class UrlTest extends UnitTestCase { @@ -51,7 +52,7 @@ class UrlTest extends UnitTestCase { public static function getInfo() { return array( 'name' => 'Url object', - 'description' => 'Tests the \Drupal\Core\Url class.', + 'description' => 'Tests the \Drupal\Core\Routing\Url class.', 'group' => 'Routing', ); } @@ -130,9 +131,27 @@ public function testCreateFromPathInvalid() { } /** + * Tests the createFromRequest method. + * + * @covers ::createFromRequest() + */ + public function testCreateFromRequest() { + $request = new Request(array(), array(), array( + '_raw_variables' => new ParameterBag(array( + 'color' => 'chartreuse', + )), + RouteObjectInterface::ROUTE_NAME => 'the_route_name', + )); + + $url = Url::createFromRequest($request); + $expected = new Url('the_route_name', array('color' => 'chartreuse')); + $this->assertEquals($expected, $url); + } + + /** * Tests the toString() method. * - * @param \Drupal\Core\Url[] $urls + * @param \Drupal\Core\Routing\Url[] $urls * An array of Url objects. * * @depends testCreateFromPath @@ -149,7 +168,7 @@ public function testToString($urls) { /** * Tests the toArray() method. * - * @param \Drupal\Core\Url[] $urls + * @param \Drupal\Core\Routing\Url[] $urls * An array of Url objects. * * @depends testCreateFromPath @@ -170,7 +189,7 @@ public function testToArray($urls) { /** * Tests the getRouteName() method. * - * @param \Drupal\Core\Url[] $urls + * @param \Drupal\Core\Routing\Url[] $urls * An array of Url objects. * * @depends testCreateFromPath @@ -186,7 +205,7 @@ public function testGetRouteName($urls) { /** * Tests the getRouteParameters() method. * - * @param \Drupal\Core\Url[] $urls + * @param \Drupal\Core\Routing\Url[] $urls * An array of Url objects. * * @depends testCreateFromPath @@ -200,18 +219,18 @@ public function testGetRouteParameters($urls) { } /** - * Tests the getRouteOptions() method. + * Tests the getOptions() method. * - * @param \Drupal\Core\Url[] $urls + * @param \Drupal\Core\Routing\Url[] $urls * An array of Url objects. * * @depends testCreateFromPath * - * @covers ::getRouteOptions() + * @covers ::getOptions() */ - public function testGetRouteOptions($urls) { + public function testGetOptions($urls) { foreach ($urls as $index => $url) { - $this->assertSame($this->map[$index][2], $url->getRouteOptions()); + $this->assertSame($this->map[$index][2], $url->getOptions()); } }