Yii 更新时,检测是不是在 beforeSave() 上更改了特定的 AR 属性

Posted

技术标签:

【中文标题】Yii 更新时,检测是不是在 beforeSave() 上更改了特定的 AR 属性【英文标题】:Yii on update, detect if a specific AR property has been changed on beforeSave()Yii 更新时,检测是否在 beforeSave() 上更改了特定的 AR 属性 【发布时间】:2013-08-27 09:16:36 【问题描述】:

我在模型的 beforeSave 上引发了一个 Yii 事件,只有在模型的特定属性发生更改时才会触发该事件。

目前我能想到的唯一方法是创建一个新的 AR 对象并使用当前 PK 查询旧模型的数据库,但这并没有得到很好的优化。

这就是我现在所拥有的(请注意,我的表没有 PK,这就是我查询所有属性的原因,除了我要比较的属性 - 因此是 unset 函数):

public function beforeSave()

    if(!$this->isNewRecord) // only when a record is modified
        $newAttributes = $this->attributes;
        unset($newAttributes['level']);
        $oldModel = self::model()->findByAttributes($newAttributes);

        if($oldModel->level != $this->level)
            // Raising event here
    
    return parent::beforeSave();

有没有更好的方法?也许将旧属性存储在 afterFind() 的新本地属性中?

【问题讨论】:

【参考方案1】:

您需要将旧属性存储在 AR 类的本地属性中,以便您可以随时将当前属性与旧属性进行比较。

第 1 步。向 AR 类添加新属性:

// Stores old attributes on afterFind() so we can compare
// against them before/after save
protected $oldAttributes;

第 2 步。覆盖 Yii 的afterFind() 并在检索到原始属性后立即存储。

public function afterFind()
    $this->oldAttributes = $this->attributes;
    return parent::afterFind();

第 3 步。比较 beforeSave/afterSave 或 AR 类中您喜欢的任何其他地方的新旧属性。在下面的示例中,我们正在检查名为 'level' 的属性是否已更改。

public function beforeSave()

    if(isset($this->oldAttributes['level']) && $this->level != $this->oldAttributes['level'])

            // The attribute is changed. Do something here...

    

    return parent::beforeSave();

【讨论】:

这确实是 Yii 中唯一“干净”的方式。我所做的是实现一个派生的 ActiveRecord,它内置了该功能,并使其可用于我的所有模型。比每次都做一遍容易得多。我还给了它“getIsChanged()”和“getChangedProperties()”等方法。【参考方案2】:

就在一行

$changedArray = array_diff_assoc($this->attributes, $this->oldAttributes);

foreach($changedArray as $key => $value)

  //What ever you want 
  //For attribute use $key
  //For value use $value


在您的情况下,您想在 foreach 中使用 if($key=='level')

【讨论】:

【参考方案3】:

Yii 1.1: mod-active-record@yiiframework.com

或Yii Active Record instance with "ifModified then ..." logic and dependencies clearing gist.github.com

【讨论】:

【参考方案4】:

您可以在更新表单中存储带有隐藏字段的旧属性,而不是再次加载模型。

【讨论】:

以上是关于Yii 更新时,检测是不是在 beforeSave() 上更改了特定的 AR 属性的主要内容,如果未能解决你的问题,请参考以下文章

Yii2 ActiveRecord save失败

Parse Serve 成功 beforeSave 为某些用户返回“找不到对象”错误

解析云代码之前保存未在更新时运行

Yii2 - ActiveRecord 到数组

如果使用 Parse 主密钥,是不是可以检查 beforeSave 方法内部?

有没有办法在 cakePHP 中将数据从 beforeSave() 传递到 afterSave()?