scopewithorder ($query, $order), $query 是怎么来的? | laravel | laravel china 社区-金年会app官方网
像这种问题,一般是先查,但文档中也只是写了如何去用,而没有提到$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: