问题描述
如何在Yii2中以一种形式使用多个模型?
How to use multiple models in one form in Yii2?
我的案子:
在我的创建动作中,我可以保存到 agenda_fiscalizacao 表中,但是在更新中,当我尝试加载表单时收到此错误:
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
我的更新操作:
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)如果要使用多个相同类型的模型,则此行中的错误是
1) If you mean working with multiple models of the same type, the error is in this line:
$valid = $modelAgenda->validade() && $valid;
首先,它应该是$modelAgenda->validate()
,第二个$modelAgenda
包含模型数组,validate()
方法只能在单个模型上调用.
First, it should be $modelAgenda->validate()
, second $modelAgenda
contains array of models, validate()
method can be called only on single model.
为了验证多个模型,Yii2建议使用内置方法validateMultiple()
:
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).
请注意,他们建议像这样先通过id
为模型数组建立索引:
Note that they recommend to index models array by id
before like this:
$models = YourModel::find()->index('id')->all();
2)如果只需要两个不同类型的模型,请不要使用findAll()
,因为它用于查找多个模型并且总是返回数组(即使结果为空).将new
用于create
操作,将findOne()
用于update
操作来初始化模型.假设您初始化了两个模型$firstModel
和$secondModel
,然后可以像这样加载和保存它们:
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,
];
然后只使用:
$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.
PS .我建议将保存分别保存到不同的控制器/动作中,并通过AJAX进行调用,这样会更加人性化.
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.
这篇关于Yii2多种形式的一种模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!