scopeWithOrder ($query, $order), $query 是怎么来的?
像这种问题,一般是先查文档,但文档中也只是写了如何去用,而没有提到$query具体是怎么来的。
因此,可以去看源码,源码分析步骤:
找到 withOrder
方法,由于步骤太多,前面的各种magic method跳转全部省略。。。(此处省略1万字)。
最终在 vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
中可以找到 __call()方法中有如下代码段:
if (method_exists($this->model, $scope = 'scope'.ucfirst($method))) {
return $this->callScope([$this->model, $scope], $parameters);
}
不难看出是检查当前正在运行的model即topic model中是否有scope开头的方法,我们已经提前在其中写了scopeWithOrderd的方法,因此,会调用Eloquent/Builder中的callScope方法。
/**
* Apply the given scope on the current builder instance.
*
* @param callable $scope
* @param array $parameters
* @return mixed
*/
protected function callScope(callable $scope, $parameters = [])
{
array_unshift($parameters, $this); //将$this即当前的builder instance放在 $parameters 数组的最开始
$query = $this->getQuery();
// We will keep track of how many wheres are on the query before running the
// scope so that we can properly group the added scope constraints in the
// query as their own isolated nested where statement and avoid issues.
$originalWhereCount = is_null($query->wheres)
? 0 : count($query->wheres);
$result = $scope(...array_values($parameters)) ?? $this; // 这里是进行回调,回调的是我们在上一步中调用callScope方法时的
那个第一参数所代表的方法,也就是topic model中的scopeWithOrderd方法。 而array_values($parameters)是依次取出数组中的值返回一个数字数组。
而...$arr这种写法时将$arr数组中的元素全部拆开依次放入对应的函数的参数列表。由于数组中第一个元素是当前的builder instance,
这样就将当前的builder instance传到了topic model中的scopeWithOrderd方法的$query参数变量中,这样对$query的操作,就是对当前的builder instance的操作了。。
因此后面的操作无非可以看成是SQL语句的一些order,where的操作。
if (count((array) $query->wheres) > $originalWhereCount) {
$this->addNewWheresWithinGroup($query, $originalWhereCount);
}
return $result; //最后这里返回的还是一个eloquent builder instance.
}
通过上面的代码注释,我们就可以基本了解scopeWithOrder ($query, $order)中的 $query 是怎么来的了。
同样,理解了上述代码,我们也不难看出在控制器中,各种条件的限制操作都是可以互换位置的,比如下面的代码:
$topics = $topic->withOrder($request->order)->where('category_id', $category->id)->paginate(20);
完全可以换为
$topics = $topic->where('category_id', $category->id)->withOrder($request->order)->paginate(20);
对运行效率没有影响。经过数十次测试,也验证了这一点。
本帖已被设为精华帖!
本帖由系统于 3年前 自动加精
这里是进行回调,回调的是我们在上一步中调用callScope方法时的
那个第一参数所代表的方法,也就是topic model中的scopeWithOrderd方法。大神scopeWithOrderd这个具体实现能在说清楚点吗
讲的通俗易懂, 看懂了 :+1: