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

BUGFIX: Have FlowQuery operations reliably detect nodes during canEvaluate #3946

Closed
wants to merge 16 commits into from

Conversation

mhsdesign
Copy link
Member

Original PR: #3723

Rebase for 5.3 #3838 (to be closed)

Rebase for 7.3 (this PR)

Fixes: #3624

When a collection of nodes is referenced some items may become invisible over time or may be deleted. In this case the references may end up with an array that has no key 0. Since this key was used to check wether a flowQuery operation can be applied this could lead to errors.

The change adjusts the detection by looking at using reset to get the first value if the context is an array and by using an foreach that returns in the first cycle for traversables.

Review Instructions

To test this you can use the contentReferences Element in Neos.Demo.

Create 3 contents
Create a reference element that references all three
Hide the content that is selected first
Apply @process.filterContent( q(value).filter('[instanceof Neos.Neos:Content]').get()) to that.

Without the change in live context no content is shown because the first item is not available live. This change allows to still proceed with the remaining nodes.

@mhsdesign
Copy link
Member Author

Fixed conflict with 928cc4a

Copy link
Member Author

@mhsdesign mhsdesign left a comment

Choose a reason for hiding this comment

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

I added pending review comments from #3723

Sadly - i cannot reopen the original pr and force push - as we deleted the master branch so the github ui doesnt offer to reopen (until we would readd the master branch ...)

foreach ($context as $item) {
return $item instanceof NodeInterface;
}
return true;
Copy link
Member Author

@mhsdesign mhsdesign Nov 2, 2022

Choose a reason for hiding this comment

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

https://github.com/neos/neos-development-collection/pull/3723/files#r920521176

i dont think we need this line.
it would be for the case that $context has no iterations, and in this case why should it pass?

Copy link
Member

Choose a reason for hiding this comment

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

Because an empty context can be evaluated.

foreach ($context as $contextNode) {
if (!$contextNode instanceof NodeInterface) {
return false;
if (is_iterable($context)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

@patricekaufmann
Copy link

I actually just ran into #3624 again, spent some time debugging to eventually figure out I already did that 1 year ago :D

What is the general progress on this PR? It would be super nice to fix those edge case errors that confuse editors.

return count($context) > 0 ? reset($context) instanceof NodeInterface : true;
} elseif ($context instanceof \Traversable) {
foreach ($context as $item) {
return $item instanceof NodeInterface;
Copy link
Member

Choose a reason for hiding this comment

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

This would return true if the first array item is a node, but the second is not.

Copy link
Member Author

Choose a reason for hiding this comment

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

yes but this was done previously like this as well. Its just super simple duck-typing to speed up performance ...

Copy link
Member

@Sebobo Sebobo Jun 28, 2023

Choose a reason for hiding this comment

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

Then please adjust the docblock above to describe the reasoning etc.

@mhsdesign
Copy link
Member Author

elseif ($context instanceof \Traversable) {
            foreach ($context as $item) {

i dislike having a side effect in the method canEvaluate. Imo it should be pure and not change the pointer of a traversable.

foreach will call rewind and next and current on the traversable and thus modifies the state. Maybe current($traversable); does as-well?

@mficzel
Copy link
Member

mficzel commented Jun 28, 2023

That is quite expensive to check the whole context array but given the current architecture it would be the only thing to do. Not sure it is wise to add this to the 8.3 branch.

If done for Neos 9 we could use the Nodes or References objects into the flowQuery context that are already iterable. That way we would only have to check with a single instanceof Nodes. This would still require changes to flowQuery in 9.0 but especially to the q() function that would have to create a Nodes object but for 9.0 there is. a chance to do this right.

@patricekaufmann
Copy link

i dislike having a side effect in the method canEvaluate. Imo it should be pure and not change the pointer of a traversable.

foreach will call rewind and next and current on the traversable and thus modifies the state. Maybe current($traversable); does as-well?

The pointer might point to other elements. However the first element should be checked to avoid changing what the function actually does. Getting the first element without resetting the pointer would actually be the first proposed solution in #3624 with array_key_first.

@mhsdesign
Copy link
Member Author

Ill close this pr for now. See #3624 (comment)

@mhsdesign mhsdesign closed this Nov 12, 2023
mhsdesign added a commit to mhsdesign/neos-development-collection that referenced this pull request Nov 12, 2023
…eferences

EEL can only operate on an array of nodes if the `[0]` item is a node (simple duck typing)

Instead of fixing eel like proposed here neos#3946 with this fix we avoid returning non 0 indexed arrays here:

```
${q(node).property("someReference")}
```

Currently, this might indeed return an array with holes like `[1 => NODE, 2 => NODE, 5 => NODE]` if the identifiers in fields 0, 3 and 4 are not resolvable.

Thats because of the "unsafe" `array_filter` method in `resolvePropertyReferences` https://github.com/neos/neos-development-collection/blob/378a029d0cc7ea6acb853751e7592873584a4aac/Neos.ContentRepository/Classes/Domain/Model/Node.php#L961 which will leave holes in the array.

Using `array_filter` was introduced with Neos 2.2 so this is technically a regression of neos@87804e1 ^^
neos-bot pushed a commit to neos/content-repository that referenced this pull request Jan 31, 2024
…ences

EEL can only operate on an array of nodes if the `[0]` item is a node (simple duck typing)

Instead of fixing eel like proposed here neos/neos-development-collection#3946 with this fix we avoid returning non 0 indexed arrays here:

```
${q(node).property("someReference")}
```

Currently, this might indeed return an array with holes like `[1 => NODE, 2 => NODE, 5 => NODE]` if the identifiers in fields 0, 3 and 4 are not resolvable.

Thats because of the "unsafe" `array_filter` method in `resolvePropertyReferences` https://github.com/neos/neos-development-collection/blob/8dc96a201dc9602d96c6d06b0c6090222cd5a198/Neos.ContentRepository/Classes/Domain/Model/Node.php#L961 which will leave holes in the array.

Using `array_filter` was introduced with Neos 2.2 so this is technically a regression of neos/neos-development-collection@da3f4df ^^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

FlowQuery operations: incompatible check on first array element in canEvaluate
7 participants