diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php index 7125bc1..f1b44a6 100644 --- a/core/lib/Drupal/Core/Url.php +++ b/core/lib/Drupal/Core/Url.php @@ -252,8 +252,9 @@ public static function fromUri($uri, $options = []) { $uri_parts += ['path' => '']; // Extract query parameters and fragment and merge them into $uri_options, // but preserve the original $options for the fallback case. + $uri_options = $options; if (!empty($uri_parts['fragment'])) { - $uri_options = $options + ['fragment' => $uri_parts['fragment']]; + $uri_options += ['fragment' => $uri_parts['fragment']]; } unset($uri_parts['fragment']); if (!empty($uri_parts['query'])) { @@ -332,9 +333,9 @@ protected static function fromUserPathUri(array $uri_parts, array $options) { * Creates a new Url object for 'route:' URIs. * * @param array $uri_parts - * Parts from an URI of the form route:{path} as from parse_url(). Where - * path is the route name optionally followed by a ";" followed by route - * parameters in key=value format with & separators. + * Parts from an URI of the form route:{route_name};{route_parameters} as + * from parse_url(), where the path is the route name optionally followed by + * a ";" followed by route parameters in key=value format with & separators. * @param array $options * An array of options, see static::fromUri() for details. * @@ -352,7 +353,7 @@ protected static function fromRouteUri(array $uri_parts, array $options, $uri) { parse_str($route_parts[1], $route_parameters); } - return new static($route_name, $route_parameters. $options); + return new static($route_name, $route_parameters, $options); } /** @@ -402,6 +403,13 @@ protected function setUnrouted() { } /** + * Return a URI string that represents tha data in the Url object. + * + * The URI will typically have the scheme of route: even if the object was + * constructed using an entity: or user-path: scheme. A user-path: URI + * that does not match a Drupal route with be returned here with the base: + * scheme, and external URLs will be returned in their original form. + * * @return string * A URI representation of the Url object data. */ @@ -415,7 +423,7 @@ public function toUriString() { else { $uri = $this->uri; } - $query = !empty($this->options['query']) ? ('?' . UrlHelper::buildQuery($options['query'])) : ''; + $query = !empty($this->options['query']) ? ('?' . UrlHelper::buildQuery($this->options['query'])) : ''; $fragment = !empty($this->options['fragment']) ? '#' . $this->options['fragment'] : ''; return $uri . $query . $fragment; } diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php index 6e2634b..d3cf641 100644 --- a/core/tests/Drupal/Tests/Core/UrlTest.php +++ b/core/tests/Drupal/Tests/Core/UrlTest.php @@ -481,26 +481,50 @@ public function testFromRouteMatch() { } /** + * Data provider for testing entity URIs + */ + public function entityUris() { + return [ + [ + 'entity:test_entity/1', + [], + 'entity.test_entity.canonical', + ['test_entity' => '1'], + NULL, + NULL, + ], + [ + 'entity:test_entity/2?page=1&foo=bar#bottom', + [], 'entity.test_entity.canonical', + ['test_entity' => '2'], + ['page' => '1', 'foo' => 'bar'], + 'bottom', + ], + [ + 'entity:test_entity/2?page=1&foo=bar#bottom', + ['fragment' => 'top', 'query' => ['foo' => 'yes', 'focus' => 'no']], + 'entity.test_entity.canonical', + ['test_entity' => '2'], + ['page' => '1', 'foo' => 'yes', 'focus' => 'no'], + 'top', + ], + + ]; + } + + /** * Tests the fromUri() method with an entity: URI. * * @covers ::fromUri + * + * @dataProvider entityUris */ - public function testEntityUris() { - $url = Url::fromUri('entity:test_entity/1'); - $this->assertSame('entity.test_entity.canonical', $url->getRouteName()); - $this->assertEquals(['test_entity' => '1'], $url->getRouteParameters()); - // Ensure the options are parsed out. - $url = Url::fromUri('entity:test_entity/2?page=1&foo=bar#bottom'); - $this->assertSame('entity.test_entity.canonical', $url->getRouteName()); - $this->assertEquals(['test_entity' => '2'], $url->getRouteParameters()); - $this->assertEquals($url->getOption('query'), ['page' => '1', 'foo' => 'bar']); - $this->assertSame($url->getOption('fragment'), 'bottom'); - // Ensure the options are parsed out and merged with $options. - $url = Url::fromUri('entity:test_entity/2?page=1&foo=bar#bottom', ['fragment' => 'top', 'query' => ['foo' => 'yes', 'focus' => 'no']]); - $this->assertSame('entity.test_entity.canonical', $url->getRouteName()); - $this->assertEquals(['test_entity' => '2'], $url->getRouteParameters()); - $this->assertEquals($url->getOption('query'), ['page' => '1', 'foo' => 'yes', 'focus' => 'no']); - $this->assertSame($url->getOption('fragment'), 'top'); + public function testEntityUris($uri, $options, $route_name, $route_parameters, $query, $fragment) { + $url = Url::fromUri($uri, $options); + $this->assertSame($route_name, $url->getRouteName()); + $this->assertEquals($route_parameters, $url->getRouteParameters()); + $this->assertEquals($url->getOption('query'), $query); + $this->assertSame($url->getOption('fragment'), $fragment); } /**