<p>Try to use EVENT_BEFORE_SAVE and try to do a query the user again to get the old user data, something like this:</p>
<pre><code>Event::on(
        User::class, 
        Element::EVENT_BEFORE_SAVE, 
              function (ModelEvent $event) {
                if (Craft::$app-&gt;getRequest()-&gt;getIsConsoleRequest()) {
                    return;
                }
    
                $user = $event-&gt;sender;
                $userLocation = $user-&gt;userLocation-&gt;one();
    
                $newLocationCategory = $user-&gt;userLocation-&gt;one();
                $newLocationGroup = Craft::$app-&gt;getUserGroups()-&gt;getGroupByHandle($newLocationCategory-&gt;title);
                $currentGroupIds = [];
                if (!$event-&gt;isNew) {
                    // to get all location we need to do a query for user again.
                    $oldUserData = User::findOne($user-&gt;id);
                    $oldUserCategory = $oldUserData-&gt;userLocation-&gt;one();
                    $oldLocationGroup = Craft::$app-&gt;getUserGroups()-&gt;getGroupByHandle($oldUserCategory-&gt;title);

                    $currentGroupIds = \array_map(function($group) {
                        return (int)$group-&gt;id;
                    }, $user-&gt;getGroups());


                    // Remove the user from their old Location group - this is not working
                    if (($key = array_search($oldLocationGroup-&gt;id, $currentGroupIds)) !== false) {
                        unset($currentGroupIds[$key]);
                    }
                }
    
                $finalGroupIds = array_merge($currentGroupIds, [$newLocationGroup?-&gt;id]);
                Craft::$app-&gt;getUsers()-&gt;assignUserToGroups($user-&gt;id, $finalGroupIds);
            }
    );
</code></pre>
<p>PS: I didn't test the code.</p>

CC BY-SA 4.0
2022-11-06T09:23:15.970Z
Nice! Re-querying for the user seems to be the trick: `$oldUserData = User::findOne($user->id);`. I'm not totally sure why that wasn't available just from `$user` but I get because it's coming from `$event->sender`?

Thanks for your help!
supazu
CC BY-SA 4.0
2022-11-07T01:53:11.920Z
Yes, because it's coming from $event->sender, and that user value you get from that has the updated one value.
aodihis
CC BY-SA 4.0
2022-11-07T08:28:47.817Z
Makes sense. However, it's introduced a new complication: this works for the profile edit form, but not for creating a new user. Using `EVENT_BEFORE_SAVE` means `$oldUserData = User::findOne($user->id);` returns `null`. Any thoughts on how I could get around that?
supazu
CC BY-SA 4.0
2022-11-08T01:56:57.470Z
@brynli64 you can check if the events is new or not, if not new then run get the old category, I updated the answer for new user.
aodihis
CC BY-SA 4.0
2022-11-08T02:58:54.163Z
Thank you, I appreciate your help on this but unfortunately the same thing exists. Because it's `EVENT_BEFORE_SAVE`, `$user->id` returns `null`. Changing to `EVENT_AFTER_SAVE` solves that, but then the group isn't removed properly (presumably because the old data is now the new data). I think I might need to think about how to set this up to handle both scenarios.
supazu
CC BY-SA 4.0
2022-11-08T03:13:43.627Z
Yes, you correct, how about to separate the process for the new user and old user, for the new user do on EVENT_AFTER_SAVE since you don't need to remove it from the old group only assign the user their registered group, and use EVENT_BEFORE_SAVE for old user.
aodihis
CC BY-SA 4.0
2022-11-08T03:22:47.363Z
Yep, I have that working now but with a bit of duplicated code. I'm going to try to learn about how to reuse things across different events. Thanks for your help!
supazu
CC BY-SA 4.0
2022-11-05T11:42:20.233Z
2022-11-08T01:55:49.197Z
2022-11-08T01:55:49.197Z
aodihis
<p>So, are you sure you only have the necessary user group IDs at the end, in $finalGroupIds ?</p>
<p>Can you try to drop the keys after deleting(unset) unnecessary items(old groupIds) in your array?</p>
<pre><code>$finalGroupIds = array_values(array_merge($currentGroupIds, [$newLocationGroup-&gt;id]));
</code></pre>

CC BY-SA 4.0
2022-11-05T02:23:17.833Z
Thanks for the reply. It seems like `$oldLocationCategory = Craft::$app->getCategories()->getCategoryById($user->userLocation->id[0]);` is returning the *new* category, rather than the exisiting one. Changing to `EVENT_BEFORE_SAVE` doesn't help...so I'm not quite sure how to get the exisiting category on the user.
supazu
CC BY-SA 4.0
2022-11-04T22:52:13.020Z
2022-11-04T22:52:13.020Z
RomanAvr
<p>I have a profile form with a select menu for a user to choose their nearest location (a Category group.) A user will select their nearest location, it will add the category to their profile and then add them to the corresponding User group.</p>
<p>I would also like to remove the user from their existing group. For example, if they change from London to New York, they should be removed from the London user group and placed in the New York group.</p>
<p>The complication is that they belong to other user groups, which they need to stay in.</p>
<p>Adding to the new location group is working well, but I'm looking for a hand in removing the exisiting one. If anyone has any thoughts on my code below, I would very much appreciate it!</p>
<pre><code>Event::on(
    User::class, Element::EVENT_AFTER_SAVE, function (ModelEvent $event) {
        if (Craft::$app-&gt;getRequest()-&gt;getIsConsoleRequest()) {
            return;
        }

        $user = $event-&gt;sender;
        $userLocation = Craft::$app-&gt;getRequest()-&gt;getBodyParam('fields[userLocation][0]');

        if (!$userLocation) {
            return;
        }

        $newLocationCategory = Craft::$app-&gt;getCategories()-&gt;getCategoryById($userLocation);
        $newLocationGroup = Craft::$app-&gt;getUserGroups()-&gt;getGroupByHandle($newLocationCategory-&gt;title);

        $oldLocationCategory = Craft::$app-&gt;getCategories()-&gt;getCategoryById($user-&gt;userLocation-&gt;id[0]);
        $oldLocationGroup = Craft::$app-&gt;getUserGroups()-&gt;getGroupByHandle($oldLocationCategory-&gt;title);

        $currentGroupIds = \array_map(function ($group) {
            return (int)$group-&gt;id;
        }, $user-&gt;getGroups());


        // Remove the user from their old Location group - this is not working
        if (($key = array_search($oldLocationGroup-&gt;id, $currentGroupIds)) !== false) {
            unset($currentGroupIds[$key]);
        }


        $finalGroupIds = array_merge($currentGroupIds, [$newLocationGroup-&gt;id]);
        Craft::$app-&gt;getUsers()-&gt;assignUserToGroups($user-&gt;id, $finalGroupIds);
    }
);
</code></pre>

<modules>
Add to / remove from user group
# Add to / remove from user group

(Asked by: username_0 on 2022-11-04)

I have a profile form with a select menu for a user to choose their nearest location (a Category group.) A user will select their nearest location, it will add the category to their profile and then add them to the corresponding User group.
I would also like to remove the user from their existing group. For example, if they change from London to New York, they should be removed from the London user group and placed in the New York group.
The complication is that they belong to other user groups, which they need to stay in.
Adding to the new location group is working well, but I'm looking for a hand in removing the exisiting one. If anyone has any thoughts on my code below, I would very much appreciate it!
Event::on(
    User::class, Element::EVENT_AFTER_SAVE, function (ModelEvent $event) {
        if (Craft::$app->getRequest()->getIsConsoleRequest()) {
            return;
        }

        $user = $event->sender;
        $userLocation = Craft::$app->getRequest()->getBodyParam('fields[userLocation][0]');

        if (!$userLocation) {
            return;
        }

        $newLocationCategory = Craft::$app->getCategories()->getCategoryById($userLocation);
        $newLocationGroup = Craft::$app->getUserGroups()->getGroupByHandle($newLocationCategory->title);

        $oldLocationCategory = Craft::$app->getCategories()->getCategoryById($user->userLocation->id[0]);
        $oldLocationGroup = Craft::$app->getUserGroups()->getGroupByHandle($oldLocationCategory->title);

        $currentGroupIds = \array_map(function ($group) {
            return (int)$group->id;
        }, $user->getGroups());


        // Remove the user from their old Location group - this is not working
        if (($key = array_search($oldLocationGroup->id, $currentGroupIds)) !== false) {
            unset($currentGroupIds[$key]);
        }


        $finalGroupIds = array_merge($currentGroupIds, [$newLocationGroup->id]);
        Craft::$app->getUsers()->assignUserToGroups($user->id, $finalGroupIds);
    }
);

**Tags:** modules

---

## 2 answers

### Answer by username_1 on 2022-11-05. Score: 2 | Accepted answer

Try to use EVENT_BEFORE_SAVE and try to do a query the user again to get the old user data, something like this:
Event::on(
        User::class, 
        Element::EVENT_BEFORE_SAVE, 
              function (ModelEvent $event) {
                if (Craft::$app->getRequest()->getIsConsoleRequest()) {
                    return;
                }
    
                $user = $event->sender;
                $userLocation = $user->userLocation->one();
    
                $newLocationCategory = $user->userLocation->one();
                $newLocationGroup = Craft::$app->getUserGroups()->getGroupByHandle($newLocationCategory->title);
                $currentGroupIds = [];
                if (!$event->isNew) {
                    // to get all location we need to do a query for user again.
                    $oldUserData = User::findOne($user->id);
                    $oldUserCategory = $oldUserData->userLocation->one();
                    $oldLocationGroup = Craft::$app->getUserGroups()->getGroupByHandle($oldUserCategory->title);

                    $currentGroupIds = \array_map(function($group) {
                        return (int)$group->id;
                    }, $user->getGroups());


                    // Remove the user from their old Location group - this is not working
                    if (($key = array_search($oldLocationGroup->id, $currentGroupIds)) !== false) {
                        unset($currentGroupIds[$key]);
                    }
                }
    
                $finalGroupIds = array_merge($currentGroupIds, [$newLocationGroup?->id]);
                Craft::$app->getUsers()->assignUserToGroups($user->id, $finalGroupIds);
            }
    );

PS: I didn't test the code.

> **Comments:**
> **username_0**: Nice! Re-querying for the user seems to be the trick: `$oldUserData = User::findOne($user->id);`. I'm not totally sure why that wasn't available just from `$user` but I get because it's coming from `$event->sender`?  Thanks for your help!  
> **username_1**: Yes, because it's coming from $event->sender, and that user value you get from that has the updated one value.  
> **username_0**: Makes sense. However, it's introduced a new complication: this works for the profile edit form, but not for creating a new user. Using `EVENT_BEFORE_SAVE` means `$oldUserData = User::findOne($user->id);` returns `null`. Any thoughts on how I could get around that?  
> **username_1**: @brynli64 you can check if the events is new or not, if not new then run get the old category, I updated the answer for new user.  
> **username_0**: Thank you, I appreciate your help on this but unfortunately the same thing exists. Because it's `EVENT_BEFORE_SAVE`, `$user->id` returns `null`. Changing to `EVENT_AFTER_SAVE` solves that, but then the group isn't removed properly (presumably because the old data is now the new data). I think I might need to think about how to set this up to handle both scenarios.  
> **username_1**: Yes, you correct, how about to separate the process for the new user and old user, for the new user do on EVENT_AFTER_SAVE since you don't need to remove it from the old group only assign the user their registered group, and use EVENT_BEFORE_SAVE for old user.  
> **username_0**: Yep, I have that working now but with a bit of duplicated code. I'm going to try to learn about how to reuse things across different events. Thanks for your help!  

---

### Answer by username_2 on 2022-11-04. Score: 1

So, are you sure you only have the necessary user group IDs at the end, in $finalGroupIds ?
Can you try to drop the keys after deleting(unset) unnecessary items(old groupIds) in your array?
$finalGroupIds = array_values(array_merge($currentGroupIds, [$newLocationGroup->id]));

> **Comments:**
> **username_0**: Thanks for the reply. It seems like `$oldLocationCategory = Craft::$app->getCategories()->getCategoryById($user->userLocation->id[0]);` is returning the *new* category, rather than the exisiting one. Changing to `EVENT_BEFORE_SAVE` doesn't help...so I'm not quite sure how to get the exisiting category on the user.  

---

