关于5.1版验证类中唯一(unique)规则的缺陷

 

你们想的太复杂了,其实修改场景的规则不用重新写,重点是编辑界面一定要使用隐藏域传递主键id就可以了,TP会自动识别是否需要判断唯一性

你们想的太复杂了,其实修改场景的规则不用重新写,重点是编辑界面一定要使用隐藏域传递主键id就可以了,TP会自动识别是否需要判断唯一性

你们想的太复杂了,其实修改场景的规则不用重新写,重点是编辑界面一定要使用隐藏域传递主键id就可以了,TP会自动识别是否需要判断唯一性

importent * 3

 

form:http://www.thinkphp.cn/topic/47768.html

 

 

 

 

 

 

 

我们通常会有这样的应用场景,比如在操作用户表(User)时,我们希望username和nickname这两个字段是唯一的,所以在新增和更新时就要对他的唯一性做验证,内置的unique规则在新增时验证没有任何问题,但是在更新时就会碰到如果提交数据时nickname没有被修改(username通常一旦注册不能修改),那么验证也会通不过,提示nickname已经存在。搜索发现有人也碰到这个问题,传送门:http://www.thinkphp.cn/topic/47768.html,随即我试着参照修改,

  1.      'edit' => ['nickname.unique'=>'require|unique:user,nickname^id']

复制代码

 

结果发现,他什么都不验证了,即使跟其他用户的nickname重复,也通过了,没办法只有查核心库源码:

  1.  /**
  2.      * 验证是否唯一
  3.      * @access public
  4.      * @param  mixed     $value  字段值
  5.      * @param  mixed     $rule  验证规则 格式:数据表,字段名,排除ID,主键名
  6.      * @param  array     $data  数据
  7.      * @param  string    $field  验证字段名
  8.      * @return bool
  9.      */
  10.     public function unique($value, $rule, $data, $field)
  11.     {
  12.         if (is_string($rule)) {
  13.             $rule = explode(',', $rule);
  14.         }
  15.         if (false !== strpos($rule[0], '\\')) {
  16.             // 指定模型类
  17.             $db = new $rule[0];
  18.         } else {
  19.             try {
  20.                 $db = Container::get('app')->model($rule[0]);
  21.             } catch (ClassNotFoundException $e) {
  22.                 $db = Db::name($rule[0]);
  23.             }
  24.         }
  25.         $key = isset($rule[1]) ? $rule[1] : $field;
  26.  
  27.         if (strpos($key, '^')) {
  28.             // 支持多个字段验证
  29.             $fields = explode('^', $key);
  30.             foreach ($fields as $key) {
  31.                 $map[] = [$key, '=', $data[$key]];
  32.             }
  33.         } else {
  34.             $map[] = [$key, '=', $data[$field]];
  35.         }
  36.  
  37.         $pk = !empty($rule[3]) ? $rule[3] : $db->getPk();
  38.  
  39.         if (is_string($pk)) {
  40.             if (isset($rule[2])) {
  41.                 $map[] = [$pk, '<>', $rule[2]];
  42.             } elseif (isset($data[$pk])) {
  43.                 $map[] = [$pk, '<>', $data[$pk]];
  44.             }
  45.         }
  46.         if ($db->where($map)->field($pk)->find()) {
  47.             return false;
  48.         }
  49.         return true;
  50.     }

复制代码

 

分析源码并打印出他最终生成的查询条件:

  1. array(3) {
  2.   [0] => array(3) {
  3.     [0] => string(8) "nickname"
  4.     [1] => string(1) "="
  5.     [2] => string(4) "tes1"
  6.   }
  7.   [1] => array(3) {
  8.     [0] => string(2) "id"
  9.     [1] => string(1) "="
  10.     [2] => int(3)
  11.   }
  12.   [2] => array(3) {
  13.     [0] => string(2) "id"
  14.     [1] => string(2) "<>"
  15.     [2] => int(3)
  16.    }
  17. }

复制代码

 

返现关于id的条件是同时满足id = 3 或 id<>3(3就是我的用户id),显然这个条件是自相矛盾的,所以等于对id没有做任何过滤,那么造成这个结果的原因就是这段代码:

  1.        $pk = !empty($rule[3]) ? $rule[3] : $db->getPk();
  2.  
  3.         if (is_string($pk)) {
  4.             if (isset($rule[2])) {
  5.                 $map[] = [$pk, '<>', $rule[2]];
  6.             } elseif (isset($data[$pk])) {
  7.                 $map[] = [$pk, '<>', $data[$pk]];
  8.             }
  9.         }

复制代码

 

这里就有个顺序问题,他的顺序是先值后字段名,那么很多情况是,我的值是通过$data传递进去的,所以值我是不设置的,而按照这个顺序,我不设置值就没法设置过滤字段名,所以最佳的解决办法就是把这两个顺序换下,把字段名方前面,值放后面:

  1. $pk = !empty($rule[2]) ? $rule[2] : $db->getPk();
  2.  
  3.         if (is_string($pk)) {
  4.             if (isset($rule[3])) {
  5.                 $map[] = [$pk, '<>', $rule[3]];
  6.             } elseif (isset($data[$pk])) {
  7.                 $map[] = [$pk, '<>', $data[$pk]];
  8.             }
  9.         }

复制代码

 

经测试,发现新增和更新都能被正确验证:更新时只要:

  1.      'edit' => ['nickname.unique'=>'require|unique:user, nickname, id']

复制代码

 

不晓得我这样分析是否正确,请大牛批评指正,同时也希望官方给予回复。

转自:http://www.thinkphp.cn/topic/53965.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值