diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php index ea552bf4cb..36d04e24fc 100644 --- a/core/lib/Drupal/Core/Url.php +++ b/core/lib/Drupal/Core/Url.php @@ -322,6 +322,33 @@ public static function fromUri($uri, $options = []) { return $url; } + /** + * Creates a new Url object from an external URL. + * + * @param string $external_url + * An URL string, will not be checked for syntax. + * @param array $options + * (optional) An associative array of additional URL options, with the + * following elements: + * - 'query': An array of query key/value-pairs (without any URL-encoding) + * to append to the URL. + * - 'fragment': A fragment identifier (named anchor) to append to the URL. + * Do not include the leading '#' character. + * - 'attributes': An associative array of HTML attributes that will be + * added to the anchor tag if you use the \Drupal\Core\Link class to make + * the link. + * + * @return static + * A new Url object. + */ + public static function fromExternalUrl(string $external_url, $options = []): Url { + $url = new static($external_url, [], $options); + $url->external = TRUE; + $url->setOption('external', TRUE); + $url->setUnrouted(); + return $url; + } + /** * Create a new Url object for entity URIs. * diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php index fef6e7cc6d..1239c9720f 100644 --- a/core/modules/image/src/Entity/ImageStyle.php +++ b/core/modules/image/src/Entity/ImageStyle.php @@ -7,7 +7,6 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityWithPluginCollectionInterface; use Drupal\Core\Site\Settings; -use Drupal\Core\Url; use Drupal\image\Event\ImageDerivativePipelineEvents; use Drupal\image\Event\ImageStyleEvent; use Drupal\image\Event\ImageStyleEvents; @@ -180,12 +179,12 @@ public function buildUri($uri) { */ public function buildUrl($path, $clean_urls = NULL) { @trigger_error('The ' . __METHOD__ . ' method is deprecated since version 9.x.x and will be removed in y.y.y.', E_USER_DEPRECATED); - $url = \Drupal::service('image.processor')->createInstance('derivative') + return \Drupal::service('image.processor')->createInstance('derivative') ->setImageStyle($this) ->setSourceImageUri($path) ->setCleanUrl($clean_urls) - ->getDerivativeImageUrl(); - return $url instanceof Url ? $url->toString() : $url; + ->getDerivativeImageUrl() + ->toString(); } /** diff --git a/core/modules/image/src/EventSubscriber/ImageDerivativeSubscriber.php b/core/modules/image/src/EventSubscriber/ImageDerivativeSubscriber.php index 0d83657e1a..e043e0c487 100644 --- a/core/modules/image/src/EventSubscriber/ImageDerivativeSubscriber.php +++ b/core/modules/image/src/EventSubscriber/ImageDerivativeSubscriber.php @@ -390,12 +390,11 @@ public function resolveDerivativeImageUrl(ImageProcessEvent $event): void { return; } - // Append the query string with the token, if necessary. - $file_url = file_create_url($derivative_uri); - if ($token_query) { - $file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($token_query); - } - + $file_url = Url::fromExternalUrl( + file_create_url($derivative_uri), [ + 'query' => $token_query, + ] + ); $pipeline->setVariable('derivativeImageUrl', $file_url); } @@ -453,19 +452,11 @@ public function saveDerivativeImage(ImageProcessEvent $event): void { * The image process event, carrying the process pipeline object. */ public function buildDerivativeImage(ImageProcessEvent $event): void { - $pipeline = $event->getPipeline(); - - try { - $pipeline - ->dispatch(ImageDerivativePipelineEvents::RESOLVE_SOURCE_IMAGE_PROCESSABILITY) - ->dispatch(ImageDerivativePipelineEvents::LOAD_SOURCE_IMAGE) - ->dispatch(ImageDerivativePipelineEvents::APPLY_IMAGE_STYLE) - ->dispatch(ImageDerivativePipelineEvents::SAVE_DERIVATIVE_IMAGE) - ->setVariable('derivativeImageBuilt', TRUE); - } - catch (ImageProcessException $e) { - // Do nothing. - } + $event->getPipeline() + ->dispatch(ImageDerivativePipelineEvents::RESOLVE_SOURCE_IMAGE_PROCESSABILITY) + ->dispatch(ImageDerivativePipelineEvents::LOAD_SOURCE_IMAGE) + ->dispatch(ImageDerivativePipelineEvents::APPLY_IMAGE_STYLE) + ->dispatch(ImageDerivativePipelineEvents::SAVE_DERIVATIVE_IMAGE); } /** diff --git a/core/modules/image/src/Plugin/ImageProcessPipeline/Derivative.php b/core/modules/image/src/Plugin/ImageProcessPipeline/Derivative.php index 426fd4fc26..4c0439cb11 100644 --- a/core/modules/image/src/Plugin/ImageProcessPipeline/Derivative.php +++ b/core/modules/image/src/Plugin/ImageProcessPipeline/Derivative.php @@ -3,7 +3,9 @@ namespace Drupal\image\Plugin\ImageProcessPipeline; use Drupal\Core\Image\ImageInterface; +use Drupal\Core\Url; use Drupal\image\Event\ImageDerivativePipelineEvents; +use Drupal\image\ImageProcessException; use Drupal\image\ImageStyleInterface; /** @@ -202,14 +204,14 @@ public function getDerivativeImageUri(): string { * * Takes the source URI and the image style to determine the derivative URL. * - * @return string|\Drupal\Core\Url + * @return \Drupal\Core\Url * The absolute URL where a style image can be downloaded, suitable for use * in an tag. * * @see \Drupal\image\Controller\ImageStyleDownloadController::deliver() * @see file_url_transform_relative() */ - public function getDerivativeImageUrl() { + public function getDerivativeImageUrl(): Url { $this->dispatch(ImageDerivativePipelineEvents::RESOLVE_DERIVATIVE_IMAGE_URL); return $this->getVariable('derivativeImageUrl'); } @@ -239,9 +241,13 @@ public function getDerivativeImageUrlSecurityToken(): ?string { * TRUE if the image was transformed, or FALSE in case of failure. */ public function buildDerivativeImage(): bool { - $this->deleteVariable('derivativeImageBuilt'); - $this->dispatch(ImageDerivativePipelineEvents::BUILD_DERIVATIVE_IMAGE); - return $this->getVariable('derivativeImageBuilt'); + try { + $this->dispatch(ImageDerivativePipelineEvents::BUILD_DERIVATIVE_IMAGE); + return TRUE; + } + catch (ImageProcessException $e) { + return FALSE; + } } } diff --git a/core/modules/image/tests/src/Kernel/DerivativeImageProcessTest.php b/core/modules/image/tests/src/Kernel/DerivativeImageProcessTest.php index 3feb935062..24f7c5baa3 100644 --- a/core/modules/image/tests/src/Kernel/DerivativeImageProcessTest.php +++ b/core/modules/image/tests/src/Kernel/DerivativeImageProcessTest.php @@ -127,26 +127,6 @@ public function testGetDerivativeImageUri() { $this->assertEquals('public://styles/thumbnail/public/core/modules/image/sample.png', $pipeline->getDerivativeImageUri()); } - /** - * @covers ::setImageStyle - * @covers ::setSourceImageUri - * @covers ::getDerivativeImageUrl - * @covers ::getDerivativeImageUrlSecurityToken - */ - public function testGetDerivativeImageUrl() { - // Starting off from an URI. - $pipeline = $this->imageProcessor->createInstance('derivative') - ->setImageStyle($this->imageStyle) - ->setSourceImageUri('public://test.png'); - $this->assertContains('files/styles/thumbnail/public/test.png?itok=' . $pipeline->getDerivativeImageUrlSecurityToken(), $pipeline->getDerivativeImageUrl()); - - // Starting off from a path. - $pipeline = $this->imageProcessor->createInstance('derivative') - ->setImageStyle($this->imageStyle) - ->setSourceImageUri('core/modules/image/sample.png'); - $this->assertContains('files/styles/thumbnail/public/core/modules/image/sample.png?itok=' . $pipeline->getDerivativeImageUrlSecurityToken(), $pipeline->getDerivativeImageUrl()); - } - /** * @covers ::setImageStyle * @covers ::setSourceImageUri @@ -163,6 +143,13 @@ public function testBuildDerivativeImageFromFile() { $this->assertSame(100, $image->getWidth()); $this->assertSame(67, $image->getHeight()); + // Starting off from an URI, file missing. + $pipeline = $this->imageProcessor->createInstance('derivative') + ->setImageStyle($this->imageStyle) + ->setSourceImageUri('public://missing.png'); + $this->assertFalse($pipeline->buildDerivativeImage()); + $this->assertFalse(file_exists('public://styles/thumbnail/public/missing.png')); + // Starting off from a path. $pipeline = $this->imageProcessor->createInstance('derivative') ->setImageStyle($this->imageStyle)