Skip to content
Open
326 changes: 29 additions & 297 deletions src/Assets/AssetReferenceUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Statamic\Assets;

use Statamic\Data\DataReferenceUpdater;
use Statamic\Facades\AssetContainer;
use Statamic\Support\Arr;

class AssetReferenceUpdater extends DataReferenceUpdater
Expand Down Expand Up @@ -33,304 +32,37 @@ public function filterByContainer(string $container)
*/
protected function recursivelyUpdateFields($fields, $dottedPrefix = null)
{
$this
->updateAssetsFieldValues($fields, $dottedPrefix)
->updateLinkFieldValues($fields, $dottedPrefix)
->updateBardFieldValues($fields, $dottedPrefix)
->updateMarkdownFieldValues($fields, $dottedPrefix)
->updateNestedFieldValues($fields, $dottedPrefix);
}

/**
* Update assets field values.
*
* @param \Illuminate\Support\Collection $fields
* @param null|string $dottedPrefix
* @return $this
*/
protected function updateAssetsFieldValues($fields, $dottedPrefix)
{
$fields
->filter(function ($field) {
return $field->type() === 'assets'
&& $this->getConfiguredAssetsFieldContainer($field) === $this->container;
})
$this->fieldsWithReferenceUpdates($fields)
->each(function ($field) use ($dottedPrefix) {
$this->hasStringValue($field, $dottedPrefix)
? $this->updateStringValue($field, $dottedPrefix)
: $this->updateArrayValue($field, $dottedPrefix);
});

return $this;
}

/**
* Update link field values.
*
* @param \Illuminate\Support\Collection $fields
* @param null|string $dottedPrefix
* @return $this
*/
protected function updateLinkFieldValues($fields, $dottedPrefix)
{
$fields
->filter(function ($field) {
return $field->type() === 'link'
&& $field->get('container') === $this->container;
})
->each(function ($field) use ($dottedPrefix) {
$this->updateStatamicUrlsInLinkValue($field, $dottedPrefix);
});

return $this;
}

/**
* Update bard field values.
*
* @param \Illuminate\Support\Collection $fields
* @param null|string $dottedPrefix
* @return $this
*/
protected function updateBardFieldValues($fields, $dottedPrefix)
{
$fields
->filter(function ($field) {
return $field->type() === 'bard'
&& $field->get('container') === $this->container;
})
->each(function ($field) use ($dottedPrefix) {
$this->hasStringValue($field, $dottedPrefix)
? $this->updateStatamicUrlsInStringValue($field, $dottedPrefix)
: $this->updateStatamicUrlsInArrayValue($field, $dottedPrefix);
});

return $this;
}

/**
* Update markdown field values.
*
* @param \Illuminate\Support\Collection $fields
* @param null|string $dottedPrefix
* @return $this
*/
protected function updateMarkdownFieldValues($fields, $dottedPrefix)
{
$fields
->filter(function ($field) {
return $field->type() === 'markdown'
&& $field->get('container') === $this->container;
})
->each(function ($field) use ($dottedPrefix) {
$this->updateStatamicUrlsInStringValue($field, $dottedPrefix);
});

return $this;
}

/**
* Get configured assets field container, or implied asset container if only one exists.
*
* @param \Statamic\Fields\Field $field
* @return string
*/
protected function getConfiguredAssetsFieldContainer($field)
{
if ($container = $field->get('container')) {
return $container;
}

$containers = AssetContainer::all();

return $containers->count() === 1
? $containers->first()->handle()
: null;
}

/**
* Update `statamic://` urls in string value on item.
*
* @param \Statamic\Fields\Field $field
* @param null|string $dottedPrefix
*/
protected function updateStatamicUrlsInStringValue($field, $dottedPrefix)
{
$data = $this->item->data()->all();

$dottedKey = $dottedPrefix.$field->handle();

$originalValue = $value = Arr::get($data, $dottedKey);

if (! $originalValue) {
return;
}

$value = preg_replace_callback('/([("])(statamic:\/\/[^()"]*::)([^)"]*)([)"])/im', function ($matches) {
$newValue = $this->isRemovingValue() ? '' : $matches[2].$this->newValue;

return $matches[3] === $this->originalValue
? $matches[1].$newValue.$matches[4]
: $matches[0];
}, $value);

if ($originalValue === $value) {
return;
}

Arr::set($data, $dottedKey, $value);

$this->item->data($data);

$this->updated = true;
}

/**
* Update asset references in link values.
*
* @param \Statamic\Fields\Field $field
* @param null|string $dottedPrefix
*/
private function updateStatamicUrlsInLinkValue($field, $dottedPrefix)
{
$data = $this->item->data()->all();

$dottedKey = $dottedPrefix.$field->handle();

$originalValue = $value = Arr::get($data, $dottedKey);

if (! $originalValue) {
return;
}

if ($value !== "asset::{$this->container}::{$this->originalValue}") {
return;
}

$newValue = $this->isRemovingValue()
? null
: "asset::{$this->container}::{$this->newValue}";

if ($originalValue === $newValue) {
return;
}

if ($this->isRemovingValue()) {
Arr::forget($data, $dottedKey);
} else {
Arr::set($data, $dottedKey, $newValue);
}

$this->item->data($data);

$this->updated = true;
}

/**
* Update asset references in bard set on item.
*
* @param \Statamic\Fields\Field $field
* @param null|string $dottedPrefix
*/
protected function updateStatamicUrlsInArrayValue($field, $dottedPrefix)
{
$this->updateStatamicUrlsInImageNodes($field, $dottedPrefix);
$this->updateStatamicUrlsInLinkNodes($field, $dottedPrefix);
}

/**
* Update asset references in bard image nodes.
*
* @param \Statamic\Fields\Field $field
* @param null|string $dottedPrefix
*/
private function updateStatamicUrlsInImageNodes($field, $dottedPrefix)
{
$data = $this->item->data()->all();

$dottedKey = $dottedPrefix.$field->handle();

$bardPayload = Arr::get($data, $dottedKey, []);

if (! $bardPayload) {
return;
}

$changed = collect(Arr::dot($bardPayload))
->filter(function ($value, $key) {
return preg_match('/(.*)\.(type)/', $key) && $value === 'image';
})
->mapWithKeys(function ($value, $key) use ($bardPayload) {
$key = str_replace('.type', '.attrs.src', $key);

return [$key => Arr::get($bardPayload, $key)];
})
->filter(function ($value) {
return $value === "asset::{$this->container}::{$this->originalValue}";
})
->map(function ($value) {
return "asset::{$this->container}::{$this->newValue}";
})
->each(function ($value, $key) use (&$bardPayload) {
Arr::set($bardPayload, $key, $this->isRemovingValue() ? '' : $value);
});

if ($changed->isEmpty()) {
return;
}

Arr::set($data, $dottedKey, $bardPayload);

$this->item->data($data);

$this->updated = true;
}

/**
* Update asset references in bard link nodes.
*
* @param \Statamic\Fields\Field $field
* @param null|string $dottedPrefix
*/
private function updateStatamicUrlsInLinkNodes($field, $dottedPrefix)
{
$data = $this->item->data()->all();

$dottedKey = $dottedPrefix.$field->handle();

$bardPayload = Arr::get($data, $dottedKey, []);

if (! $bardPayload) {
return;
}

$changed = collect(Arr::dot($bardPayload))
->filter(function ($value, $key) {
return preg_match('/(.*)\.(type)/', $key) && $value === 'link';
})
->mapWithKeys(function ($value, $key) use ($bardPayload) {
$key = str_replace('.type', '.attrs.href', $key);

return [$key => Arr::get($bardPayload, $key)];
})
->filter(function ($value) {
return $value === "statamic://asset::{$this->container}::{$this->originalValue}";
})
->map(function ($value) {
return "statamic://asset::{$this->container}::{$this->newValue}";
})
->each(function ($value, $key) use (&$bardPayload) {
Arr::set($bardPayload, $key, $this->isRemovingValue() ? '' : $value);
$data = $this->item->data()->all();
$dottedKey = $dottedPrefix.$field->handle();
$oldData = Arr::get($data, $dottedKey);

if ($oldData === null) {
return;
}

$newData = $field->fieldtype()->replaceAssetReferences(
$oldData,
$this->newValue,
$this->originalValue,
$this->container
);

if ($oldData === $newData) {
return;
}

if ($newData === null && $this->isRemovingValue()) {
Arr::forget($data, $dottedKey);
} else {
Arr::set($data, $dottedKey, $newData);
}

$this->item->data($data);
$this->updated = true;
});

if ($changed->isEmpty()) {
return;
}

Arr::set($data, $dottedKey, $bardPayload);

$this->item->data($data);

$this->updated = true;
$this->updateNestedFieldValues($fields, $dottedPrefix);
}
}
Loading