2013-08-27 28 views
6

我的模型,如果模型的特定属性的改变只应被解雇的beforeSave养的Yii事件。的Yii上更新,检测一个特定的AR属性已在beforeSave改变()

我能想到的是如何做到这一点在目前的唯一方法是通过创建一个新的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()的新本地属性中?

回答

12

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

的这的确是唯一的“干净”的方式做到这一点Yii中。我所做的是实现派生的ActiveRecord,该功能内置了该功能,并使其可用于我的所有模型。每次再做一次都要容易得多。我也给了它像“getIsChanged()”和“getChangedProperties()”等方法。 – Blizz

0

你可以再次更新形式,而不是加载模型里面隐藏字段老性存储。

0

只要在一行

$ changedArray和array_diff_assoc =($这 - >属性, $这 - > oldAttributes);

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

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

} 

你的情况,你要使用如果($键==“级别”)内的foreach