Handling tabular data loading and validation in Yii 2

How do you read and handle tabular data submission via form in Yii framework 2.0? Sometimes we want to collect user input in a batch mode. That is, the user can enter the information for multiple model instances and submit them all at once. We call this tabular input because the input fields are often presented in an HTML table.

Tabular Input Solution

If you are coming over from Yii 1 – the concepts of tabular data handling remain the same as mentioned in the Yii 1.x guide – collecting tabular input section.

The only differences in Yii 2 is that its much simpler due to available functions in the Model class for loading and validating models.

Option 1: Use a prebuilt solution

You can use a prebuilt solution to render and manage tabular data. You can use the TabularForm widget from Krajee’s yii2-builder extension package. Refer details of the TabularForm widget here.

Option 2: Doing it yourself

You can use the same concepts as mentioned in the guide link mentioned before – here are the changes you need to do for Yii 2:

To work with tabular input, we first need to create or populate an array of model instances, depending on whether we are inserting or updating the data. We then retrieve the user input data from the $_POST variable and assign it to each model. A slight difference from single model input is that we retrieve the input data using $_POST['ModelClass'][$i] instead of $_POST['ModelClass'].

Controller

Your controller can include a batch update action as shown below:

use yii\base\Model;
use frontend\models\Item;

// fetch the list of Item models for updating
public function getItemsToUpdate() {
    $criteria = 'item_category = "xyz"'; // any criteria
    $items = Item::find()->where($criteria)->indexBy('id')->all();
    return $items;
}

// perform the batch update
public function actionBatchUpdate()
{
    // retrieve items to be updated in a batch mode
    // assuming each item is of model class 'Item'
    $items=$this->getItemsToUpdate();
    if (Model::loadMultiple($items, Yii::$app->request->post()) && 
        Model::validateMultiple($items)) {
        $count = 0;
        foreach ($items as $item) {
           // populate and save records for each model
            if ($item->save()) {
                // do something here after saving
                $count++;
            }
        }
        Yii::$app->session->setFlash('success', "Processed {$count} records successfully.");
        return $this->redirect(['index']); // redirect to your next desired page
    } else {
        return $this->render('update', [
            'items' => $items,   
        ]);
    }
}

View

A sample code for your view file:

<div class="form">
    <?php $form = ActiveForm::begin(); ?>
    <table>
        <tr>
            <th>Name</th>
            <th>Price</th>
            <th>Count</th>
            <th>Description</th>
        </tr>
        <?php foreach($items as $i=>$item): ?>
            <tr>
                <td><?= $form->field($item,"[$i]name"); ?></td>
                <td><?= $form->field($item,"[$i]price"); ?></td>
                <td><?= $form->field($item,"[$i]count"); ?></td>
                <td><?= $form->field($item,"[$i]description"); ?></td>
            </tr>
        <?php endforeach; ?>
    </table>
    <?= Html::submitButton('Save'); ?>
    <?php ActiveForm::end(); ?>
</div><!-- form -->

6 thoughts on “Handling tabular data loading and validation in Yii 2

  1. Hello,
    Thanks for your tutorial.
    Could you please explain where is this getItemsToUpdate() array come from ?
    Thanks again

    1. The getItemsToUpdate function will basically return the list of AR models you wish to update. I have updated the web tip with the example.

  2. Hi Kartik , when you get value from db (ex. getItemsToUpdate) is better indexing query by primary key ,
    otherwise you cannot use loadMultiple and validateMultiple.
    That’s because AR doesn’t know what record needs to update.
    bye

  3. Hi Kartik,
    I was doing something with a model array in an ActiveForm and came across this tutorial. Everything seems to be working fine for me except when I use a File Input.

    How can I use kartik\widgets\FileInput.
    I was using it as

    field($model, “[$k]image”)->widget(FileInput::classname(), [
    ‘options’ => [‘multiple’ => false, ‘accept’ => ‘image/*’],
    ‘pluginOptions’ => [
    ‘previewFileType’ => ‘image’,
    ‘showUpload’ => false,
    ‘showRemove’ => true,
    ]
    ]); ?>

    But this doesn’t seem to be working.
    Neither I can see anything in UploadedFile::getInstance nor in $_FILES.

    Can you help?

Comments are closed.