## 软删除:SoftDelete >[info] 软删除其实就是:伪删除,没有真正的删除。正所谓,吃软饭的都是伪男一样的。 软删除是相对于硬删除来说的,所谓“软”是指删除以后,还可以恢复的。而“硬删除”则是物理删除,是真正的将数据从硬盘上擦掉了。 * * * * * #### 1. 步骤:总的来说就二步 1. 在对应的模型类中做好相关的设置工作; 2. 在控制器中对该模型进行调用。 * * * * * #### 2. 源码:/thinkphp/library/traits/model/SoftDelete.php >[info] 源码中注释是本人单独添加,官方源码中并无这么多的注释 ~~~ <?php namespace 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; } } ~~~ >[warning] 阅读源码,发现有很多有用的方法,可以供模型类调用!其中的delete和destroy方法,直接拦截了调用Model类的对应方法,实现了软删除,理解这点很重要,这也是trait类的作用之一。 * * * * * #### 3. 方法总结: * 普通方法(public function ) | 序号 | 名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | --- | | 1 | trashed | 无 | 布尔值 | 判断当前实例是否被软删除 | | 2 | delete | 布尔值 | 删除数量 | 删除当前的数据对象 | | 3 | restore | 条件表达式 | 恢复数量 | 恢复被软删除的记录 | * 静态方法(public static) | 序号 | 名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | --- | | 1 | withTrashed | 无 | Query对象 | 查询软删除数据 | | 2 | onlyTrashed | 无 | Query对象 | 只查询软删除数据 | | 3 | destroy | 主键/表达多/闭包 | 删除数量 | 删除数据 | * 保护方法(protected function) | 序号 | 名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | --- | | 1 | base | Query对象 | 无定义 | 查询默认不包含软删除数据 | | 2 | getDeleteTimeField| 布尔值 | 字段名称 | 获取软删除字段| * * * * * >[success] 下一节,我们以实例来详细讲解几个常用方法~~