How to save the multi-records in one model in a single transaction in Yii2
Home » BLOG » Yii2.0 framework » How to save the multi-records in one model in a single transaction in Yii2

How to save the multi-records in one model in a single transaction in Yii2

category:  Yii2.0 framework

Recently I just add the new feature on my application. What new feature does, it generates the new invoice from the time-sheet. This way, my clients can see my log time and note on each task. So they know in detail what I did for their project.

The steps are:

  • get the time-sheet data filtered by the specific client, date range and unbilled status
  • In the time-sheet loop, insert the new invoice and invoice detail
  • If something goes wrong while inserting, I will rollback all the transactions
  • If nothing fails, I will commit all transactions

Yii/db/Transaction

What I use is yii/db/Transaction which is the DB transaction. I would recommend using when you want to insert or update the master-detail transaction just like invoice and invoice detail tables in my case.

I will skip the first step which is the time-sheeting query and talk about the next step since they are my focus on this post. In code below, shows how to use the DB transaction. Simply import the Yii class in the file first, so you can call Yii::$app->db->beginTransaction(). Next, we start the transaction scope with Yii::$app->db->beginTransaction(). Everything inside the transaction scope can rollback or commit.

<?php
namespace frontend\controllers;
use Yii;  // import for using "Yii::$app->db->beginTransaction()"
use yii\web\NotFoundHttpException;  // import for error exception
use frontend\models\Invoice;
use frontend\models\InvoiceDetail;
use \frontend\modules\timesheet\models\Timesheet;


/**
 * Generate the invoice from the timesheet
 * @return mixed
 */
public function actionGenerate() 
{

    // Start here..
    $transaction = Yii::$app->db->beginTransaction();
    
    try {
    
        $invoice = new Invoice();
        $invoice->field = 'value';
        // # save the invoice model with validation check
        // if you want to disable the validation, you can use $invoice->save(false)
        if( $invoice->save() ) {
            // # get the new invoice id that we just save
            $new_invoice_id = $invoice->id;
            
            // # check time logs for inserting to the invoice detail model
            $flag = true;
            if( is_array($timesheets) && count($timesheets)>0 ) {
                foreach($timesheets as $timesheet) {
                    
                    // # insert into invoice detail model
                    $invoiceDetail = new InvoiceDetail;
                    $invoiceDetail->field = $timesheet->hours;
                    if (!($flag = $invoiceDetail->save(false))) { // save InvoiceDetail model without validation
                        $transaction->rollBack(); // if save fails then rollback
                        break;
                    }                
                }
            }
        }    
    
        // # save all transactions
        if($flag) {
            $transaction->commit();
        }
    
    } catch (Exception $e) {
        // # if error occurs then rollback all transactions
        $transaction->rollBack();
    }

}
?>

That’s it.