Drupal 8 has two ways of dispatching events: using hooks and through Symfony's event dispatcher, which Drupal exposes as a service. As events do not have many of the drawbacks of hooks (implementations cannot collide and they are extensible due to OOP), I propose we research the possibility of building upon them to automate some of the event workflow.

A few ideas I have:

  1. Make Rules events extend Symfony events. Using PHP interfaces and traits developers can easily add Rules functionality to custom events.
  2. We can use hooks or YAML to let developers expose those event classes to Rules. Annotated class discovery is not always possible, because developers may want to expose events that are plugins for more modules than just Rules, so the class name must be set dynamically.

Comments

xano’s picture

I don't think it's technically possible to make Rules listen to any event, simply because event listeners have to register the specific events they are supposed to respond to.

However, as every dispatched event must have a machine name, we can expose events using that identifier using a discovery mechanism that is custom to Rules.

fago’s picture

By the way: shouldn't the Drupal 8 branch of Rules be named 8.x-3.x instead of 8.x-1.x? Version 2 was for Drupal 7, and seeing as the version for Drupal 8 will have a completely different API, we might want to increase the major version number instead of lowering it.

Agreed, I think it will be 2.x or 3.x depending on how well it matches the 7.x-2.x branch.

The idea of symfony events is awesome if people are using symfony events anyway, but it looks like symfony events will be nothing average d8 module developers will use so far. Thus, wouldn't basing rules events on symfony events create a big DX burden on devs?

xano’s picture

The only thing developers need to worry about is dispatching events, which requires the event dispatcher instead of the module handler, and an Event object rather than an undocumented array structure for parameters.

In Drupal 7, Rules events had to be invoked using some custom code already. Converting this to event dispatching introduces more flexibility and may convince developers to convert their existing hooks to events as well.

jpstrikesback’s picture

Not having read up on symfony events I may be polluting the conversation...but...if rules events are (ported to) symfony event dispatchers would we then have symfony events that any other event listener could piggyback on? That might sell the DX?

jpstrikesback’s picture

In the event (haha) that some module is using symfony events that we want to utilize would one just add a listener?

xano’s picture

In the event (haha) that some module is using symfony events that we want to utilize would one just add a listener?

Yes, but we need to know which events to respond to in order to execute the conditions and actions that have been configured through the UI. We can use Symfony's event infrastructure, to which we'll need to add a small layer to expose the events to Rules.

jpstrikesback’s picture

From Symfony docs

Events¶
When an event is dispatched, it's identified by a unique name (e.g. kernel.response), which any number of listeners might be listening to. An Event instance is also created and passed to all of the listeners. As you'll see later, the Event object itself often contains data about the event being dispatched.

Does that mean the Rules layer could register a catch all listener and act as necessary? Not to get ahead of the topic here or anything, just wondering if that is what you had in mind?

xano’s picture

Catch all is not possible. Take a look at \Symfony\Component\EventDispatcher\EventDispatcherInterface and \Symfony\Component\EventDispatcher\EventDispatcher. You are required to register a listener for every event you want to listen to. This should not be a problem for Rules, as we'll need to expose events anyway to let people create rules for them. We can write an event subscriber that just loads all rules, checks the events they are for, and adds the same listener for all these events. The listener (a method on the event subscriber class) can then load all rules for the dispatched event and execute them. All this should not require any extra code.

What does require extra code is the exposure of event context to the conditions and actions associated with a rule. We may need to introduce a \Drupal\rules\RulesEventInterface that specifies methods to access contexts stored in an event, so Rules can pass them on to the rule for execution.

klonos’s picture

This is a follow-up of #1211396: [META] Getting started with Rules 8.x so adding this to the issue metadata.

Also moved the OT idea from the issue summary to its own dedicated issue: #2173645: Rules: Bump 8.x version to 3.x

dasjo’s picture

Issue tags: +d8rules
dasjo’s picture

xano’s picture

For what it's worth to other contrib developers: I made a module-specific wrapper around event handling in order to be able to add Rules events after my modules have become stable. See #2371003: Prepare for dispatching Rules events.

klausi’s picture

My current plan is to support *.rules.events.yml files where the Rules event metadata is defined. We don't need annotations since there is no logic and no execution in Rules events, they just define metadata.

Work in progress pull request: https://github.com/fago/rules/pull/194

klausi’s picture

I'm also thinking about integrating Symfony events here. Goal: the implementing module should not have a module dependency to Rules, only the *.rules_events.yml file is required to make the Symfony event of the module known to Rules.

Symfony's event dispatching component has a GenericEvent class. It has methods such as getArgument() and hasArgument() for a list of arbitrary arguments on the event. My plan is to call getArgument() for each context definition name we know from the *.rules_events.yml file. The only problem is that GenericEvent also has a getSubject() method (the "main" context of the event), but I guess we will figure out some convention (like the event subject goes into the first context of the Rules event).

That way a module can implement and fire standard Symfony events and can optionally specify a *.rules_events.yml file to integrate with Rules. No module dependency at all, awesome!!!!!

I'm currently implementing a GenericEventSubscriber in Rules that should return all the active events that are configured in a reaction rule. The problem is that the method getSubscribedEvents() has to be static; and I'm not sure if we can do dynamic stuff in there like loading config entities (reaction rules with an event configured). Maybe we need a compiler pass to do that? I guess as first step I will just use \Drupal::entityManager()->getStorage($entity_type)->load($id); in there and see where it blows up ;-)

dasjo’s picture

Adding related core issue #2443763: Expose events as plugins

klausi’s picture

Status: Active » Needs review

The pull request at https://github.com/fago/rules/pull/194 is no ready for review!

I solved the registration of events that Rules wants to listen to with the state service; whenever a reaction rule is saved the registered events get updated in the state service and on the next container rebuild the Rules event subscriber gets written to the compiled container on disk.

I'm not sure if we should trigger container rebuilds every time a reaction rule is saved automatically, so I left that out in ReactionRuleStorage.

  • klausi committed 1525f73 on 8.x-3.x
    Issue #2145343: Added basic Rules event system and reaction rule concept
    
klausi’s picture

Version: 8.x-1.x-dev » 8.x-3.x-dev
Status: Needs review » Active

OK, committed this, good enough as working prototype that we can build on.

I want to add some documentation to http://thefubhy.gitbooks.io/rules/ about events before I mark this issue as fixed, so leaving open for now. Event system refinement and improvements should handled in new issues then.

fago’s picture

awesome to see that! I commented at the PR

klausi’s picture

Status: Active » Needs review

Took that comments and created a new event improvements PR: https://github.com/fago/rules/pull/200

  • klausi committed 27b08c7 on 8.x-3.x
    Issue #2145343: Event handling improvements
    
klausi’s picture

Status: Needs review » Fixed

Committed the improvements and wrote the docs: thefubhy.gitbooks.io/rules/content/extending_rules/events.html

Status: Fixed » Closed (fixed)

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