Problem/Motivation

Tests in #3255608: Tutorial, how to set values in entity reference field for the purpose of back reference are failing since we merged the loops from #3256217: Infinite loop when cross updating multiple entities, the reason is the context which wraps the plugin execution.

The underlying issue is that in the new context, we change the [entity] that we receive from the token environment. Before adding context support in action loops, [entity] always referred to the entity from the triggering event. But now, this changes, if an action is based on a different entity. Then, this other entity is in the current content, not the outer one any more.

We may want to keep context support in action loops, but we should keep the reference to the event entity. Maybe we need to define a new and enhanced convention for this, e.g. evententity and contextentity instead of just entity. And while thinking about this, we may also provide some syntax to access the entity from predecessors, e.g. contextentity:parent, and ideally with infinite nesting in mind.

Comments

jurgenhaas created an issue. See original summary.

mxh’s picture

From a logical point of view, the context logic is correct and thus I don't see this as a bug. One thing that might be confusing ATM though is that we implicitly assume "entity" to be the "main" entity, or let's say "entity" is currently assumed to be the current entity in scope. We have several options now:

  • For locally available Tokens in scope, use the action "Token: set value" and set the current entity as a custom specified Token name right after the event. You should be able to access that Token within the local scope of the ECA process flow (but not in any isolated child flow).
  • Use the action "Define a new context" (Plugin ID "eca_new_context") and define the ("source"?) entity that you want to keep for accessing later on with a custom specified context ID. The Token service can already access that context value by using the same value of context ID as Token name, thus you don't need to extra specify the Token name using "Token: set value" for example. This context value should then also be accessible within any child process flow, but not in any other process flow that is completely decoupled from the current flow in scope.
  • For some cases, it might be already sufficient to just use the Token value of the parent entity from the context stack by using the parent Token [parent:eca:entity:*] or use the root entity by using the Token [root:eca:entity:*].
mxh’s picture

Before adding context support in action loops, [entity] always referred to the entity from the triggering event.

Just for clarification: Before adding the context, the behavior was also already different. It was first asking the plugin whether it's using a certain Token and then received the Token value from the Token service. If that was not there, it looked into its plugin ID whether that gave a hint to the used entity type. If that wasn't successful either, it asked any predecessor (beginning at the closest one) until it got one. And if that failed also, it was finally asking the triggering event whether it had an entity.

The main difference is now that the Token service is aware of the context stacks, and asks them for a value in case it has no value on its own.

mxh’s picture

Maybe we need to define a new and enhanced convention for this, e.g. evententity and contextentity instead of just entity

While we could additionally add the event-related entity into the context stack by using a certain ID, I guess it's hard to find out that the entity is actually available under those names/IDs. If we want to specify additional context, it might make sense to have some sort of documentation in any way for it. But maybe one of the suggested approaches in #2 may be already fine enough.

jurgenhaas’s picture

StatusFileSize
new5.47 KB
new43.67 KB
new46.18 KB

Let me talk with pictures. Hopefully that makes it more transparent. The following image shows a condition and an action:

Both are operating on the same data: the id of the current entity and the id of a referenced entity. Both config forms are using the same config values:

The condition plugin config

The action plugin config


Problem being, the action operates within a different context than the condition and hence produces results that a user would not expect. And even worse: the access check of the plugin also works in a different context from the execute method, which can also produce different results: any access check outside the context could be true, but would be false inside the action context.

What I'm saying is 2 things:

  • We broke existing functionality by introducing context stack for action plugin executions. This is not a logical error but we had the convention, that the token alias entity always refers to the triggering event.
  • Yes, it's still time to change the convention. But we should avoid leaving it to the modeller (the user who builds the model) to carefully deal with contexts. Instead, we should bring back a reliable syntax for entity token aliases, that now keep context in mind as well.

From your 3 options above, the third one sounds like being close. Is that a proposal for implementation, or would that already work now?

jurgenhaas’s picture

Issue summary: View changes

Looks like we were cross posting ;-)

Just for clarification: Before adding the context, the behavior was also already different. It was first asking the plugin whether it's using a certain Token and then received the Token value from the Token service. If that was not there, it looked into its plugin ID whether that gave a hint to the used entity type. If that wasn't successful either, it asked any predecessor (beginning at the closest one) until it got one. And if that failed also, it was finally asking the triggering event whether it had an entity.

That was then an additional change introduced earlier. Originally, entity was a reserved token alias. But it was too vague, so it's good we run into this issue now, so that we can solve it properly.

jurgenhaas’s picture

Issue summary: View changes

[parent:eca:entity:*] or use the root entity by using the Token [root:eca:entity:*].

The more I think about it, the more I like it. Not sure if then even something like [parent:parent:eca:entity:*] and the likes would work?

mxh’s picture

This is not a logical error but we had the convention, that the token alias entity always refers to the triggering event.

I didn't know about that yet. But we can define such a convention from now on and rely on that. We could manifest that convention in form of an automated (Kernel)Test, so that we can make sure future additions won't break it.

That was then an additional change introduced earlier. Originally, entity was a reserved token alias. But it was too vague, so it's good we run into this issue now, so that we can solve it properly.

Yes, the changes were introduced incrementally, context being the last addition to that whole logic. And I'd still say the way "entity" is being defined is too vague, thus we could make this an explicit convention by writing it down as an automated test.

From your 3 options above, the third one sounds like being close. Is that a proposal for implementation, or would that already work now?

That works but currently only if it was added to the context stack using either the according correct entity type ID or token type. I can see whether I can add another current context that just uses "entity" as context ID.

mxh’s picture

I've tagged a new release (1.0.0-alpha4) of Context Stack, which now supports the current generic "entity" as a Token. You could try it out whether replacing [entity:nid] with [root:eca:entity:nid] works on your example config.

The more I think about it, the more I like it. Not sure if then even something like [parent:parent:eca:entity:*] and the likes would work?

Currently nested parenting is not supported within Token replacement, and I currently doubt if that is commonly needed. I was identifying for most cases, either root or the direct parent ancestor (and of course the current one itself) would be used. In case we have a concrete use case example, we may think about an approach for it. Setting a dynamic number would be possible, for example [parent:2:eca:entity:nid] could mean to go two levels up. But as said, I'd only like to do the implementing work once we really have a concrete case for it. Another counter-argument would be that in such a situation, the user would need to take special care for correct context anyway, because the higher level you go up, the more likely is it that things change unexpectedly. Thus it's more advisable to set a custom Token or context as suggested above.

jurgenhaas’s picture

Status: Active » Fixed

First thing in 2022: testing this new feature in context_stack, and it works as expected. Great stuff, thank you so much.

Currently nested parenting is not supported within Token replacement, and I currently doubt if that is commonly needed.

Agreed!

Happy New Year!


Oh, and the kernel test for this is included in #3255608: Tutorial, how to set values in entity reference field for the purpose of back reference, waiting for a review.

mxh’s picture

That's great, happy new year! Will review that one as soon as I can.

mxh’s picture

Oh, and the kernel test for this is included in #3255608: Tutorial, how to set values in entity reference field for the purpose of back reference, waiting for a review.

Took a first look into that, but it does only "implicitly" cover the convention we want to manifest. Instead it covers a use case example for setting a (back-)reference. I recommend to write a single KernelTest method that solely covers the convention when and how the "entity" Token should be defined along the way. This makes it easier to understand and validate the convention in the future. Shall we cover that within its own issue?

jurgenhaas’s picture

Shall we cover that within its own issue?

Sounds good.

mxh’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.