Update
For the latest work on this issue skip to comment #71. This uses a new approach aligned with potential core enhancements in #2329937: Allow definition objects to provide options. Patches 78+ here therefore also need core patch #61 https://www.drupal.org/files/issues/2020-07-24/2329937-61-options-provid... to be applied to your core code.
Original issue summary
In Rules 7.x, certain conditions and actions (such as "Show a message on the site") use select lists to allow a user to choose a value for a particular parameter/context (such as the type of message shown), and third-party modules can define the options for select lists using callback functions. It would be nice to have this functionality in 8.x as well.
I have uploaded a patch that implements this functionality (with "Show a message on the site") as an example. It certainly needs work, but hopefully it can be a starting point for something.
| Comment | File | Size | Author |
|---|---|---|---|
| #118 | 2664280-118.select-lists.patch | 7.43 KB | nwom |
Comments
Comment #2
shabana.navas commentedThis feature should definitely be a part of Rules asap because the UI is just absolutely confusing without it. I have taken the initial patch and did some further work on it and added the select options to most of the Rules actions and conditions that seemed in dire need of it like:
Comment #4
maaty388 commentedHi,
I was searching for this patch but it still needs work I see some warning and I hope you can fix them soon. What about if I have multiple context fields lets say I have a drop-down of node_types and next context fields I need to get somehow value which node was selected so I can display node fields of this node...
Comment #5
jonathan1055 commentedThis is very useful. Good work @Amerie for starting this and @shabana.navas for extending it. Some of those test failures are unrelated, and I will try to work out what is happening with the others. I will also make a Github branch for this.
Comment #6
jonathan1055 commentedGood changes, @shabana.navas, I can see you fixed the missing quotes line 83 of ContextFormTrait.php which had caused
Exception: Notice: Use of undefined constant list_options - assumed 'list_options', Drupal\rules\Form\Expression\ActionForm->buildContextForm()(). Also good that you cleaned up whitespace and tidied-up some coding standards.Looking at the test failures in #2 I have made the following fixes:
ServiceNotFoundException: You have requested a non-existent service "logger.factory"This was caused by leaving old debug in the patch in EntityIsOfBundle:
This is resolved by defining the functions as
public staticinstead of justpublicI think this is unrelated, that got into the patch by accident? I recognise it from a separate issue, so have removed it from here
There are some more things to do, for coding standards and also for structure in ContextFormTrait, but here is a patch which addresses the items above. I will follow up when the tests are passing, as it is always good to get that target fixed first.
Jonathan
Comment #7
jonathan1055 commentedAll the tests pass, that's nice. In this patch I have also fixed the coding standards faults (our codebase is completely clean at the moment, and we want to keep it like that). The three reported coding standards fixes are:
userRolesListOptions()in UserHasRole.php$entity_typefromfieldListOptions()in EntityHasField.phpOther fixes for readabilty and clarity:
$listOptionsCallbackholds the optional function name, so should be a string with default valueNULLConstdefinitions in the Drupal coding standard. These two are covered by the single comment so it is better to have them together without a blank between.setListOptionsCallback()is the function name so calling it $options is confusing as it sounds like it contains the list options. I have changed it to$name. Also referred to UI not GUI in the comments.messageTypeListOptions()put the types in ascending order or severity: info, status, warning, errorThe Travis build which matches this patch is https://travis-ci.org/jonathan1055/rules/builds/290551706
Comment #8
jonathan1055 commentedWhile making these changes and adding more selection lists, I realised that the UI for adding conditions and actions is only very minimally covered by our automated testing. Only one condition (
rules_data_comparison) and one action (rules_system_message) are used in the existing UI functional tests. Hence I have added new tests to check adding all of the actions and conditions. The work is not finished, but here is a start. This patch is exactly the same as #7 apart from the new tests. It will fail in a few places, which shows that the code changes that passed in patch #7 has faults not being discovered by our existing tests.Comment #9
jonathan1055 commentedAs expected the tests fail, showing that the original changes were not covered by tests before. The listOptions functions all need
public static. Here's a patch which should pass the new tests.Comment #10
jonathan1055 commentedThat's good, we now have test coverage for adding Conditions and Actions via UI.
This patch has several improvements:
src/Form/Expression/ContextFormTrait.phpwe need to cater for multiple selections within the options list, for example when checking a condition for user having multiple roles, or adding/removing multiple roles. This was already catered for when using plain text entry by switching to textarea. We need'#multiple' => $context_definition->isMultiple()in the array$form['context'][$context_name]['setting']. The coding can be simplified by re-organising, which also removes the need to check!empty($configuration['list_options']). The interdiff may look complex, but the actual change from the current committed code becomes more simple, and hence easier to understand. This structure also allows for better descriptions beneath the entry field or selection, more appropriate to the type of field.Comment #11
zenimagine commentedThank you #10 works for me
Comment #12
jonathan1055 commentedHere are the final changes I intend (apart for fixing any review points). I have added the action or condition id in brackets in the selction list text if it is different from label, as this helps to make it clear what is being selected. For example:

Comment #13
jonathan1055 commentedI've created a PR for this patch https://github.com/fago/rules/pull/496
My Travis build is https://travis-ci.org/jonathan1055/rules/builds/297494582
Comment #14
tr commentedThis is great functionality, which is essential for many of the Rule conditions and actions I'm trying to port from D7. I am testing it right now and evaluating the patch. I hope it's OK if I bump this to Major, because this is a D7 feature that just doesn't exist in D8 so it's a serious blocking issue for almost anyone porting conditions and actions.
The big problem I see is that the way this patch is written, the callback functions have to be static functions. That's a problem because I have many options lists which need to be dynamically defined, often through the use of a service injected into the condition or action. You can't really do this properly with a static function.
Indeed, if you look at the patch, many of the conditions and actions you are modifying to use this new feature need services to compute the list of options, and in all cases you're having to get those services through \Drupal::service() rather than injecting them into the condition or action class.
I would like to hear if there is a compelling reason to make these callbacks class methods instead of instance methods. I've made those changes locally and it works just fine as non-static methods.
One smaller point:
ContextDefinition::setListOptionsCallback() should return $this. That's standard practice for setters, so that function calls may be chained. Note that the two other setter functions in that class, ContextDefinition::setAssignmentRestriction() and ContextDefinition::setAllowNull(), both already return $this, it's just this one new function that doesn't. The doc comments for ContextDefinitionInterface::setListOptionsCallback() will also need to be modified with a @return $this.
Comment #15
jonathan1055 commentedHi TR,
This is great feedback, thanks very much. I am new'ish to OO design, so just picked up how the original patch creator did it. I'd be happy to take advice on using dynamic functions instead of static, so would you be able to post your code here? or a patch, or you can contact me via my profile page and we can share code directly. Or if you use github you can fork Rules and show us your alternative versions.
Thanks for the tip on returning $this - I will add that change in the next patch.
Jonathan
Comment #16
jonathan1055 commented@TR I've made the change to remove 'static' from all the list options callback functions, and simply replaced
$condition::$list_callback()with$condition->$list_callback(). Also returnedreturn $thisto etListOptionsCallback(). Here's the patch and interdiff.Comment #17
jonathan1055 commentedMinor omission in src/Context/ContextDefinition.php.
Comment #18
tr commentedI took #17 and injected the services into the list_options_callback functions rather than using \Drupal::service(). No other changes.
The only other thing I think I would do is to move the doEvaluate() methods to the end of each controller class - there is always a lot of almost boilerplate stuff at the top (doc comments, instance variables, constructors, static create functions, and now list option callbacks) that it's difficult to find the real functional code for these conditions unless it's always at the bottom of the file.
I didn't want to make that move in this patch because it would only confuse the interdiff.
Also, in your new test, you have a comment
That failure is because you have to enable the core "ban" module in the test (or interactively) in order for the service to be defined. Just stick that in public static $modules. I didn't make that modification.
Comment #19
tr commentedAlso, what's the deal with testing in this queue? It behaves oddly compared to all other issue queues - is the testbot not configured to test patches for 8.x-3.x ?
Do I have to start the test manually? I tried doing that with the trivial patch in #2922828: Spelling. but if failed miserably - "PHP 5.3 & MySQL 5.5, D8.5 Unable to start phantomjs"
Comment #20
tr commentedAlso, the UserHasRoles::doEvaluate() function does not work, as noted in #2816157: Simplify UserHasRole::doEvaluate(). But with the changes in this current issue, we're controlling the input to doEvaluate() by presenting a select widget with the user role selections enumerated as rid => role_name. The $roles array passed to UserHasRole::doEvaluate() will like:
array ( 0 => 'authenticated', 1 => 'administrator', )
Note that this is key => rid
Then doEvaluate() tries to use the rid (e.g. 'authenticated') as an object, and calls $role->id() on it. That's just wrong. This is a legacy from the D7 code. This is why it sounds like we need a full Role object here and that upcasting is the solution, but it isn't
doEvaluate() just has to check if the selected rids are in an the $account->getRoles() array - no Role object needed.
UserHasRole::doEvaluate() does NOT need the Role object, and there is no need to upcast here, and the failure in that other issue ("Call to a member function id() on a non-object") is a logic failure.
Try this very simple fix with no upcasting required, after applying #18. I'm posting this separately because I don't know if this should be fixed here or in #2816157: Simplify UserHasRole::doEvaluate() after #18 (or something like it) is committed.
Comment #21
tr commented#18 failed because I didn't change the tests when I injected the services into the conditions and the actions. The tests don't know about the new constructor parameters yet.
I'll work on fixing these tomorrow.
Comment #22
jonathan1055 commentedFrom #18
That makes sense. Do it in a separate step, so that interdiff is clear.
Thanks for the info and for raising #2922804: BanIP action causes PHP Exception. Maybe we can set that item to be disabled in the condition selection list if the module is not enabled. Then users can see it exists but cannot choose it.
From #19
Yeah, I noticed that patches are not automatically queued. This is a maintainer-controlled setting, and probably an oversight. But most testing is first done on Github and Travis, which I find very helpful, as you can test out all core versions and php versions before even submitting a patch here.
From #20
Thanks for this. We can continue the discussion on #2816157: Simplify UserHasRole::doEvaluate()
From #21
OK thanks. I will not make any more patch changes just yet, to allow you to make the test fixes.
Comment #23
tr commentedOK, took me longer than a day to get back to this ... Made some minor changes to #18 now the tests pass locally. Let's see what the testbot says.
Note, I've made extensive use of this patch over the past week - I've been porting dozens of D7 rules conditions and actions to D8, and almost every single one of them needed a list_options_callback. So for my use case, D8 Rules is unusable without this patch or something like it.
Comment #24
tr commentedBetter, now one more time...
Comment #25
jonathan1055 commentedThanks TR. this is really great. I have made just a couple of small changes to keep the 'use' statements in alphabetical order. I have also tested the 'Ban IP' test alongside your patch in #2922804-5: BanIP action causes PHP Exception and have made the changes to the test file and referenced that issue.
Comment #26
jonathan1055 commentedI have updated my github branch to cover all code changes to #25. The PR is still the same https://github.com/fago/rules/pull/496 but I have now squashed the commits into one for ease of compare and rebase. Setting this to RTBC just to see who shouts ;-)
Comment #27
fagoThanks for your work on this. This work has been blocked a long time due to https://www.drupal.org/node/2329937 being finished. The issue there remains a lot of valuable code though, which we could bring to the typed data module and leverage here. We need to evaluate possible ways forward here before move on with code - suggestions welcome!
Comment #28
jonathan1055 commentedOK. Adding #2329937: Allow definition objects to provide options as a related issue.
Comment #29
jonathan1055 commentedTo follow up the testing question in #19 I have raised #2927534: More automated test runs on drupal.org which is a simple job for the maintainer but very helpful for us all when done ;-)
Comment #30
fagook, I see those ways forward here:
a) Move allowed-options code to typed data module and work based upon that. Obviously that misses the metadata of core field definitions and the framework for getting that, but allows us to move on with custom options here at least.
b) Get the core issue done and require latest 8.5.x-dev of core for the feature to work. As we are in alpha state I think that would be do doable
Comment #31
fagoComment #32
fagoI must say the code looks really good here and I'd love to just move on and commit this, however I think we should make sure this is compatible with the solution that is implemented in #2329937: Allow definition objects to provide options. I'd suggest adding a getOptionsProvider() method that matches the method in the WIP patch there, i.e. we'd need the intermediate wrapper class who could get the action plugin injected? The goal would be to have an $options object which has all dependencies set, such that we can pass it on to future typed data widget plugins which then can rely on the options results.
Comment #33
marlonjuc commentedHi guys, the patch in #10 works good. You guys rock putting this module to work.
I got a question. I need to assign a Role to the Commerce Order Owner. What should be the selector?
Comment #34
Erso commentedGreetins,
As I am also blocked by add user role issue, I reached here. After some search and some problems, in the end I reached a role solution by "set a data value". I didn't do any patch that mentioned above.
Data selector: node.uid.entity.roles
Value: -role system name- (example: administration)
So it would set the user's role as "administration" and erase all other roles as well. I didn't tried other roads but at least it is possible by set a data value for the role as I see. I just wanted to add for possible blocked guys for roles.
Comment #35
tr commentedComment #36
mchaplin commenteddeleted
Comment #37
tr commentedThe patch from #25 needed a lot of re-rolling due to the many changes in Rules since it was posted. This new patch applies to the latest -dev and hopefully the modified tests will run without error on the testbot ...
Comment #39
tr commentedI missed compensating for rules_ban in its own module and for the Condition: and Action: labels that were removed from the list builder. Let's see if that's all ...
Comment #41
tr commentedThere are still a few places where the ConfigureAndExecuteTest needs to be updated. Also there's some commented code in there which is throwing coding standards violations - that should be looked at an probably uncommented because I think it should work now.
However, these are just problems with the test - the code should work fine, so feel free to use it and post feedback.
Comment #42
jonathan1055 commented@TR would you like me to investigate the failing tests, or are you doing this?
Comment #43
tr commentedIf you have time it would be great if you could work on the tests. I think there are also probably new conditions/actions that were added since this patch was last rolled, and those will need to be examined to see if they also need to add options providers and be included in the tests.
The reason I re-rolled this was so I can start testing it along with the typed data widgets patch to make sure they play well together, then I want to see if I can address @fago's comment in #32 because that impacts both of these. I want to get both of these issues committed before the next alpha because they both are major usability improvements.
Comment #44
jonathan1055 commentedThere were five tests that failed (four separate cases in testAddConditions and the testMultipleInputContext). The tests now pass OK locally so should run on d.o. You were right that the actual code is OK and it was problems with the tests. The main reason is that before we had the assignment restrictor we were using the free-text entry and using dummy values, but now that some fields only have select lists we need to provide accurate values for the forms. You can see the slight changes to the test data values in the interdiff.
The testMultipleInputContext() failed becuase it was using the
node_is_of_typecondition which has the types field has 'multiple = TRUE'. However, this field is now a selection list (with this patch) so the values cannot be entered free-text. I changed the test to use actionrules_send_emailinstead, because this also has a multiple field, the 'To' addresses, but unlike the node types, this is still a textarea with free text to enter each address.In addition to fixing the five test failures, I took the oportunity to enhance the test file, making it easier to use/develop/test. The changes are:
This patch also includes the one-line change to add
assignment_restriction = "selector"to src/Plugin/Condition/DataListCountIs.php as mentioned in #3094046-9: Set 'assignment_restriction' in Condition and RulesAction contexts. This is necessary for the tests to pass, but that change will be done in a separate issue, and ultimately will be removed from this patch.Comment #46
jonathan1055 commentedThat's irritating - the MultipleInput test passes locally but not on d.o. Reverting back to the long-hand way of creating the rule.
Comment #47
Anonymous (not verified) commentedI am attempting to create a rule that will assign a role to a user based upon the status of a custom user field on the registration form and user edit form (in this case a boolean single checkbox).
Unfortunately, I have been unable to find a way of accessing this custom field when attempting to create a data comparison condition.
I have tried to make the field available by following other suggestions of adding conditions “Entity has field” and/or “Entity is of type” (and saved the rule before adding the data comparison condition).
This hasn't worked.
I have attempted to follow the suggestion offered in #11 here Finding custom fields & creating users - which is to add the condition that “Entity is of bundle”.
According to the suggestion, the values for Entity, Type, and Bundle should all be “user”. It's stated that the latter two values can be entered by Direct Input.
However, in my case, where I have used the latest patch in this thread to add support for select lists, both of those values use select lists with no option of switching to Direct Input.
For Type, “user” is available from the select list.
However, it is not available in the Bundle select list.
Is there something screwy with my installation/patch? Can somebody confirm that the “user” value is available from the Bundle select list.
Any pointers or suggestions for working around this issue would be very welcome. Thanks
Comment #48
tr commentedThis patch did not code the bundle selection in the "Entity is of bundle" condition properly. Here is a new version of the patch with this fixed, and an interdiff to show the differences.
Note that the "Entity is of bundle" condition does work ... your problem is a result of this patch only. I generally suggest that you get something working first before you test new features with patches like this, that way you will know whether the problem is with the patch or not.
Comment #49
tr commentedThat should have been interdiff-46-48.txt. Here it is again.
Comment #51
tr commentedThe patch needed to be updated for the current HEAD of Rules, but it did still apply but one test needed to be adjusted for changes made in another issue.
Here's a new patch with that update, and an interdiff against #46. You can ignore the patch in #48.
Comment #52
jonathan1055 commentedRe-roll after #3159876-7: Set assignment restrictor for two list and data conditions
Comment #54
jonathan1055 commentedThe updated tests failed due to #3045738-33: Convert entity manager service usage to split up services ( Part 2 ) when Drupal 8.8 becomes the lowest supported version but simple to fix. I also sorted the coding standards message.
Comment #55
jonathan1055 commentedAnd fix the coding standard.
Comment #56
glynster commentedApplied latest patch against dev and works as expected. RTBC +1
Comment #57
glynster commentedFYI: patch fails now due to latest dev updates. You guys are doing well the progress on Rules has been awesome!
Comment #59
tr commentedYeah, one of the three commits made in the two hours between #55 where the patch ran green and #57 where @gynster tested it seems to have broken this patch.
Those commits are:
#3101026: Replace deprecated path.alias_manager and AliasManager when Drupal 8.8 becomes the lowest supported version
#3115367: Add provider = "path_alias" to all path conditions and actions when Drupal 8.8 becomes the lowest supported version
#3160067: Refactor and expand ActionsFormTest and ConditionsFormTest
I didn't look at this too deeply, but one thing I noticed is that the 'path_alias' module will need to be enabled in the ConfigureAndExecuteTest in this patch. That shouldn't cause any test failures because it will really only be required for D9, but as I'm working on the deprecated path alias issues right now it's something I noticed.
Comment #60
jonathan1055 commentedThanks @glynster for testing and for the +1 to RTBC. I never mind re-rolling patches and/or fixing things if the reason is that @TR has committed work which improves Rules. I will see what can be done here.
Comment #61
jonathan1055 commentedFixing the tests turned out to be quite easy. It was the new tests added in #3160067: Refactor and expand ActionsFormTest and ConditionsFormTest which failed, due to some random values I specified for the field values and role names. In this issue, because the fields become drop-down selection lists they automatically have validation built in. Also the test failure message gave very good hints as to what the field would accept.
The change involved creating a named role for use in the tests, as apart from 'authenticated' the only other role was a random name, and
DrupalCreateUser()does not give any way to specify the role name it creates.Comment #62
jonathan1055 commentedRe-rolled due to #3160067: Refactor and expand ActionsFormTest and ConditionsFormTest
Comment #63
jonathan1055 commentedThe action plugin SystemEmailToUsersOfRole should have a
list_options_callbackwas defined to select the Roles, but this got missed before. So I have added it - and consequently had to fix the test case. In fact, it was the new tests passing which alerted me to the omission, as the specified role was not an actual existing one.I also tightened up the test case data for the user selection, which now has 'data selector' not just the free input text.
Comment #64
glynster commented@jonathan1055 works like a charm. All patches are working together at this time! Keep you the great work as rules is awesome!
Comment #65
tr commentedThat makes sense, because SystemEmailToUsersOfRole wasn't ported to D8 until July 2019, which was long after this patch was started. See #2409059: Port Send mail to all users of a role (mail_to_users_of_role) action to D8.
Which raises the question, are there any other 'new' Conditions/RulesActions which are missed by this patch? (I raised that in #43 as well). I'll take a look to see, but this could use another set of eyes as well.
I have been using #51 on my test site for almost two months now, and I have been using the various previous patches for probably a year, and I think what I've used is working well, but I'm a bit wary because of issues like #47 where it appears the options list for Entity is of Bundle had never been tested by anyone and it had never worked - this patch would have actually broken the Enitity is of Bundle condition had it been committed before that was fixed. That's why I think all the new tests @jonathan1055 has been writing have been very important and useful.
Really the only reason I have held back on committing this is because of #32 - It really would be nice to make this patch consistent with the proposed core change in #2329937: Allow definition objects to provide options. In the past, and hopefully in the future, Rules has been used as a prototype for functionality that gets put into core. The long-term goal should be to build missing core functionality which can be used in places other than Rules. It is hard to maintain code that extends core when core gradually diverges from our implementation - consider for example the core Entity context that is causing a problem with porting Rules to D9. We should be developing this patch with an eye towards the future - a common architecture for options providers is needed in core too, so let's build them the same way as we would for core. That will help get this functionality into core as well as help us offload a lot of our customized code into core which makes it far more maintainable. While this will require a re-working of the above patch, it should also simplify the code because we won't have to duplicate options callbacks for each plugin that uses them. For example,
userRolesListOptions()is defined/duplicated three times in this patch. If that were an options provider for user roles, then it would be defined only once and reused. Then, if we ever have to fix a bug in this function, it will only have to be fixed in one place and there will be no chance that three different implementations diverge from each other.Comment #66
jonathan1055 commentedThanks TR. I am pleased you've been using this and found it basiaclly working. It's good that the new tests are proving worthwhile.
I have checked all the conditions and actions and there are some which do not have lookups/selection but possibly should
rounding_behavior
field_name
Oeration and operator are easy to add, just a hardcoded list of the values that the context will accept.
Data covert Target type and Variable Add type should be easy, just a choice of string/integer/float/boolean etc..
field_name can re-use the existing functionalty
rounding_behavior and pos are simple hard-coded selection values
Language is a new one, we've not used that before but it could make sense to limit this to just the languages enabeld on the site.
email_type is this a fixed list, or is it dynamic?
Yes I agree, for all the reasons you give.
Yes I also noticed that, and was wondering how to avoid it. I will read up on how the proposed solution works in #2329937: Allow definition objects to provide options I see you have been involved in that issue, so any pointers or starters for the re-work would be helpful as I have not read any of that yet.
Regarding the tests in this issue, they are also useful in other issues such as
#2471481: Integrate Typed Data Widgets
#2723259: Allow single-valued data selector input to be passed as an array for 'multiple' context fields
#2800749: Support upcasting entity IDs to full entity contexts
I think it would be beneficial to get the new and updated tests committed sooner, rather than leave them in this patch. That would mean I could work on any of those issues and have the new tests available instead of having to copy them from branch to branch, or add them in more than one patch. I will prepare a patch here which gets all the relevent test additions together but without any functional code changes so we can see what it looks like.
Comment #67
jonathan1055 commentedBefore starting the re-work discussed in #32 and #65 I want to get the tests sorted out. I realised after my work in #3160067: Refactor and expand ActionsFormTest and ConditionsFormTest that we have most of that test coverage duplicated in the patches on this issue. So I have worked a lot on ActionsFormTest.php and ConditionsFormTest.php to incorporate the few elements of test coverage which had been added in this issue, so that we can drop completely the two new tests 'testAddActions' and 'testAddConditions' from ConfigureAndExecuteTest.php in the patches on this issue.
Here is a full patch, same as #63 except for changes to three test files. I've included an interdoiff. I can explain more about the changes if required.
There may be one test failure in testMultipleInputContext, as commented in the code, but I want to try it on drupal.org, as this passes locally and on Travis.
Comment #69
jonathan1055 commentedOK, so the failure still happens (just wondered if other things might have fixed it).
The code in question is:
$expected_config_value is a hard-coded array, so the message means that
$to = $rule->get('expression.actions.actions.0.context_values.to')has returned NULL not an array. Reverting back to the long-hand way just for that test (the others work fine)Comment #70
jonathan1055 commentedPatch #70 is just the changes to the three test files, so this is being tested again the existing codebase, with no changes. This should pass, and I propose that we get this committed, as the expanded test coverage will be useful in other issues such as:
#2471481: Integrate Typed Data Widgets
#2723259: Allow single-valued data selector input to be passed as an array for 'multiple' context fields
#2800749: Support upcasting entity IDs to full entity contexts
#3010055: Multiple Event Triggers
All of these involve the actions and conditions forms, and all have had lots of work done. Getting the tests committed (and therefore off this patch) will be a useful step forward.
Comment #71
jonathan1055 commentedAfter studying the work-in-progress in #2329937: Allow definition objects to provide options and in particular @fago's comments starting with #11 and using the final patch #61 I have worked on how to implement this in Rules, and I now have an operatioal version for our conditons and actions, using the OptionsProvider class and the functions in
Drupal\Core\TypedData\OptionsProviderInterface. It is all working well with the core patch #61 applied.I have made the necessary changes to Rules' own ContextDefinition (which is already extending Core ContextDefinition) and which won't be required if/when the core patch is committed.
However, when I try it on plain Core 8.9 (without the patch) it obviously fails, because there are necesary changes to
Drupal\Core\TypedData\TypedDataManager. I am trying to work out the best way to resolve this, as Rules does not have its own TypedDataManager extension of the core version.I will post a patch here, with work done so far, but until I resolve the TypedDataManager changes it wont work on d.o. testing.
Comment #72
jonathan1055 commentedHere's a patch with the new
OptionsProviderwork, including a drupalci.yml file to attempt to patch core with patch #61 so that the tests run OK.I have made some decisions, just to get this started, but there are things that we'll need to discuss
src/Plugin/OptionsProviderbut this may not be the right place\Drupal\rules\Plugin\OptionsProvider\{name}Optionsbut this can be discussedThere will be plenty more to discuss. But let's see how the patching of core does.
Comment #73
jonathan1055 commentedForgot the interdiff
Comment #74
jonathan1055 commentedActually patch #72 includes more than is necessary, as it had some of my WIP to make this run without the core patch. Here is the reduced version.
Comment #75
vdsh commentedHi jonathan. And thanks for dedicating so much of your time on this. But it's moving so fast that I can't follow.
I have applied patch #74 from here and the core patch #61 in #2329937: Allow definition objects to provide options
I am now trying to do a rule to give a specific role to the current user. I can see the list fine in the rules administration. But when my rules is triggered, I got an error:
Call to a member function id() on string in Drupal\rules\Plugin\RulesAction\UserRoleAdd->doExecute() (line 55 of modules\contrib\rules\src\Plugin\RulesAction\UserRoleAdd.php)What am I missing?
Comment #76
jonathan1055 commentedHi vdsh,
Thanks for testing, and good to hear that the selection lists are working for you.
Call to a member function id() on stringis another well-known issue. Please see#2725525: Fatal error: Call to a member function id() on a non-object in UserRoleAdd.php on line 49 and
#2824360: Error "Call to a member function id() on string" for condition 'user has role(s)'
Both of these will be solved by the patch on #2800749-48: Support upcasting entity IDs to full entity contexts which you can try.
Comment #77
vdsh commentedThanks jonathan, indeed with the upcasting patch, it is all working as expected. Thanks for your help
Comment #78
jonathan1055 commentedStraight re-roll of #74 due to #3168040: Query string in AddressEquals (D9.1 test failure)
Comment #79
vasyok commentedToday if apply #78 to current rules dev, i cannot edit any condition or action in rules.
In Recent log:
Message Error: Call to undefined method Drupal\rules\Context\ContextDefinition::getOptionsProvider() in Drupal\rules\Form\Expression\ConditionForm->form() (line 115 of /var/www/html/web/modules/contrib/rules/src/Form/Expression/ConditionForm.php)
Comment #80
jonathan1055 commentedHi VasyOK,
The function
getOptionsProvider()is new and comes from the core issue #2329937-61: Allow definition objects to provide options patch #61. This was mentioned in the comments above but I agree that unless the reader has been following this issue closely that would not have been obvious. So I have updated the issue summary here to explain what is needed.When you have applied that core patch (if you can) let me know if the conditions and actions selection lists work for you. Thanks.
Comment #81
jonathan1055 commentedI had already worked on some extra optionsProviders and your post above prompted me to add the patch here. There are nine additional options providers, covering all the text and numeric data comparisions we cater for, the data conversion types, rounding option, list position, system email type and system language options. This now covers every action and condition that could have selection lists, apart the 'type' choice in VariableAdd
rules_variable_addbecause this probably should be derived from the current system/environment (and that is a bigger task, suitable for follow-up work).This patch still needs this core patch #61, which applies OK in core 8.8, 8.9, 9.0 and 9.1
Comment #82
vdsh commentedPatch updated for latest dev
Comment #83
ConradFlashback commentedError #82 patch with last dev.
Comment #84
jonathan1055 commentedThanks ConradFlashback. Here's a re-rolled the patch following the commit on #2694553: Description wrong: "content is of type" should be "Entity is of bundle"
Comment #85
sushylTested the last patch on SystemMail action, noticed and fixed the following issues/errors.
- Fixed error on rounding behavior during data conversion.
- Added support for data conversion of lists
- Fixed error "Warning: preg_match_all() expects parameter 2 to be string" during token replacement
Comment #87
sushylFixing a typo in the last patch
Comment #89
sushylAdded missing files added in previous patch
Comment #90
Yuri commentedpatch #89 returns this error when trying to add an action to set a data value. Using D9.2.6
Error: Call to undefined method Drupal\rules\Context\ContextDefinition::getOptionsProvider() in Drupal\rules\Form\Expression\ActionForm->form() (line 104 of /home/projects/public_html/web/modules/contrib/rules/src/Form/Expression/ActionForm.php)Comment #91
tr commentedThe patch currently under consideration is #84.
What is #85 supposed to be? There is no interdiff, so the only way to see the changes between this and #84 is to compare them line-by-line. But if the text of the comment is any indication, this new patch adds a number of out-of-scope changes to #84 without explaining them.
Likewise, the latest iteration #89 doesn't even apply.
Please provide an interdiff against #84, along with an explanation of why the changes were made. Also, please fix the patch so it applies and passes the tests.
Comment #92
sushylSorry, I have been away for few days and will add the interdiff very soon, I tried to explain the changes in #85 but I will try and elaborate it.
Comment #93
spiritcapsule commentedI attempted to apply patch in #84 to the latest version of the 8.x-3.x-dev (commit 615221dd) and it failed. I'm not sure exactly why yet - that's a really long patch file!
Comment #94
spiritcapsule commentednevermind, my bad, I had another patch applied and #84 conflicted with the changes from the other patch. It does apply cleanly on 615221dd.
Comment #95
jonathan1055 commentedPatch #95 is a re-roll of #84 due to recent commits. No functional changes. This uses core patch 65 from #2329937: Allow definition objects to provide options which is applicable to core 9.1 - the default for Rules testing on drupal.org.
[To test here at 9.2 the core patch would be 69, and to test at core 9.3 the core patch would be 72]
Comment #97
jonathan1055 commentedInvestigating these six new test failures
The test output on drupal.org is only indirectly helpful, the actual cause of the faults is a repsonse code 500, and testing locally I see the exception
This is a new exception, created in the new
Drupal\Core\Field\TypedData\FieldDefinitionOptionsProviderTrait.In the ConditionsFormWidgets test, all 20 conditions are tested and only 2 fail. In ActionsFormWidgets all 36 actions are tested but only 3 fail.
Comment #98
jonathan1055 commentedThe problem is nothing to do with recent Rules commits, it is the change in the core patch from 61 to 65 on #2329937: Allow definition objects to provide options that has caused it. That change, shown in interdiff_61-65.txt removed
FieldDefinitionOptionsProviderTraitfrom Drupal\Core\Field\BaseFieldDefinition.php and put it into Drupal\Core\TypedData\ListDataDefinition.php. This fixed one of the core test failuresso it may be the correct change.
The Rules problems occur only with the actions
rules_email_to_users_of_role,rules_user_role_addandrules_user_role_remove, and the conditionsrules_node_is_of_typeandrules_user_has_role. None of the other actions and conditions have this problem. The difference with these is they havemultiple=TRUE. Removing this parameter removes the error and the problematic conditions and actions can be edited.That obviously is not a solution but at least we now know what the problem is.
Comment #99
tr commentedComment #100
tr commented@jonathan1055: What do you think about committing this in stages? I think the OptionsProvider plugins (1 commit) and the changes to the Condition/Action annotation (1 commit) are ready to go in right away without affecting any other code - the new annotation and the new plugins will be ignored without the code that uses them. That's the bulk of the patch anyway, aside from the tests. We can use a new issue for each of those commits in order to separate out the description of what the commits do so we can track these changes in the future. It will also make a good reference for documenting this feature so that contrib can start to use it.
Once those are committed, I think it will be easier to get this finished. For me, at least.
I notice there is some code in the patch that injects new services into some conditions (EntityHasField, EntityIsOfBundle, EntityIsOfType, NodeIsOfType) - I believe that is no longer needed now that the options are in a plugin rather than as methods on those conditions.
Comment #101
jonathan1055 commentedI think that is a very good idea. It will reduce the patch, save re-rolls and make it easier to work on.
Here's a patch which removes the injected services from those four actions. I also have some improvements to the tests, for better analysis following the failures in #95 but I will add those to a subsequent patch, not to confuse the work with removing the injected services.
Comment #102
jonathan1055 commentedOK we have the same 6 test failures as expected. Patch #102 makes two changes to the tests:
phpunit modules/rules --filter='ActionsForm.*(32|33)'will run just test cases 32 and 33 from the ActionsForm test.rules_node_is_of_typecondition. The failure is nothing to do with assignment testing, and this condition is tested to the same extent in ConditionsFormTest, therefore no loss of test coverage results from simplifying this test.There should be just 5 failures now, only in ActionsFormTest and ConditionsFormTest
Comment #104
jonathan1055 commentedAs expected we have five test failures, and these are for the options providers which are used with multiple=true, as explained earlier. The failures are now response code 500, which shows that some kind of exception prevented the page from loading.
The ConditionsForm failures are:
and the ActionsForm failures are
Comment #105
tr commentedThe create() methods and the ContainerInterface and ContainerFactoryPluginInterface need to go, too.
We can commit that part right away, if you put it in a separate issue.
Here are the artifacts for the test fails in #102:
https://dispatcher.drupalci.org/job/drupal8_contrib_patches/90786/artifa...
https://dispatcher.drupalci.org/job/drupal8_contrib_patches/90786/artifa...
Comment #106
tr commentedI extracted this part out of #102 and put it into a child issue #3254675: Improve ActionsFormTest and ConditionFormTest
Comment #107
tr commentedThe patch in the core issue #2329937: Allow definition objects to provide options makes a lot of changes to core Fields that aren't needed in order for Rules to use options providers.
I *think* the only part of that patch that might be needed for our purposes are the changes to the typed data manager?
If that's the case, can't we just extract those changes to the typed data manager and put them into the Typed Data API module for use by Rules? That way we can get this issue working without requiring a core patch. The way to do this would be to override the typed data manager service with our own typed data manager class that subclasses core in includes the changes from the core patch.
Comment #108
tr commentedBetween #3254620: Add new OptionsProvider files #3254624: Add options_provider annotations to conditons and actions and #3254675: Improve ActionsFormTest and ConditionFormTest, it looks like about 2000 lines of this patch has now been committed, leaving us with less than 500 lines. That's going to be a lot easier to manage!
Comment #109
jonathan1055 commentedYes, and I have just rasied #3255074: Improve ConfigureAndExecute test which will reduce the changes here even further, and give us better test coverage. When that is done it will leave just four files in this issue:
Comment #110
jonathan1055 commentedNew patch #110 now only changes four Rules files (plus the drupalci.yml file to apply the core patch). There are no changes from patch 102 for these files. The entire patch is 148 lines compared to 2,470 in patch #102.
This patch will still fail for the actions and conditions which have an
options_providerspecified and also havemultiple=trueThe next step would be to try out TR's ideas in #107 and create an issue and patch for Typed Data API which we could use here instead of the core patch.
Comment #112
jonathan1055 commentedIn additon to the known failures, we have a new one:
This is not caused by the change to test at Core 9.2 compared to 9.1 in the previous patch, as it fails in Core 8.9. So why the extra failure?
Comment #113
jonathan1055 commentedThe same test failure occurs on the main 8.x-3.x Rules branch following the commits on #3254620: Add new OptionsProvider files and #3254620: Add new OptionsProvider files when the core branch also has the appropriate patch from #2329937: Allow definition objects to provide options. Hence the failure can be seen even without the patches on this issue.
Comment #114
tr commentedI already did this work - one minor problem to fix first before I post it, but I won't be able to get to that today. I'll be posting an issue in the typed_data issue queue and linking to that here.
Sounds like it's related to this, from the LoopTest:
Comment #115
jonathan1055 commentedI found the cause of the extra test failure. A change to getContextDefinitionFor() in
tests/src/Unit/Integration/RulesEntityIntegrationTestBase.phpwhich was in patch 102 had got missed when I created patch 110. I must have lost it, due to all the other test file changes, action and conditions, and providers being done in other issues. I have now double-checked and nothing else has got dropped by mistake.Comment #116
tr commentedThe "minor problem" turned into a major problem, to the extent that I don't think this strategy is feasible. The typed data code is just too interdependent on the context code and the whole data definition hierarchy, so while decorating the typed data manager works there are too many places where context and data definitions are obtained outside of the typed data manager that can't be controlled without hacking core.
So we're back to needing to get the core issue finished.
Note that the test failures also show up interactively. For example, try the "Node is of type" condition and try to choose the type, and you'll see:
Uncaught PHP Exception LogicException: "The "Content types" object (class \\Drupal\\Core\\TypedData\\Plugin\\DataType\\ItemList) must either implement FieldDefinitionInterface or FieldStorageDefinitionInterface." at /var/www/example.com/public_html/core/lib/Drupal/Core/Field/TypedData/FieldDefinitionOptionsProviderTrait.php line 115Comment #117
tr commentedI'm actually getting that logic exception for almost every single condition/action that has an options provider.
I'm using 2329937-75.options-provider.patch with core Drupal 9.3.x
Comment #118
nwom commented#115 no longer applied to the newest dev, so here is a re-roll. No interdiff needed since nothing was changed.
Comment #119
nwom commentedI'm not getting any Logic Exceptions with the latest core patch, but I'm getting alot of InvalidArgumentExceptions when choosing the wrong options.
Comment #120
socialnicheguru commentedJust wanted to note this patch conflicts with Integrate Typed Data Widgets
Comment #121
joseph.olstadpatch 118 crashes with 3.x-dev 9595fcaCall to undefined method Drupal\rules\Context\ContextDefinition::getOptionsProvider()NVM, I see I need a core patch from:
#2329937-91: Allow definition objects to provide options
, thanks for the work on this! :)
The latest patch is excellent, thank you!
Comment #122
nilesh.addweb commentedAs I'm not getting any select list in rules module version 4.0.x-dev , I have applied changes in patch #118.
Please review.