内容简介:除了我们上篇教程介绍的一些基本使用之外,还可以通过传递额外的参数实现一些更高级的转化器功能。我们可以在响应构建器的但是这个功能只有在 Fractal 的序列化器为
转化器的高级功能
除了我们上篇教程介绍的一些基本使用之外,还可以通过传递额外的参数实现一些更高级的转化器功能。
资源键
我们可以在响应构建器的 item
、 collection
或 paginator
方法传入一个参数数组作为第三个参数,在这个数组中,可以通过 key
传入 Fractal 资源的类型标识:
return $this->item($task, new TaskTransformer, ['key' => 'task']);
但是这个功能只有在 Fractal 的序列化器为 JsonApiSerializer
时才有效。关于 Fractal 系列化器的设置我们下面会提到。
使用回调
Fractal 转化层允许你注册一个创建资源之后触发的回调,这个回调接收 League\Fractal\Resource\Item
或者 League\Fractal\Resource\Collection
资源作为第一个参数, League\Fractal\Manager
实例作为第二个参数,在这个回调函数中我们可以自定义序列化器、设置游标、以及其它与 Fractal 交互的功能。
设置序列化器
比如我们设置序列化器可以这么做(默认使用的序列化器是 DataArraySerializer
):
// 引入命名空间 use League\Fractal\Serializer\JsonApiSerializer; $task = Task::findOrFail($id); return $this->response->item($task, new TaskTransformer(), ['key' => 'task'], function ($resource, $fractal) { $fractal->setSerializer(new JsonApiSerializer()); });
这样,我们访问对应的资源路由,返回的响应就变成了遵循 JSON-API 规范的数据格式:
同时也会应用第三个参数设置的资源键值作为返回资源的数据类型。关于 Fractal 支持的其它序列化器可以参考之前的Fractal 教程。
设置游标
此外,学院君前面介绍 Fractal 对分页数据进行处理的时候讲到,对于结果集很大的、对性能要求严苛的系统,除了分页器之外,还可以通过游标获取分页数据,同样,也可以在第四个回调函数中设置游标来转化分页数据,下面我们改写 Api\TaskController
的 index
方法实现代码如下:
public function index(Request $request) { $current = $request->input('current'); $previous = $request->input('previous'); $limit = $request->input('limit') ? : 10; if ($current) { $tasks = Task::where('id', '>', $current)->take($limit)->get(); } else { $tasks = Task::take($limit)->get(); } $next = $tasks->last()->id; $cursor = new Cursor($current, $previous, $next, $tasks->count()); return $this->response->collection($tasks, new TaskTransformer, [], function ($resource, $fractal) use ($cursor) { $resource->setCursor($cursor); }); }
再次访问首页路由,就可以看到通过游标转化的分页数据了:
自定义转化层
Dingo API 默认基于 Fractal 转化层实现转化器,你可以在 config/api.php
中看到这个默认配置:
'transformer' => env('API_TRANSFORMER', Dingo\Api\Transformer\Adapter\Fractal::class),
如果你不想使用 Fractal 作为转化层,可以在 Dingo API 中创建自己的转化层。要实现自定义的转化层,需要创建一个继承自 Dingo\Api\Contract\Transformer\Adapter
基类的子类,并且实现 transform
方法:
use Dingo\Api\Http\Request; use Dingo\Api\Transformer\Binding; use Dingo\Api\Contract\Transformer\Adapter; class MyCustomTransformerAdapter implements Adapter { public function transform($response, $transformer, Binding $binding, Request $request) { // 调用转化层对响应数据进行转化 } }
transform
是唯一必须实现的方法(因为基类中只声明了这个抽象方法),你也可以添加自己需要的其他方法,就像 Dingo\Api\Transformer\Adapter\Fractal
那样。 transform
方法的目的是获取 $response
,然后和 $transformer
一起传递给转化层处理,转化层处理之后会返回一个数组,最终这个数组被 transform
方法返回。如果你的转化层很简单,可以完全在这个方法中实现所有逻辑。
$bindings
参数用于支持更多特性,比如添加元数据或者允许开发者通过回调与转化层交互。
$request
参数是当前的 HTTP 请求,当你的转化层需要查询字符串参数或者其他相关数据时会用到它。
自定义转化层类定义好了之后,可以将其配置到 .env
的 API_TRANSFORMER
配置项作为全局默认转化层,也可以在运行时通过如下方式动态设置:
$this->app['Dingo\Api\Transformer\Factory']->setAdapter(function ($app) { return new MyCustomTransformerAdapter(...); });
自定义响应数据格式
默认情况下,Dingo API 返回的响应会自动使用 JSON 格式并设置相应的 Content-Type
头。除了 JSON 之外 Dingo 还支持 JSONP 格式,该格式会将响应封装到一个回调中,要将响应数据默认格式调整为该格式,只需要简单将配置文件 config/api.php
中的默认 JSON 格式替换成 JSONP 即可:
'defaultFormat' => env('API_DEFAULT_FORMAT', 'json'), 'formats' => [ 'json' => Dingo\Api\Http\Response\Format\Jsonp::class, ],
默认情况下回调参数默认查询字符串是 callback
,这可以通过修改 Jsonp
构造函数的第一个参数来设置:
如果查询字符串不包含任何参数将会返回 JSON 响应。当然,你还可以在运行时动态设置返回数据格式:
use Dingo\Api\Http\Response; public function show($id) { $task = Task::findOrFail($id); Response::addFormatter('json', new Response\Format\Jsonp); return $this->response->item($task, new TaskTransformer()); }
如果 Dingo 自带的 JSON 和 JSONP 格式满足不了你的需求,还可以自定义数据格式类。自定义的数据格式类需要继承自 Dingo\Api\Http\Response\Format\Format
基类,同时还要实现 formatEloquentModel
、 formatEloquentCollection
、 formatArray
以及 getContentType
方法。
Morphing 和 Morphed 事件
在 Dingo API 发送响应之前会先对该响应数据进行转化(morph),这个过程包括运行所有转换器(Transformer)以及通过配置的响应数据格式发送响应。如果你需要控制响应数据如何被转化可以使用 Dingo 提供的 ResponseIsMorphing
(转化前触发)和 ResponseWasMorphed
(转化后触发)事件。
我们可以在 app/Listeners
目录下为上述事件创建监听器:
php artisan make:listener AddPaginationLinksToResponse
编辑 app/Listeners/AddPaginationLinksToResponse.php
代码如下:
<?php namespace App\Listeners; use Dingo\Api\Event\ResponseWasMorphed; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; class AddPaginationLinksToResponse { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param object $event * @return void */ public function handle(ResponseWasMorphed $event) { if (isset($event->content['meta']['pagination'])) { $links = $event->content['meta']['pagination']['links']; $next = isset($links['next']) ? $links['next'] : null; $previous = isset($links['previous']) ? $links['previous'] : null; $event->response->headers->set( 'link', sprintf('<%s>; rel="next", <%s>; rel="prev"', $next, $previous) ); } } }
然后通过在 EventServiceProvider
中注册事件及其对应监听器之间的映射关系来监听该事件:
use App\Listeners\AddPaginationLinksToResponse; use Dingo\Api\Event\ResponseWasMorphed; protected $listen = [ ... ResponseWasMorphed::class => [ AddPaginationLinksToResponse::class ] ];
现在所有包含分页链接的响应也会将这些链接添加到 Link
响应头。修改 Api\TaskController
的 index
方法实现代码如下:
public function index(Request $request) { $limit = $request->input('limit') ? : 10; $tasks = Task::paginate($limit); return $this->response->paginator($tasks, new TaskTransformer()); }
在 Postman 中访问该方法对应路由,就可以看到相应结果:
以上所述就是小编给大家介绍的《使用 Dingo API 扩展包快速构建 Laravel RESTful API(六) —— 转化器及响应构建器的高级使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 使用 Dingo API 扩展包快速构建 Laravel RESTful API(五) —— 转化器篇(下):结合响应构建器构...
- 使用 Dingo API 扩展包快速构建 Laravel RESTful API(四) —— 转化器篇(上):Fractal 及其使用入门
- vueSSR: 从0到1构建vueSSR项目 --- 路由的构建
- 在 Android Studio 里使用构建分析器提升构建性能
- [译] 使用 React 和 ImmutableJS 构建一个拖放布局构建器
- 为 Envoy 构建控制面指南第4部分:构建的可扩展性
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
决战618:探秘京东技术取胜之道
京东集团618作战指挥中心 / 电子工业出版社 / 2017-11 / 99
《决战618:探秘京东技术取胜之道》以京东技术团队备战618为主线,集合京东数百位技术专家,对京东所有和618相关的关键技术系统进行了一次全面的梳理和总结,是京东技术体系的智慧结晶。 《决战618:探秘京东技术取胜之道》从前端的网站、移动入口到后端的结算、履约、物流、供应链等体系,系统展示了京东最新的技术成就。同时,也涵盖了京东正在充分运用大数据、人工智能等先进技术对所有技术体系架构进行整体......一起来看看 《决战618:探秘京东技术取胜之道》 这本书的介绍吧!