💾 更新助手
SaveHelper 是 ThinkAdmin 提供的数据更新助手,专注于简化数据状态的更新操作,如数据禁用、启用以及状态更改等。通过简洁的接口和直观的操作,快速实现数据状态的更新。
📚 基础概念
🤔 基本介绍
SaveHelper(更新助手)是 ThinkAdmin 框架提供的一个工具类,专门用于快速更新数据记录的状态或字段值。
简单理解:就像数据的"状态切换器",帮你快速更新数据的状态,如启用/禁用、上架/下架等。
传统方式(不推荐):
// ❌ 传统方式:需要手动处理更新逻辑
public function state()
{
$ids = input('id');
$status = input('status');
// 1. 验证数据
if (empty($ids)) {
$this->error('ID 不能为空');
}
if (!in_array($status, [0, 1])) {
$this->error('状态值范围异常');
}
// 2. 批量更新
$ids = str2arr($ids);
foreach ($ids as $id) {
SystemUser::where('id', $id)->update(['status' => $status]);
}
$this->success('更新成功');
}使用 SaveHelper(推荐):
// ✅ 使用 SaveHelper:一行代码完成更新
public function state()
{
SystemUser::mSave($this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]));
}🤔 使用优势
问题1:代码重复
不使用 SaveHelper 时,每个状态更新都需要重复编写相同的逻辑:
// ❌ 每个状态更新都要写这些代码
$ids = input('id');
$status = input('status');
// 验证、更新、返回结果... 大量重复代码问题2:容易出错
手动处理更新逻辑容易出错:
// ❌ 容易出错:忘记验证、忘记处理条件等
$ids = input('id');
SystemUser::whereIn('id', $ids)->update(['status' => $status]);
// 没有验证,可能更新错误的数据问题3:维护困难
当需要修改更新逻辑时,需要在多个地方修改:
// ❌ 需要在多个控制器中修改相同的逻辑
// UserController.php
SystemUser::whereIn('id', $ids)->update(['status' => $status]);
// OrderController.php
SystemOrder::whereIn('id', $ids)->update(['status' => $status]);
// 重复代码使用 SaveHelper 的优势:
// ✅ 统一接口,代码简洁
SystemUser::mSave($this->_vali([...]));
SystemOrder::mSave($this->_vali([...]));🎯 核心功能
功能1:快速更新
一行代码完成数据更新:
// 更新用户状态
SystemUser::mSave($this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]));功能2:批量操作
支持批量更新多条记录:
// 批量更新用户状态
// POST 数据:id=1,2,3&status=1
SystemUser::mSave($this->_vali([
'status.require' => '状态值不能为空!',
]));
// 自动更新 id=1,2,3 的用户状态为 1功能3:条件限制
支持设置更新条件,确保数据安全:
// 只更新未删除的记录
SystemUser::mSave(
$this->_vali([...]),
'id',
['is_deleted' => 0] // 更新条件
);功能4:回调处理
支持前置和后置回调,处理业务逻辑:
// 前置回调:更新前处理
protected function _save_filter($query, array &$data)
{
// 验证和处理数据
}
// 后置回调:更新后处理
protected function _save_result(bool $result)
{
// 处理更新结果
}📖 相关概念
状态字段
- 用于标识数据状态的字段
- 例如:
status(0=禁用,1=启用)
批量更新
- 一次性更新多条记录
- 例如:同时更新多个用户的状态
条件限制
- 设置更新条件,只更新符合条件的记录
- 例如:只更新未删除的记录
🎯 使用场景
场景1:用户管理
启用/禁用用户账号:
public function state()
{
SystemUser::mSave($this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]));
}场景2:商品管理
上架/下架商品:
public function state()
{
SystemGoods::mSave($this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]), 'id', ['is_deleted' => 0]);
}场景3:订单管理
审核通过/拒绝订单:
public function audit()
{
SystemOrder::mSave($this->_vali([
'audit_status.require' => '审核状态不能为空!',
'audit_status.in:1,2' => '审核状态范围异常!',
]));
}场景4:内容管理
发布/隐藏文章:
public function publish()
{
SystemArticle::mSave($this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]));
}🚀 主要功能
- 状态更新: 快速更新数据状态(启用/禁用等)
- 批量处理: 支持批量更新多条数据记录
- 安全验证: 完善的数据验证和权限控制
- 错误处理: 详细的错误处理和日志记录
- 事务支持: 支持数据库事务操作
📋 使用场景
- 用户状态管理(启用/禁用用户)
- 商品状态管理(上架/下架商品)
- 订单状态管理(处理/完成订单)
- 内容状态管理(发布/隐藏内容)
- 批量数据操作
⚙️ 工作原理
数据定位
- 根据传入的数据 ID 和条件自动定位数据记录
- 支持主键字段和自定义查询条件
- 确保数据操作的安全性和准确性
- 支持批量数据定位
状态更新
- 提供清晰的状态选项供用户选择
- 自动执行状态更新操作
- 支持单条和批量数据更新
- 支持自定义状态值
安全保护
- 数据验证和权限控制
- 防止恶意数据修改
- 详细的操作日志记录
- 支持操作权限验证
事务处理
- 支持数据库事务操作
- 确保数据一致性
- 支持回滚机制
- 异常处理机制
具体实现原理
为了充分利用 SaveHelper 数据更新助手在模型(Model)和控制器(Controller)中的功能,系统进行了以下优化:
- 模型继承:若需在模型中使用 SaveHelper 快捷查询器,该模型应继承
\think\admin\Model类。这样做可以确保模型拥有 SaveHelper 提供的所有功能,方便进行数据的快速保存和查询操作。 - 控制器继承:对于需要使用 SaveHelper 快捷查询器的控制器,应继承
\think\admin\Controller类。通过继承这个基类,控制器可以方便地调用 SaveHelper 的相关方法,实现对数据的快速处理和响应。 - 前端数据传递:前端需要传递需要修改的数据 ID 以及数据状态值给后端。为了确保数据的安全性和准确性,强烈建议前端传递第二个参数(如操作类型、验证信息等)。这样可以为后端提供更多的上下文信息,有助于后端进行更精确的数据处理和验证。
- 数据安全考虑:为了防止数据被恶意修改,使用 SaveHelper 时指定第二个参数是非常必要的。此外,还可以结合验证器
_vali()和限定条件$where变量来进一步确保数据的安全性。验证器可以对数据进行严格的校验,确保只有符合规则的数据才能被保存;而$where变量则可以限制操作的范围,防止对不应修改的数据进行操作。
通过以上优化,SaveHelper 快捷查询器在模型和控制器中的使用变得更加灵活和安全,同时前端传递的数据也得到了更好的处理和验证,提升了整个系统的稳定性和安全性。
// 1.0 模型用法
// 参数 $data 为待修改数据
// 参数 $field 为主键字段
// 参数 $where 为修改查询条件
SystemUser::mSave($data, $field, $where);
// 1.1 模型通用更新
SystemUser::mSave();
// 1.2 配合验证器使用(推荐方式)
SystemUser::mSave($this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]));
// 1.3 配置验证器和限制条件
SystemUser::mSave($this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]), 'id', [
'is_deleted' => 0,
'status' => 1,
]);
// 2.0 控制器用法(不推荐,建议使用模型方法)
// 参数 $dbQuery 为模型名称
// 参数 $data 为待修改数据
// 参数 $field 为主键字段
// 参数 $where 为修改查询条件
$this->_save('SystemUser', $data, $field, $where);
// 2.1 通用修改器(不推荐,建议使用模型方法)
$this->_save('SystemUser');
// 2.2 配合验证器使用(不推荐,建议使用模型方法)
$this->_save('SystemUser', $this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]));数据回调处理
对于数据更新操作,Controller 内置了两个回调方法:
// 更新前置操作,允许使用引用更改查询条件和数据
// 参数 $query:查询对象
// 参数 $data:待更新的数据数组
// 返回 false 时,默认行为将不会再执行
[_ACTION]_save_filter($query, array &$data)
// 更新后置操作
// 参数 $result:更新结果,成功为 true,失败为 false
// 返回 false 时,默认行为将不会再执行
[_ACTION]_save_result(bool $result)实际应用案例
<?php
declare(strict_types=1);
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\model\SystemUser;
/**
* 系统用户管理
* @class User
* @package app\admin\controller
*/
class User extends Controller
{
/**
* 修改数据状态
* @auth true
*/
public function state()
{
// 实际项目中的安全检查示例
$this->_checkInput();
SystemUser::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 检查输入变量(实际项目中的私有方法示例)
*/
private function _checkInput()
{
// 防止删除系统超级账号
if (in_array('10000', str2arr(input('id', '')))) {
$this->error('系统超级账号禁止删除!');
}
}
/**
* 更新前置回调(在更新前进行数据过滤)
* @param $query 查询对象
* @param array $data 待更新的数据
*/
protected function _save_filter($query, array &$data)
{
// 可以修改查询条件
$query->where('is_deleted', 0);
// 可以修改待更新的数据
if (isset($data['status'])) {
// 添加额外的数据
$data['update_at'] = date('Y-m-d H:i:s');
}
}
/**
* 更新后置回调(通用回调)
* @param bool $result 更新结果
*/
protected function _save_result(bool $result)
{
if ($result) {
sysoplog('系统用户管理', '更新用户状态成功');
}
}
/**
* 当一个控制器存在多个 save 操作时,可以指定回调前缀
* @param bool $result 更新结果
*/
protected function _state_save_result(bool $result)
{
// 可以根据 $result 状态返回结果
// 失败 $this->error(MESSAGE);
// 成功 $this->success(MESSAGE);
}
}
如果是在 `ThinkAdmin` 后台基于 `admin.js` 的情况下,可使用 `data-action` 来与 `SaveHelper` 配合使用。
## 🔧 前端配合使用
**自动状态更新**
```html
<!-- 使用 data-action 属性自动更新状态 -->
<button data-action="{:url('save')}"
data-value="id#{{d.id}};status#1"
data-confirm="确认要启用这条记录吗?"
class="layui-btn layui-btn-sm">启用</button>批量状态更新
<!-- 批量更新多条记录 -->
<button data-action="{:url('save')}"
data-value="id#1,2,3;status#1"
data-confirm="确认要批量启用这些记录吗?"
class="layui-btn layui-btn-sm">批量启用</button>前端提交格式说明 前端提交上来的内容 data-value 支持多组数据,以英文分号 ; 分隔,键与值以英文 # 分隔,如:data-value="id#1;status#0;"
格式说明:
- 单条记录:
data-value="id#1;status#0" - 多条记录:
data-value="id#1,2,3;status#1"
SaveHelper 深入应用
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 batchState()
{
$data = $this->_vali([
'ids.require' => '用户ID不能为空!',
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]);
// 开启数据库事务
Db::startTrans();
try {
// 批量更新用户状态
SystemUser::mk()
->whereIn('id', str2arr($data['ids']))
->where('is_deleted', 0)
->update(['status' => $data['status']]);
// 记录操作日志
sysoplog('系统用户管理', "批量更新用户状态[{$data['status']}]");
// 提交事务
Db::commit();
$this->success('批量更新成功!');
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
$this->error('批量更新失败:' . $e->getMessage());
}
}
}2. 复杂业务逻辑处理
protected function _save_filter(array &$data)
{
// 业务规则验证
if (!empty($data['id'])) {
$user = SystemUser::mk()->find($data['id']);
if (empty($user)) {
$this->error('用户不存在!');
}
// 状态变更时的特殊处理
if ($user['status'] != $data['status']) {
// 禁用用户时,清除登录会话
if ($data['status'] == 0) {
$this->app->session->delete("user_{$data['id']}");
}
// 记录状态变更日志
sysoplog('系统用户管理', "用户[{$user['username']}]状态变更为[{$data['status']}]");
}
}
}
protected function _save_result(bool $result)
{
if ($result) {
// 触发用户状态变更事件
$this->app->event->trigger('PluginAdminUserStatusChange', [
'id' => input('id'),
'status' => input('status'),
]);
}
}3. 条件限制和权限控制
public function save()
{
// 非超级管理员只能更新自己的数据
$where = [];
if (!AdminService::isSuper()) {
$where['uuid'] = AdminService::getUserId();
}
SystemUser::mSave(
$this->_vali([
'status.require' => '状态值不能为空!',
'status.in:0,1' => '状态值范围异常!',
]),
'id',
$where
);
}4. 性能优化建议
// 批量更新时,使用 whereIn 而不是循环更新
// ❌ 不推荐:循环更新
foreach ($ids as $id) {
SystemUser::mk()->where('id', $id)->update(['status' => 1]);
}
// ✅ 推荐:批量更新
SystemUser::mk()
->whereIn('id', $ids)
->update(['status' => 1]);
// 使用索引字段进行查询
SystemUser::mk()
->where('id', $id) // id 是主键,有索引
->where('status', 1) // 如果 status 有索引,查询更快
->update(['status' => 0]);- 多字段更新:
data-value="id#1;status#1;name#test"
