如何在League Fractal中使用?include=参数包含多嵌套子关系?
在League Fractal中使用
?include参数同时包含多个嵌套子关系 刚好我之前在项目里折腾过League Fractal的嵌套关联加载,你提到的通过?include参数同时加载多个嵌套子关系的需求完全可以实现,下面给你拆解具体步骤:
1. 先搞懂Fractal的Include语法规则
Fractal的include参数支持两种关键符号:
- 用
.表示嵌套关联(比如books.author表示加载books关联下的author) - 用
,或者:表示同级关联(两种符号都支持,比如books.author:books.downloads或者books.author,books.downloads,都表示同时加载books下的author和downloads)
你的示例请求/store/1?include=books.author:downloads,如果是想加载store下的books,同时每个book加载author和downloads,更清晰的写法是books.author,books.downloads,不过Fractal也能识别:分隔的写法。
2. 配置对应的Transformer类
每个资源都需要创建Transformer,并且在里面定义可包含的关联关系:
首先是DownloadsTransformer(处理下载统计数据)
class DownloadsTransformer extends TransformerAbstract { public function transform(Downloads $downloads) { return [ 'weekly' => $downloads->weekly, 'monthly' => $downloads->monthly, ]; } }
然后是AuthorTransformer(处理作者数据)
class AuthorTransformer extends TransformerAbstract { public function transform(Author $author) { return [ 'id' => $author->id, 'name' => $author->name, ]; } }
核心的BookTransformer(定义可包含的author和downloads关联)
class BookTransformer extends TransformerAbstract { // 声明当前资源支持哪些可包含的关联 protected $availableIncludes = ['author', 'downloads']; public function transform(Book $book) { return [ 'id' => $book->id, 'name' => $book->name, ]; } // 处理author关联的加载逻辑 public function includeAuthor(Book $book) { $author = $book->author; // 返回单个关联资源 return $this->item($author, new AuthorTransformer()); } // 处理downloads关联的加载逻辑 public function includeDownloads(Book $book) { $downloads = $book->downloads; return $this->item($downloads, new DownloadsTransformer()); } }
最后是StoreTransformer(关联到books资源)
class StoreTransformer extends TransformerAbstract { protected $availableIncludes = ['books']; public function transform(Store $store) { return [ 'id' => $store->id, 'name' => $store->name, ]; } // 处理store下的books集合 public function includeBooks(Store $store) { $books = $store->books; // 返回集合类型的关联资源 return $this->collection($books, new BookTransformer()); } }
3. 在控制器中处理Include参数
在接口控制器里,需要把请求中的include参数传递给Fractal Manager,让它自动处理关联加载:
use League\Fractal\Manager; use League\Fractal\Resource\Item; public function show($id) { // 获取目标store数据(这里假设用Eloquent ORM,你可以替换成自己的数据源) $store = Store::with(['books.author', 'books.downloads'])->findOrFail($id); $fractal = new Manager(); // 解析请求中的include参数 $includeParam = request()->get('include'); if ($includeParam) { $fractal->parseIncludes($includeParam); } // 包装资源并生成响应 $resource = new Item($store, new StoreTransformer()); return response()->json($fractal->createData($resource)->toArray()); }
注意:这里用
with(['books.author', 'books.downloads'])是为了提前预加载关联,避免N+1查询问题,如果你用的不是Eloquent,记得自己处理关联数据的预加载逻辑。
4. 请求示例与返回结果
当你调用接口/store/1?include=books.author,books.downloads时,返回的简化结构会和你期望的一致:
{ "data": { "id": 1, "name": "My Book Store", "books": { "data": [ { "id": 1, "name": "Book Name", "author": { "data": { "id": 1, "name": "Author name" } }, "downloads": { "data": { "weekly": 100, "monthly": 1000 } } } ] } } }
如果你的接口是直接返回单本图书(而非store下的图书集合),只需要把顶层Transformer换成BookTransformer,并使用?include=author,downloads即可。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

