"Check" checkboxes if they have a record in reference table

More fun converting a Cake 2.x app to Cake 4.x. I have a ‘Manage Roles’ option in my user management setup. When I click ‘Manage Roles’ for a user, I’m taken to admin_groups.php and I get an array of checkboxes read from my Groups table. This is the code from my UsersController that brings these in:

$this->set('groups', $this->Groups->find('list', [
        'keyfield' => 'id', 'valueField' => 'group_name',
        'order' => ['group_name ASC']
        ])
    );

I also contained my UserGroups table when looking up the user, thinking that would help.

$user = $this->Users->get($id, [
        'contain' => ['UserGroups'],
    ]); 

Users, Groups, and UserGroups tables have the following associations:

Users hasMany UserGroups FK = user_id
UserGroups belongsTo Users FK = user_id
UserGroups belongsTo Groups FK = group_id
Groups hasMany Users FK = group_id

And here is the code from my admin_groups.php that displays the checkboxes and their labels.

<?= $this->Form->create($user) ?>
        <fieldset>
            <legend><?= __('Edit User Roles for ' . $user->full_name) ?></legend>
            <?php
                echo $this->Form->control("UserGroups.group_id", [
                    'type' => 'select', 
                    'multiple' => 'checkbox', 
                    'options' => $groups, 
                    'label' => '',
                ]);
            ?>
        </fieldset>
        <?= $this->Form->button(__('Submit')) ?>
        <?= $this->Form->end() ?>

I have no trouble displaying the checkboxes or selecting them and saving the result to the UserGroups table; however, I’m struggling with displaying the checkboxes as “checked” after they’ve been selected. The user’s group memberships are retrieved by calling getGroups in my UsersTable:

public function getGroups($user_id, $keys = true) 
{
    // Get the user's group memberships
    $groups = [];
    foreach($this->UserGroups->find('all', ['contain' => ['Groups']])->where (['user_id' => $user_id]) as $data) {
        $groups[$data->group->id] = $data->group->group_key;
    } 
    return ($keys) ? $groups : array_keys($groups);
}

In the old days, all it took was a modification to the request object to populate the checkboxes, like so:

$this->request->data['UserGroup']['group_id'] = $this->User->getGroups($id, false);

Obviously, that’s forbidden now, so I’m looking for the Cake 4 equivalent.

You can use the request’s withData() method which I believe will create a new request object with your added data included.

Or, I like to pull the data out of the request and work with it separately:

$postData = $this->request->getData();

Then the immutable request is not in my way.

So that’s close to what I’m after, but when the page loads, there isn’t any request data for me to extract yet (I think? Please correct me if I’m wrong). I need the selected boxes to be checked when I visit the page.

Now, when I do something like this, using getData() instead of withData():

$test = $this->request->getData('UserGroups.group_id', $this->Users->getGroups($user->id, false));

and I debug $test, I see the correct results: an array of group_id's assigned to the user.

[
 (int) 0 => (int) 33, 
 (int) 1 => (int) 31, 
 (int) 2 => (int) 24, 
 (int) 3 => (int) 21, 
 (int) 4 => (int) 20, 
 (int) 5 => (int) 2, 
 (int) 6 => (int) 1,
]

What’s eluding me is how to use that data to populate my checkboxes.

Aaaand I just figured it out! $this->set('test', $test) in my UsersController and then add this to my checkbox display:

'default' => $test,

Just tested it out and it works perfectly. Thanks for the nudge!