Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Extensible followup after asset replacement #4816

Open
wants to merge 2 commits into
base: 9.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Neos.Media/Classes/Domain/Model/AdjustmentCapableInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
namespace Neos\Media\Domain\Model;

use Neos\Media\Domain\Model\Adjustment\ImageAdjustmentInterface;

interface AdjustmentCapableInterface
{
/** @return iterable<ImageAdjustmentInterface> */
public function getAdjustments(): iterable;

public function addAdjustment(ImageAdjustmentInterface $adjustment): void;

/**
* @param ImageAdjustmentInterface[] $adjustments
* @return void
*/
public function addAdjustments(array $adjustments): void;
}
18 changes: 18 additions & 0 deletions Neos.Media/Classes/Domain/Model/Dto/AssetResourceReplaced.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
namespace Neos\Media\Domain\Model\Dto;

use Neos\Flow\ResourceManagement\PersistentResource;
use Neos\Media\Domain\Model\AssetInterface;

/**
*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems there is a little place of a doc comment already anticipated and i would very much like this.

*/
final readonly class AssetResourceReplaced
{
public function __construct(
public AssetInterface $asset,
public PersistentResource $previousResource,
public PersistentResource $newResource
) {
}
}
2 changes: 1 addition & 1 deletion Neos.Media/Classes/Domain/Model/ImageVariant.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
*
* @Flow\Entity
*/
class ImageVariant extends Asset implements AssetVariantInterface, ImageInterface
class ImageVariant extends Asset implements AssetVariantInterface, ImageInterface, AdjustmentCapableInterface, PresetVariantInterface
{
use DimensionsTrait;

Expand Down
32 changes: 32 additions & 0 deletions Neos.Media/Classes/Domain/Model/PresetVariantInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
namespace Neos\Media\Domain\Model;

/**
* Methods to identify a variant to be based on a preset
*/
interface PresetVariantInterface
{
/**
* Sets the identifier of the variant preset which created this variant (if any)
*
* @param string $presetIdentifier For example: 'Acme.Demo:Preset1'
*/
public function setPresetIdentifier(string $presetIdentifier): void;

/**
* Returns the identifier of the variant preset which created this variant (if any)
*
* @return string|null
*/
public function getPresetIdentifier(): ?string;

/**
* @param string $presetVariantName
*/
public function setPresetVariantName(string $presetVariantName): void;

/**
* @return string|null
*/
public function getPresetVariantName(): ?string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
namespace Neos\Media\Domain\Service;

use Neos\Media\Domain\Model\Dto\AssetResourceReplaced;

/**
* Contract for handling any other
*/
interface AssetResourceReplacementFollowUpInterface
{
public function handle(AssetResourceReplaced $assetResourceReplaced): void;
}
120 changes: 69 additions & 51 deletions Neos.Media/Classes/Domain/Service/AssetService.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
* source code.
*/

use GuzzleHttp\Psr7\Uri;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Http\Exception as HttpException;
use Neos\Flow\Log\Utility\LogEnvironment;
Expand All @@ -22,22 +21,26 @@
use Neos\Flow\Mvc\Routing\UriBuilder;
use Neos\Flow\ObjectManagement\ObjectManagerInterface;
use Neos\Flow\Package\PackageManager;
use Neos\Flow\Persistence\Exception\UnknownObjectException;
use Neos\Flow\Persistence\RepositoryInterface;
use Neos\Flow\Reflection\ReflectionService;
use Neos\Flow\ResourceManagement\PersistentResource;
use Neos\Flow\ResourceManagement\ResourceManager;
use Neos\Media\Domain\Model\AdjustmentCapableInterface;
use Neos\Media\Domain\Model\AssetInterface;
use Neos\Media\Domain\Model\AssetVariantInterface;
use Neos\Media\Domain\Model\Dto\AssetResourceReplaced;
use Neos\Media\Domain\Model\ImageInterface;
use Neos\Media\Domain\Model\ImageVariant;
use Neos\Media\Domain\Model\PresetVariantInterface;
use Neos\Media\Domain\Model\Thumbnail;
use Neos\Media\Domain\Model\ThumbnailConfiguration;
use Neos\Media\Domain\Model\VariantSupportInterface;
use Neos\Media\Domain\Repository\AssetRepository;
use Neos\Media\Domain\Strategy\AssetUsageStrategyInterface;
use Neos\Media\Exception\AssetServiceException;
use Neos\Media\Exception\AssetVariantGeneratorException;
use Neos\Media\Exception\ThumbnailServiceException;
use Neos\RedirectHandler\Storage\RedirectStorageInterface;
use Neos\Utility\Arrays;
use Neos\Utility\MediaTypes;
use Psr\Log\LoggerInterface;
Expand Down Expand Up @@ -287,73 +290,88 @@ public function replaceAssetResource(AssetInterface $asset, PersistentResource $
$asset->getResource()->setMediaType($resourceMediaType);
}

$uriMapping = [];
$redirectHandlerEnabled = isset($options['generateRedirects']) && (boolean)$options['generateRedirects'] === true && $this->packageManager->isPackageAvailable('Neos.RedirectHandler');
if ($redirectHandlerEnabled) {
$originalAssetResourceUri = new Uri($this->resourceManager->getPublicPersistentResourceUri($originalAssetResource));
$newAssetResourceUri = new Uri($this->resourceManager->getPublicPersistentResourceUri($asset->getResource()));
$uriMapping[$originalAssetResourceUri->getPath()] = $newAssetResourceUri->getPath();
}
$replacedResources = [];

$replacedResources[] = new AssetResourceReplaced($asset, $originalAssetResource, $resource);

if (method_exists($asset, 'getVariants')) {
if ($asset instanceof VariantSupportInterface) {
$variants = $asset->getVariants();
/** @var AssetVariantInterface $variant */
foreach ($variants as $variant) {
$newVariant = null;
$originalVariantResource = $variant->getResource();
$presetIdentifier = $variant->getPresetIdentifier();
$variantName = $variant->getPresetVariantName();
if (isset($presetIdentifier, $variantName)) {
try {
$variant = $this->assetVariantGenerator->recreateVariant($asset, $presetIdentifier, $variantName);
if ($variant === null) {
$this->logger->debug(
sprintf('No variant returned when recreating asset variant %s::%s for %s', $presetIdentifier, $variantName, $asset->getTitle()),
LogEnvironment::fromMethodName(__METHOD__)
);
continue;
}
} catch (AssetVariantGeneratorException $exception) {
$this->logger->error(
sprintf('Error when recreating asset variant: %s', $exception->getMessage()),
LogEnvironment::fromMethodName(__METHOD__)
);
continue;
}
} else {
$variant->refresh();
foreach ($variant->getAdjustments() as $adjustment) {
if (method_exists($adjustment, 'refit') && $this->imageService->getImageSize($originalAssetResource) !== $this->imageService->getImageSize($resource)) {
if ($asset instanceof ImageInterface && $asset->getWidth() !== null && $asset->getHeight() !== null) {
$adjustment->refit($asset);
}
}
}
$this->getRepository($variant)->update($variant);
if ($variant instanceof PresetVariantInterface && !empty($variant->getPresetIdentifier()) && !empty($variant->getPresetVariantName())) {
$newVariant = $this->refreshPresetVariant($asset, $variant);
}

if ($redirectHandlerEnabled) {
$originalVariantResourceUri = new Uri($this->resourceManager->getPublicPersistentResourceUri($originalVariantResource));
$newVariantResourceUri = new Uri($this->resourceManager->getPublicPersistentResourceUri($variant->getResource()));
$uriMapping[$originalVariantResourceUri->getPath()] = $newVariantResourceUri->getPath();
if (
($newVariant === null && $variant instanceof AdjustmentCapableInterface)
&& $this->imageService->getImageSize($originalAssetResource) !== $this->imageService->getImageSize($resource)
) {
$newVariant = $this->refitAdjustmentsForVariant($asset, $variant);
}

$replacedResources[] = new AssetResourceReplaced($newVariant, $originalVariantResource, $newVariant->getResource());
}
}

if ($redirectHandlerEnabled) {
/** @var RedirectStorageInterface $redirectStorage */
$redirectStorage = $this->objectManager->get(RedirectStorageInterface::class);
foreach ($uriMapping as $originalUri => $newUri) {
$existingRedirect = $redirectStorage->getOneBySourceUriPathAndHost($originalUri);
if ($existingRedirect === null && $originalUri !== $newUri) {
$redirectStorage->addRedirect($originalUri, $newUri, 301);
try {
$assetResourceReplacementFollowUp = $this->objectManager->get(AssetResourceReplacementFollowUpInterface::class);
if ($assetResourceReplacementFollowUp !== null) {
foreach ($replacedResources as $assetResourceReplaced) {
$assetResourceReplacementFollowUp->handle($assetResourceReplaced);
}
}
}
} catch (UnknownObjectException $exception) {}

$this->getRepository($asset)->update($asset);
$this->emitAssetResourceReplaced($asset);
}

protected function refreshPresetVariant(AssetInterface $asset, PresetVariantInterface $variant): ?AssetVariantInterface
{
$presetIdentifier = $variant->getPresetIdentifier();
$variantName = $variant->getPresetVariantName();

try {
$variant = $this->assetVariantGenerator->recreateVariant($asset, $presetIdentifier, $variantName);
} catch (AssetVariantGeneratorException $exception) {
$this->logger->error(
sprintf('Error when recreating asset variant: %s', $exception->getMessage()),
LogEnvironment::fromMethodName(__METHOD__)
);
return null;
}

if ($variant === null) {
$this->logger->debug(
sprintf('No variant returned when recreating asset variant %s::%s for %s', $presetIdentifier, $variantName, $asset->getTitle()),
LogEnvironment::fromMethodName(__METHOD__)
);

return null;
}

return $variant;
}

protected function refitAdjustmentsForVariant(AssetInterface $asset, AssetInterface $variant): AssetInterface
{
$variant->refresh();
if (!($asset instanceof ImageInterface) || !($variant instanceof AdjustmentCapableInterface) || $asset->getWidth() < 1 || $asset->getHeight() < 1) {
$this->getRepository($variant)->update($variant);
return $variant;
}

foreach ($variant->getAdjustments() as $adjustment) {
if (method_exists($adjustment, 'refit')) {
$adjustment->refit($asset);
}
}
$this->getRepository($variant)->update($variant);
return $variant;
}

/**
* Signals that an asset was added.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public function createVariant(AssetInterface $asset, string $presetIdentifier, s
* @param AssetInterface $asset
* @param string $presetIdentifier
* @param string $variantIdentifier
* @return AssetVariantInterface The created variant (if any)
* @return AssetVariantInterface|null The created variant (if any)
* @throws AssetVariantGeneratorException
*/
public function recreateVariant(AssetInterface $asset, string $presetIdentifier, string $variantIdentifier): ?AssetVariantInterface
Expand Down
Loading