首页 文章

Yii2模型加载不能按预期工作

提问于
浏览
0

我的问题可能看起来像以下问题:

yii2 - 模型加载函数不设置某些模型属性

但是,由于通过联结表处理多对多关系,这里的情况不同 .

例如,我有三个表, JobsEqtypes 和联结表 Eqtype_jobs . 我想使用多个select dropDownList 将一些 Eqtypes 与使用简单 activeform 的当前 Job 相关联 . 以下是我所拥有的代码,控制器和视图:

//the controller code
public function actionEqtypeCreate($id)
{
  $eqtypes = \app\modules\crud\models\Eqtype::find()->all();
  $model = Job::findOne(['id' => $id]);
  if ($model->load(Yii::$app->request->post())){    
    var_dump($model->eqtypes);
    die(); // for debuging <<<<<<<<<<*>>>>>>>>
    foreach ($eqtypes as $eqt){
      $model->eqtypes->id = $eqt->id;
      $model->eqtypeJobs->eqtype_id = $eqt->eqtype_id;
      $model->save();
    }
    return $this->redirect(['index']);
  }
  return $this->render('eqtype-create', ['model' => $model, 'eqtypes' => $eqtypes]);  

}

这里的观点:

//The view code i.e Form
<?php
//use Yii;
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;

$form = ActiveForm::begin([
    'enableClientValidation' => true,
]);

echo $form->field($model, 'eqtypes')->dropDownList(ArrayHelper::map($eqtypes,'id','title'), ['multiple' => true]);

 echo Html::submitButton(
        '<span class="glyphicon glyphicon-check"></span> ' .
        ($model->isNewRecord ? Yii::t('cruds', 'Create') : Yii::t('cruds', 'Save')),
        [
        'id' => 'save-' . $model->formName(),
        'class' => 'btn btn-success'
        ]
        );      

$form->end();

这里我有一个问题: var_dump($model->eqtypes) 的输出,就在控制器代码中的 die() 之前,总是返回空数组 array(0) { } .

确实,是什么让我尝试使用 die() 调试,没有调试,我有以下错误:

间接修改重载属性app \ modules \ crud \ models \ Job :: $ eqtypes对第149行没有影响

在我的情况下,第149行是控制器代码中 foreach 语句之后的第一行:

$model->eqtypes->id = $eqt->id;

编辑

所有模型都使用yii2-giiant创建 . 但是以下是作业模型的部分副本:

<?php
// This class was automatically generated by a giiant build task
// You should not change it manually as it will be overwritten on next build

namespace app\modules\crud\models\base;

use Yii;
abstract class Job extends \yii\db\ActiveRecord
{



    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'jobs';
    }


    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['machine_id', 'product_id', 'title', 'qty'], 'required'],
            [['machine_id', 'product_id', 'qty', 'updated_by' ,'created_by'], 'integer'],
            [['created', 'started', 'completed'], 'safe'],
            [['desc'], 'string'],
            [['title', 'speed'], 'string', 'max' => 255],
            [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => \app\modules\crud\models\Product::className(), 'targetAttribute' => ['product_id' => 'id']],
            [['machine_id'], 'exist', 'skipOnError' => true, 'targetClass' => \app\modules\crud\models\Machine::className(), 'targetAttribute' => ['machine_id' => 'id']]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => Yii::t('app', 'ID'),
            'machine_id' => Yii::t('app', 'Machine ID'),
            'created' => Yii::t('app', 'Created'),
            'started' => Yii::t('app', 'Started'),
            'completed' => Yii::t('app', 'Completed'),
            'product_id' => Yii::t('app', 'Product ID'),
            'title' => Yii::t('app', 'Title'),
            'qty' => Yii::t('app', 'Qty'),
            'speed' => Yii::t('app', 'Speed'),
            'created_by' => Yii::t('app', 'Created By'),
            'desc' => Yii::t('app', 'Desc'),
        ];
    }
 public function getEqtypeJobs()
    {
        return $this->hasMany(\app\modules\crud\models\EqtypeJob::className(), ['job_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getEqtypes()
    {
        return $this->hasMany(\app\modules\crud\models\Eqtype::className(), ['id' => 'eqtype_id'])->viaTable('eqtype_jobs', ['job_id' => 'id']);
    }

我确切地说,由于 var_dump 的输出导致表单中的POST数据未能加载,或者我的代码中缺少另一个东西,我确切地知道问题是什么?!

所以,我想知道,为什么 load 没有按预期工作? In other words var_dump($model->eqtypes) 打印连词表中存储的值而不是表单中提交的值,然后如果我们能够解决这个问题,为什么关于间接修改的错误消息?

3 回答

  • 0

    您遇到的“间接修改重载属性”的错误是由于您正在尝试修改“__get”魔术方法返回的属性 . 看一下“yii \ db \ BaseActiveRecord”的“__get”,简而言之,它首先检查你的模型是否具有属性“eqtypes”,如果没有检查你的模型关系 .

    如您所知,您无法在帖子中加载模型中的关系并只是保存它 . 我认为在您的解决方案中,您正在超越问题并使您的代码过于复杂 .

    我建议你使用这个模块:https://github.com/cornernote/yii2-linkall安装它并将你的行动改为:

    $model = Job::findOne(['id' => $id]);
        if ($model->load(Yii::$app->request->post())){
            $postData = Yii::$app->request->post();
            $eqtypesIds = $postData['Job']['eqtypes'];
            $eqtypes = \app\models\Eqtype::findAll($eqtypesIds);
            $transaction = Yii::$app->db->beginTransaction();
            $extraColumns = []; // extra columns to be saved to the many to many table
            $unlink = true; // unlink tags not in the list
            $delete = true; // delete unlinked tags
            try {
                $model->linkAll('eqtypes', $eqtypes, $extraColumns, $unlink, $delete);
                $model->save();
    
                $transaction->commit();
            } catch (Exception $e) {
    
                $transaction->rollBack();
    
            }
            return $this->redirect(['index']);
        }
        $eqtypes = \app\models\Eqtype::find()->all();
        return $this->render('eqtype', ['model' => $model, 'eqtypes' => $eqtypes]);
    

    并添加您的工作模型:

    public function behaviors()
    {
        return [
            \cornernote\linkall\LinkAllBehavior::className(),
        ];
    }
    

    如果您不想使用此模块,则应覆盖模型的默认load()和save()方法,以包括加载和保存关系 .

  • 1

    检查你的模型验证rulse和post参数,你的模型是验证ruls?

    if($model->load(Yii::$app->request->post()) && $model->validate())
    {
       echo "<pre>";
       print_r($_POST); // check the post parameter
       exit;    
    }
    else {
       echo "<pre>";
       print_r($model->getErrors());
       exit;
    }
    
  • 0

    我找到了一个解决方案,但我不认为它是直接的解决方案或更好的解决方案 . 它没有应用ORM或activerecords的假定好处 . 解决方案大纲如下所示:

    1.直接从POST中选择多个选择下拉列表中的eqytpes id,如控制器操作中的以下内容:

    public function actionEqtypeCreate($id)
        {
          $eqtypes = \app\modules\crud\models\Eqtype::find()->all();
          $model = Job::findOne(['id' => $id]);  
          if ($model->load(Yii::$app->request->post())){
     // <<<<<<<<<<<<<<<<<<<<<<,*>>>>>>>>>>>>>>>>>>> 
     // Direct Collect the IDs      
            $model->eqtypesIds = Yii::$app->request->post()['Job']['eqtypes'];
     // <<<<<<<<<<<<<<<<<<<<<*>>>>>>>>>>>>>>>>
    
              $model->save();
    
            return $this->redirect(['index']);
          }
          return $this->render('eqtype-create', ['model' => $model, 'eqtypes' => $eqtypes]);
    
    
        }
    
    • 在上一步中,我不得不将新属性添加到名为 eqtypesIds 的作业模型中,以将临时存储在其中 .

    • 在作业模型中,我必须使用 afterSave 回调在结合表 eqtype_jobs 中执行保存选定的 eqtypes ids,如下所示:

    8787

    public function afterSave($insert, $changedAttributes)
            {
             // recal the saved values eqtype_id list to check the absence items of it from the submited and then delete the absence
                $ee = $this->hatEqtypeIdsArray(); // method returns avaialble eqtype_id as array
                //die(var_dump($ee));
                foreach ($ee as $a){
                  if (!in_array($a, $this->eqtypesIds)){
                          $eq = \app\modules\crud\models\EqtypeJob::findOne(['job_id' => $this->id, 'eqtype_id' => $a]);
                          $eq->delete();
                  }
                }
        // adding the ids submitted to the conjunction table.
                foreach ($this->eqtypesIds as $eqtype) {
                    $tag = \app\modules\crud\models\EqtypeJob::findOne(['job_id' => $this->id, 'eqtype_id' => $eqtype]);            
                    if ($tag) {
    
                    }
                    else{
                      $tag = new \app\modules\crud\models\EqtypeJob();
                      $tag->job_id = $this->id;
                      $tag->eqtype_id = $eqtype;
                      $tag->save();
    
                    }
                }
    
                parent::afterSave($insert, $changedAttributes);
            }
    
    • 要在作业模型的任何其他保存过程中使任何错误或错误删除与作业模型关联的eqtypes无效,我必须在模型中使用 beforeSave handler,如下所示:

    545

    public function beforeSave($insert) {
              parent::beforeSave($insert);
              if(is_null($this->eqtypesIds)){// i.e it has no values.
                $this->eqtypesIds = $this->hatEqtypeIdsArray();// get stored values for it
              }....
    

    但是,正如我上面所说,这个解决方案很脏 . 它可能会重复并消耗更多资源 . 例如,假设您只想编辑作业 Headers ,这将导致选择相关的作业eqtypes,然后重新更新它 .

相关问题