Yii2 multiple models in one form

2019-06-22 11:17发布

How to use multiple models in one form in Yii2?

My case: ER diagram

In my create action I can save into agenda_fiscalizacao table, but in update I receive this error when I try to load the form:

Call to a member function formName() on array    

My Update Action:

public function actionUpdate($id)
{
    $model = $this->findModel($id);
    $modelAgenda = AgendaFiscalizacao::findAll(['fiscalizacao_id' => $id]);

    if ($model->load(Yii::$app->request->post()) && Model::loadMultiple($modelAgenda, Yii::$app->request->post())) {
        $valid = $model->validate();
        $valid = $modelAgenda->validade() && $valid;

        if ($valid) {
            $model->save(false);
            $modelAgenda->save(false);
            return $this->redirect(['view', 'id' => $model->id]);
        }
    }

    return $this->render('update', [
        'model' => $model,
        'modelAgenda' => $modelAgenda
    ]);
}

My form view

<?= $form->field($modelAgenda, 'agenda_id')->checkboxList(Agenda::combo(), ['class' => 'checkbox']) ?>
<?= $form->field($model, 'bioma_id')->dropDownList(Bioma::combo(), ['prompt' => $prompt]) ?>
<?= $form->field($model, 'nome')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'tipo_doc')->radioList(['CPF'=>'CPF', 'CNPJ'=>'CNPJ'], ['class' => 'radio']) ?>
<?= $form->field($model, 'n_doc')->widget(MaskedInput::className(), ['mask' => ['999.999.999-99', '99.999.999/9999-99']]) ?>
<?= $form->field($model, 'observacao')->textarea(['rows' => 7]) ?>    

What could be wrong?

EDIT (full error):

enter image description here

3条回答
太酷不给撩
2楼-- · 2019-06-22 11:26
public function actionUpdate($id)
{
    $model = $this->findModel($id);
    $modelAgenda = AgendaFiscalizacao::findAll(['fiscalizacao_id' => $id]);

    if ($model->load(Yii::$app->request->post()) && $modelAgenda->load(Yii::$app->request->post()) && Model::validateMultiple([$model, $modelAgenda])) {

            $model->save(false);
            $modelAgenda->save(false);
            return $this->redirect(['view', 'id' => $model->id]);

    }

    return $this->render('update', [
        'model' => $model,
        'modelAgenda' => $modelAgenda
    ]);
}

You can refer following link for example : http://blog.dedikisme.com/blog/2014/10/13/yii2-building-a-single-form-with-multiple-models

查看更多
小情绪 Triste *
3楼-- · 2019-06-22 11:27

1) If you mean working with multiple models of the same type, the error is in this line:

$valid = $modelAgenda->validade() && $valid;

First, it should be $modelAgenda->validate(), second $modelAgenda contains array of models, validate() method can be called only on single model.

For validating multiple models Yii2 suggests using built-in method validateMultiple():

use yii\base\Model;

...

$valid = Model::validateMultiple($modelAgenda) && $valid;

Working with multiple models is well covered in official docs (Collecting Tabular Input).

Note that they recommend to index models array by id before like this:

$models = YourModel::find()->index('id')->all();

2) If you need just two models of different type, don't use findAll() because it's for finding multiple models and always returns array (even on empty result). Use new for create action and findOne() for update action to initialize models. Let's say you initialized two models, $firstModel and $secondModel, then you can load and save them like this:

$isSuccess = false;

Yii::$app->db->transaction(function () use ($isSuccess) {
    $areLoaded = $firstModel->load(Yii::$app->request->post()) && $secondModel->load(Yii::$app->request->post();
    $areSaved = $firstModel->save() && $secondModel->save();
    $isSuccess = $areLoaded && $areSaved;
});

if ($isSuccess) {
    return $this->redirect(['view', 'id' => $model->id]);
}

Transaction is added in case of saving of second model will fail (so the first model also will not be saved).

Alternatively, you can declare transactions inside your model, for example:

return [
    'admin' => self::OP_INSERT,
    'api' => self::OP_INSERT | self::OP_UPDATE | self::OP_DELETE,
    // the above is equivalent to the following:
    // 'api' => self::OP_ALL,
];

Then just use:

$firstModel->scenario = 'scenarioForTransaction';
$secondModel->scenario = 'scenarioForTransaction';
$areLoaded = $firstModel->load(Yii::$app->request->post()) && $secondModel->load(Yii::$app->request->post();
$areSaved = $firstModel->save() && $secondModel->save();

if ($areLoaded && $areSaved) {
    return $this->redirect(['view', 'id' => $model->id]);
}

For more than two models, it's better to use loops.

P.S. I'd recommend to separate saving to different controllers / actions and call it via AJAX, it will be more user friendly.

For saving relations read - Saving Relations.

查看更多
倾城 Initia
4楼-- · 2019-06-22 11:41

You are not rendering $modelAgenda from view/update.php to view/_form.php file while using render in update file.

查看更多
登录 后发表回答