Rules action could be modifying the triggering event's context.
Unless I am mistaken, we have no way of doing this currently. It would be great to be able to do so, so we could use Rules as "hook_alter" functionnality.
1 example: I am sending some data (in my case, an array of "strategies") via an event, and subscribers can modify the order of those strategies (or event theoretically add or remove some) so that strategy #1 is applied if we meet condition A, and strategy #2 is applied if we meet condition B. But this is temporary and should not be saved as it's done uniquely in the context of that specific request.
| Comment | File | Size | Author |
|---|---|---|---|
| #9 | rules-updating_event_context-3141206-9.patch | 4.54 KB | vdsh |
| #9 | rules-test_only-3141206.patch | 3.51 KB | vdsh |
Comments
Comment #2
vdsh commentedComment #3
vdsh commentedHere is a patch that is mirroring what is done when the rule is initializing and getting all the data from the event.
I haven't added a test yet, I first want to have a feedback on the request / proposed solution. What do you think?
Comment #4
tr commentedMaybe something like this, to add a way to alter events? #2984501: Alter hooks available
Comment #5
vdsh commentedHi TR, thanks for your quick reply.
I checked the link from your comment, and I think it's similar to what I am currently doing:
So that event subscribers can alter the $event->strategies variable (which is an event context variable). My issue is that it doesn't seem that RulesAction can modify those directly. Is there any way to access the triggering event from a RulesAction?
And what do you think overall of this patch which update the event context variable after the rules execution? That way, I can use in my RulesAction eg
and it is properly picked up when I do
$strategies = $event->getStrategies();Comment #6
tr commentedThe data provided by the event becomes part of the Rules context, available to all conditions and actions. But Rules needs to deal with Typed Data - that is the only way Rules can introspect the data to find out its type and content and to be able to manipulate it programmatically. This is why Rules can automatically use any Entity type. So instead of using an array of data you should be using a typed data object, maybe a map data type.
I have never tried to modify a Drupal event object, so I don't know whether that modification will propagate to other users of the event, but even if it does Rules may not allow modification directly because that's a sure way to cause problems in a complex system like Rules. But I think there is a function like setContextDefinition() that allows you to explicitly add to or modify the context used by Rules - you might have to do something like that to allow the changes to your event to be available. Or you can take a different approach of adding the strategy to the context so that it is available to other conditions/actions. Perhaps a "save" action at the end of your Rule to write back the value of strategy. Another way to go about this, since it sounds like you don't want to do everything in Rules, is to simply use the Rules conditions (or components) programmatically within your own event subscribers. So you wouldn't be setting up reaction rules, you would simply be calling the conditions and using the results.
Anyway, I'm sure you can do what you want, and maybe Rules is useful for this (or maybe completely custom code is easier) but I don't really have time to look into this myself.
Comment #7
vdsh commentedHi TR,
And thanks again for answering so fast. You are right I am sending a "list" conditions as context (so a TypedData)
But I don't want to modify an entity object (just a list of string), and I don't want to persist the result of the rule (so I cannot use 'Save')
Let me try to explain a bit better what I am doing (I feel that giving more explanations could help you see what I am trying to achieve):
- I am developping a module Libraries Delay Load where administrators can define various 'strategies' of delaying some javascripts load to improve performance
- On each page, this module finds out which strategy best applies. Basically, the first strategy from the list is the one applied.
When the delay load module executes, it loads the ordered list of strategies (just an array of machine names, not the configuration entity collection) and triggers a Drupal event with this strategies list as event context so that other modules can alter this list (remove a strategy if not applicable on that page /put 1 strategy first so that it's the one applied / ...).
I don't want to save / persist the result as on another page (or the same but with different conditions, eg a different user), the strategy to use can be a different one. So I want the rules to be evaluated every time with the same default set of strategies and return to the event an updated version of the strategies list.
- Then, retrieving the updated list for this page list is done by doing
$strategies = $event->getStrategies();after the event has been triggered which is retrieving the (maybe modified) list of strategies from the event's context.From what I understood from looking into the Rules engine, it is reading the Drupal event's context, but never updating it: it's creating its own rules context which can then be evaluated/modified through actions but changes are never propagated back to the Drupal event's context.
So in my RulesAction, I already have the 'strategies' context provided by the Rules Event. I am updating the strategies list doing eg:
This strategies list is available for further rules actions - but after the event executes, doing
$strategies = $event->getStrategies();in my module, I can see that the list hasn't been updated (this is because the rules' context hasn't been propagated back to the triggering Drupal event)This is what I am fixing with the patch attached in #3. Which is working great for what I am trying to achieve.
But as I am quite new to Rules, I want to make sure that what I am explaining here makes sense, that I didn't miss an important concept, and that sending the (possibly updated) event's context back to the Drupal event is a desirable behavior for Rules.
PS I would like to avoid using Rules Components to avoid having a hard dependancy to the Rules modules (users can either implement the event subscriber or use Rules or even do nothing if they only want 1 global strategy that will always be applied)
Comment #8
vdsh commentedFor additional information, this is my event in module.events.yml:
And let's imagine I have a RulesAction to pick a strategy at random. RulesAction definition:
This is working well (with the patch attached in #3. I properly have my strategies randomized.
Comment #9
vdsh commentedI thought about this a bit more and I think this is the best way to go.
Attached a test case only, which should fail - and then the patch with the test case - which should pass.
Comment #10
vdsh commentedResults are as expected, please review :)
Comment #11
tr commented