Now that #2800749: Support upcasting entity IDs to full entity contexts is done the original problem in this issue is fixed. However, when we have the roles presented as a selection list we can simplify UserHasRole::doEvaluate() and reduce processing overhead. See @TR's comments in #10.

Hence postponing on #2664280: Select lists in action & condition configuration forms, which itself is reliant on core issue #2329937: Allow definition objects to provide options


Original

When executing a Rule with the `rules_user_has_role` condition, the following error is thrown:

Error: Call to a member function id() on string in Drupal\rules\Plugin\Condition\UserHasRole->Drupal\rules\Plugin\Condition\{closure}() (line 76 of modules/contrib/rules/src/Plugin/Condition/UserHasRole.php).

The problem is that the doEvaluate() method in UserHasRole.php expects an array of $role objects. The data selector widget does not list available roles, and the direct input mode widget sends the items to the doEvaluate method as an array of string values.

Along the same vein as #2815967: Action UserRoleAdd always throws an exception

Comments

coderdan created an issue. See original summary.

coderdan’s picture

Status: Active » Needs review
fago’s picture

Status: Needs review » Closed (duplicate)

This is yet another issue for #2800749: Support upcasting entity IDs to full entity contexts. The PR just fixes a symptom, not the root issue. If you want to help, please see #2800749: Support upcasting entity IDs to full entity contexts!

coderdan’s picture

coderdan’s picture

StatusFileSize
new1.33 KB
jhedstrom’s picture

Priority: Normal » Major
Status: Closed (duplicate) » Needs review
StatusFileSize
new1.41 KB
new1.5 KB

Re-opening for now since this is a major issue for folks using UserHasRole, and this fix seems like at least a temporarily valid workaround until the upcasting issue is properly resolved.

This updates the patch in #5 to always trim the role value in case it comes through with line breaks (which then fails to load the corresponding role object). It also adds an exception if the role still isn't found.

Status: Needs review » Needs work

The last submitted patch, 6: 2816157-06.patch, failed testing. View results

jonathan1055’s picture

I have started working on the blocker #2800749: Support upcasting entity IDs to full entity contexts and would appreciate any feedback, to check I am on the right lines. Thanks.

tr’s picture

Status: Needs work » Needs review
StatusFileSize
new972 bytes

Actually, this doesn't need upcasting. UserHasRole::doEvaluate() does NOT need the Role object, so there is no need to upcast here, and the failure is a logic failure.

The attached very simple fix REQUIRES #2664280: Select lists in action & condition configuration forms to be applied first, as that patch changes the role name input to use a select widget with the selections enumerated as rid => role_name.

With the changes in #2664280: Select lists in action & condition configuration forms, we will be 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 look like:
array ( 0 => 'authenticated', 1 => 'administrator', )
Note that this is key => rid

doEvaluate() just has to check if the selected rids are in the $account->getRoles() array - no Role object needed.

Try this patch with no upcasting required, no Role object required, after applying #18 from #2816157: Simplify UserHasRole::doEvaluate(). I'm posting this is both issues 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.

tr’s picture

So I see this fix was proposed as part of #2824360: Error "Call to a member function id() on string" for condition 'user has role(s)'.

The difference is, that issue changes the context annotation to pass a string for the role selection, whereas with the changes #2664280: Select lists in action & condition configuration forms, my patch above in this issue leaves that annotation as entity:user_role.

In #2824360-6: Error "Call to a member function id() on string" for condition 'user has role(s)' @fago says

We should not change the argument from the entity to a dumb string, that will make the condition worse in the end.

So I think this meets that criterion?

jonathan1055’s picture

Issue summary: View changes

Thanks TR, this is very useful. I had also seen that once the selection lists were implemented there would be a simpler way to evaluate the condition. If @fago is OK with this, then it makes sense to me. But I am not the designer or maintainer of Rules, just a willing volunteer happy to contribute my time to getting things fixed. It seems like #2664280: Select lists in action & condition configuration forms is the one to work on first.

jonathan1055’s picture

Status: Needs review » Postponed

Postponing this until #2664280: Select lists in action & condition configuration forms has landed. Then the patch in #10 above is a good solution.

jonathan1055’s picture

Related issues: +#2664280: Select lists in action & condition configuration forms
promo-il’s picture

Thanks #10 It's work

tr’s picture

Category: Bug report » Task
Priority: Major » Normal

I am leaving this open because it is easier to find this issue, but the solution has to come in #2800749: Support upcasting entity IDs to full entity contexts so if this is important to you please contribute to that issue, not here.

tr’s picture

Assigned: coderdan » Unassigned
jonathan1055’s picture

@Promo-IL #2800749-36: Support upcasting entity IDs to full entity contexts has a generic patch to solve this. Please test it. Thanks.

We will probably still want patch #10 above committed anyway, once #2664280: Select lists in action & condition configuration forms is done.

Steven McCoy’s picture

StatusFileSize
new993 bytes

EDIT: please disregard this post (I don't know how to delete it). Proper updated patch is in comment #20

Steven McCoy’s picture

StatusFileSize
new996 bytes

I've updated the patch to work with 3.0@alpha

chucksimply’s picture

Just to followup... patch on #68 here solved it for me. https://www.drupal.org/project/rules/issues/2800749#comment-13942286

EDIT: I lied, still having issues even with the above patch :(

4kant’s picture

#20 works for me.
Thanks!

jonathan1055’s picture

Title: Condition UserHasRole throws an error » Simplify UserHasRole::doEvaluate()
Issue summary: View changes
StatusFileSize
new1.06 KB

Changed the issue summary now that #2800749: Support upcasting entity IDs to full entity contexts is done.

Needed a re-roll, no material changes from patch #10 / #20

Steven McCoy’s picture

StatusFileSize
new1.15 KB

Edit: please disregard this post and my file from comment #24. Apparently there was a mistake in it

Steven McCoy’s picture

StatusFileSize
new1.15 KB

#23 wouldn't patch for me. I re-rolled from #20 and fixed a few code linting issues

Steven McCoy’s picture

StatusFileSize
new1.15 KB

#23 wouldn't patch for me. I re-rolled from #20 and fixed a few code linting issues

jonathan1055’s picture

Hi @Steven McCoy,
When making patches it would help us if you could do the following:
(a) please add the comment number within the patch name, as is done in the previous patches here and is standard Drupal good practice. It makes it so much quicker to identify patch files, to make sure a link is to the correct one, and when comparing patches locally
(b) if fixing anything (other than a straight clean re-roll with no actual content changes) then provide an interdiff so that others can more easily identify the changes. You'll get a quicker more helpful review that way.
Thanks
Jonathan

jonathan1055’s picture

Issue summary: View changes

I have just looked at your patches in #24, #25 and #26. None of these apply to the latest 8.x-3.x dev code. I think you are patching against the alpha7 tagged release. Patches have to be applied to -dev. Patch #23 is still the current patch.

However, as this issue is postponed on #2664280: Select lists in action & condition configuration forms there is no automated testing here. And also no point in making any patches for use on sites running alpha7 unless that site also has the patch on 2664280, which is in turn is dependent on the core issue #2329937: Allow definition objects to provide options

jonathan1055’s picture

StatusFileSize
new1.37 KB
new971 bytes

However, thank you for noticing the coding standards faults. Here's a new patch #29 which fixes both of those, even though strictly they are faults already committed in -dev and not introduced by the changes in this patch.

tr’s picture

Status: Postponed » Needs work

At some point this patch lost sync with the changes to Rules. Specifically, all the lines that change $user to $account need to go. For example, this should not be done:

-   * @param \Drupal\user\UserInterface $user
+   * @param \Drupal\user\UserInterface $account

The reason we need to continue to use $user now is because of PHP 8 and the changes made in #3210303: PHP 8 introduced breaking change to call_user_func_array().

And ... Do we have a test for this?

jonathan1055’s picture

Status: Needs work » Needs review
StatusFileSize
new971 bytes

Yes you are right, patch #20 introduced the backwards change. Here's an updated clean patch.

This condition is covered by Unit\Integration\Condition\UserHasRoleTest and this patch 31 will fail now. This is because #2800749: Support upcasting entity IDs to full entity contexts has been committed, so the $roles parameter is now an array of fully upcast roles. We need to change the context of roles from "entity:user_role" to just "string" but that will be done in the next patch. First to demonstarte the failure.

Status: Needs review » Needs work

The last submitted patch, 31: 2816157-31.simplify-user-has-role.patch, failed testing. View results

jonathan1055’s picture

Status: Needs work » Needs review
StatusFileSize
new4.45 KB
new3.71 KB

Here is the change to set the roles context to string. This also requires a change to Unit/Integration/Condition/UserHasRoleTest.php where the roles array is now just the role ids not the objects.

jonathan1055’s picture

All tests pass.
Regarding the three long array lines, in #3178576-11: [meta] Coding Standards in Rules 8.x we talked about increasing the allowed length, so I won't fix those here until the discussion on that issue has been done.

tr’s picture

the $roles parameter is now an array of fully upcast roles.

My patch in #10 was to avoid the need to upcast, and thus avoid having to wait for that patch (which is now committed).

But with upcasting, is there any need for this issue anymore? I guess I had assumed that we would just close this when upcasting was added. If we have the full Role object, then that's a lot more useful in general than just the string role machine name.

jonathan1055’s picture

The changes here are not strictly required any more. But I assumed that because you changed it to 'needs work' you were still interested in making the small efficiency saving in time and processing by not upcasting the role(s) and not having the array_map function to re-extract the ids when they can be made available directly in the $roles parameter. I can't see that the fully upcast role objects would be any use in this condition as we only need the role id here, nothing else. The role objects will still be upcast for the other actions, it is only this condition which I set back to keep them as strings.

Or maybe you are thinking about expanding the condition? Or using the role label in db logging? I'm fine if you want to leave it as is.