ThinkPHP5.0数据更新验证唯一性怎么验证。

简单的小项目在自定义验证字段时,数据插入数据库可以正常验证!想要在数据更新时也使用本套验证方法,就是一个字段比如catename字段,需要验证是否存在,然后在数据库中是否是唯一一个.ThinkPHP5
以下自定义验证是代码:(很简单的)
class Admin extends validate
{

protected $rule = [
    'catename' => 'unique:cate|require|length:4,25'
];
protected $message = [
    'catename.require' => '请填写栏目名称',
    'catename.unique' => '栏目已存在',
    'catename.length' => '长度不在3-5个字符',
];

}
然后数据更新代码:model层
//栏目修改

public function edit($data)
{

    $validate = new Admin();
    if ($validate->check($data)) {//验证数据是否正确
        $num = Cate::isUpdate(true)->save($data);
        return $num;
    } else {
        return $validate->getError();
    }
}

这里出现了一个问题:就是当我不做修改的时候数据是肯定修改失败的!因为没有做任何修改返回没有影响的行数!但是if判断那边他是执行的!也是执行成功的!就好比我修改的数据是"菜单栏",我不修改原样放进去它验证成功!我依稀记得更新操作都是先删除原始数据重新插入数据这样一个流程,那我判断唯一性就失效了!但是更新时我又要怎么判断他是否唯一呢!小白还请各位给点意见!

阅读 10.4k
8 个回答

问题应该就是更新时的唯一性判定是要排除自身的。
我记得看过tp5验证这块的代码,要是单独在valide验证器类里是实现不了的,因为这个类里没找到怎么获取传递过来的参数。但是在controller中可以实现,但文档中根本没有细说,我在他们官方文档下面的评论中有具体的怎么实现的代码,可以参考下,或者帮忙贴过来。


自己贴过来吧:

文档太简陋了,还要看源码才行,'name' => 'unique:user,status=1&account='.$data['account'],这种的只能放在controller中,自己来定义rulemessage,在单独的validate类中无法将相关的值传递过去。
规则是:unique:【模型类名(或表名)】,【要验证的字段(或者包含=号或者包含^号,但是必须把本身的条件加入,别以为前面有name了就不把name本身加进去了)】,【要排除的字段】,【主键(可不填)】
示例:

$id = $this->request->post('id');
$shopId = session('shop_id');
$name = $this->request->post('name');
$sort = $this->request->post('sort', 0, 'intval');
$postData = [
    'name' => $name,
    'sort' => $sort
];
$rule = [
    'name' => 'require|unique:ArticleCategory,shop_id=' . $shopId . '&name=' . $name,//名称
    'sort' => 'number'
];
$message = [
    'name.require' => '分类名称必须填写',
    'name.unique' => '分类名称已存在',
    'sort.number' => '排序必须填写整数',
];
$validate = new Validate($rule, $message);
if (!empty($id)) {
    $validate->scene('edit',
        [
            'sort',
            'name' => 'require|unique:ArticleCategory,shop_id=' . $shopId . '&name=' . $name . ',' . $id
        ]);
    $validateRes = $validate->scene('edit')->check($postData);
} else {
    $validate->scene('add', ['sort', 'name']);
    $validateRes = $validate->scene('add')->check($postData);
}
if (true !== $validateRes) {
    $data['msg'] = $validate->getError();
    return json($data);
}

我觉得数据库表字段设置成唯一就可以了,如果存在,就直接插入失败。如果想高级的话就根据用户输入内容先查询下,存在了返回一个友好提示。这应该难不到你。

感谢评论区的回答

新手上路,请多包涵

我的是tp5.0.19用上面的方法不行,但是看了这篇文章:https://www.cnblogs.com/PHPak...
在编辑页面form表单中添加一个隐藏域:<input type="hidden" name="表中id字段名" value="get方式传过来的id值">(千万注意name要和主键同名),然后定义好验证器类中的相关规则,此时不需再要定义验证场景了,添加编辑都用同一规则:
class Admin extends Validate
{
protected $rule = [
[
'account', 'require|length:3,15|checkChanese:|checkSpecial:|unique:admin,admin_account', '账号必须填写|账号长度在3~15个字符之间|账号中不能含有中文|账号中不能含有特殊字符|该账号已存在,请重新添加']
]
}
模型中验证:
//执行验证
$validate = validate('Admin');
if ($validate->check($data)) {//验证通过......}else{//验证失败......}
亲测可用。。。希望可以帮到大家

新手上路,请多包涵

如果不是使用独立验证器,楼上方法是可行的。
我的版本是5.1.x。使用的独立验证器,可以这样在update方法中重新设置规则,原理是排除检查当前更新的这条数据ID。
我翻阅了几遍文档,好像没有验证场景可以传参的案例,所以用这种勉强不怎么优雅的写法。

        $validate->rule('name', "unique:tags,name,{$id}");
        if (!$validate->check($data))
        {
            // todo
        }

如果有更好的解决方法,记得@我

使用tp5.1
保存时,保存的数据包含当前主键信息即可,不必用scene,会自动排除当前的数据进行唯一验证,源码具体如何实现的目前尚未了解。
使用方法如下:

  $data=[
            'id'=>$input["id"],
            'code'=>$input["EditCode"],
            'description'=>$input["EditDescription"],
            'update_time'=>date("Y-m-d H:i:s"),
            'update_by'=>Session::get('name')
        ];
        $validate=new Validate($this->rule,$this->message);
        $validateRes=$validate->check($data);
        if(!$validateRes){
            $msg=$validate->getError();
            return $this->returnMsg("204",$msg);
        }
        else{
         //验证成功的操作
        }

只要确保我们传入的验证数据中包含unique验证字段所在的数据表的主键,就会跳过该主键对应的数据行再进行唯一性验证,这也就解决了更新的时候出现的唯一性验证问题,如

$validate = new Validate([
    'name'  => 'require|max:25',
    'mobile' => 'unique:user'
]);
$validate->check([
    'id' => $data['id'], //当验证数据包含user表的主键id的时候,视为数据更新
    'name' => 'xxx',
    'mobile' => '13888888888' //传入的校验数据有主键值的情况下,判断唯一性的时候跳过该主键值对应的行
])

thinkphp5源码中实现该功能的的地方

// 位于 \think\Validate 中
        $pk = isset($rule[3]) ? $rule[3] : $db->getPk();
        if (is_string($pk)) {
            if (isset($rule[2])) {
                $map[$pk] = ['neq', $rule[2]];
            } elseif (isset($data[$pk])) {
                $map[$pk] = ['neq', $data[$pk]];
            }
        }
        if ($db->where($map)->field($pk)->find()) {
            return false;
        }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏