Yii2で複数のモデルを1つのフォームで使用するにはどうすればよいですか?
作成アクションでは、agenda_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]) ?>
何が悪いのでしょうか?
1)同じタイプの複数のモデルを操作する場合、エラーは次の行にあります。
_$valid = $modelAgenda->validade() && $valid;
_
まず、$modelAgenda->validate()
である必要があり、2番目の_$modelAgenda
_にはモデルの配列が含まれ、validate()
メソッドは単一のモデルでのみ呼び出すことができます。
複数のモデルを検証するために、Yii2は組み込みメソッドvalidateMultiple()
の使用を提案しています。
_use yii\base\Model;
...
$valid = Model::validateMultiple($modelAgenda) && $valid;
_
複数のモデルでの作業については、公式ドキュメントで詳しく説明されています( 表形式の入力の収集 )。
次のように、モデル配列にid
でインデックスを付けることをお勧めします。
_$models = YourModel::find()->index('id')->all();
_
2)異なるタイプのモデルが2つだけ必要な場合は、findAll()
を使用しないでください。これは、複数のモデルを検索するためのものであり、常に配列(空の結果でも)。モデルを初期化するには、new
アクションにはcreate
を使用し、update
アクションにはfindOne()
を使用します。 _$firstModel
_と_$secondModel
_の2つのモデルを初期化したとすると、次のようにロードして保存できます。
_$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]);
}
_
2番目のモデルの保存が失敗した場合にトランザクションが追加されます(したがって、最初のモデルも保存されません)。
または、モデル内で transactions を宣言することもできます。次に例を示します。
_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]);
}
_
3つ以上のモデルの場合は、ループを使用することをお勧めします。
P.S。異なるコントローラー/アクションへの保存を分離し、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
更新ファイルでrenderを使用しているときに、$ modelAgendaをview/update.phpからview/_form.phpファイルにレンダリングしていません。