diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php index b2e2b86..70e0461 100644 --- a/core/lib/Drupal/Core/Url.php +++ b/core/lib/Drupal/Core/Url.php @@ -252,20 +252,22 @@ public static function fromUri($uri, $options = []) { $uri_parts += ['path' => '', 'fragment' => '']; // Extract query parameters and fragment and merge them into $options. $options += ['fragment' => $uri_parts['fragment']]; + unset($uri_parts['fragment']); if (!empty($uri_parts['query'])) { $uri_query = []; parse_str($uri_parts['query'], $uri_query); $options['query'] += $uri_query; + unset($uri_parts['query']); } if ($uri_parts['scheme'] === 'entity') { - $url = static::fromEntityUri($uri, $options); + $url = static::fromEntityUri($uri_parts, $options); } elseif ($uri_parts['scheme'] === 'user-path') { - $url = static::fromUserPathUri($uri, $options); + $url = static::fromUserPathUri($uri_parts, $options); } elseif ($uri_parts['scheme'] === 'route') { - $url = static::fromRouteUri($uri, $options); + $url = static::fromRouteUri($uri_parts, $options); } else { $url = new static($uri, array(), $options); @@ -282,8 +284,8 @@ public static function fromUri($uri, $options = []) { /** * Create a new Url object for entity URIs. * - * @param string $uri - * An URI of the form entity:{entity_type}/{entity_id}. + * @param array $uri_parts + * Parts from an URI of the form entity:{entity_type}/{entity_id}. * @param array $options * An array of options, see static::fromUri() for details. * @@ -293,8 +295,7 @@ public static function fromUri($uri, $options = []) { * @throws \InvalidArgumentException * Thrown if the entity URI is invalid. */ - protected static function fromEntityUri($uri, $options) { - $uri_parts = parse_url($uri); + protected static function fromEntityUri(array $uri_parts, $options) { list($entity_type_id, $entity_id) = explode('/', $uri_parts['path'], 2); if ($uri_parts['scheme'] != 'entity' || $entity_id === '') { throw new \InvalidArgumentException(String::format('The entity URI "@uri" is invalid. You must specify the entity id in the URL. e.g., entity:node/1 for loading the canonical path to node entity with id 1.', ['@uri' => $uri])); @@ -306,16 +307,15 @@ protected static function fromEntityUri($uri, $options) { /** * Creates a new Url object for 'user-path:' URIs. * - * @param string $uri - * An URI of the form user-path:{path}. + * @param array $uri_parts + * Parts from an URI of the form user-path:{path}. * @param array $options * An array of options, see static::fromUri() for details. * * @return \Drupal\Core\Url * A new Url object for a 'user-path:' URI. */ - protected static function fromUserPathUri($uri, array $options) { - $uri_parts = parse_url($uri); + protected static function fromUserPathUri(array $uri_parts, array $options) { $url = \Drupal::pathValidator() ->getUrlIfValidWithoutAccessCheck($uri_parts['path']) ?: static::fromUri('base:' . $uri_parts['path'], $options); // Allow specifying additional options. @@ -327,18 +327,17 @@ protected static function fromUserPathUri($uri, array $options) { /** * Creates a new Url object for 'route:' URIs. * - * @param string $uri - * An URI of the form route:{path}. Where path is the route name optionally - * followed by a ";" followed by query parameters in key=value format - * with & separators. + * @param array $uri_parts + * Parts from an URI of the form route:{path}. Where path is the route name + * optionally followed by a ";" followed by query parameters in key=value + * format with & separators. * @param array $options * An array of options, see static::fromUri() for details. * * @return \Drupal\Core\Url * A new Url object for a 'route:' URI. */ - protected static function fromRouteUri($uri, array $options) { - $uri_parts = parse_url($uri); + protected static function fromRouteUri(array $uri_parts, array $options) { $route_parts = explode(';', $uri_parts['path'], 2); $route_name = $route_parts[0]; $route_parameters = []; diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php index a6a9a6c..9c5efcb 100644 --- a/core/tests/Drupal/Tests/Core/UrlTest.php +++ b/core/tests/Drupal/Tests/Core/UrlTest.php @@ -520,13 +520,52 @@ public function testInvalidEntityUriParameter() { } /** - * Tests the fromUri() method with an entity: URI. + * Tests the toUriString() method with entity: URI. * - * @covers ::fromUri + * @covers ::toUriString */ - public function testToUriString() { + public function testToUriStringForEntity() { $url = Url::fromUri('entity:test_entity/1'); $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1'); + $url = Url::fromUri('entity:test_entity/1', ['fragment' => 'top', 'query' => ['page' => '2']]); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1?page=2#top'); + $url = Url::fromUri('entity:test_entity/1?page=2#top'); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1?page=2#top'); + } + + /** + * Tests the toUriString() method with user-path: URI. + * + * @covers ::toUriString + */ + public function testToUriStringForUserPath() { + $url = Url::fromRoute('entity.test_entity.canonical', ['test_entity' => '1']); + $this->pathValidator->expects($this->any()) + ->method('getUrlIfValidWithoutAccessCheck') + ->with('test-entity/1') + ->willReturn($url); + $url = Url::fromUri('user-path:test-entity/1'); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1'); + $url = Url::fromUri('user-path:test-entity/1', ['fragment' => 'top']); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1#top'); + $url = Url::fromUri('user-path:test-entity/1', ['fragment' => 'top', 'query' => ['page' => '2']]); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1?page=2#top'); + $url = Url::fromUri('user-path:test-entity/1?page=2#top'); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1?page=2#top'); + } + + /** + * Tests the toUriString() method with route: URI. + * + * @covers ::toUriString + */ + public function testToUriStringForRoute() { + $url = Url::fromUri('route:entity.test_entity.canonical;test_entity=1'); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1'); + $url = Url::fromUri('route:entity.test_entity.canonical;test_entity=1', ['fragment' => 'top', 'query' => ['page' => '2']]); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1?page=2#top'); + $url = Url::fromUri('route:entity.test_entity.canonical;test_entity=1?page=2#top'); + $this->assertSame($url->toUriString(), 'route:entity.test_entity.canonical;test_entity=1?page=2#top'); } /**