Php Yii更新时,检测beforeSave()上的特定AR属性是否已更改

Php Yii更新时,检测beforeSave()上的特定AR属性是否已更改,php,yii,before-save,Php,Yii,Before Save,我在模型的beforeSave上引发了一个Yii事件,仅当模型的特定属性发生更改时才应激发该事件 public function beforeSave() { if(isset($this->oldAttributes['level']) && $this->level != $this->oldAttributes['level']){ // The attribute is changed. Do something her

我在模型的beforeSave上引发了一个Yii事件,仅当模型的特定属性发生更改时才应激发该事件

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

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

    }

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

下面是我现在拥有的(请注意,我的表没有PK,这就是为什么除了我要比较的属性之外,我还按所有属性进行查询-因此使用了
unset
函数):


有更好的方法吗?可能将旧属性存储在
afterFind()中的新本地属性中

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

您需要将旧属性存储在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();
}
在yiiframework.com

或者在gist.github.com上

只需一行

$changedArray=array\u diff\u assoc($this->attributes, $this->oldAttributes)

在您的例子中,您希望在foreach内部使用if($key=='level')这确实是在Yii中唯一“干净”的方法。我所做的是实现一个派生的ActiveRecord,该ActiveRecord内置了该功能,并可用于我的所有模型。比每次都做一次容易多了。我还为它提供了“getIsChanged()”和“getChangedProperties()”等方法。
foreach($changedArray as $key => $value){

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

}