CakePHP 3.x update multiple rows

have a table AssetsAssignations, with hundreds of rows. In some cases, the user needs to select many rows with a checkbox, and change the “status” for all of them together.

In my controller, I have this function

public function editMultiple()
{
$assetStatuses = $this->AssetsAssignations->AssetStatuses->find(‘list’);
$this->paginate = [
‘contain’ => [‘Assets’, ‘AssetStatuses’, ‘Clients’, ‘Rooms’],
‘sortWhitelist’ => [
‘Assets.model_number’,
‘Assets.serial_number’,
‘AssetStatuses.name’,
‘Clients.last_name’,
‘Rooms.name’,
]
];

$assetsAssignations = $this->request->data;

$assetsAssignations_ids = array();

foreach($assetsAssignations as $a){
    $assetsAssignations_ids[$a['id']] = $a['id'];
    $this->AssetsAssignations->updateAll(

        array('AssetAssignation.id' => $assetsAssignations_ids)
    );
    $this->Session->setFlash(__('Statsus is updated for the selcted entries!'));
}            
debug($assetsAssignations);

$query = $this->AssetsAssignations->find()
    ->contain(['Assets', 'AssetStatuses', 'Clients', 'Rooms']);
$filter = $this->Filter->prg($query);
$assetsAssignations = $this->paginate($filter, ['maxLimit' => 10000, 'limit' => 10000]);        

$this->set(compact('assetsAssignations', 'assetStatuses'));
$this->set('_serialize', ['assetsAssignations']);

}

In my edit_multiple.ctp, I use a javascript to filter the data. And I put this code:

    <thead>
            <tr>
                <th>Select</th><th>Model Number</th><th>Serial Number</th><th>Room</th><th>Client</th><th>Status</th>
            </tr>
    </thead>
    </thead>
                <?php foreach ($assetsAssignations as $assetsAssignation): ?>
                <tr>
                    <td><input name="data[AssetsAssignations][id][]" value="<?= $assetsAssignation->id ?>" id="AssetsAssignationsId1" type="checkbox"></td>
                    <td><?= $assetsAssignation->has('asset') ? $assetsAssignation->asset->model_number : '' ?></td>
                    <td><?= $assetsAssignation->has('asset') ? $assetsAssignation->asset->serial_number : '' ?></td>
                    <td><?= $assetsAssignation->has('room') ? $assetsAssignation->room->name : '' ?></td>
                    <td><?= $assetsAssignation->has('client') ? $assetsAssignation->client->last_name . ', ' . $assetsAssignation->client->first_name: '' ?></td>
                    <td><?= $assetsAssignation->has('asset_status') ? $assetsAssignation->asset_status->name : '' ?></td>
                </tr>
                <?php endforeach; ?>
</table>
<legend><?= __('') ?></legend>
</div>
    <?= $this->Form->create($assetsAssignation) ?>
<fieldset>
    <div class="row">
        <div class="col-xs-3"><?= $this->Form->input('asset_status_id', ['options' => $assetStatuses, 'empty' => true, 'label' => __('Change Status To')]) ?></div>
    </div>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>

When I debug the result, checking 3 entries, I get this:

[
‘data’ => [
‘AssetsAssignations’ => [
‘id’ => [
(int) 0 => ‘411’,
(int) 1 => ‘413’,
(int) 2 => ‘415’
]
]
],
‘asset_status_id’ => ‘3’
]

My question is: How to pass the selected row IDs to the “Submit” button after selecting the checkboxes ?

Thanks in advance.

Adding hidden fields with name according to scheme and value= “id” help for me with “passing” to submit.
If I’m right your code works, but you want get it better/faster?
Think of transactional and atomic->false or get updateAll,Flash outside foreach, but i’m not familiar with updateAll().

thanks @jarekgol . Sure, I’m interested in using the best/faster way.
Can you suggest the changes to do in my code, or refer me to an example near to my case ?

I was reading and trying to use the code about transactional here:
https://book.cakephp.org/3.0/en/orm/saving-data.html
but I failed to adapt to my need.
Basically, this what I put:

  $assetsAssignations_ids = array();
  $connection = ConnectionManager::get('default');
  $assetsAssignations = $connection->transactional(function () use ($assetsAssignations, $entities) {
        foreach ($entities as $entity) {
            
            $assetsAssignations->save($entity, ['atomic' => false]);
        }
    });

I got three notices:

Notice (8): Undefined variable: assetsAssignations [APP/Controller\AssetsAssignationsController.php, line 241]
Notice (8): Undefined variable: entities [APP/Controller\AssetsAssignationsController.php, line 241]
Warning (2): Invalid argument supplied for foreach() [APP/Controller\AssetsAssignationsController.php, line 242]

I dont understant where and how I should get the selected ID’s.
I would appreciate if you can help more, @jarekgol.

for save() you must have ‘entity’ first. So official way is to load them from DB, change desired values (in foreach) or run patchEntity/patchEntities if you got proper structure of post (submited) data, and then save like you do.

Anyway you can try adapt this https://book.cakephp.org/3.0/en/orm/database-basics.html#Cake\Database\Connection::transactional
in foreach inside transactional function for your UPDATE purpouse.
Please note, that this don’t use ‘save()’ but almost direct UPDATE SQL statement, but with protection against injections = ? , [data]

I read the documentation, but I failed to configure it. The issue comes in 2 things:
1- how to pass the selected asset_status_id to the controller ? for this, I wrote:

if ($this->request->is([‘patch’, ‘post’, ‘put’])) {
$asset_status_id = $this->request->data(‘asset_status_id’);
}

and in the view:

<?= $this->Form->input('asset_status_id', ['options' => $assetStatuses, 'empty' => true, 'label' => __('Change Status To')]) ?>

2- how to pass the id of the selected rows (selected with checbox) ?
I used:

if ($this->request->is([‘patch’, ‘post’, ‘put’])) {
$ids = $this->request->data(‘AssetsAssignations.id’);
}

in the view:

< input name=“data[AssetsAssignations][id]” value=“<?= $assetsAssignation->id ?>” id=“AssetsAssignationsId1” type=“checkbox”>