Skip to content

Commit

Permalink
BUGFIX Flush cache when asset has changed
Browse files Browse the repository at this point in the history
  • Loading branch information
dlubitz committed Mar 17, 2024
1 parent b994e5f commit 48af637
Showing 1 changed file with 73 additions and 44 deletions.
117 changes: 73 additions & 44 deletions Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@
use Neos\Media\Domain\Model\AssetVariantInterface;
use Psr\Log\LoggerInterface;
use Neos\ContentRepository\Core\Factory\ContentRepositoryId;
use Neos\Media\Domain\Service\AssetService;
use Neos\Neos\AssetUsage\Dto\AssetUsageReference;
use Neos\Flow\Persistence\PersistenceManagerInterface;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Neos\AssetUsage\Dto\AssetUsageFilter;
use Neos\Neos\AssetUsage\GlobalAssetUsageService;

/**
* This service flushes Fusion content caches triggered by node changes.
Expand All @@ -47,11 +46,15 @@ class ContentCacheFlusher
#[Flow\InjectConfiguration(path: "fusion.contentCacheDebugMode")]
protected bool $debugMode;

/**
* @var array<string,string>
*/
private array $tagsToFlushOnShutdown = [];

public function __construct(
protected readonly ContentCache $contentCache,
protected readonly LoggerInterface $systemLogger,
protected readonly AssetService $assetService,
protected readonly PersistenceManagerInterface $persistenceManager,
protected readonly GlobalAssetUsageService $globalAssetUsageService,
protected readonly ContentRepositoryRegistry $contentRepositoryRegistry,
) {
}
Expand All @@ -68,28 +71,41 @@ public function flushNodeAggregate(
ContentStreamId $contentStreamId,
NodeAggregateId $nodeAggregateId
): void {
$tagsToFlush = [];

$tagsToFlush[ContentCache::TAG_EVERYTHING] = 'which were tagged with "Everything".';

$this->registerChangeOnNodeIdentifier($contentRepository->id, $contentStreamId, $nodeAggregateId, $tagsToFlush);
$tagsToFlush = array_merge(
$this->collectTagsForChangeOnNodeAggregate($contentRepository, $contentStreamId, $nodeAggregateId),
$tagsToFlush
);

$this->flushTags($tagsToFlush);
}

/**
* @return array<string,string>
*/
protected function collectTagsForChangeOnNodeAggregate(
ContentRepository $contentRepository,
ContentStreamId $contentStreamId,
NodeAggregateId $nodeAggregateId
): array {
$nodeAggregate = $contentRepository->getContentGraph()->findNodeAggregateById(
$contentStreamId,
$nodeAggregateId
);
if (!$nodeAggregate) {
// Node Aggregate was removed in the meantime, so no need to clear caches on this one anymore.
return;
return [];
}
$tagsToFlush = $this->collectTagsForChangeOnNodeIdentifier($contentRepository->id, $contentStreamId, $nodeAggregateId);

$this->registerChangeOnNodeType(
$tagsToFlush = array_merge($this->collectTagsForChangeOnNodeType(
$nodeAggregate->nodeTypeName,
$contentRepository->id,
$contentStreamId,
$nodeAggregateId,
$tagsToFlush,
$contentRepository
);
), $tagsToFlush);

$parentNodeAggregates = [];
foreach (
Expand Down Expand Up @@ -136,54 +152,49 @@ public function flushNodeAggregate(
$parentNodeAggregates[] = $parentNodeAggregate;
}
}
$this->flushTags($tagsToFlush);

return $tagsToFlush;
}


/**
* Please use registerNodeChange() if possible. This method is a low-level api. If you do use this method make sure
* that $cacheIdentifier contains the workspacehash as well as the node identifier:
* $workspaceHash .'_'. $nodeIdentifier
* The workspacehash can be received via $this->getCachingHelper()->renderWorkspaceTagForContextNode($workpsacename)
*
* @param array<string,string> &$tagsToFlush
* @return array<string, string>
*/
private function registerChangeOnNodeIdentifier(
private function collectTagsForChangeOnNodeIdentifier(
ContentRepositoryId $contentRepositoryId,
ContentStreamId $contentStreamId,
NodeAggregateId $nodeAggregateId,
array &$tagsToFlush
): void {
): array {
$tagsToFlush = [];

$nodeCacheIdentifier = CacheTag::forNodeAggregate($contentRepositoryId, $contentStreamId, $nodeAggregateId);
$tagsToFlush[$nodeCacheIdentifier->value] = sprintf(
'which were tagged with "%s" because that identifier has changed.',
$nodeCacheIdentifier->value
);

$descandantOfNodeCacheIdentifier = CacheTag::forDescendantOfNode($contentRepositoryId, $contentStreamId, $nodeAggregateId);
$tagsToFlush[$descandantOfNodeCacheIdentifier->value] = sprintf(
$descendantOfNodeCacheIdentifier = CacheTag::forDescendantOfNode($contentRepositoryId, $contentStreamId, $nodeAggregateId);
$tagsToFlush[$descendantOfNodeCacheIdentifier->value] = sprintf(
'which were tagged with "%s" because node "%s" has changed.',
$descandantOfNodeCacheIdentifier->value,
$descendantOfNodeCacheIdentifier->value,
$nodeCacheIdentifier->value
);

return $tagsToFlush;
}

/**
* This is a low-level api. Please use registerNodeChange() if possible. Otherwise make sure that $nodeTypePrefix
* is set up correctly and contains the workspacehash wich can be received via
* $this->getCachingHelper()->renderWorkspaceTagForContextNode($workpsacename)
*
* @param array<string,string> &$tagsToFlush
* @return array<string,string> $tagsToFlush
*/
private function registerChangeOnNodeType(
private function collectTagsForChangeOnNodeType(
NodeTypeName $nodeTypeName,
ContentRepositoryId $contentRepositoryId,
ContentStreamId $contentStreamId,
?NodeAggregateId $referenceNodeIdentifier,
array &$tagsToFlush,
ContentRepository $contentRepository
): void {
): array {
$tagsToFlush = [];

try {
$nodeTypesNamesToFlush = $this->getAllImplementedNodeTypeNames(
$contentRepository->getNodeTypeManager()->getNodeType($nodeTypeName)
Expand All @@ -202,11 +213,13 @@ private function registerChangeOnNodeType(
$nodeTypeName->value
);
}

return $tagsToFlush;
}


/**
* Flush caches according to the previously registered node changes.
* Flush caches according to the given tags.
*
* @param array<string,string> $tagsToFlush
*/
Expand Down Expand Up @@ -263,18 +276,34 @@ public function registerAssetChange(AssetInterface $asset): void
$asset = $asset->getOriginalAsset();
}

if (!$this->assetService->isInUse($asset)) {
return;
}

$tagsToFlush = [];
foreach ($this->assetService->getUsageReferences($asset) as $reference) {
if (!$reference instanceof AssetUsageReference) {
continue;
$filter = AssetUsageFilter::create()
->withAsset($asset->getAssetSourceIdentifier())
->includeVariantsOfAsset();

foreach ($this->globalAssetUsageService->findByFilter($filter) as $contentRepositoryId => $usages) {
foreach ($usages as $usage) {
$contentRepository = $this->contentRepositoryRegistry->get(ContentRepositoryId::fromString($contentRepositoryId));
$tagsToFlush = array_merge(
$this->collectTagsForChangeOnNodeAggregate(
$contentRepository,
$usage->contentStreamId,
$usage->nodeAggregateId
),
$tagsToFlush
);
}
$contentRepository = $this->contentRepositoryRegistry->get($reference->getContentRepositoryId());
$this->flushNodeAggregate($contentRepository, $reference->getContentStreamId(), $reference->getNodeAggregateId());
}
$this->flushTags($tagsToFlush);

$this->tagsToFlushOnShutdown = array_merge($tagsToFlush, $this->tagsToFlushOnShutdown);
}

/**
* Flush caches according to the previously registered changes.
*/
public function shutdownObject(): void
{
$this->flushTags($this->tagsToFlushOnShutdown);
$this->tagsToFlushOnShutdown = [];
}
}

0 comments on commit 48af637

Please sign in to comment.