Yii: Soft delete behavior

In general I don’t physically delete records in database. I use soft delete, so that data are easier to recover and re-instate.

However, soft delete is not available in Yii. Codes generated by Gii physically deletes a record.

The code in this post is based on this forum post and the code for CTimestampBehavior. It will timestamp a deleted field to mark it’s deleted. By default the field name is delete_time but can be set to a different name.

Create a Soft Delete Behavior

create a new file in /path/to/protected/components/behaviors/SoftDeleteBehavior.php:

class SoftDeleteBehavior extends CActiveRecordBehavior {
    public $deleteAttribute = 'deleted_time';
    public $timestampExpression = null;
 
    public function beforeDelete($event) {
        if ($this->deleteAttribute !== null) {
            $this->getOwner()->{$this->deleteAttribute} = $this->getTimestampByAttribute($this->deleteAttribute);
            $this->getOwner()->save();
 
            // prevent real deletion of record from database
            $event->isValid = false;
        }
    }
 
    // copy codes from the same function names from
    // /path/to/framework/zii/behaviors/CTimestampBehavior.php
    protected function getTimestampByAttribute($attribute) {
        // paste function code here
    }
    protected function getTimestampByColumnType($columnType) {
        // paste function code here
    }
}

Add a behavior to ActiveRecord

in /path/to/protected/models/Model.php:

class <name of model> extends CActiveRecord {
    public function behaviors {
        return array(
            'SoftDeleteBehavior' => array(
                'class' => 'application.components.behaviors.SoftDeleteBehavior',
                'deleteAttribute' => 'deleted_date', // optional, default is 'deleted_time'
                'timestampExpression' => 'date("Y-m-d H:i:s");',
            ),
        );
    }
}

Re-instating deleted record

add a reinstate function to the behavior defined above:

class SoftDeleteBehavior extends CActiveRecordBehavior {
    ....
    function reinstate() {
        if ($this->deleteAttribute !== null) {
            if ($this->getOwner()->{$this->deleteAttribute} !== null) {
                $this->getOwner()->{$this->deleteAttribute} = null;
                $this->getOwner()->save();
            }
        }
    }
    ....
}

In controller file, add a new reinstate action:

class MyController extends Controller {
    public function actionReinstate($id) {
        $this->loadModel($id)->reinstate();
    }
}

Notes

This has not been tested with deleting multiple records.

I’m still not proficient with Yii. appreciated any comments and feedback to improve codes in this post, or if there’s a better way to do this.

Leave a Reply

Your email address will not be published. Required fields are marked *