繁体   English   中英

Yii2 //将模型作为模型属性

[英]Yii2 // Model as Model attribute

实际上我在一个项目上工作,我想将所有数据库表都作为模型。 但是现在我停留在某一点。 可以说我有一个“主”表,其中定义了许多不同的关系,如下所示(简单的示例):

人有一颗心; 人类有一个大脑……等等……是否有可能用其他模型填充主模型? 在PHP中看起来像这样:

$human = new Human();
$human->heart = new Heart(); 
$human->brain = new Brain(); 

最后我想说:

$human-save(TRUE);

验证所有关系模型并将所有关系数据和人类对象保存在DB中。

那可能吗? 我在整个互联网上都找不到类似的内容O_o。

非常感谢你!

您可以根据docs覆盖ActiveModel Save方法:

public function save($runValidation = true, $attributeNames = null)
{
    if ($this->getIsNewRecord()) {
        $save = $this->insert($runValidation, $attributeNames);
    } else {
        $save = $this->update($runValidation, $attributeNames) !== false;
    }

    /* Condition Work if heart and brain is also ActiveModel then 
       you can trigger save method on these models as well
       or you can add your custom logic as well.  
    */

    if($this->heart && $this->brain) {
         return $this->heart->save() && $this->brain->save();
    }

    return $save;

}

我建议您采用以下方法:

  1. 假设您具有与嵌套对象的属性名称相同的关系名称(调用$model->link()方法需要一些规则)
  2. 为具有嵌套模型的模型声明通用类(例如ActiveRecordWithNestedModels)
  3. 覆盖通用类方法savevalidate以执行这些操作的级联(使用反射)
  4. 让您的模型继承这个通用类

或者 ,作为压倒一切的另一种validate方法,你可以建立一些适合的实施rules共同类方法。

该通用类如下所示( 这是一个简单的草稿,未经测试,仅用于显示概念 ):

<?php

namespace app\models;

use yii\db\ActiveRecord;

class ActiveRecordWithNestedModels extends ActiveRecord
{

    public function save($runValidation = true, $attributeNames = null)
    {
        $saveResult = parent::save($runValidation, $attributeNames);

        $class = new \ReflectionClass($this);

        foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
            $propertyValue = $property->getValue($this);
            if (!empty($propertyValue) && is_subclass_of($propertyValue, ActiveRecord::className())) {
                /* @var ActiveRecord $nestedModel */
                $nestedModel = $propertyValue;
                $nestedModel->save($runValidation);
                $relation = $property->name;
                $this->link($relation, $nestedModel);
            }
        }

        return $saveResult;
    }

    public function validate($attributeNames = null, $clearErrors = true)
    {
        $class = new \ReflectionClass($this);

        foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
            $propertyValue = $property->getValue($this);
            if (!empty($propertyValue) && is_subclass_of($propertyValue, ActiveRecord::className())) {
                /* @var ActiveRecord $nestedModel */
                $nestedModel = $propertyValue;

                if (!$nestedModel->validate(null, $clearErrors)) {
                    array_push($this->errors, [
                        $property->name => $nestedModel->errors
                    ]);
                }
            }
        }

        parent::validate($attributeNames, $clearErrors);

        if ($this->hasErrors()) return false;

        return true;
    }

}

然后您的模型可以如下所示:

class Heart extends ActiveRecordWithNestedModels
{

}

class Human extends ActiveRecordWithNestedModels
{
    /* @var Heart $heart */
    public $heart = null;

    /**
     * The relation name will be 'heart', same as property `heart'
     *
     * @return \yii\db\ActiveQuery
     */
    public function getHeart()
    {
        return $this->hasOne(Heart::className(), ['id', 'heart_id']);
    }
}

并且(理论上),您可以执行以下操作:

$human = new Human();
$human->heart = new Heart();
$human->save();

此处的PS在进一步的实现中可能包含许多复杂的细节,例如

  • 使用事务回滚save ,如果一些子对象无法保存
  • 覆盖delete
  • 服务one-to-manymany-to-many关系
  • 如果属性没有对应关系,则跳过级联
  • 在级联操作中提供$attributeNames
  • 等等

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM