8

我在模型的 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()

4

4 回答 4

17

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

步骤 1。向 AR 类添加一个新属性:

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

步骤 2。覆盖 YiiafterFind()并在检索到原始属性后立即存储它们。

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

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

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

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

    }

    return parent::beforeSave();
}
于 2013-08-27T10:09:44.223 回答
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')

于 2016-11-10T12:50:35.573 回答
1

Yii 1.1: yiiframework.com 上的 mod-active-record

带有“ifModified then ...”逻辑的 Yii Active Record 实例和清除gist.github.com 上的依赖项

于 2014-08-19T19:57:51.813 回答
0

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

于 2013-08-27T09:27:21.673 回答