[英]Laravel: cannot access resource collection in middleware
I'm trying to create a middleware which wraps the returned response into a uniform JSON response for my API.我正在尝试创建一个中间件,它将返回的响应包装为我的 API 的统一 JSON 响应。 This will ensure that all API responses have the same base structure which looks like this:这将确保所有 API 响应具有相同的基本结构,如下所示:
{
"success": true,
"data": {...}
}
Now this is the middleware I am currently using:现在这是我目前使用的中间件:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ApiResponseWrapper
{
/**
* Handle an incoming request.
*
* @param Request $request
*
* @return mixed
*/
public function handle($request, Closure $next)
{
/** @var Response $response */
$response = $next($request);
$original = $response->getOriginalContent();
$content = [
'success' => $response->isSuccessful(),
'data' => $original,
];
$jsonContent = json_encode($content, JsonResponse::DEFAULT_ENCODING_OPTIONS);
$response->setContent($jsonContent);
return $response;
}
}
The two key points of this middleware are:这个中间件的两个关键点是:
$original = $response->getOriginalContent();
$original = $response->getOriginalContent();
line gets the content of the response to wrap. line 获取要换行的响应内容。json_encode
the $content
with the default encoding options for a JSON response.这就是为什么我使用 JSON 响应的默认编码选项对$content
进行json_encode
。 The problem arises when I want to pass a paginated ResourceCollection
into the middleware.当我想将分页的ResourceCollection
传递到中间件时,就会出现问题。 The controller method looks like this:控制器方法如下所示:
public function index(): AnonymousResourceCollection
{
/** @var User $user */
$user = auth()->user();
return PostResource::collection($user->posts->paginate(20));
}
Normally, the ->paginate(...)
method does not exist in a Laravel Collection.通常,Laravel 集合中不存在->paginate(...)
方法。 It is a macro taken from here: gist.github.com/simonhamp/549e8821946e2c40a617c85d2cf5af5e .这是从这里获取的宏: gist.github.com/simonhamp/549e8821946e2c40a617c85d2cf5af5e 。
If I now hit the endpoint that calls the index()
method, the expected output is something like this:如果我现在点击调用index()
方法的端点,预期的输出是这样的:
{
"success": true,
"data": {
"data": [
<PostResource as JSON object>
],
"meta": {...},
"links": {...},
}
}
But what I actually get is this:但我实际得到的是:
{
"success": true,
"data": [
<Post Model as array>
]
}
I thought I might have to call a method to encode the $original
(which is of type Illuminate\\Support\\Collection
) into a paginated resource collection, but I didn't find one.我想我可能需要调用一种方法来将$original
(类型为Illuminate\\Support\\Collection
)编码为分页资源集合,但我没有找到。
All other responses are fine.其他回复都正常。 For example on another controller method I simply return an array or a string and they are wrapped as expected.例如,在另一个控制器方法上,我只返回一个数组或字符串,它们按预期包装。
Does anyone have an idea what is wrong here?有谁知道这里有什么问题?
Edit:编辑:
I also tried to add this before the $content
variable is set:我还尝试在设置$content
变量之前添加它:
if (method_exists($original, 'toArray')) {
$original = $original->toArray();
}
It results in the same output for ResourceCollections
.它导致ResourceCollections
输出相同。
After investigating the variable types and looking through the Laravel API, I found that the easiest solution was to just check if the response is a JsonResponse
and get the rendered pagination data from it:在调查变量类型并查看 Laravel API 后,我发现最简单的解决方案是检查响应是否为JsonResponse
并从中获取呈现的分页数据:
public function handle($request, Closure $next)
{
/** @var Response $response */
$response = $next($request);
$content = [
'success' => $response->isSuccessful(),
];
if ($response instanceof JsonResponse) {
/** @var JsonResponse $response */
$data = $response->getData(true);
$content = array_merge($content, $data);
} else {
$content['data'] = $response->getOriginalContent();
}
$jsonContent = json_encode($content, JsonResponse::DEFAULT_ENCODING_OPTIONS);
$response->setContent($jsonContent);
return $response;
}
This results in the expected responses for my use case:这导致了我的用例的预期响应:
{
"success": true,
"data": [
<PostResource as JSON object>
],
"meta": {...},
"links": {...},
}
Also note that I originally specified the data
, meta
and links
keys within the wrapping data
key.另请注意,我最初在包装data
键中指定了data
、 meta
和links
键。 I find the result above a bit prettier because I got around double wrapped data
.我发现上面的结果有点漂亮,因为我绕过了双包装data
。
I hope this will help anyone who came across this question!我希望这会帮助任何遇到这个问题的人!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.