全局作用域:
简单方便的为每个模型查询都加上约束条件。其中软删除功能就是利用该特性从数据库中获取未删除的模型。
代码演示:
实现Illuminate\Database\Eloquent\Scope.php接口中apply方法。根据需求编写apply方法。
在app下新建一个Scopes文件夹,然后创建ReadScope类。
注意:如果需要用select语句准确获取对应字段的内容,应使用addSelect方法。防止替换现有select语句。
使用你所编写的全局作用域,那么就需要重写模型的boot方法并使用addGlobalScope方法:
当你使用Topic::all()时会生成如下SQL语句:
select * from `topic` where `read_num` > 200;
匿名全局作用域:不需要为了一个简单的作用域而编写一个单独的类
那怎么取消呢?
非匿名:Topic::withoutGlobalScope(ReadScope::class)->get(); 匿名:Topic::withoutGlobalScope('read')->get(); 取消所有用withoutGlobalScopes Topic::withoutGlobalScopes()->get(); 球 Topic::withoutGlobalScopes([ ReadScope::class, WriteScope::class])->get();
本地作用域
只需要在对应的Eloquent模型方法前添加scope前缀
如何使用呢?可以链式调用你所定义的所有本地作用域,但是调用的时候不需要加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();
动态作用域:传参的形式
如何使用呢?
$topics = Topic::withOrder('created_at')->get();
重点介绍下$query的由来
介绍完了以上作用域,可能你应该还有点懵,很好奇$query是哪里跑出来的?文档中好像也只是提了怎么去用。这时该怎么办呢?文档又查不到。这时只能看源码了。来开始分析源码如下步骤:
找到vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php这个文件中的__call()方法,你会发现有这么一段代码:
我们在上面已经定义了多个scope开头的方法,完全符合我们的预算。其会调用callScope方法,接下来我们就去会会这个callScope。
我们用一丢丢的力气就找到了这个玩意:
源码解读:
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.
慕友们你们看懂了嘛?点个赞支持下呗。
共同学习,写下你的评论
评论加载中...
作者其他优质文章