Search code examples
phploggingyii2audit-trail

Yii2 Duplication of Model - row


when a model attributes are edited or updated I do not want that record to updated. Instead a new record should be created and the old record should be disabled. Also I have another log table where the old record is saved.

My code is given below

public function afterSave($insert, $changedAttributes)
{


  if ($insert) {
           // Да это новая запись (insert)
            $model = new Test3log();
            $model->desc = $this->desc ;
            $model->id_old = $this->id;
            $model->isdisabled=1;
            $model->save();
        } else {

            $save = "";
            foreach ($changedAttributes as $change => $val) {
                if (trim($val) != trim($this->{$change})) {
                    $save .= $this->attributeLabels()[$change] . '[' . $val . '->' . $this->{$change} . "]\n";
                }
            }
            $xx =$this->getoldattributes();
            if ($save != "") {
                 //  Get Old data
                 // Get New data
                 // repl new record with old id
                 // repl old record with new id
                $modelnewline = new Test3();
                $modelnewline->desc = $xx['desc'];
                $modelnewline->id_old = $xx['id'];
                $modelnewline->id = NULL;
                $modelnewline->isdisabled = 1;
                $modelnewline->save();
                $newid = $modelnewline->id;
                $oldid =$this->id;
                $this->isdisabled=1;
                $this->id = $newid;
                $this->desc = $changedAttributes['desc'];
                $this->save(false);

             }
        }
        parent::afterSave($insert, $changedAttributes);
    }

Solution

  • Above all, the problem you described needs to be implemented in your model's beforeSave() which is called at the beginning of inserting or updating a record, rather than afterSave() as your record will already be updated with the new values and you definitely don't want to do that.

    As per your requirements.

    when a model attributes are edited or updated I do not want that record to be updated. Instead, a new record should be created and the old record should be disabled. Also, I have another log table where the old record is saved.

    So there are 3 main things when attributes change for the existing record

    • Disable the current record by updating status to 0.
    • Add a new Record holding the new values.
    • Add a new Record with the old values inside the backup or logs table.

    I will not be adding the actual code as there isn't much information available regarding what models are interacted so looking at the requirements i will use the scenario where i will assume that i have books and whenever the name of the book is changed or updated it should add a new record with the new values and keep the old record as is changing the status column to 0 so that the book is disabled and backup the old values to BooksBackup table. So basically you will have a wireframe to adjust your code accordingly.

    You can use the logic according to the models that you are using.

    Below is the sample schema

    • Books model

    • name varchar(255)

    • status tinyint(1)

    • BooksBackup model

    • id int(11)

    • book_id int(11)

    • name varchar(255)

    I will add the following beforeSave() function in my Books Model

    public function beforeSave($insert) {
        if( !parent::beforeSave($insert) ){
            return false;
        }
    
        //your custom code
        if( !$insert ){
    
            $ifAttributesChanged = (!empty($this->dirtyAttributes) );
    
            //if attributes were changed
            if( $ifAttributesChanged ){
    
                //add new record with the new values
                $book = new self();
                $book->attributes = $this->attributes;
                $book->save();
    
                //add back the old values of the changed attributes 
                //to the current record so nothing is changed for the current record
                foreach( $this->dirtyAttributes as $attribute => $value ){
                    $this->$attribute = $this->oldAttributes[$attribute];
                }
    
                //disable the current record
                $this->status = 0;
    
                //backup old record
                $backup = new BackupBooks();
                $backup->book_id = $this->id;
                $backup->name = $this->name;
                $backup->save();
            }
        }
        return true;
    }