Yii2 несколько моделей в одной форме

Как использовать несколько моделей в одной форме в Yii2?

Мое дело: ER диаграмма

В моем действии создания я могу сохранить в таблицу nda_fiscalizacao, но при обновлении я получаю эту ошибку, когда пытаюсь загрузить форму:

Call to a member function formName() on array    

Мое обновление действий:

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
    ]);
}

Мой вид формы

<?= $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]) ?>    

Что может быть не так?

РЕДАКТИРОВАТЬ (полная ошибка):

введите описание изображения здесь

3 ответа

1) Если вы имеете в виду работу с несколькими моделями одного типа, ошибка в этой строке:

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

Во-первых, это должно быть $modelAgenda->validate()второй $modelAgenda содержит массив моделей, validate() метод может быть вызван только на одной модели.

Для проверки нескольких моделей Yii2 предлагает использовать встроенный метод validateMultiple():

use yii\base\Model;

...

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

Работа с несколькими моделями хорошо описана в официальных документах ( Сбор табличных данных).

Обратите внимание, что они рекомендуют индексировать массив моделей по id раньше, как это:

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

2) Если вам нужны только две модели разного типа, не используйте findAll() потому что это для поиска нескольких моделей и всегда возвращает массив (даже при пустом результате). использование new за create действие и findOne() за update действие по инициализации моделей. Допустим, вы инициализировали две модели, $firstModel а также $secondModelзатем вы можете загрузить и сохранить их так:

$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]);
}

Транзакция добавляется в случае, если сохранение второй модели не удастся (поэтому первая модель также не будет сохранена).

Кроме того, вы можете объявить транзакции внутри вашей модели, например:

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,
];

Тогда просто используйте:

$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]);
}

Для более чем двух моделей лучше использовать петли.

PS Я бы порекомендовал разделить сохранение на разные контроллеры / действия и вызвать его через AJAX, это будет более удобным для пользователя.

Для сохранения отношений читайте - Сохранение отношений.

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
    ]);
}

Вы можете сослаться на следующую ссылку, например: http://blog.dedikisme.com/blog/2014/10/13/yii2-building-a-single-form-with-multiple-models

Вы не визуализируете $modelAgenda из view/update.php для просмотра /_form.php файла при использовании render в файле обновления.

Другие вопросы по тегам