Transaction in loop updates inserted record!


#1

Hello,

I need to ensure the images uploaded, then insert into DB (id, car, name), the issue in the loop is inserting only the first item, then it updates the same record only.

<?php

foreach ($model->car_image as $image) {
    $transaction = Yii::$app->db->beginTransaction();
    Yii::info("this for image name:" . $image->getBaseName(), "app");
    if (in_array($image->extension, ['jpg', 'jpeg'])) {
        if ($image->size <= $maxFileSize) {
            $model->name = "t_" . time() . "_i_" . uniqid() . '.' . $image->extension;
            if ($image->saveAs($imageDir . '/' . $model->name)) {
                $saveIt = true;
            } else {
                throw new InvalidValueException('Failed to create the object for unknown reason. [APIx000]');
            }
        } else {
            throw new InvalidValueException("Failed to save! Maximum file size is $maxFileSize. [APIx003]");
        }
    } else {
        throw new InvalidValueException("Failed to save! Only jpg file format allowed. [APIx004]");
    }

    if ($model->save(false) and $saveIt) {
        $transaction->commit();
        $imageId[] = $model->id;
    } else {
        $transaction->rollBack();
        throw new InvalidValueException("Failed to save the data due to validation. [APIx002]");
    }
}

Any idea how to solve it?!


(Wilson) #2

transaction is for commit batch transaction, if one failed, then rollback. not one by one commit.


(Alirz23) #3

I am not sure about the context which you are developing this code so I will be shooting in the dark here

  1. transaction begin/commit/rollback should not be in the loop, it is a bad idea to have it in the loop.
  2. do your file validation with yii’s builtin file validators (https://www.yiiframework.com/doc/guide/2.0/en/tutorial-core-validators#file)
  3. you need to create a new instance of model for each item in your loop if you want to save multiple rows

I did not test the following code but I simplified just give you an indicator

<?php

$transaction = Yii::$app->db->beginTransaction();
$saved = false;

foreach ($model->car_image as $image) {
    Yii::info("this for image name:" . $image->getBaseName(), "app");
    
    in_array($image->extension, ['jpg', 'jpeg']) // move it to validator 
    $image->size <= $maxFileSize // move to file validators

	$model->name = "t_" . time() . "_i_" . uniqid() . '.' . $image->extension;
    if ($image->saveAs($imageDir . '/' . $model->name) && $model->save()) {
        $saved = true;
        $imageId[] = $model->id;
    } else {
        $saved = false;
    }
}

if ($saved) { {
	$transaction->commit();
} else {
	$transaction->rollBack();
}

#4

I got, thanks a lot.