-
-
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
BUGFIX: make tethered node ids deterministic #4313
Conversation
// Write the auto-created descendant node aggregate ids back to the command; | ||
// so that when rebasing the command, it stays fully deterministic. | ||
$command = $command->withTetheredDescendantNodeAggregateIds($descendantNodeAggregateIds); |
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 think we can remove this step now?
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.
good point.. yes, I think so
); | ||
|
||
// handle multiple levels of autocreated child nodes | ||
foreach ($childNodeType->tetheredNodeAggregateIds($childNodeAggregateId)->getNodeAggregateIds() as $nestedChildNodeName => $nodeAggregateId) { |
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.
howdy there, my name is re cursion.
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.
howdy there, I think there should be some kind of endless-recursion-check :)
I mean.. If you have something like
'Some:NodeType':
children:
'foo':
type: 'Some:NodeType'
it probably won't work anyways. But maybe we should detect those cases anyways to provide a better error message than "memory limit exceeded..."
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.
Looks great, thanks.
Just a couple of mini nitpicks and some comment re endless recursions
@@ -58,6 +58,9 @@ final class CreateNodeAggregateWithNode implements CommandInterface | |||
* using this assignment registry. | |||
* Since tethered child nodes may have tethered child nodes themselves, | |||
* this registry is indexed using relative node paths to the node to create in the first place. | |||
* | |||
* Specifying them is optional, and otherwise they are calculated deterministic based on the $nodeAggregateId and the tethered nodeName. |
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.
Nice addition! Just a mini nitpick
* Specifying them is optional, and otherwise they are calculated deterministic based on the $nodeAggregateId and the tethered nodeName. | |
* Specifying them is optional, and otherwise they are calculated deterministically based on the $nodeAggregateId and the tethered nodeName. |
// Write the auto-created descendant node aggregate ids back to the command; | ||
// so that when rebasing the command, it stays fully deterministic. | ||
$command = $command->withTetheredDescendantNodeAggregateIds($descendantNodeAggregateIds); |
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.
good point.. yes, I think so
@@ -490,11 +493,34 @@ public function hasAutoCreatedChildNode(NodeName $nodeName): bool | |||
*/ | |||
public function getTypeOfAutoCreatedChildNode(NodeName $nodeName): ?NodeType | |||
{ | |||
$this->initialize(); |
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.
good catch!
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.
haha actually not the only missing 😂
#4333
will revert this and must be fixed correctly in another pr
); | ||
|
||
// handle multiple levels of autocreated child nodes | ||
foreach ($childNodeType->tetheredNodeAggregateIds($childNodeAggregateId)->getNodeAggregateIds() as $nestedChildNodeName => $nodeAggregateId) { |
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.
howdy there, I think there should be some kind of endless-recursion-check :)
I mean.. If you have something like
'Some:NodeType':
children:
'foo':
type: 'Some:NodeType'
it probably won't work anyways. But maybe we should detect those cases anyways to provide a better error message than "memory limit exceeded..."
should we then remove (as a follow up) |
$hex = md5($parentNodeAggregateId->value . '-' . $tetheredNodeName->value); | ||
return new self( | ||
substr($hex, 0, 8) . '-' . substr($hex, 8, 4) . '-' . substr($hex, 12, 4) . '-' . substr($hex, 16, 4) . '-' . substr($hex, 20, 12) | ||
); |
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.
to discuss: does this have to be a UUID pattern?
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.
to follow up on this:
node ids used to be UUIDs and that is the reason for this algorithm.
But now they can be anything basically (as long as they match the regex /^([a-z0-9\-]{1,64})$/
).
I would suggest to just do $parentNodeAggregateId->value . '-' . $tetheredNodeName->value
really (with some deterministic changes to satisfy the regex)
@@ -50,6 +50,23 @@ public static function fromString(string $value): self | |||
return new self($value); | |||
} | |||
|
|||
/** | |||
* Calculates a deterministic nodeAggregateId. | |||
* |
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.
used for new nodes, but previously created tethered node ids were random
comment
* NodeAggregateId::fromParentNodeAggregateIdAndNodeName($parentNodeAggregateId, NodeName::fromString('main')) | ||
* | ||
*/ | ||
public static function fromParentNodeAggregateIdAndNodeName(NodeAggregateId $parentNodeAggregateId, NodeName $tetheredNodeName): self |
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.
move to NodeName
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 agree that this should be moved because it contains a concept that does not belong to the Node Aggregate ID itself.. It's not too bad though IMO and I'm not sure if NodeName
is a better place.. @skurfuerst do you have an idea where to put this (and please don't say "utility class" ;))
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.
A few more comments after discussing this in our weekly.
And some more thoughts:
tetheredDescendantNodeAggregateIds
should be removed from the CreateNodeAggregateWithNode
command, but this has some implications and can be done in a separate changeset (see #4375)
In the long(!) run we would like to get rid of Node::nodeName
and all the path related complexity. As a result, a tethered node would not know its own name. To retrieve a tethered node we could use ContentSubgraphInterface::findChildNodeConnectedThroughEdgeName()
like today.
* | ||
* Used for determining the nodeAggregateIds of tethered nodes. | ||
* | ||
* e.g. in case you want to get the main content collection node aggregate id: |
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.
* e.g. in case you want to get the main content collection node aggregate id: | |
* e.g. in case you want to get the main content collection node aggregate id: | |
* | |
* NOTE: Previously ids of tethered nodes were _not_ deterministic, so this method should not be used to look up tethered nodes | |
* Instead {@see \Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface::findChildNodeConnectedThroughEdgeName()} can be used |
* NodeAggregateId::fromParentNodeAggregateIdAndNodeName($parentNodeAggregateId, NodeName::fromString('main')) | ||
* | ||
*/ | ||
public static function fromParentNodeAggregateIdAndNodeName(NodeAggregateId $parentNodeAggregateId, NodeName $tetheredNodeName): self |
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 agree that this should be moved because it contains a concept that does not belong to the Node Aggregate ID itself.. It's not too bad though IMO and I'm not sure if NodeName
is a better place.. @skurfuerst do you have an idea where to put this (and please don't say "utility class" ;))
$hex = md5($parentNodeAggregateId->value . '-' . $tetheredNodeName->value); | ||
return new self( | ||
substr($hex, 0, 8) . '-' . substr($hex, 8, 4) . '-' . substr($hex, 12, 4) . '-' . substr($hex, 16, 4) . '-' . substr($hex, 20, 12) | ||
); |
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.
to follow up on this:
node ids used to be UUIDs and that is the reason for this algorithm.
But now they can be anything basically (as long as they match the regex /^([a-z0-9\-]{1,64})$/
).
I would suggest to just do $parentNodeAggregateId->value . '-' . $tetheredNodeName->value
really (with some deterministic changes to satisfy the regex)
@mhsdesign I'm going through open 9.0 PRs right now and was wondering: Are you still working on this one? |
Not actively since June ^^ as you had some legit points, they need to be implemented and #4313 (comment) also needs to be discussed (its currently a bit over my head ^^) So feel free to continue my work - otherwise ill pick it up in half a month or something ;) |
@mhsdesign half a month is over now :) |
…eIdByParent($parentId)` instead of `NodeAggregateId::fromParentNodeAggregateIdAndNodeName`
Important points of our (extensive ^^) discussions from the last weeklies: A future without
|
Thanks so much ❤️❤️ |
Hmm upsi - i just thought of a case were these deterministic id's wont be fun: What should happen when the tethered node "main" is renamed to "foo"? The algorithm will encode that the name is still "main" - but what if we actually now want to later reintroduce a "main" childNode? The "correct" id is already in use now :/ |
Good point. What happens today in that case? |
I guess strictly speaking it's not a use case we ever cared about? But the repair command at least should reassign new ids based on the new name AFAIK? So currently it could be solved that way. |
That would defeat the purpose of allowing custom ids to be specified via command. |
hmm maybe keeping it totally random then is still better than trying to bring to much structure into the ids? |
because of the fact that a migration to rename auto created nodes will give us trouble with the node id: #4313 (comment) we will close this pr and keep the node ids random to avoid any conflicts. but to make things like node templates easier, we want a “helper“ to create all random node ids before the command is issued |
… tethered node ids The pr neos/neos-development-collection#4313 was declined and tethered node ids cannot be calculated deterministically but must be generated and specified in the command beforehand.
This was @bwaidelich idea as he saw me fooling around with pre-filing them randomly - you dont need to prefil random ids if you can determine them.
The logic was copied from Neos 8.3's
Neos\ContentRepository\Utility::buildAutoCreatedChildNodeIdentifier
neos-development-collection/Neos.ContentRepository/Classes/Utility.php
Lines 76 to 91 in f90d29f
Related: #4343
Related: #4375