ThinkPHP5模型实例详解
/ SoftDelet类源码分析
SoftDelet类源码分析
软删除:SoftDelete
软删除其实就是:伪删除,没有真正的删除。正所谓,吃软饭的都是伪男一样的。
软删除是相对于硬删除来说的,所谓“软”是指删除以后,还可以恢复的。而“硬删除”则是物理删除,是真正的将数据从硬盘上擦掉了。
1. 步骤:总的来说就二步
- 在对应的模型类中做好相关的设置工作;
- 在控制器中对该模型进行调用。
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 )
序号 | 名称 | 参数 | 返回值 | 功能 |
---|---|---|---|---|
1 | trashed | 无 | 布尔值 | 判断当前实例是否被软删除 |
2 | delete | 布尔值 | 删除数量 | 删除当前的数据对象 |
3 | restore | 条件表达式 | 恢复数量 | 恢复被软删除的记录 |
- 静态方法(public static)
序号 | 名称 | 参数 | 返回值 | 功能 |
---|---|---|---|---|
1 | withTrashed | 无 | Query对象 | 查询软删除数据 |
2 | onlyTrashed | 无 | Query对象 | 只查询软删除数据 |
3 | destroy | 主键/表达多/闭包 | 删除数量 | 删除数据 |
- 保护方法(protected function)
序号 | 名称 | 参数 | 返回值 | 功能 |
---|---|---|---|---|
1 | base | Query对象 | 无定义 | 查询默认不包含软删除数据 |
2 | getDeleteTimeField | 布尔值 | 字段名称 | 获取软删除字段 |
下一节,我们以实例来详细讲解几个常用方法~~