🗑️ 删除助手

DeleteHelper 是 ThinkAdmin 提供的快捷删除助手,能够根据提交的数据自动执行软删除或硬删除操作,简化数据删除流程。

📚 基础概念

🤔 基本介绍

DeleteHelper(删除助手)是 ThinkAdmin 框架提供的一个工具类,用于简化数据删除操作。

简单理解:就像数据的"删除器",帮你安全地删除数据,支持软删除和硬删除两种方式。

传统方式(不推荐)

// ❌ 传统方式:需要手动处理删除逻辑
public function remove()
{
    $ids = input('id');
    
    // 1. 验证数据
    if (empty($ids)) {
        $this->error('ID 不能为空');
    }
    
    // 2. 安全检查
    if (in_array('10000', str2arr($ids))) {
        $this->error('系统超级账号禁止删除!');
    }
    
    // 3. 批量删除
    $ids = str2arr($ids);
    foreach ($ids as $id) {
        SystemUser::where('id', $id)->delete();
    }
    
    $this->success('删除成功');
}

使用 DeleteHelper(推荐)

// ✅ 使用 DeleteHelper:一行代码完成删除
public function remove()
{
    $this->_checkInput();  // 安全检查
    SystemUser::mDelete();
}

🔄 删除方式

DeleteHelper 支持两种删除方式,各有特点:

软删除(Soft Delete)

不真正删除数据,只是标记为已删除。

工作原理

// 软删除:更新 is_deleted 字段
UPDATE system_user SET is_deleted = 1 WHERE id = 1;
// 数据仍然在数据库中,只是标记为已删除

优点

  • 数据可恢复,安全性高
  • 可以查看删除历史
  • 适合重要数据

缺点

  • 占用数据库空间
  • 查询时需要过滤已删除的数据

使用场景

  • 用户管理:删除用户账号(建议使用软删除)
  • 商品管理:删除商品信息(建议使用软删除)
  • 订单管理:删除订单(建议使用软删除)

硬删除(Hard Delete)

真正从数据库中删除数据。

工作原理

// 硬删除:真正删除数据
DELETE FROM system_user WHERE id = 1;
// 数据从数据库中彻底删除,无法恢复

优点

  • 节省数据库空间
  • 性能更好
  • 数据彻底清除

缺点

  • 数据无法恢复,风险较高
  • 不适合重要数据

使用场景

  • 日志清理:清理过期日志(可以使用硬删除)
  • 临时数据:删除不需要恢复的临时数据
  • 缓存数据:清理缓存数据

🤔 选择建议

DeleteHelper 会自动检测数据表是否有 is_deleteddeleted 字段:

自动检测逻辑

// 1. 检查数据表是否有 is_deleted 或 deleted 字段
if (字段存在) {
    // 使用软删除
    UPDATE table SET is_deleted = 1 WHERE id = ?;
} else {
    // 使用硬删除
    DELETE FROM table WHERE id = ?;
}

实际例子

// 表有 is_deleted 字段 → 自动使用软删除
SystemUser::mDelete();
// 执行:UPDATE system_user SET is_deleted = 1 WHERE id = 1;

// 表没有 is_deleted 字段 → 自动使用硬删除
SystemLog::mDelete();
// 执行:DELETE FROM system_log WHERE id = 1;

📖 相关概念

级联删除

  • 删除主记录时,同时删除关联的子记录
  • 例如:删除用户时,同时删除用户的订单

批量删除

  • 一次性删除多条记录
  • 例如:同时删除多个用户

条件限制

  • 设置删除条件,只删除符合条件的记录
  • 例如:只删除未使用的权限

🎯 使用场景

场景1:用户管理

删除用户账号(建议使用软删除):

public function remove()
{
    // 防止删除系统超级账号
    $this->_checkInput();
    
    // 软删除用户(自动检测 is_deleted 字段)
    SystemUser::mDelete();
}

场景2:商品管理

删除商品信息(建议使用软删除):

public function remove()
{
    // 只删除未上架的商品
    SystemGoods::mDelete('id', ['status' => 0]);
}

场景3:日志清理

清理过期日志(可以使用硬删除):

public function clear()
{
    // 硬删除 30 天前的日志(表没有 is_deleted 字段)
    SystemLog::mDelete('id', [
        'create_at' => ['<', date('Y-m-d H:i:s', strtotime('-30 days'))]
    ]);
}

🚀 主要功能

  • 自动判断: 根据数据自动判断执行软删除或硬删除
  • 简化操作: 无需编写繁琐的删除逻辑
  • 安全删除: 提供安全的数据删除机制
  • 灵活配置: 支持多种删除参数配置
  • 权限控制: 支持删除前的权限检查
  • 数据保护: 防止非法删除操作

📋 删除类型

软删除

  • 特点: 数据不会真正删除,只是标记为已删除
  • 优势: 数据可以恢复,安全性高
  • 适用场景: 重要数据、需要审计的数据

硬删除

  • 特点: 数据从数据库中彻底删除
  • 优势: 节省存储空间,性能更好
  • 适用场景: 临时数据、不需要恢复的数据

⚙️ 使用要求

模型继承

  • 模型必须继承自 \think\admin\Model
  • 确保模型能够利用 DeleteHelper 的快捷删除功能
  • 简化删除操作的实现过程

控制器继承

  • 控制器必须继承自 \think\admin\Controller
  • 方便调用 DeleteHelper 提供的方法
  • 实现数据的快速删除

🔒 安全机制

数据验证

  • 删除前验证: 在删除操作前进行数据验证
  • 权限检查: 结合权限控制机制防止非法删除
  • 条件限制: 通过限定条件确保删除安全

参数配置

  • 主键字段: 指定数据主键字段
  • 限定条件: 设置删除的限定条件
  • 安全筛选: 通过条件筛选确保删除安全

调用快捷删除

// 1.0 模型用法(推荐方式)
// 参数 $field 主键字段,默认自动获取
// 参数 $where 限制条件,安全筛选删除
SystemUser::mDelete(string $field, array $where);

// 1.1 模型通用删除
SystemUser::mDelete();

// 1.2 指定数据主键
SystemUser::mDelete('id');

// 1.3 指定数据主键,指定限定条件
SystemUser::mDelete('id', [
    'is_deleted' => 0,
    'status' => 0,
]);


// 2.0 控制器用法(不推荐,建议使用模型方法)
// 参数 $dbQuery 模型名称
// 参数 $field 主键字段,默认自动获取
// 参数 $where 限制条件,安全筛选删除
$this->_delete('SystemUser', string $field, array $where);

// 2.1 控制器通用删除(不推荐,建议使用模型方法)
$this->_delete('SystemUser');

// 2.2 指定数据主键(不推荐,建议使用模型方法)
$this->_delete('SystemUser', 'id');

// 2.3 指定数据主键,指定限定条件(不推荐,建议使用模型方法)
$this->_delete('SystemUser', 'id', [
    'is_deleted' => 0,
    'status' => 0,
]);

永久 & 硬删除

如果数据表中不存在is_deleteddeleted字段,则为硬删除。

标记 & 软删除

当前数据表中存在is_deleteddeleted字段时,调用DeleteHelper则自动为软删除操作,在列表查询搜索时加上对应的条件就可以显示需要的数据列表。

数据回调处理

对于数据删除操作,Controller 内置了两个回调方法:

// 删除前置操作,允许使用引用更改查询条件
// 参数 $query:查询对象
// 参数 $where:删除条件数组
// 返回 false 时,默认行为将不会再执行
[_ACTION]_delete_filter($query, array &$where)

// 删除后置操作
// 参数 $result:删除结果,成功为 true,失败为 false
// 返回 false 时,默认行为将不会再执行
[_ACTION]_delete_result(bool $result)

回调函数规则说明:

  • [_ACTION] 代表执行的具体动作,例如方法名为 remove 时,[_ACTION] 会被替换为 _remove
  • 如果方法名为 removeAuth,则回调函数名为 _removeAuth_delete_filter_removeAuth_delete_result
  • 通用回调函数名为 _delete_filter_delete_result(不带动作前缀)

完整示例:

<?php
declare(strict_types=1);

namespace app\admin\controller;

use think\admin\Controller;
use think\admin\model\SystemAuth;
use think\admin\model\SystemUser;

/**
 * 系统用户管理
 * @class User
 * @package app\admin\controller
 */
class User extends Controller
{
    /**
     * 删除系统用户(实际项目中的完整示例)
     * @auth true
     */
    public function remove()
    {
        // 安全检查:防止删除系统超级账号
        $this->_checkInput();
        
        // 表单令牌,为防止重复操作,前端使用 data-csrf='{:systoken("remove")}'生成 token
        SystemUser::mDelete();
    }

    /**
     * 检查输入变量(实际项目中的私有方法)
     */
    private function _checkInput()
    {
        // 防止删除系统超级账号(ID 为 10000)
        if (in_array('10000', str2arr(input('id', '')))) {
            $this->error('系统超级账号禁止删除!');
        }
    }
}

/**
 * 系统权限管理
 * @class Auth
 * @package app\admin\controller
 */
class Auth extends Controller
{
    /**
     * 删除系统权限(关联数据清理示例)
     * @auth true
     */
    public function removeAuth()
    {
        $this->_applyFormToken();
        SystemAuth::mDelete();
    }

    /**
     * 删除前置回调(在删除前进行条件过滤)
     * @param $query 查询对象
     * @param array $where 删除条件
     */
    protected function _removeAuth_delete_filter($query, array &$where)
    {
        // 可以修改查询条件,例如只允许删除未使用的权限
        $query->where('status', 0);
        
        // 可以修改删除条件
        // $where['is_deleted'] = 0;
    }

    /**
     * 删除结果处理(实际项目中的后处理示例)
     * @param bool $result 删除结果
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    protected function _removeAuth_delete_result(bool $result)
    {
        if ($result) {
            // 删除关联的权限节点数据
            $where = ['auth' => $this->request->post('id')];
            $this->app->db->name('SystemAuthNode')->where($where)->delete();
            sysoplog('系统权限管理', "删除权限成功");
            $this->success("权限删除成功!", '');
        } else {
            $this->error("权限删除失败,请稍候再试!");
        }
    }
}

如果是在 ThinkAdmin 后台基于 admin.js 的情况下,可使用 data-action 来与 DeleteHelper 配合使用。

🔧 前端配合使用

单条记录删除

<!-- 使用 data-action 属性自动删除单条记录 -->
<button data-action="{:url('remove')}" 
        data-value="{{d.id}}" 
        data-confirm="确认要删除这条记录吗?"
        class="layui-btn layui-btn-sm layui-btn-danger">删除</button>

批量记录删除

<!-- 批量删除多条记录 -->
<button data-action="{:url('remove')}" 
        data-csrf="{:systoken('remove')}" 
        data-rule="id#{key}"
        data-confirm="确认要删除选中的记录吗?"
        class="layui-btn layui-btn-sm layui-btn-danger">批量删除</button>

前端提交格式说明 前端提交上来的主键值支持多个,以英文逗号分隔。表单 CSRF 根据后台是否开启表单令牌而决定要不要配置使用。

格式说明:

  • 单条记录:data-value="1"
  • 多条记录:data-value="1,2,3"
  • 批量操作:data-rule="id#{key}"{key} 会自动搜索表格已选择的 checkbox 值)

表格工具栏配置

<script type="text/html" id="toolbar">
    <!--{if auth('remove')}-->
    <a data-action='{:url("remove")}' 
       data-value="id#{{d.id}}" 
       data-confirm="确认要删除这条记录吗?" 
       class="layui-btn layui-btn-sm layui-btn-danger">删除</a>
    <!--{/if}-->
</script>

DeleteHelper 深入应用

1. 软删除和硬删除

<?php
declare(strict_types=1);

namespace app\admin\controller;

use think\admin\Controller;
use think\admin\model\SystemUser;
use think\facade\Db;

class User extends Controller
{
    /**
     * 软删除用户(推荐方式)
     * @auth true
     */
    public function remove()
    {
        // 使用软删除,只更新 is_deleted 字段
        SystemUser::mDelete();
    }

    /**
     * 硬删除用户(物理删除)
     * @auth true
     */
    public function forceRemove()
    {
        $ids = str2arr(input('id', ''));
        
        // 开启事务
        Db::startTrans();
        try {
            foreach ($ids as $id) {
                // 删除关联数据
                $this->app->db->name('SystemUserAuth')->where('uuid', $id)->delete();
                
                // 物理删除用户
                SystemUser::mk()->where('id', $id)->delete();
            }
            
            Db::commit();
            sysoplog('系统用户管理', "硬删除用户成功");
            $this->success('删除成功!');
        } catch (\Exception $e) {
            Db::rollback();
            $this->error('删除失败:' . $e->getMessage());
        }
    }
}

2. 级联删除处理

protected function _remove_filter(array &$data)
{
    // 删除前的验证和处理
    foreach ($data as $id) {
        $user = SystemUser::mk()->find($id);
        if (empty($user)) {
            continue;
        }
        
        // 检查是否可以删除
        if ($user['id'] == '10000') {
            $this->error('系统超级账号禁止删除!');
        }
        
        // 检查是否有关联数据
        $authCount = $this->app->db->name('SystemUserAuth')
            ->where('uuid', $id)
            ->count();
        
        if ($authCount > 0) {
            $this->error("用户[{$user['username']}]存在关联数据,无法删除!");
        }
    }
}

protected function _remove_delete_result(bool $result)
{
    if ($result) {
        $ids = str2arr(input('id', ''));
        
        // 删除关联数据
        foreach ($ids as $id) {
            // 删除用户权限关联
            $this->app->db->name('SystemUserAuth')
                ->where('uuid', $id)
                ->delete();
            
            // 删除用户操作日志(可选)
            // $this->app->db->name('SystemOplog')
            //     ->where('username', $user['username'])
            //     ->delete();
        }
        
        sysoplog('系统用户管理', "删除用户成功");
        $this->success('删除成功!');
    }
}

3. 批量删除优化

public function batchRemove()
{
    $ids = str2arr(input('id', ''));
    if (empty($ids)) {
        $this->error('请选择要删除的记录!');
    }
    
    // 开启事务
    Db::startTrans();
    try {
        // 批量删除(使用 whereIn 提高性能)
        SystemUser::mk()
            ->whereIn('id', $ids)
            ->where('is_deleted', 0)
            ->where('id', '<>', '10000')  // 防止删除超级账号
            ->update(['is_deleted' => 1]);
        
        // 删除关联数据
        $this->app->db->name('SystemUserAuth')
            ->whereIn('uuid', $ids)
            ->delete();
        
        Db::commit();
        sysoplog('系统用户管理', "批量删除用户成功");
        $this->success('批量删除成功!');
    } catch (\Exception $e) {
        Db::rollback();
        $this->error('批量删除失败:' . $e->getMessage());
    }
}

4. 条件限制删除

public function remove()
{
    // 非超级管理员只能删除自己的数据
    $where = ['is_deleted' => 0];
    if (!AdminService::isSuper()) {
        $where['uuid'] = AdminService::getUserId();
    }
    
    SystemUser::mDelete('', $where);
}

5. 删除性能优化

// ❌ 不推荐:循环删除
foreach ($ids as $id) {
    SystemUser::mk()->where('id', $id)->delete();
}

// ✅ 推荐:批量删除
SystemUser::mk()
    ->whereIn('id', $ids)
    ->delete();

// 使用索引字段进行查询
SystemUser::mk()
    ->where('id', $id)  // id 是主键,有索引
    ->where('is_deleted', 0)  // 如果 is_deleted 有索引,查询更快
    ->delete();
最近更新:
Contributors: 邹景立, Anyon