Saving linked models in the same view

It could be convenient to save different kind of models in the same view. This approach allows us to save time and to navigate from every single detail until a final item that merges all data is created. Handling different kind of models linked to each other it is not so different from what we have seen so far. The only point to take care of is the link (foreign keys) between models, which we must ensure is valid.

Therefore, the controller action will receive the $_POST data encapsulated in the model's class name container; if we are thinking, for example, of the customer and reservation models, we will have two arrays in the $_POST variable, $_POST['Customer'] and $_POST['Reservation'], containing all the fields about the customer and reservation models.

Then all data must be saved together. It is advisable to use a database transaction while saving data because the action can be considered as ended only when all the data has been saved.

Using database transactions in Yii2 is incredibly simple! A database transaction starts with calling beginTransaction() on the database connection object and finishes with calling the commit() or rollback() method on the database transaction object created by beginTransaction().

To start a transaction:

$dbTransaction = Yii::$app->db->beginTransaction();

Commit a transaction, to save all the database activities:

$dbTransaction->commit();

Rollback a transaction, to clear all the database activities:

$dbTransaction->rollback();

So, if a customer was saved and the reservation was not (for any possible reason), our data would be partial and incomplete. Using a database transaction, we will avoid this danger.

Example – creating a customer and reservation in the same view

We now want to create both the customer and reservation models in the same view in a single step. In this way, we will have a box containing the customer model fields and a box with the reservation model fields in the view.

Create a view in basic/views/reservations/createCustomerAndReservation.php, with the fields from the customer and reservation models:

<?php

use yiihelpersHtml;
use yiiwidgetsActiveForm;
use yiihelpersArrayHelper;
use appmodelsRoom;
?>

<div class="room-form">

    <?php $form = ActiveForm::begin(); ?>

    <div class="model">
        
      <?php echo $form->errorSummary([$customer, $reservation]); ?>

      <h2>Customer</h2>        
      <?= $form->field($customer, "name")->textInput() ?>
      <?= $form->field($customer, "surname")->textInput() ?>
      <?= $form->field($customer, "phone_number")->textInput() ?>

      <h2>Reservation</h2>        
      <?= $form->field($reservation, "room_id")->dropDownList(ArrayHelper::map(Room::find()->all(), 'id', function($room, $defaultValue) {
          return sprintf('Room n.%d at floor %d', $room->room_number, $room->floor);
      })); ?>
      <?= $form->field($reservation, "price_per_day")->textInput() ?>
      <?= $form->field($reservation, "date_from")->textInput() ?>
      <?= $form->field($reservation, "date_to")->textInput() ?>
      
    </div>

    <div class="form-group">
        <?= Html::submitButton('Save customer and room', ['class' => 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

We have created two blocks in the form to fill out the fields for the customer and the reservation.

Now, create a new action named actionCreateCustomerAndReservation in ReservationsController in basic/controllers/ReservationsController.php:

    public function actionCreateCustomerAndReservation()
    {
        $customer = new appmodelsCustomer();
        $reservation = new appmodelsReservation();

        // It is useful to set fake customer_id to reservation model to avoid validation error (because customer_id is mandatory)
        $reservation->customer_id = 0;
        
        if(
            $customer->load(Yii::$app->request->post())
            &&
            $reservation->load(Yii::$app->request->post())
            &&
            $customer->validate()
            &&
            $reservation->validate()
        )
        {
        
            $dbTrans = Yii::$app->db->beginTransaction();
            
            $customerSaved = $customer->save();
            
            if($customerSaved)
            {
                $reservation->customer_id = $customer->id;
                $reservationSaved = $reservation->save();
                
                if($reservationSaved)
                {
                    $dbTrans->commit();
                }
                else {
                    $dbTrans->rollback();
                }                
            }
            else {
                $dbTrans->rollback();
            }
        }
        
        
        return $this->render('createCustomerAndReservation', [ 'customer' => $customer, 'reservation' => $reservation ]);
    }

Ensure you pay attention to these two matters:

  • $reservation->customer_id = 0: With this code, we avoid the validation error relating to the customer_id requirement that appears when $reservation is validated
  • The database transaction will be committed only if the customer model and reservation model's save action are completed

Browse to http://hostname/basic/web/reservations/create-customer-and-reservation to see the complete page:

Example – creating a customer and reservation in the same view

A customer and reservation created together

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.78.174