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

WIP 5150 flush content cache correctly #5160

Closed
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
use Neos\ContentRepository\Core\Feature\SubtreeTagging\Dto\SubtreeTags;
use Neos\ContentRepository\Core\Feature\SubtreeTagging\Event\SubtreeWasTagged;
use Neos\ContentRepository\Core\Feature\SubtreeTagging\Event\SubtreeWasUntagged;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Event\WorkspaceWasPartiallyDiscarded;
use Neos\ContentRepository\Core\Infrastructure\DbalCheckpointStorage;
use Neos\ContentRepository\Core\Infrastructure\DbalSchemaDiff;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
Expand Down Expand Up @@ -171,6 +172,7 @@ public function canHandle(EventInterface $event): bool
RootNodeAggregateWithNodeWasCreated::class,
SubtreeWasTagged::class,
SubtreeWasUntagged::class,
WorkspaceWasPartiallyDiscarded::class
]);
}

Expand All @@ -195,6 +197,9 @@ public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void
RootNodeAggregateWithNodeWasCreated::class => $this->whenRootNodeAggregateWithNodeWasCreated($event, $eventEnvelope),
SubtreeWasTagged::class => $this->whenSubtreeWasTagged($event),
SubtreeWasUntagged::class => $this->whenSubtreeWasUntagged($event),
// workaround to allow the content graph catchuphook to react on this already now
// with https://github.com/neos/neos-development-collection/pull/5096 we will really handle the event here as well
WorkspaceWasPartiallyDiscarded::class => null,
default => throw new \InvalidArgumentException(sprintf('Unsupported event %s', get_debug_type($event))),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
use Neos\ContentRepository\Core\Feature\Common\EmbedsContentStreamAndNodeAggregateId;
use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved;
use Neos\ContentRepository\Core\Feature\NodeRemoval\Event\NodeAggregateWasRemoved;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Event\WorkspaceWasPartiallyDiscarded;
use Neos\ContentRepository\Core\Projection\CatchUpHookInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\EventStore\Model\EventEnvelope;
Expand Down Expand Up @@ -133,19 +135,28 @@ public function onBeforeEvent(EventInterface $eventInstance, EventEnvelope $even
return;
}

if ($eventInstance instanceof WorkspaceWasPartiallyDiscarded) {
foreach ($eventInstance->discardedNodes as $discardedNode) {
$this->scheduleCacheFlushJobForNodeAggregate(
$this->contentRepository,
$eventInstance->workspaceName,
$discardedNode->nodeAggregateId
);
}
}

Comment on lines +138 to +147
Copy link
Member Author

Choose a reason for hiding this comment

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

fixes one ui test

FIX #3184: Discarded node move changes are reflected correctly in the document tree
Scenario #2: Moved nodes do not just disappear after discarding the move change

if (
$eventInstance instanceof NodeAggregateWasRemoved
// NOTE: when moving a node, we need to clear the cache not just after the move was completed,
// but also on the original location. Otherwise, we have the problem that the cache is not
// cleared, leading to presumably duplicate nodes in the UI.
|| $eventInstance instanceof NodeAggregateWasMoved
) {
$workspace = $this->contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId($eventInstance->getContentStreamId());
if ($workspace === null) {
try {
$contentGraph = $this->contentRepository->getContentGraph($eventInstance->workspaceName);
Copy link
Member Author

Choose a reason for hiding this comment

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

using $eventInstance->workspaceName fixes most of the ui discard failures

} catch (WorkspaceDoesNotExist) {
return;
}
// FIXME: EventInterface->workspaceName
$contentGraph = $this->contentRepository->getContentGraph($workspace->workspaceName);
$nodeAggregate = $contentGraph->findNodeAggregateById(
$eventInstance->getNodeAggregateId()
);
Expand All @@ -157,7 +168,7 @@ public function onBeforeEvent(EventInterface $eventInstance, EventEnvelope $even
assert($parentNodeAggregate instanceof NodeAggregate);
$this->scheduleCacheFlushJobForNodeAggregate(
$this->contentRepository,
$workspace->workspaceName,
$eventInstance->workspaceName,
$parentNodeAggregate->nodeAggregateId
);
}
Expand All @@ -177,19 +188,25 @@ public function onAfterEvent(EventInterface $eventInstance, EventEnvelope $event
!($eventInstance instanceof NodeAggregateWasRemoved)
&& $eventInstance instanceof EmbedsContentStreamAndNodeAggregateId
) {
$workspace = $this->contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId($eventInstance->getContentStreamId());
if ($workspace === null) {
// Hack, we don't declare the `workspaceName` as part of the `EmbedsContentStreamAndNodeAggregateId` events,
// but it will always exist!
// See https://github.com/neos/neos-development-collection/issues/5152
/** @phpstan-ignore property.notFound */
$workspaceName = $eventInstance->workspaceName;

try {
$contentGraph = $this->contentRepository->getContentGraph($workspaceName);
} catch (WorkspaceDoesNotExist) {
return;
}
// FIXME: EventInterface->workspaceName
$nodeAggregate = $this->contentRepository->getContentGraph($workspace->workspaceName)->findNodeAggregateById(
$nodeAggregate = $contentGraph->findNodeAggregateById(
$eventInstance->getNodeAggregateId()
);

if ($nodeAggregate) {
$this->scheduleCacheFlushJobForNodeAggregate(
$this->contentRepository,
$workspace->workspaceName,
$workspaceName,
$nodeAggregate->nodeAggregateId
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
@flowEntities
Feature: Tests for the ContentCacheFlusher and cache flushing when applied in user workspaces

Background:
Given using no content dimensions
And using the following node types:
"""yaml
'Neos.ContentRepository:Root': {}
'Neos.Neos:Sites':
superTypes:
'Neos.ContentRepository:Root': true
'Neos.Neos:Document':
properties:
title:
type: string
uriPathSegment:
type: string
'Neos.Neos:ContentCollection':
constraints:
nodeTypes:
'Neos.Neos:Document': false
'*': true
'Neos.Neos:Content':
constraints:
nodeTypes:
'*': false
'Neos.Neos:Site':
superTypes:
'Neos.Neos:Document': true
'Neos.Neos:Test.DocumentTypeWithMainCollection':
superTypes:
'Neos.Neos:Document': true
childNodes:
main:
type: 'Neos.Neos:ContentCollection'
'Neos.Neos:Test.TextNode':
superTypes:
'Neos.Neos:Content': true
properties:
text:
type: string
"""
And using identifier "default", I define a content repository
And I am in content repository "default"
And I am user identified by "editor"

When the command CreateRootWorkspace is executed with payload:
| Key | Value |
| workspaceName | "live" |
| newContentStreamId | "cs-identifier" |
And the command CreateWorkspace is executed with payload:
| Key | Value |
| workspaceName | "user-editor" |
| baseWorkspaceName | "live" |
| newContentStreamId | "user-editor-cs-identifier" |
And I am in workspace "live" and dimension space point {}
And the command CreateRootNodeAggregateWithNode is executed with payload:
| Key | Value |
| nodeAggregateId | "root" |
| nodeTypeName | "Neos.Neos:Sites" |
And the following CreateNodeAggregateWithNode commands are executed:
| nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | tetheredDescendantNodeAggregateIds |
| site | root | Neos.Neos:Site | {} | site | {} |
| test-document-with-contents | site | Neos.Neos:Test.DocumentTypeWithMainCollection | {"uriPathSegment": "test-document-with-contents", "title": "Test document with contents"} | test-document-with-contents | {"main": "test-document-with-contents--main"} |
| text-node-start | test-document-with-contents--main | Neos.Neos:Test.TextNode | {"text": "Text Node at the start of the document"} | text-node-start | {} |
| text-node-end | test-document-with-contents--main | Neos.Neos:Test.TextNode | {"text": "Text Node at the end of the document"} | text-node-end | {} |
When the command RebaseWorkspace is executed with payload:
| Key | Value |
| workspaceName | "user-editor" |
And A site exists for node name "site" and domain "http://localhost"
And the sites configuration is:
"""yaml
Neos:
Neos:
sites:
'*':
contentRepository: default
contentDimensions:
resolver:
factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory
"""
And the Fusion context node is "site"
And the Fusion context request URI is "http://localhost"
And I have the following Fusion setup:
"""fusion
include: resource://Neos.Fusion/Private/Fusion/Root.fusion
include: resource://Neos.Neos/Private/Fusion/Root.fusion

prototype(Neos.Neos:Test.TextNode) < prototype(Neos.Neos:ContentComponent) {
renderer = ${"[" + q(node).property("text") + "]"}
}
"""

Scenario: ContentCache gets flushed when a node that was just created gets discarded
Given I have Fusion content cache enabled
And I am in workspace "user-editor" and dimension space point {}
And the Fusion context node is "test-document-with-contents"
And I execute the following Fusion code:
"""fusion
test = Neos.Neos:ContentCollection {
nodePath = "main"
}
"""
Then I expect the following Fusion rendering result:
"""
<div class="neos-contentcollection">[Text Node at the start of the document][Text Node at the end of the document]</div>
"""

When the command CreateNodeAggregateWithNode is executed with payload:
| Key | Value |
| nodeAggregateId | "text-node-middle" |
| nodeTypeName | "Neos.Neos:Test.TextNode" |
| parentNodeAggregateId | "test-document-with-contents--main" |
| initialPropertyValues | {"text": "Text Node in the middle of the document"} |
| succeedingSiblingNodeAggregateId | "text-node-end" |
| nodeName | "text-node-middle" |
And I execute the following Fusion code:
"""fusion
test = Neos.Neos:ContentCollection {
nodePath = "main"
}
"""
Then I expect the following Fusion rendering result:
"""
<div class="neos-contentcollection">[Text Node at the start of the document][Text Node in the middle of the document][Text Node at the end of the document]</div>
"""

When the command DiscardWorkspace is executed with payload:
| Key | Value |
| workspaceName | "user-editor" |
And I am in workspace "user-editor" and dimension space point {}
Then I expect node aggregate identifier "text-node-middle" to lead to no node

When I execute the following Fusion code:
"""fusion
test = Neos.Neos:ContentCollection {
nodePath = "main"
}
"""
Then I expect the following Fusion rendering result:
"""
<div class="neos-contentcollection">[Text Node at the start of the document][Text Node at the end of the document]</div>
"""

Scenario: ContentCache gets flushed when a node that was just created gets explicitly discarded
Given I have Fusion content cache enabled
And I am in workspace "user-editor" and dimension space point {}
And the Fusion context node is "test-document-with-contents"
And I execute the following Fusion code:
"""fusion
test = Neos.Neos:ContentCollection {
nodePath = "main"
}
"""
Then I expect the following Fusion rendering result:
"""
<div class="neos-contentcollection">[Text Node at the start of the document][Text Node at the end of the document]</div>
"""

When the command CreateNodeAggregateWithNode is executed with payload:
| Key | Value |
| nodeAggregateId | "text-node-middle" |
| nodeTypeName | "Neos.Neos:Test.TextNode" |
| parentNodeAggregateId | "test-document-with-contents--main" |
| initialPropertyValues | {"text": "Text Node in the middle of the document"} |
| succeedingSiblingNodeAggregateId | "text-node-end" |
| nodeName | "text-node-middle" |
And I execute the following Fusion code:
"""fusion
test = Neos.Neos:ContentCollection {
nodePath = "main"
}
"""
Then I expect the following Fusion rendering result:
"""
<div class="neos-contentcollection">[Text Node at the start of the document][Text Node in the middle of the document][Text Node at the end of the document]</div>
"""

When the command DiscardIndividualNodesFromWorkspace is executed with payload:
| Key | Value |
| workspaceName | "user-editor" |
| nodesToDiscard | [{"dimensionSpacePoint": {}, "nodeAggregateId": "text-node-middle"}] |
And I am in workspace "user-editor" and dimension space point {}
Then I expect node aggregate identifier "text-node-middle" to lead to no node

When I execute the following Fusion code:
"""fusion
test = Neos.Neos:ContentCollection {
nodePath = "main"
}
"""
Then I expect the following Fusion rendering result:
"""
<div class="neos-contentcollection">[Text Node at the start of the document][Text Node at the end of the document]</div>
"""
Loading