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);

对运行效率没有影响。经过数十次测试,也验证了这一点。

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1
__中国人

这里是进行回调,回调的是我们在上一步中调用callScope方法时的
那个第一参数所代表的方法,也就是topic model中的scopeWithOrderd方法。大神scopeWithOrderd这个具体实现能在说清楚点吗

4个月前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

社区文档:

将托管在 packagist.org 和 github.com 的扩展包使用国内 CDN 加速
GitHub Laravel 扩展包 TOP 250
速查表方便快速查询框架功能,支持手机访问,支持中英文版本
Laravel 中文文档,由社区用户翻译和维护,将会保持一直更新
此文档的目的,就是为了提高技术团队的凝聚力、一致性和生产效率。
开发环境的部署,开发者工具的选择,适用于 Mac 和 Windows。
浓缩过后的精华
Laravel Nova 后台管理面板文档的中文翻译
Lumen 中文文档,由社区用户翻译和维护,将会保持一直更新
Laravel 下知名扩展包 Dingo API 的中文文档,Laravel API 开发必知必会