From 332cb9d1da184ee621596c58ffaa03cda169ba24 Mon Sep 17 00:00:00 2001 From: i-just Date: Wed, 6 Aug 2025 14:48:23 +0100 Subject: [PATCH 1/2] pre eager load all requested srcsets --- src/elements/Asset.php | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/elements/Asset.php b/src/elements/Asset.php index 478fe51c925..5f4cc6202a4 100644 --- a/src/elements/Asset.php +++ b/src/elements/Asset.php @@ -1884,13 +1884,15 @@ public function getImg(mixed $transform = null, ?array $sizes = null): ?Markup * * @param string[] $sizes * @param ImageTransform|string|array|null $transform A transform handle or configuration that should be applied to the image + * @param bool $preload Whether all requested transforms should be preloaded * @return string|false The `srcset` attribute value, or `false` if it can’t be determined * @throws InvalidArgumentException + * @since 5.9.0 Added $preload param * @since 3.5.0 */ - public function getSrcset(array $sizes, mixed $transform = null): string|false + public function getSrcset(array $sizes, mixed $transform = null, bool $preload = false): string|false { - $urls = array_filter($this->getUrlsBySize($sizes, $transform)); + $urls = array_filter($this->getUrlsBySize($sizes, $transform, $preload)); if (empty($urls)) { return false; @@ -1933,10 +1935,12 @@ public function getSrcset(array $sizes, mixed $transform = null): string|false * * @param string[] $sizes * @param ImageTransform|string|array|null $transform A transform handle or configuration that should be applied to the image + * @param bool $preload Whether all requested transforms should be preloaded * @return array + * @since 5.9.0 Added $preload param * @since 3.7.16 */ - public function getUrlsBySize(array $sizes, mixed $transform = null): array + public function getUrlsBySize(array $sizes, mixed $transform = null, bool $preload = false): array { if ($this->kind !== self::KIND_IMAGE) { return []; @@ -1963,6 +1967,30 @@ public function getUrlsBySize(array $sizes, mixed $transform = null): array return []; } + // eager load transforms + if ($preload) { + $baseTransform = []; + if ($transform) { + $baseTransform['width'] = $transform->width; + $baseTransform['height'] = $transform->height; + $baseTransform['mode'] = $transform->mode; + $baseTransform['position'] = $transform->position; + $baseTransform['quality'] = $transform->quality; + } else { + // if we don't have a transform, only use the width + $baseTransform['width'] = $currentWidth; + } + + $transforms[] = $baseTransform; + + foreach ($sizes as $size) { + [$value, $unit] = Assets::parseSrcsetSize($size); + $transforms[] = $value . $unit; + } + + Craft::$app->getImageTransforms()->eagerLoadTransforms([$this], $transforms); + } + foreach ($sizes as $size) { if ($size === '1x') { $urls[$size] = $this->getUrl($transform); From aaaec0087fded6ec2ea6dc0af98a3b11457a21a6 Mon Sep 17 00:00:00 2001 From: i-just Date: Wed, 6 Aug 2025 14:50:21 +0100 Subject: [PATCH 2/2] AssetQuery::withTransforms() can accept true to eager load all image transform indexes --- .../EagerImageTransformerInterface.php | 8 ++++++ src/elements/db/AssetQuery.php | 18 ++++++++----- src/imagetransforms/ImageTransformer.php | 26 +++++++++++++++++++ src/services/ImageTransforms.php | 20 ++++++++++++++ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/base/imagetransforms/EagerImageTransformerInterface.php b/src/base/imagetransforms/EagerImageTransformerInterface.php index 6e9ffa02d0d..c7e00f4e311 100644 --- a/src/base/imagetransforms/EagerImageTransformerInterface.php +++ b/src/base/imagetransforms/EagerImageTransformerInterface.php @@ -25,4 +25,12 @@ interface EagerImageTransformerInterface * @param Asset[] $assets */ public function eagerLoadTransforms(array $transforms, array $assets): void; + + /** + * Eager-loads all the transforms for the given assets. + * + * @param Asset[] $assets + * @since 5.9.0 + */ + public function eagerLoadAllTransforms(array $assets): void; } diff --git a/src/elements/db/AssetQuery.php b/src/elements/db/AssetQuery.php index 0f64f3b492d..09fc35c7aab 100644 --- a/src/elements/db/AssetQuery.php +++ b/src/elements/db/AssetQuery.php @@ -848,11 +848,11 @@ public function folderPath(mixed $value): static * ->all(); * ``` * - * @param string|array|null $value The transforms to include. + * @param string|array|null|bool $value The transforms to include. * @return static The query object itself * @uses $withTransforms */ - public function withTransforms(string|array|null $value = null): static + public function withTransforms(string|array|null|bool $value = null): static { $this->withTransforms = $value; return $this; @@ -868,12 +868,16 @@ public function afterPopulate(array $elements): array // Eager-load transforms? if ($this->withTransforms && !$this->asArray) { - $transforms = $this->withTransforms; - if (!is_array($transforms)) { - $transforms = is_string($transforms) ? StringHelper::split($transforms) : [$transforms]; - } + if ($this->withTransforms === true) { + Craft::$app->getImageTransforms()->eagerLoadAllTransforms($elements); + } else { + $transforms = $this->withTransforms; + if (!is_array($transforms)) { + $transforms = is_string($transforms) ? StringHelper::split($transforms) : [$transforms]; + } - Craft::$app->getImageTransforms()->eagerLoadTransforms($elements, $transforms); + Craft::$app->getImageTransforms()->eagerLoadTransforms($elements, $transforms); + } } return $elements; diff --git a/src/imagetransforms/ImageTransformer.php b/src/imagetransforms/ImageTransformer.php index e2f9e803d07..c1292eaf928 100644 --- a/src/imagetransforms/ImageTransformer.php +++ b/src/imagetransforms/ImageTransformer.php @@ -284,6 +284,32 @@ public function eagerLoadTransforms(array $transforms, array $assets): void } } + /** + * @inheritdoc + */ + public function eagerLoadAllTransforms(array $assets): void + { + // Index the assets by ID + $assetsById = ArrayHelper::index($assets, 'id'); + + // Query for the indexes + $results = $this->_createTransformIndexQuery() + ->where(['assetId' => array_keys($assetsById)]) + ->all(); + + foreach ($results as $result) { + // Get the transform's fingerprint + $transformFingerprint = $result['transformString']; + + if ($result['format']) { + $transformFingerprint .= ':' . $result['format']; + } + + $indexFingerprint = $result['assetId'] . ':' . $transformFingerprint; + $this->eagerLoadedTransformIndexes[$indexFingerprint] = $result; + } + } + // Protected methods // ============================================================= diff --git a/src/services/ImageTransforms.php b/src/services/ImageTransforms.php index f5411c6599b..6984194172e 100644 --- a/src/services/ImageTransforms.php +++ b/src/services/ImageTransforms.php @@ -455,6 +455,26 @@ public function eagerLoadTransforms(array $assets, array $transforms): void } } + /** + * Eager-loads all transform indexes for the given list of assets. + * + * @param array $assets + * @return void + * @throws InvalidConfigException + * @since 5.9.0 + */ + public function eagerLoadAllTransforms(array $assets): void + { + if (empty($assets)) { + return; + } + + $transformer = $this->getImageTransformer(ImageTransformer::class); + if ($transformer instanceof EagerImageTransformerInterface) { + $transformer->eagerLoadAllTransforms($assets); + } + } + /** * @template T of ImageTransformerInterface * @param class-string $type