From 0a635ca0a2936ee2884f77b33c73748a262ac7ed Mon Sep 17 00:00:00 2001 From: Tim Kelty Date: Thu, 26 Mar 2026 09:24:53 -0400 Subject: [PATCH 1/3] Fix non-standard props in non-cloud envs --- src/AppConfig.php | 1 - src/Module.php | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AppConfig.php b/src/AppConfig.php index 83dc452..0fde7f1 100644 --- a/src/AppConfig.php +++ b/src/AppConfig.php @@ -159,7 +159,6 @@ private function getDefinitions(): array { return [ Temp::class => TmpFs::class, - CraftImageTransform::class => ImageTransform::class, MonologTarget::class => function($container, $params, $config) { return new MonologTarget([ 'logContext' => false, diff --git a/src/Module.php b/src/Module.php index 4b31729..321537a 100644 --- a/src/Module.php +++ b/src/Module.php @@ -6,6 +6,7 @@ use craft\base\Event; use craft\base\Model; use craft\cloud\fs\AssetsFs; +use craft\cloud\imagetransforms\ImageTransform; use craft\cloud\imagetransforms\ImageTransformer; use craft\cloud\twig\TwigExtension; use craft\cloud\web\assets\uploader\UploaderAsset; @@ -19,6 +20,7 @@ use craft\helpers\App; use craft\helpers\ConfigHelper; use craft\log\MonologTarget; +use craft\models\ImageTransform as CraftImageTransform; use craft\services\Fs as FsService; use craft\services\ImageTransforms; use craft\web\Application as WebApplication; @@ -83,6 +85,10 @@ public function bootstrap($app): void ), ]); + // Replace ImageTransform with cloud ImageTransform via DI + // We do this here and not in AppConfig, because non-Cloud envs need it to support non-standard transform props + Craft::$container->set(CraftImageTransform::class, ImageTransform::class); + if (Helper::isCraftCloud()) { $this->bootstrapCloud($app); } From 53fe1ae733da764a77fafbe755becce82b6deecf Mon Sep 17 00:00:00 2001 From: Tim Kelty Date: Thu, 26 Mar 2026 09:50:12 -0400 Subject: [PATCH 2/3] Fix image transforms ignoring focal points The fields() override called normalize(), which mutated the model by writing computed CF values (fit, gravity, etc.) onto $this. Since Yii's toArray() calls fields(), any serialization path (e.g. srcset via getUrlsBySize) would pre-fill gravity from position, blocking the focal point override in ImageTransformer. Remove fields()/normalize() and refactor toOptions() to compute derived values into the returned array without mutating the model. Fixes https://github.com/craftcms/cloud/issues/144 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/imagetransforms/ImageTransform.php | 31 +++++++++----------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/imagetransforms/ImageTransform.php b/src/imagetransforms/ImageTransform.php index 1402d33..4f69dc2 100644 --- a/src/imagetransforms/ImageTransform.php +++ b/src/imagetransforms/ImageTransform.php @@ -110,32 +110,23 @@ class ImageTransform extends \craft\models\ImageTransform public ?float $zoom = null; - /** - * @inheritdoc - */ - public function fields(): array - { - $this->normalize(); - return parent::fields(); - } - - public function normalize(): static - { - $this->format = $this->computeFormat(); - $this->fit = $this->computeFit(); - $this->background = $this->computeBackground(); - $this->gravity = $this->computeGravity(); - return $this; - } - public function toOptions(): array { $reflection = new \ReflectionClass($this); - $this->normalize(); - return Collection::make($reflection->getProperties(\ReflectionProperty::IS_PUBLIC)) + $options = Collection::make($reflection->getProperties(\ReflectionProperty::IS_PUBLIC)) ->filter(fn($property) => $property->getDeclaringClass()->getName() === self::class) ->mapWithKeys(fn($property) => [$property->getName() => $property->getValue($this)]) + ->all(); + + // Compute derived Cloudflare values from Craft's base transform settings, + // without mutating the model (so the same instance can be safely reused). + $options['format'] = $this->computeFormat(); + $options['fit'] = $this->computeFit(); + $options['background'] = $this->computeBackground(); + $options['gravity'] ??= $this->computeGravity(); + + return Collection::make($options) ->filter(fn($value) => $value !== null) ->all(); } From 819bac0c09634beda7ff279ab987dbe3852f0872 Mon Sep 17 00:00:00 2001 From: Tim Kelty Date: Thu, 26 Mar 2026 09:53:36 -0400 Subject: [PATCH 3/3] code style --- src/AppConfig.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/AppConfig.php b/src/AppConfig.php index 0fde7f1..ad538e6 100644 --- a/src/AppConfig.php +++ b/src/AppConfig.php @@ -7,7 +7,6 @@ use craft\cachecascade\CascadeCache; use craft\cloud\fs\TmpFs; use craft\cloud\Helper as CloudHelper; -use craft\cloud\imagetransforms\ImageTransform; use craft\cloud\queue\SqsQueue; use craft\cloud\web\AssetManager; use craft\db\Table; @@ -15,7 +14,6 @@ use craft\fs\Temp; use craft\helpers\App; use craft\log\MonologTarget; -use craft\models\ImageTransform as CraftImageTransform; use craft\queue\Queue as CraftQueue; use yii\caching\ArrayCache; use yii\redis\Cache as RedisCache;