活用laravel的where闭包
编辑时间:2020-05-26 15:28:37 作者:666666

转自链接:https://learnku.com/articles/6044/laravel-series-orwhere-conditional

目前我对于学习 Laravel 还是有些吃力的,基本方法都能很快掌握,但是一旦遇到了比较复杂的问题后,想要去查看源码进行调试的时候,总是会显得不知所措。 官方文档不会把所有方法都讲一遍,也不会把方法的各个使用场景都描述一遍,所以遇到这些问题去看文档一般解决不了。

这次我遇到的问题是 orWhere 条件式造成的查询语句写法始终不是自己想要的。

场景描述

我需要根据商品分类、商品名称和条形码这三个查询条件去取出结果集,这三者的关系是:商品分类 and (商品名称 or 条形码)

错误尝试

第一次写出来的代码是这样的:

$goodsModel = new Goods;

if (!empty($category)) {
  $goodsModel = $goodsModel->where('category', $category);
}

if (!empty($keyword)) {
  $goodsModel = $goodsModel->where('name', 'like', "%{$keyword}%")->orWhere('barcode', 'like', "%{$keyword}%");
}

$goodsList = $goodsModel->limit(10)->get();

然后会发现这样的写法会导致三者的关系变成了:商品分类 and 商品名称 or 条形码。

谷歌一下

也是找了一会才找到,如果需要将 or 两边的查询项作为一组查询条件,那么建议使用 where 的闭包方式。

闭包

这种方式将 or 部分写成 closure 传入 where(),与 Eloquent 风格一致,可读性较好。代码如下:

if (!empty($keyword)) {
  $goodsModel = $goodsModel->where(function ($query) use ($keyword) {
  		$query->where('name', 'like', "%{$keyword}%")->orWhere('barcode', 'like', "%{$keyword}%");
  });
}

原生

实在想不出怎么写,就写原生 SQL 好了。这也是最后一种保险但不提倡的做法了吧,代码如下:

if (!empty($keyword)) {
  $keyword = "%{$keyword}%";
  $goodsModel = $goodsModel->whereRaw('(name like ? or barcode like ?)', [$keyword, $keyword]);
}

需要注意的是,单引号里面的括号是不能省略的,否则一样会导致这三者的关系是:商品分类 and 商品名称 or 条形码。

占位符

再友情提示一下,你可能会对 like ? 觉得奇怪,我第一次写的时候直接是 whereRaw('name like "%?%"', [$keyword]'),但是这样是没效果的,原因是占位符是对某一个完整的值进行占位,而不是简单的替换效果,所以需要将 like 的参数全部用 ? 替代,将百分号的拼接放在后面的占位数组的变量中去。


如果需要一条语句查询的话

DB::table('users')
  ->where('name', '=', 'John')
  ->where(function ($query) {
    $query->where('votes', '>', 100)
      ->orWhere('title', '<>', 'Admin');
  })
  ->get();

我没试过,但理论上是可以的。另外,你也可以将判断条件拆分成 or 连接的形式,然后用类似

$users = DB::table('users')->where([
    ['status', '=', 1],
    ['subscribed', '<>', 1]
])
->orWhere()
->get();

这时博主个人补充:

如果是类似右侧这种方式的查询 a=1 and b=2 and ( ( c > 3 and c < 4 ) or ( d > 5 and d < 6) )则代码如下

$cStart = 3;
$cEnd = 4;

$dStart = 5;
$dEnd = 6;

DB::table('user')
    ->where('a', '=', 1)
    ->where('b', '=', 2)
    ->where(function ($query) use ($cStart, $cEnd, $dStart, $dEnd) {

        $query->where(function ($query) use ($cStart, $cEnd) {
            $query->where('c', '>', $cStart)
                ->where('c', '<', $cEnd);
        });

        $query->orWhere(function ($query) use ($dStart, $dEnd) {
            $query->where('d', '>', $dStart)
                ->where('d', '<', $dEnd);
        });
    })
 点赞 0
 收藏 0
 分享
来说两句吧
最新评论
    暂无评论
天气预报
万年历
2015年
7月
返回今天

博客声明

本博客属个人所有,不涉及商业目的。遵守中华人民共和国法律法规、中华民族基本道德和基本网络道德规范,尊重有节制的言论自由和意识形态自由,反对激进、破坏、低俗、广告、投机等不负责任的言行。所有转载的文撰写页面章、图片仅用于说明性目的,被要求或认为适当时,将标注署名与来源。避免转载有明确“不予转载”声明的作品。若不愿某一作品被转用,请及时通知本人。对于无版权或自由版权作品,本博客有权进行修改和传播,一旦涉及实质性修改,本博客将对修改后的作品享有相当的版权。二次转载者请再次确认原作者所给予的权力范围。

本博客所有原创作品,包括文字、资料、图片、网页格式,转载时请标注作者与来源。非经允许,不得用于赢利目的。本博客受中国知识产权、互联网法规和知识共享条例保护和保障,任何人不得进行旨在破坏或牟取私利的行为。本博客声明以简体中文版为准,不对其他语言版本负责。

如有侵权请及时联系我进行处理。邮箱youseeim666@163.com