In GenericEventSubscriber::onRulesEvent()
we have the following @todo:
// @todo Add support for the getter method.
// @see https://www.drupal.org/project/rules/issues/2762517
Currently, Rules can make use any type of Symfony Event, provided that event has public visibility properties. Defining metadata in a MODULE.rules.events.yml exposes these events to Rules and declares the event properties that Rules may access as context variables.
Rules can also use Symfony Events with no properties (e.g. KernelEvents::REQUEST), or use events that have protected/private properties as long as Rules does not need to add those protected/private properties as context variables.
Rules can also make use of Symfony GenericEvents using the methods on GenericEvent intended for accessing properties.
What Rules cannot do currently is to use Symfony Events where the properties are protected or private and need to be accessed as context variables.
The work in this issue before comment #13 attempted to extend the current Rules capability, and make it so Rules could access some protected and private properties - the approach taken was to search for getter methods for these protected/private properties, and to use these methods (if found) to access the protected/private properties. The problem with this approach is that it relies on naming conventions to locate the getters. So for example if the event had a property name 'element', the code would look for a 'getElement' method to access that property. While this will work in some cases, when code follows the "expected" naming conventions, it won't work in all other cases (e.g. when a property is snake_cased and the getter is camelCased). And while this is better than nothing, it is not a general solution and will only marginally improve the current situation.
The proposal in #13, and the patches in the comments since then, take a more general and useful approach. This new approach allows Rules to access any property with any visibility in any Event, AND allows for modules to override the Rules default. The way this works is to let the getter method be declared explicitly in the metadata MODULE.rules.events.yml, if desired. Because the getter method may be (but does not need to be) defined in the metadata, this getter method may be added or altered by any module, by implementing the existing hook_rules_event_info_alter()
hook. Likewise, if no getter method is specified, Rules will still be able to access any public/protected/private property on the event as long as the context variable name in the metadata matches the property name declared in the Event class.
This means, with the current patch (currently in #24), Rules will be able to use ANY event dispatched by Symfony, Drupal core, or any Drupal contributed module. This opens up a whole new level of Rules integration that wasn't previously available. For example, the core Migrate module defines 11 different events that were not usable by Rules because their properties have protected visibility. But with this patch, all these events are now completely usable (and useful!) - all that needs to be done is to write a few lines of metadata in a MODULE.rules.events.yml to expose them for use by Rules.
Comment | File | Size | Author |
---|---|---|---|
#24 | 2762517-24-getters.patch | 22.32 KB | TR |
Comments
Comment #2
asgorobets CreditAttribution: asgorobets at FFW commentedComment #3
daria.a CreditAttribution: daria.a commentedI had the same problem. This patch solved it.
Comment #4
daria.a CreditAttribution: daria.a commentedComment #5
dragos-dumi CreditAttribution: dragos-dumi as a volunteer commentedHi,
The patch worked for me but with a small modification. The getter method it's not called as a method, but as property. Shouldn't be like in the interdiff attached?
Comment #7
asgorobets CreditAttribution: asgorobets at FFW commentedYou are correct dragos.dumitrescu! Thanks for pointing this out, not sure how I missed it. I'll update the patch
Comment #8
asgorobets CreditAttribution: asgorobets at FFW commentedAttaching the updated patch
Comment #9
asgorobets CreditAttribution: asgorobets at FFW commentedAttaching the updated patch
Comment #10
asgorobets CreditAttribution: asgorobets at FFW commentedThis time actually attach the patch
Comment #11
fagoThanks, the patch looks good. A remark though:
I do not think we should do magic conversion of the context name for variables. Either it fits, or you have to use the method.
Comment #12
TommyChrisI created a less complex patch.
Comment #13
dbiscalchin CreditAttribution: dbiscalchin commentedHi,
My suggestion is to allow a "getter" property to be provided in the YAML like so:
We could still check if a method with the standard name exists when this property is missing, but I think explicitly providing the method makes it much more flexible - one wouldn't have to wrap a third-party event just because it did not follow naming conventions.
It also has the advantage of decoupling the name exposed to data selection ("user" in this example) from the Event's class implementation (the method name). This would be useful in cases the getter has a generic name like "getEntity" as in the example below:
Comment #14
TR CreditAttribution: TR commented@dbiscalchin: I think that sounds like a good idea. IMO it has advantages over what has been proposed earlier in this thread, and like you said it affords much more flexibility in how event classes work. Additionally, because the means of accessing a context variable would be part of the plugin definition, it could be altered using the plugin manager's hook_rules_event_alter().
Can you create a patch to do this?
I think this is very important for integration with contributed modules, where event properties tend to be protected so we currently can't just add the .yml and make use of those events.
Comment #15
TR CreditAttribution: TR commentedThis patch implements the idea from #13.
Additionally, this patch allows access to Event properties when those properties are declared as protected or private - this has always been a problem that prevented Rules from making use of Events defined by other modules, because most Event objects don't use public visibility for their properties.
And of course, tests are included to ensure this works.
Event properties are accessed as follows:
This should finally allow us to use any third-party event directly from Rules, simply by adding the necessary metadata into a MODULE.rules.events.yml file.
Comment #17
TR CreditAttribution: TR commentedRemove commented out code and clean up coding standards.
Comment #19
TR CreditAttribution: TR commentedSome more coding standards, fix plugin discovery in Unit tests (hopefully).
Comment #20
TR CreditAttribution: TR commentedComment #21
TR CreditAttribution: TR commentedComment #22
TR CreditAttribution: TR commentedAdded a bunch of comments.
Also re-wrote the issue summary.
Comment #23
TR CreditAttribution: TR commentedComment #24
TR CreditAttribution: TR commentedThe patch in #22 adds to the 8 branch failures in the D10 tests (see #3259445: Symfony\Component\EventDispatcher\Event is deprecated in drupal:9.1.0 for the cause of these branch failures). Let's try to avoid making the situation worse.
Because this is just a test, we can afford to remove the explicit Event type hint in order to make the code run in both D9 and D10.
Note: This patch contains a test module named 'rules_test_event', which it primarily intended for use in test cases. But you may also enable this test module using drush if you first add the line
$settings['extension_discovery_scan_tests'] = TRUE;
somewhere in your settings.php. Once you enable this module, you will have access to some test events (in the 'Tests' category) and you may use these test events to trigger any Rules you like. There is also a test page defined at/dispatch-form
that allows you to manually dispatch these test events from the browser. This is very useful for manual testing!Comment #25
TR CreditAttribution: TR commented#24 fixes the two D10 failures caused by the code in this patch. It does not fix two failures that come from the same problem as in #3259445: Symfony\Component\EventDispatcher\Event is deprecated in drupal:9.1.0 - those can't be avoided in this patch.
In summary, I think #24 is ready to commit (the two coding standards warnings will be fixed on commit, to keep from cluttering this issue with yet another patch).
Comment #26
TR CreditAttribution: TR commentedComment #28
TR CreditAttribution: TR commentedCommitted #24. This patch adds new capability without changing the existing capability, so I don't have any BC concerns. There are plenty of new tests added to ensure the new capability works properly.