Home » Php » php – Yii on update, detect if a specific AR property has been changed on beforeSave()

php – Yii on update, detect if a specific AR property has been changed on beforeSave()

Posted by: admin July 12, 2020 Leave a comment


I am raising a Yii event on beforeSave of the model, which should only be fired if a specific property of the model is changed.

The only way I can think of how to do this at the moment is by creating a new AR object and querying the DB for the old model using the current PK, but this is not very well optimized.

Here’s what I have right now (note that my table doesn’t have a PK, that’s why I query by all attributes, besides the one I am comparing against – hence the unset function):

public function beforeSave()
    if(!$this->isNewRecord){ // only when a record is modified
        $newAttributes = $this->attributes;
        $oldModel = self::model()->findByAttributes($newAttributes);

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

Is there a better approach? Maybe storing the old properties in a new local property in afterFind()?

How to&Answers:

You need to store the old attributes in a local property in the AR class so that you can compare the current attributes to those old ones at any time.

Step 1. Add a new property to the AR class:

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

Step 2. Override Yii’s afterFind() and store the original attributes immediately after they are retrieved.

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

Step 3. Compare the old and new attributes in beforeSave/afterSave or anywhere else you like inside the AR class. In the example below we are checking if the property called ‘level’ is changed.

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

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


    return parent::beforeSave();


Just in one line

$changedArray = array_diff_assoc($this->attributes,

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

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


In your case you want to use if($key==’level’) inside of foreach


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

or Yii Active Record instance with “ifModified then …” logic and dependencies clearing at gist.github.com


You can store old properties with hidden fields inside update form instead of loading model again.