ThinkPHP5模型实例详解 / SoftDelet类源码分析

SoftDelet类源码分析

软删除:SoftDelete

软删除其实就是:伪删除,没有真正的删除。正所谓,吃软饭的都是伪男一样的。
 软删除是相对于硬删除来说的,所谓“软”是指删除以后,还可以恢复的。而“硬删除”则是物理删除,是真正的将数据从硬盘上擦掉了。


1. 步骤:总的来说就二步

  1. 在对应的模型类中做好相关的设置工作;
  2. 在控制器中对该模型进行调用。

2. 源码:/thinkphp/library/traits/model/SoftDelete.php

源码中注释是本人单独添加,官方源码中并无这么多的注释

<?phpnamespace traits\model;trait SoftDelete
{/**
     * 判断当前实例是否被软删除
     * @access public
     * @return boolean
     */public function trashed(){   //获取软删除字段名称$field = $this->getDeleteTimeField();//如果当前数据对象的软删除字段为null,则已软删除if (!empty($this->data[$field])) {return true;
        }  //否则返回false,表示没有被软删除return false;
    }/**
     * 查询软删除数据
     * @access public
     * @return \think\db\Query
     */public static function withTrashed(){   //实例化静态调用该方法的类,通常是子类:自定义的模型类,如Staff,User$model = new static();//getDeleteTimeField(true)表示当前为读操作:false表示写操作$field = $model->getDeleteTimeField(true);//在查结结果中,去掉已软删除的记录return $model->db(false)->removeWhereField($field);
    }/**
     * 只查询软删除数据
     * @access public
     * @return \think\db\Query
     */public static function onlyTrashed(){   //实例化静态调用该方法的类$model = new static();//获取软删除字段(true为读操作)$field = $model->getDeleteTimeField(true);//只输出删除字段不为空的数据,其实就是已经软删除的记录:理论上已删除return $model->db(false)->where($field, 'exp', 'is not null');
    }/**
     * 删除当前的记录
     * 此方法会覆盖父类Model类中的delete方法,就是trait类的用处:多继承
     * @access public
     * @param bool  $force 是否强制删除  true:硬删除
     * @return integer
     */public function delete($force = false){if (false === $this->trigger('before_delete', $this)) {return false;
        }$name = $this->getDeleteTimeField();if (!$force) {// 软删除$this->change[]    = $name;$this->data[$name] = $this->autoWriteTimestamp($name);$result            = $this->isUpdate()->save();
        } else {$result = $this->db()->delete($this->data);
        }$this->trigger('after_delete', $this);return $result;
    }/**
     * 删除记录/软删除
     * 该方法同样覆盖父类Model同名方法,用于静态调用
     * @access public
     * @param mixed $data 主键列表 支持闭包查询条件
     * @param bool  $force 是否强制删除
     * @return integer 成功删除的记录数
     */public static function destroy($data, $force = false){   //实例化当前调用类$model = new static();$query = $model->db();if (is_array($data) && key($data) !== 0) {$query->where($data);$data = null;
        } elseif ($data instanceof \Closure) {
            call_user_func_array($data, [ & $query]);$data = null;
        } elseif (is_null($data)) {return 0;
        }$resultSet = $query->select($data);$count     = 0;if ($resultSet) {foreach ($resultSet as $data) {$result = $data->delete($force);$count += $result;
            }
        }return $count;
    }/**
     * 恢复被软删除的记录
     * @access public
     * @param array $where 更新条件
     * 参数为空,则恢复全部被软删除的数据
     * @return integer
     */public function restore($where = []){$name = $this->getDeleteTimeField();// 恢复删除return $this->isUpdate()->save([$name => null], $where);

    }/**
     * 查询默认不包含软删除数据
     * @access protected
     * @param \think\db\Query $query 查询对象
     * @return void
     */protected function base($query){$field = $this->getDeleteTimeField(true);$query->where($field, 'null');
    }/**
     * 获取软删除字段
     * @access public
     * @param bool  $read 是否查询操作 写操作的时候会自动去掉表别名
     * @return string
     */protected function getDeleteTimeField($read = false){   //获取软删除字段名称,如用户没有自定义,则设置成默认值:delete_time$field = isset($this->deleteTime) ? $this->deleteTime : 'delete_time';//判断字段名如果存在'.',则获取表名,并添加到字段前if (!strpos($field, '.')) {$field = $this->db(false)->getTable() . '.' . $field;
        }//写操作时,去掉表名if (!$read && strpos($field, '.')) {$array = explode('.', $field);$field = array_pop($array);
        }//返回软删除字段名称return $field;
    }
}

阅读源码,发现有很多有用的方法,可以供模型类调用!其中的delete和destroy方法,直接拦截了调用Model类的对应方法,实现了软删除,理解这点很重要,这也是trait类的作用之一。


3. 方法总结:

  • 普通方法(public function )
序号名称参数返回值功能
1trashed布尔值判断当前实例是否被软删除
2delete布尔值删除数量删除当前的数据对象
3restore条件表达式恢复数量恢复被软删除的记录
  • 静态方法(public static)
序号名称参数返回值功能
1withTrashedQuery对象查询软删除数据
2onlyTrashedQuery对象只查询软删除数据
3destroy主键/表达多/闭包删除数量删除数据
  • 保护方法(protected function)
序号名称参数返回值功能
1baseQuery对象无定义查询默认不包含软删除数据
2getDeleteTimeField布尔值字段名称获取软删除字段

下一节,我们以实例来详细讲解几个常用方法~~