-
-
Notifications
You must be signed in to change notification settings - Fork 223
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: Introduce NodeIdentity
#4868
Conversation
Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php
Outdated
Show resolved
Hide resolved
Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php
Outdated
Show resolved
Hide resolved
4e56a48
to
8912655
Compare
NodeIdentity
DtoNodeIdentity
and NodeSerializer
8912655
to
cd7ad38
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some initial comments.
My main concern (not with this PR but in general regarding this topic) is the implicit distinction between the "content stream" and the "workspace" view.
E.g. ContentSubgraphIdentity
vs NodeIdentity
Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php
Outdated
Show resolved
Hide resolved
Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php
Outdated
Show resolved
Hide resolved
cd7ad38
to
1bfdef1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As recap from the weekly:
I like the NodeIdentity
DTO and I think that it really makes sense.
NodeSerializer
does not really make sense to me yet and I think it highlights some inconsistencies we currently have.
I could imagine that we could change the Node
read model from:
subgraphIdentity:
contentRepositoryId
contentStreamId
dimensionSpacePoint
visibilityConstraints
nodeAggregateId
originDimensionSpacePoint
...
to
identity
contentRepositoryId
workspaceName
dimensionSpacePoint
nodeAggregateId
originDimensionSpacePoint
...
But I'm not sure about all implications yet
@bwaidelich the suggested properties for node would prevent us from ever addressing a node that is in a contentstream without workspace attachment. I think it's fine to not plan for this from outside, but we might need to load one eg. for conflict resolution? |
I just discussed this topic with @skurfuerst and he also agrees to getting rid of the CS id in the public APIs as much as possible. We do probably still need @kitsunet re
That's true and might be a potential issue. class NodeIdentity
{
private function __construct(
// ...
public WorkspaceName|VirtualWorkspaceName $workspaceName
// ... For write operations, i.e. commands, we would always require a |
NodeIdentity
and NodeSerializer
NodeIdentity
I implemented some wip stuff, edit moved to https://github.com/mhsdesign/neos-development-collection/tree/feature/NodeIdentityDto-original-draft Details
ala (my goal was to not have to keep track of the workspaces in the content graph projection) final class ContentRepository
{
public function getSubgraph(NodeIdentity $nodeIdentity, VisibilityConstraints $visibilityConstraints): ContentSubgraphInterface
{
if ($nodeIdentity->workspaceName instanceof DetachedWorkspaceName) {
return $this->getContentGraph()->getSubgraph(
$nodeIdentity->workspaceName->contentStreamId,
$nodeIdentity->dimensionSpacePoint,
$visibilityConstraints
);
}
$workspace = $this->getWorkspaceFinder()->findOneByName($nodeIdentity->workspaceName);
// ...
interface ContentGraphInterface extends ProjectionStateInterface
{
public function getSubgraph(
ContentStreamId|Workspace $contentStreamReference,
DimensionSpacePoint $dimensionSpacePoint,
VisibilityConstraints $visibilityConstraints
): ContentSubgraphInterface;
final readonly class NodeIdentity implements \JsonSerializable
{
private function __construct(
public ContentRepositoryId $contentRepositoryId,
public WorkspaceName|DetachedWorkspaceName $workspaceName,
public DimensionSpacePoint $dimensionSpacePoint,
public NodeAggregateId $nodeAggregateId,
) {
}
final class ContentSubgraph implements ContentSubgraphInterface
{
// todo what if there was already a subgraph with runtime cache constructed and different / no workspace name?
public function __construct(
private readonly ContentRepositoryId $contentRepositoryId,
private readonly ContentStreamId $contentStreamId,
private readonly ?WorkspaceName $workspaceName,
final class NodeFactory
{
public function __construct(
private readonly ContentRepositoryId $contentRepositoryId,
private readonly NodeTypeManager $nodeTypeManager,
private readonly PropertyConverter $propertyConverter
) {
}
/**
* @param array<string,string> $nodeRow Node Row from projection (<prefix>_node table)
*/
public function mapNodeRowToNode(
array $nodeRow,
DimensionSpacePoint $dimensionSpacePoint,
VisibilityConstraints $visibilityConstraints,
?WorkspaceName $workspaceName,
): Node {
$nodeType = $this->nodeTypeManager->hasNodeType($nodeRow['nodetypename'])
? $this->nodeTypeManager->getNodeType($nodeRow['nodetypename'])
: null;
return Node::create(
NodeIdentity::create(
$this->contentRepositoryId,
$workspaceName ?? DetachedWorkspaceName::fromContentStreamId(
ContentStreamId::fromString($nodeRow['contentstreamid'])
),
$dimensionSpacePoint,
NodeAggregateId::fromString($nodeRow['nodeaggregateid'])
), |
The VirtualWorkspaceName idea seems fine, I think that should cover most bases, I like it :) Re the visibility constraints, IMHO it makes sense to know where exactly that node is from, to refer to other nodes, eg. if I get one of those nodes handed in userland code without them being available on the node I would need to pass that in parallel to not suddenly drop into a different visibility if I need a subtree for this node. |
IMO that would be the "better" way to solve this: To traverse the graph from a given node, you'd need the visibility constraints, too. But the usecase you describe is exactly why we would need it for now because the alternative would be to introduce the visibility constraints as some kind of context to the fusion runtime |
Any update on this one? |
Jup. #4790 should be merged first as i was about to adjust the node factory and was like wait a second, dont make it harder with the conflicts ;) |
ae02b4c
to
c9feaca
Compare
The nodeadress was added 6 years ago without the concept of multiple crs. It will be replaced by the node identity
@mhsdesign Thanks for the update and let me know if I can help with this one! |
It will keep track of the current workspace name to content stream id mapping
c9feaca
to
e37a4b8
Compare
@@ -175,6 +196,7 @@ public function mapNodeRowsToNodeAggregate( | |||
// ... so we handle occupation exactly once ... | |||
$nodesByOccupiedDimensionSpacePoints[$occupiedDimensionSpacePoint->hash] = $this->mapNodeRowToNode( | |||
$nodeRow, | |||
WorkspaceName::forLive(), // todo use workspace name in content graph api |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NodeAggregates
also need to operate on workspace names, but for that we would have to adjust the content graph api. That might go in a separate pr.
public function findNodeAggregateById(
WorkspaceName $workspaceName,
NodeAggregateId $nodeAggregateId
): ?NodeAggregate;
the cs id would be looked up internally via the workspaces
table.
And the cache would be similar flushed on markStale
as the cached subgraphs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with this would be that the write site heavily relies on the ContentGraph
and must work on a specific contentstream id (see ContentStreamIdOverride
)
unless we create a custom ContentGraph
which will use our content stream, or by actually hacky checking against the state in ContentStreamIdOverride
we wont get around that.
@@ -71,6 +71,8 @@ private function handleMoveDimensionSpacePoint( | |||
$streamName = ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) | |||
->getEventStreamName(); | |||
|
|||
// todo use WorkspaceName here as well but the command doesnt expose it | |||
// https://github.com/neos/neos-development-collection/issues/4942 | |||
self::requireDimensionSpacePointToBeEmptyInContentStream( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great to find out why #4942 is how it is.
These were the only commands untouched by bernhards refactoring.
// todo UNSAFE as override via ContentStreamIdOverride will NOT be taken into account!!! | ||
$command->workspaceName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this MUST not be used as a custom repoint via ContentStreamIdOverride
would be ignored.
We possibly have to pass both as touple and create a new ContentGraph
by hand.
// todo use workspace name instead!!! | ||
$usage->contentStreamId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i guess adding the workspace
to the AssetUsage
will not be trivial, so we should just use the workspace finder beforehand and get a workspace that will be internally resolved again to a content stream?
@@ -193,7 +193,7 @@ private function handleChangeNodeAggregateType( | |||
$tetheredNodeName = NodeName::fromString($serializedTetheredNodeName); | |||
|
|||
$subgraph = $contentRepository->getContentGraph()->getSubgraph( | |||
$node->subgraphIdentity->contentStreamId, | |||
$node->identity->workspaceName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is illegal as well because of ContentStreamIdOverride
.
Thanks for all the discussion here, but this branch is super outdated. I cherry picked all the changes to a new pr and we can continue on a blank page: #5042 |
Resolves partially: #4564
Required for a new
NodeUriBuilder
api #4552 which in-turn "should" solve cross cr linking: #4441The
NodeIdentity
will containWorkspaceName
instead of theContentStreamId
For most, if not all use cases, like caching a reference to a node in fusions @cache.context or serializing a node into the frontend and passing it around as query parameter, the workspace name should be used.
That guarantees that a node is still findable, when a workspace will be rebased (which can happen anytime, and thus the csid would be changed
Upgrade instructions
Review instructions
getIdentity
FEATURE 4327 - Expose a subgraph's identity #4678#4943 (comment) but maybe manual
refresh
instead of implicit through handle.TODOs as discussed with @mhsdesign and @kitsunet today:
ContentGraph::getSubgraph()
(with runtime cache in theContentGraph
– the same workspace will resolve to the same CS ID in one request, maybe reset runtime cache viamarkStale()
)ContentGraph::find*
queries to use workspaceName instead of contentStreamId (IMO it's totally fine to join the workspaceName <-> cs id table here for those queries. Alternatively we could add a dedicated lookup + runtime cache)Afterwards we have to find out whether there are places that need to be able to override the worspace name -> cs id mapping for tests or CR constraints. If so we could either:
ContentGraph::getSubgraphInternal()
– but that would be dangerous because it is part of the public interface (even if marked internal)ContentsubgraphFactoryInterface
that can be used via CR service$contentGraph->dangerousSetContentStreamIdForWorkspaceNameFooBar(...)
Checklist
FEATURE|TASK|BUGFIX
!!!
and have upgrade-instructions