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

Php Yii2//模型作为模型属性,php,validation,yii2,models,composite,Php,Validation,Yii2,Models,Composite,实际上我在做一个项目,我想把所有的DB表都作为模型。但现在我有一点结巴了。 假设我有一个“主”表,其中定义了许多不同的关系,如下所示(简单示例): 人有一颗心;人类只有一个大脑。。。等等 是否可以用其他模型填充主模型? 在PHP中,它看起来是这样的: $human = new Human(); $human->heart = new Heart(); $human->brain = new Brain(); 最后,我想说: $human-save(TRUE); 验证所有关系模

实际上我在做一个项目,我想把所有的DB表都作为模型。但现在我有一点结巴了。 假设我有一个“主”表,其中定义了许多不同的关系,如下所示(简单示例):

人有一颗心;人类只有一个大脑。。。等等 是否可以用其他模型填充主模型? 在PHP中,它看起来是这样的:

$human = new Human();
$human->heart = new Heart(); 
$human->brain = new Brain(); 
最后,我想说:

$human-save(TRUE);
验证所有关系模型,并将所有关系数据和人类对象保存在数据库中

可能吗?我在整个互联网上都找不到这样的东西


多谢各位

您可以根据以下内容覆盖
ActiveModel
Save
方法:


我建议你采取以下方法:

  • 假设您具有与嵌套对象的属性名称相同的关系名称(调用
    $model->link()
    方法需要一些规则)
  • 为具有嵌套模型的模型声明公共类(例如ActiveRecordWithNestedModels)
  • 在公共类方法中重写
    save
    validate
    以对这些操作执行级联(使用反射)
  • 让您的模型继承这个公共类
  • ,作为重写
    验证
    方法的替代方法,您可以为公共类中的
    规则
    方法构建一些合适的实现

    这个普通类可以如下所示(这是一个简单的草稿,没有经过测试,只是为了展示概念):

    (理论上)你可以做到:

    $human = new Human();
    $human->heart = new Heart();
    $human->save();
    
    p.S.在进一步的实施中,可能会有许多复杂的细节,例如

    • 如果某个子对象保存失败,则使用事务回滚
      保存
    • 覆盖
      delete
    • 服务于
      一对多
      多对多
      关系
    • 如果属性没有对应关系,则跳过级联
    • 在级联操作中提供
      $attributeNames

    如果DB表是模型关系,它们通常也会在所有写入尝试时强制执行,因此我完全不清楚要在何处验证内容。在DB级别,如果支持,我看到的最接近的是事务块(失败或成功)。您正在从Yi框架中搜索方法吗?谢谢。嘿,我会尽量跟你说清楚的。如果我使用“true”参数调用$human->save(true),我将强制执行模型验证。所以我的第一个问题是:如果我在一个模型中有不同的模型(如上面的例子),那么“子模型”也得到验证了吗?第二个问题:我如何访问在模型中拥有模型的目标?我必须在我的主模型和子模型中做什么才能实现这一点?@jiGL yii2中的模型类没有
    save()
    方法。您是在使用ActiveRecord还是其他ORM实现?@Maxim是的,对不起!我的模型继承自ActiveRecord!是 啊这正是我想要的。。。非常感谢。我想这会容易一点,或者类似的东西在yii2中现成存在。无论如何,谢谢你!
    <?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();