为了账号安全,请及时绑定邮箱和手机立即绑定

详解Laravel中Eloquent ORM的查询作用域

标签:
PHP laravel

全局作用域:

    简单方便的为每个模型查询都加上约束条件。其中软删除功能就是利用该特性从数据库中获取未删除的模型。

代码演示:

    实现Illuminate\Database\Eloquent\Scope.php接口中apply方法。根据需求编写apply方法。

    https://img1.sycdn.imooc.com//5d424db500014d1310600424.jpg

    在app下新建一个Scopes文件夹,然后创建ReadScope类。

    https://img1.sycdn.imooc.com//5d424e760001e08e11950563.jpg

    注意:如果需要用select语句准确获取对应字段的内容,应使用addSelect方法。防止替换现有select语句。

使用你所编写的全局作用域,那么就需要重写模型的boot方法并使用addGlobalScope方法:

    https://img1.sycdn.imooc.com//5d4250a700018b0409980366.jpg

当你使用Topic::all()时会生成如下SQL语句:

select * from `topic` where `read_num` > 200;

匿名全局作用域:不需要为了一个简单的作用域而编写一个单独的类

    https://img1.sycdn.imooc.com//5d4251af00010ff712000447.jpg

那怎么取消呢?

非匿名:Topic::withoutGlobalScope(ReadScope::class)->get();
匿名:Topic::withoutGlobalScope('read')->get();

取消所有用withoutGlobalScopes
Topic::withoutGlobalScopes()->get();
球
Topic::withoutGlobalScopes([
    ReadScope::class, WriteScope::class])->get();

本地作用域

    只需要在对应的Eloquent模型方法前添加scope前缀

    https://img1.sycdn.imooc.com//5d4253a80001fc0e11060669.jpg

如何使用呢?可以链式调用你所定义的所有本地作用域,但是调用的时候不需要加scope

    $topics = Topic::read()->top()->orderBy('topic_id')->get();
    闭包形式
    $topics = Topic::read()->orWhere(function (Builder $query){
        $query->top();
    })->get();
    闭包形式的高级用法:
    $topics = Topic::read()->orWhere->top()->get();

动态作用域:传参的形式

    https://img1.sycdn.imooc.com//5d42552d000135ba09690341.jpg

如何使用呢?

$topics = Topic::withOrder('created_at')->get();

重点介绍下$query的由来

介绍完了以上作用域,可能你应该还有点懵,很好奇$query是哪里跑出来的?文档中好像也只是提了怎么去用。这时该怎么办呢?文档又查不到。这时只能看源码了。来开始分析源码如下步骤:

    找到vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php这个文件中的__call()方法,你会发现有这么一段代码:

    https://img1.sycdn.imooc.com//5d4259790001ff6911270660.jpg

我们在上面已经定义了多个scope开头的方法,完全符合我们的预算。其会调用callScope方法,接下来我们就去会会这个callScope。

    我们用一丢丢的力气就找到了这个玩意:

    https://img1.sycdn.imooc.com//5d425a4d0001d65507420467.jpg

源码解读:

array_unshift($parameters, $this);//将$this即当前的builder instance放在 $parameters 数组的第一个
$result = $scope(...array_values($parameters)) ?? $this;
回调。回调的是我们在上一步中调用callScope方法时的那个第一个参数所代表的方法,即我们定义在model中前
缀为scope的方法。array_values($parameters)是依次取出数组中的值返回一个数字数组。...$arr这种写法是将
$arr数组中的元素全部拆开依次放入对应的函数的参数列表。由于数组中第一个元素是当前的builder instance,
这样就将当前的builder instance传到了model中的前缀为scope方法的$query参数变量中,这样对$query的操作,
就是对当前的builder instance的操作了。因此后面的操作无非可以看成是SQL语句的一些order,where的操作。
return $result;   //返回的是一个eloquent builder instance.

慕友们你们看懂了嘛?点个赞支持下呗。

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消