本文实例代码是基于当下最新的tp版本(8.0.3),应该也适用于tp5 和 tp6,如有需要自行按照本文思路进行实践验证即可。
ThinkPHP 官网地址:https://www.thinkphp.cn/
ThinkPHP8 官方手册:https://doc.thinkphp.cn/v8_0/preface.html
ThinkPHP6 官方手册:https://doc.thinkphp.cn/v6_1/default.html
ThinkPHP5.1 官方手册:https://doc.thinkphp.cn/v5_1/default.html
ThinkPHP5.0 官方手册:https://doc.thinkphp.cn/v5_0/default.html
下图是截取自tp8官网手册的介绍:
本文只介绍如下规则:
上面截图中的其他规则目前还没有应用场景,暂不做分享。
‘field’ => ‘unique:tableName,field,except,pk’
注意:unique:tableName,field,except,pk 之间不能存在任何空格,尤其是逗号(,)后面一定不能有空格!!!
以数据迁移 migrate
的方式创建数据表,以及通过 seed
插入测试数据。具体操作步骤本站另外一篇文章《tp8 数据迁移migrate和seed插入测试数据的完整示例》已做详细介绍,本文不做赘述。
在 tp 项目根目录下,运行php think make:model Users
便可成功创建 Users 验证器。打开验证器文件并修改内容如下:
<?php
declare (strict_types=1);
namespace app\validate;
use think\Validate;
class Users extends Validate
{
protected $failException = true;
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [
// 验证规则一:下面这个规则约束users表中username必须唯一
// 'username' => 'unique:users,username'
// 验证规则二:下面这个规则约束users表中username与login_status组合唯一,
// 即:如果表中存在username=James且login_status=1,
// 那么[username=James, login_status=1]则验证通不过
// 而[username=James, login_status=0]则验证可通过
'username' => 'unique:users,username^login_status'
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [];
}
注意:验证器中必须设置这个属性 $failException 为 true,否则验证不通过时不会抛出异常,而是直接通过 return 的方式返回验证结果。
个人觉得通过创建指令测试无需打开浏览器简单方便,当然你可以通过控制器编写测试代码然后再浏览器执行也可以的。
在 tp 项目根目录下,运行php think make:command Ttys
便可成功创建 ttys 指令。打开指令文件并修改内容如下:
<?php
declare (strict_types=1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use app\validate\Users as UsersValidate;
use think\exception\ValidateException;
class Ttys extends Command
{
protected function configure()
{
// 指令配置
$this->setName('ttys')
->setDescription('控制台调试工具命令');
}
protected function execute(Input $input, Output $output)
{
try {
// 新增时验证
validate(UsersValidate::class)
->check(['username' => 'test', 'login_status' => '1']);
// 编辑时验证
// validate(UsersValidate::class)
// ->check(['username' => 'test', 'login_status' => '1', 'id' => 22]);
$output->writeln('validate pass');
} catch (ValidateException $e) {
$output->error($e->getMessage());
}
}
}
指定文件编辑保存后,还需要编辑 config/console.php 文件,配置上面自定义的指定 Ttys,具体配置如下:
<?php
// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
// .... 其他自定义指令
\app\command\Ttys::class
],
];
最后在 tp 项目根目录下,运行php think ttys
便可运行自定义的 ttys 指令,查看验证结果。
源代码位置:vendor/topthink/framework/src/think/Validate.php,在文件内搜索 unique()
方法
/**
* 验证是否唯一
* @access public
* @param mixed $value 字段值
* @param mixed $rule 验证规则 格式:数据表,字段名,排除ID,主键名
* @param array $data 数据
* @param string $field 验证字段名
* @return bool
*/
public function unique($value, $rule, array $data = [], string $field = ''): bool
{
if (is_string($rule)) {
$rule = explode(',', $rule);
}
if (str_contains($rule[0], '\\')) {
// 指定模型类
$db = new $rule[0];
} else {
$db = $this->db->name($rule[0]);
}
$key = $rule[1] ?? $field;
$map = [];
if (str_contains($key, '^')) {
// 支持多个字段验证
$fields = explode('^', $key);
foreach ($fields as $key) {
if (isset($data[$key])) {
$map[] = [$key, '=', $data[$key]];
}
}
} elseif (isset($data[$field])) {
$map[] = [$key, '=', $data[$field]];
} else {
$map = [];
}
$pk = !empty($rule[3]) ? $rule[3] : $db->getPk();
if (is_string($pk)) {
if (isset($rule[2])) {
$map[] = [$pk, '<>', $rule[2]];
} elseif (isset($data[$pk])) {
$map[] = [$pk, '<>', $data[$pk]];
}
}
if ($db->where($map)->field($pk)->find()) {
return false;
}
return true;
}