-
Notifications
You must be signed in to change notification settings - Fork 61
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
getVersionByLabel() is not correct when called in the same request as addVersionLabel() #348
Comments
thanks for the detailed analysis! hm, this is indeed not good. i think we must not remove the node cache from the ObjectManager, as there might still be references to that node. rather, we should update the node internal state. i did not try it out, but i think we should update the state in the node. there is the Property::_setValue method to change a property from within the implementation that does not do any checks. ah, but the label is adding a new property. there is Node::_setProperty but that one is protected. i haven't touched any of this in ages. do you see a way where we could internally set that? is the labels node a regular node or a special class like |
Thanks for the guidance. This bit of code added to the bottom of addVersionLabel takes care of updating any existing labels to their new version and works:
Since the _setValue just updates the new internal state. However, as you said, if it's a new label, then _setProperty is protected, and thus not accessible. Calling $node->setProperty() seems to work as far as updating the internal state correctly, but errors with a 409 "HTTP 409: Unable to perform operation. Node is protected." as soon as you flush. So I do think the only way to fix this would be expose a method on the Node that just updates the internal state, as you suggested. Though I think the code snippet above could be added and would not damage anything, and would cover the case of moving labels, making a niche issue even more niche. |
but your snippet only works if the label already exists, right? i think if we fix this, we better fix it completely. i wonder if we should add a separate method like |
Sorry for the delay. Yes, my snippet only works for the one case, so I understand not wanting to incorporate it. I'm afraid that what needs to be done is beyond my limits given the time I have to work on it. I appreciate the time you have spent helping me so far. |
If you follow this sequence, you do not get the correct Version. Instead, you get the previous version that held the label:
addVersionLabel
checkin (or by calling notifyHistoryChanged directly)
getVersionByLabel
Performing acts in that sequence will get you the Version that had the label before you moved it. The reason is due to the ObjectManager's in memory caching of the jcr:versionLabels node.
addVersionLabels updates its PHP internal property for where the label is, here: https://github.com/jackalope/jackalope/blob/master/src/Jackalope/Version/VersionHistory.php#L197
At this point, if you call getVersionByLabel, everything is fine. However, if within the same HTTP request, you perform a checkin or otherwise call notifyHistoryChanged, then that PHP internal property for versionLabels is emptied: https://github.com/jackalope/jackalope/blob/master/src/Jackalope/Version/VersionHistory.php#L319
Now the next time you call getVersionByLabel, it needs to now call initVersionLabels again, since the Version state was cleared via notifyHistoryChanged.
The problem is then here, when VersionHistory calls getNode: https://github.com/jackalope/jackalope/blob/master/src/Jackalope/Version/VersionHistory.php#L279
That calls Node:;getNode, which calls ObjectManager's getNodeByPath: https://github.com/jackalope/jackalope/blob/master/src/Jackalope/Node.php#L666
And at this point, the Node in question has already been fetched once, so it's in memory, and thus returned without fetching it fresh: https://github.com/jackalope/jackalope/blob/master/src/Jackalope/ObjectManager.php#L205
The in memory node returned here contains where the label was prior to moving it.
I believe I have found a bug, but I'm not sure of any solutions.
Possible ideas:
$node = $this->getNode('jcr:versionLabels'); $node->setProperty($label, $version);
However, the property is protected, and thus errors, when setProperty is called.
As a work around for me, I am calling clear on the ObjectManager after a checkin, which resets the in memory map of ObjectManager so that the Version history node is fetched fresh next time.
But clear is deprecated, so I don't believe this is a durable workaround.
The text was updated successfully, but these errors were encountered: