From 6080e5d91e2c7a1158475322054425b0949a99ad Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 27 Apr 2026 18:43:38 +0200 Subject: [PATCH] Fix asset reference updates for Statamic 6.6+ Statamic 6.6 removed the AssetReferenceUpdater::getConfiguredAssetsFieldContainer() helper and reworked reference updates around an UpdatesReferences trait on fieldtypes (statamic/cms@4730e89). Adopt the new API: drop the custom ResponsiveReferenceUpdater and listener, and let the responsive fieldtype implement replaceAssetReferences() so Statamic's built-in UpdateAssetReferences subscriber handles renames and deletions. Fixes #270 --- src/Fieldtypes/ResponsiveFieldtype.php | 62 +++++++++++++ src/Listeners/UpdateResponsiveReferences.php | 61 ------------- src/ResponsiveReferenceUpdater.php | 96 -------------------- src/ServiceProvider.php | 5 - 4 files changed, 62 insertions(+), 162 deletions(-) delete mode 100644 src/Listeners/UpdateResponsiveReferences.php delete mode 100644 src/ResponsiveReferenceUpdater.php diff --git a/src/Fieldtypes/ResponsiveFieldtype.php b/src/Fieldtypes/ResponsiveFieldtype.php index b3f533d..43709e2 100644 --- a/src/Fieldtypes/ResponsiveFieldtype.php +++ b/src/Fieldtypes/ResponsiveFieldtype.php @@ -13,6 +13,7 @@ use Statamic\Fields\Field; use Statamic\Fields\Fields as BlueprintFields; use Statamic\Fields\Fieldtype; +use Statamic\Fieldtypes\UpdatesReferences; use Statamic\Support\Arr; use Statamic\Tags\Context; use Statamic\Tags\Parameters; @@ -20,6 +21,8 @@ class ResponsiveFieldtype extends Fieldtype { + use UpdatesReferences; + protected static $handle = 'responsive'; protected $categories = ['media', 'relationship']; @@ -252,6 +255,65 @@ public function toGqlType() return GraphQL::type(GraphQLResponsiveFieldtype::NAME); } + public function replaceAssetReferences($data, ?string $newValue, string $oldValue, string $container) + { + if ($this->configuredContainerHandle() !== $container) { + return $data; + } + + if (! is_array($data)) { + return $data; + } + + $oldReference = "{$container}::{$oldValue}"; + $newReference = $newValue !== null ? "{$container}::{$newValue}" : null; + + $modified = false; + + $result = collect($data) + ->map(function ($value, $key) use ($oldReference, $newReference, &$modified) { + if (! str_ends_with((string) $key, 'src')) { + return $value; + } + + if (is_string($value) && $value === $oldReference) { + $modified = true; + + return $newReference; + } + + if (is_array($value) && in_array($oldReference, $value, true)) { + $modified = true; + + $transformed = array_map( + fn ($item) => $item === $oldReference ? $newReference : $item, + $value, + ); + + return array_values(array_filter($transformed, fn ($item) => $item !== null)); + } + + return $value; + }) + ->filter(fn ($value) => $value !== null) + ->all(); + + return $modified ? $result : $data; + } + + protected function configuredContainerHandle(): ?string + { + if ($container = $this->config('container')) { + return $container; + } + + $containers = AssetContainer::all(); + + return $containers->count() === 1 + ? $containers->first()->handle() + : null; + } + protected function getFieldsWithValues(array $values): BlueprintFields { $fields = $this->fields()->all()->map( diff --git a/src/Listeners/UpdateResponsiveReferences.php b/src/Listeners/UpdateResponsiveReferences.php deleted file mode 100644 index b7fbe29..0000000 --- a/src/Listeners/UpdateResponsiveReferences.php +++ /dev/null @@ -1,61 +0,0 @@ -listen(AssetSaved::class, [self::class, 'handleSaved']); - $events->listen(AssetDeleted::class, [self::class, 'handleDeleted']); - } - - public function handleSaved(AssetSaved $event): void - { - $asset = $event->asset; - - $this->replaceReferences( - $asset->container()->handle(), - $asset->getOriginal('path'), - $asset->path(), - ); - } - - public function handleDeleted(AssetDeleted $event): void - { - $asset = $event->asset; - - $this->replaceReferences( - $asset->container()->handle(), - $asset->getOriginal('path'), - null, - ); - } - - protected function replaceReferences(string $container, ?string $originalPath, ?string $newPath): void - { - if (! $originalPath || $originalPath === $newPath) { - return; - } - - $newValue = $newPath ? "{$container}::{$newPath}" : null; - - $this->getItemsContainingData()->each(function ($item) use ($container, $originalPath, $newValue) { - ResponsiveReferenceUpdater::item($item) - ->filterByContainer($container) - ->updateReferences("{$container}::{$originalPath}", $newValue); - }); - } -} diff --git a/src/ResponsiveReferenceUpdater.php b/src/ResponsiveReferenceUpdater.php deleted file mode 100644 index 38b2cc4..0000000 --- a/src/ResponsiveReferenceUpdater.php +++ /dev/null @@ -1,96 +0,0 @@ -updateResponsiveFieldValues($fields, $dottedPrefix) - ->updateNestedFieldValues($fields, $dottedPrefix); - } - - protected function updateResponsiveFieldValues($fields, $dottedPrefix): static - { - $fields - ->filter(fn ($field) => $field->type() === 'responsive' - && $this->getConfiguredAssetsFieldContainer($field) === $this->container) - ->each(fn ($field) => $this->updateResponsiveValue($field, $dottedPrefix)); - - return $this; - } - - protected function updateResponsiveValue($field, $dottedPrefix): void - { - $data = $this->item->data()->all(); - - $dottedKey = $dottedPrefix.$field->handle(); - - $fieldData = collect( - Arr::get($data, $dottedKey, []) - ); - - $referencesUpdated = 0; - - $fieldData->transform(function ($value, $key) use (&$referencesUpdated) { - if (! str_ends_with($key, 'src')) { - return $value; - } - - // In content files, the src value can be either string or array. - // First handle the string value, and then handle the array value. - // Handle asset deletion, return null now for filtering later. - if ($value === $this->originalValue() && $this->isRemovingValue()) { - $referencesUpdated++; - - return null; - } - - if (is_string($value) && $value === $this->originalValue()) { - $referencesUpdated++; - - return $this->newValue(); - } - - // Handle array value. - if (is_array($value) && in_array($this->originalValue(), $value)) { - $transformedFieldDataArray = array_map(function ($item) use (&$referencesUpdated) { - // Handle asset deletion, return null now for filtering. - if ($item === $this->originalValue() && $this->isRemovingValue()) { - $referencesUpdated++; - - return null; - } - - if ($item === $this->originalValue()) { - $referencesUpdated++; - - return $this->newValue(); - } - - return $item; - }, $value); - - return array_filter($transformedFieldDataArray, fn ($item) => $item !== null); - } - - return $value; - }); - - $fieldData = $fieldData->filter(fn ($item) => $item !== null); - - if ($referencesUpdated === 0) { - return; - } - - Arr::set($data, $dottedKey, $fieldData->all()); - - $this->item->data($data); - - $this->updated = true; - } -} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index f9c9718..3a43b33 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -12,7 +12,6 @@ use Spatie\ResponsiveImages\GraphQL\SourceType; use Spatie\ResponsiveImages\Jobs\GenerateImageJob; use Spatie\ResponsiveImages\Listeners\GenerateResponsiveVersions; -use Spatie\ResponsiveImages\Listeners\UpdateResponsiveReferences; use Spatie\ResponsiveImages\Tags\ResponsiveTag; use Statamic\Events\AssetUploaded; use Statamic\Facades\GraphQL; @@ -40,10 +39,6 @@ class ServiceProvider extends AddonServiceProvider ], ]; - protected $subscribe = [ - UpdateResponsiveReferences::class, - ]; - protected $commands = [ GenerateResponsiveVersionsCommand::class, RegenerateResponsiveVersionsCommand::class,