API Resource 分页参数如何重写

请问大家如何重写 Laravel 框架中默认的请求和响应参数?

目前的场景是这样:

我们跟前端约束了驼峰方式的请求和响应参数命名规范,但发现 Laravel 和分页和授权相关参数,都是下划线的命名规范。我也想过使用中间件来对参数名进行转换处理,但 Resource 里面已经处理多数参数名,再使用中间件感觉有些浪费计算资源。所以相对两块做单独处理,对于分页这块我特地翻了一下 5.8 版本的源码,貌似写的非常死,分页都是通过键值对使用 toArray 方法返回的,API Resource 里面也是直接判断并调用了分页类,并没有找到能替换分页类的地方。请问如何能替换分页类 或者 替换其分页的请求和响应参数?

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

重写的类:

那几个 url 相关的键,不能改,,,

class CustomPaginator extends \Illuminate\Pagination\LengthAwarePaginator
{
    public function toArray()
    {
        return [
            'currentPage' => $this->currentPage(),
            'data' => $this->items->toArray(),
            'first_page_url' => $this->url(1),
            'from' => $this->firstItem(),
            'lastPage' => $this->lastPage(),
            'last_page_url' => $this->url($this->lastPage()),
            'next_page_url' => $this->nextPageUrl(),
            'path' => $this->path,
            'perPage' => $this->perPage(),
            'prev_page_url' => $this->previousPageUrl(),
            'to' => $this->lastItem(),
            'total' => $this->total(),
        ];
    }
}

绑定:
$this->app->bind(\Illuminate\Pagination\LengthAwarePaginator::class, CustomPaginator::class);

效果:

file

其实直接在中间件里处理下简单多了,,,

就多执行两条语句,,,估计执行时间,1 毫秒都不需要吧,,能浪费啥计算资源啊,,

这样绑定一下,不也多执行了几条语句么,,,

5年前 评论
sanders (楼主) 5年前
讨论数量: 8
野犭

后端为什么要委屈自己,一个参数而已,让他们换一下不就好了,何必浪费你宝贵的时间

5年前 评论
sanders (楼主) 5年前
leo

『再使用中间件感觉有些浪费计算资源』唯一方便的路被你自己堵死了……如果你真的这么在意这些完全可以忽略的性能,建议换一个语言。

5年前 评论
sanders (楼主) 5年前

我和你说一下我们这边的做法,后端api 都是只接受 下划线 参数的,前端使用的时候都是 驼峰式 的,但是前端在 api request 的地方可以使用了一个 驼峰转下划线 的拦截器,从而达到统一。
其实我觉得这样的问题,要么后端统一处理,要么前端统一处理,别为它法。

5年前 评论

我看了下 模型的 paginate 方法,里面调用了 paginator 方法,,,这个方法里,,,使用容器来解析分页类 Illuminate\Pagination\LengthAwarePaginator 的,,

所以,,,,自己写一个分页类,继承自这个,然后改一下 toArray 方法,然后注册到容器里,应该就可以了,,,

我没试过,,,

5年前 评论
sanders (楼主) 5年前
sanders (楼主) 5年前

重写的类:

那几个 url 相关的键,不能改,,,

class CustomPaginator extends \Illuminate\Pagination\LengthAwarePaginator
{
    public function toArray()
    {
        return [
            'currentPage' => $this->currentPage(),
            'data' => $this->items->toArray(),
            'first_page_url' => $this->url(1),
            'from' => $this->firstItem(),
            'lastPage' => $this->lastPage(),
            'last_page_url' => $this->url($this->lastPage()),
            'next_page_url' => $this->nextPageUrl(),
            'path' => $this->path,
            'perPage' => $this->perPage(),
            'prev_page_url' => $this->previousPageUrl(),
            'to' => $this->lastItem(),
            'total' => $this->total(),
        ];
    }
}

绑定:
$this->app->bind(\Illuminate\Pagination\LengthAwarePaginator::class, CustomPaginator::class);

效果:

file

其实直接在中间件里处理下简单多了,,,

就多执行两条语句,,,估计执行时间,1 毫秒都不需要吧,,能浪费啥计算资源啊,,

这样绑定一下,不也多执行了几条语句么,,,

5年前 评论
sanders (楼主) 5年前
izhengmy
5年前 评论

分页参数写死了,调用方法的时候传进去吧

返回参数可以扩展Response,判断是资源数据,先获取到数据,然后自己处理

Response::macro('table', [$this, 'responseTable']);

public function responseTable($data = [])
{
    if($data instanceof JsonResource){
        $resource = $data->response()->getData(TRUE);
        //分页数据
        if(Arr::has($resource, ['data', 'links', 'meta']) && count(array_keys($resource)) == 3){
            //单个数据
        }else if(Arr::isAssoc($resource)){
            //数据集合
        }else{
        }
    }
}

控制器中用扩展方法返回数据

return Response::table($list);
5年前 评论
sanders (楼主) 5年前

我们是封装了一个success方法 然后自动判断 显示哪些字段你自己决定

public function success($responseData = '',$code = 200)
    {
        $response = [
            'code'    => $code ?: 200,
            'message' => is_string($responseData) && !empty($responseData) ? $responseData : 'OK'
        ];
        if(!is_string($responseData)){
            /**
             * @var ResourceCollection   $responseData
             * @var LengthAwarePaginator $resource
             */
            $response['data'] = $responseData;

            if($responseData instanceof ResourceCollection && $responseData->resource instanceof LengthAwarePaginator){
                $resource = $responseData->resource;
                $response['meta'] = [
                    'page'     => $resource->currentPage(),
                    'perPage'  => $resource->perPage(),
                    'total'    => $resource->total(),
                    'lastPage' => $resource->lastPage(),
                ];
            }

            if($responseData instanceof LengthAwarePaginator){
                $response['data'] = $responseData->items();
                $response['meta'] = [
                    'page'     => $responseData->currentPage(),
                    'perPage'  => $responseData->perPage(),
                    'total'    => $responseData->total(),
                    'lastPage' => $responseData->lastPage(),
                ];
            }
        }
        return response()->json($response);
    }
5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!