Problem/Motivation

Currently, there is only the function addMember(UserInterface $account, $values = []) for adding roles to a user in a group.
A need for adding or removing a group role is needed as its own function.
This is also stated in one of the test classes in the module

// @todo This displays a desperate need for addRole() and removeRole().
    $membership = $member->getGroupContent();
    $membership->group_roles[] = 'default-custom';
    $membership->save();

Proposed resolution

Add 2 new functions for adding or removing a group role.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork group-3132084

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Ginovski created an issue. See original summary.

ginovski’s picture

Issue summary: View changes
ginovski’s picture

Issue summary: View changes
lobsterr’s picture

Status: Active » Needs review
StatusFileSize
new2.82 KB
ginovski’s picture

Status: Needs review » Needs work
+++ b/src/GroupMembership.php
@@ -121,4 +121,33 @@ class GroupMembership implements CacheableDependencyInterface {
+    $this->groupContent->group_roles[] = $role;

1.A check for duplicate is missing, the role could already have been added before.



<code>
+++ b/src/GroupMembership.php
@@ -121,4 +121,33 @@ class GroupMembership implements CacheableDependencyInterface {
+  public function removeRole($role) {

2.This method can be inserted in the test to check its functionality.

lobsterr’s picture

Status: Needs work » Needs review
StatusFileSize
new4.03 KB
new1.94 KB

@Ginovski I've added checks:
1) If a user has the role
2) if a role exists for the current group type

I will add tests later

kristiaanvandeneynde’s picture

Status: Needs review » Needs work

This looks great. Could you add a test perhaps? You have some safety checks in there and it would be nice for a test to confirm they work as expected. It can be as simple as a unit test with a few prophecy mocks.

Also:

'group_type' => $this->groupContent->getGroup()->getGroupType()->id(),

This can save a few ms by not having to load the group type:

$this->groupContent->getGroup()->bundle(),

Thanks for working on this!

liquidcms’s picture

Just a somewhat related comment:

I guess most people want to run this code on a User entity? When i needed to make a view to be able to set/remove a role from members i created a Group content (membership) view; and then wrote a new VBO action to add as simply:

  $entity->group_roles->target_id = 'company-coordinator';
  $entity->save();

The entity in this case is "Group content" but not membership; even though i am filtering my group content on "group membership" content type. So even though i can see group_roles in my $entity values (and apparently set them); i never load the membership. There is also no need to check if already set. It is my only (real) role at the moment; so not sure how this works if i create a 2nd role. Maybe it doesn't and i could use these new methods in what would now require a somewhat convoluted approach:

  $member = User::load($entity->entity_id->target_id);
  $group = $entity->getGroup();
  $membership = $group->getMember($member);
  $membership->addRole('company-coordinator');
  $membership->save();

Do I have this all correct? It does seem odd that i can set role by either modifying the group content entity or the membership entity.

Without your new remove method; not sure how to go about this as i am doing it now (against group content entities); possibly just set target_id = ''.

spokje’s picture

Assigned: ginovski » Unassigned
Status: Needs work » Needs review
StatusFileSize
new6.75 KB
new4.12 KB

Addressed #7:

- Used $this->groupContent->getGroup()->bundle() to save a few ms by not having to load the group type
- Added some tests, couldn't think of a way to use a unit test, since I couldn't see any way to get this to work without using getRoles(), so I used a KernelTest.
- Updated some comments.

spokje’s picture

Coding Standard messages and 9.2 failure (looks like expectExceptionMessageRegExp, which was already deprecated, has been removed from PHPUnit 9.5.8) are unrelated to this patch AFAICT.

lobsterr’s picture

StatusFileSize
new2.95 KB
new6.58 KB

I agree, Unit tests are suitable in this case. I have tried to do it also, it didn't work for me.
I checked the tests everything looks ok. I have added some minor changes.
Just to improve code a bit.

I believe we can mark it as RTBTC

jordik’s picture

Status: Needs review » Reviewed & tested by the community
jordik’s picture

It would be awesome to also have a hasRole() method checking for a certain role. What do you think?

aporie’s picture

Component: Group (group) » Code
StatusFileSize
new1.9 KB

Regarding the hasRole method I also needed something like that.
I've opened a child issue and will post the complete patch here.

Sorry, I'm not able to make an interdiff right now. I don't have patchutils installed and have an issue with my package manager.

Patch 11 + hasRole method in attachment.

aporie’s picture

StatusFileSize
new7.36 KB
new1.38 KB

Well, maybe a patch not made in the rush would be better. Finally, got patchutils installed also, that helps.

Sorry for previous rushy patch.

sweetchuck’s picture

Status: Reviewed & tested by the community » Needs work

Change back to "Needs work" because of the failing tests.

I think the roles added into the array in a reverse order.

sweetchuck’s picture

With the current solution every ::addRole() and ::removeRole() triggers an individual ::groupContent->save().

I think the following methods would be useful.

class GroupMembership implements CacheableDependencyInterface {

  /**
   * Add or remove certain roles.
   *
   * @param iterable<string, bool> $role_ids
   *   Key: Role ID.
   *   Value: Indicates that if the role has to be added(TRUE) or removed(FALSE).
   *
   * @return $this
   */
  public function updateRoles(iterable $role_ids) {
    // @todo
    return $this;
  }

  /**
   * Add all the roles listed in $role_ids, remove those which aren't.
   * 
   * @param iterable<string> $role_ids
   *
   * @return $this
   */
  public function setRoles(iterable $role_ids) {
    // @todo
    return $this;
  }

kristiaanvandeneynde’s picture

Version: 8.x-1.x-dev » 3.2.x-dev
Category: Support request » Feature request
Issue tags: +Group 3.3.0

Will try to add this to next minor release.

jdleonard’s picture

The patches are not yet relevant to Group 3.x.

I found that I had to do the following to programmatically add a group role for a user with an existing membership:

      // Get the user's membership in the group.
      $membership = $group->getMember($account);

      // If the user is already a member of the group.
      if ($membership) {
        /** @var \Drupal\group\GroupMembership $membership */

        $group_roles = $membership->getRoles(FALSE);

        $has_member_role = FALSE;

        foreach ($group_roles as $group_role) {
          if ($group_role->id() == $member_role) {
            $has_member_role = TRUE;
            break;
          }
        }

        // If the user doesn't already have the member role in this group.
        if (!$has_member_role) {
          // Add the member role for this user.
          $group_relationship = $membership->getGroupRelationship();
          $group_relationship->group_roles[] = $member_role;
          $group_relationship->save();
        }
      }
jordik’s picture

Status: Needs work » Needs review
StatusFileSize
new3.15 KB

Re-rolling the patch to 2.2.x-dev, using the proper groupRelationship instead of groupContent and omitting the changes to ChainGroupPermissionCalculatorTest.php.

jordik’s picture

Version: 3.2.x-dev » 2.2.x-dev
kristiaanvandeneynde’s picture

Version: 2.2.x-dev » 3.3.x-dev

kristiaanvandeneynde’s picture

This needs test coverage for the new methods and I'm not sure if we can simply get away with calling the shared bundle class from the old wrapper like that. For new methods it would make sense, as there is nothing to keep BC for.

kristiaanvandeneynde’s picture

Hiding patches in favor of MR

kristiaanvandeneynde’s picture

Okay, this looks ready to me now. Will add a follow-up for moving the role checking logic in a preSave() hook.

kristiaanvandeneynde’s picture

kristiaanvandeneynde’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

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