将数组从控制器传递到中间件 Slim 3 PHP
Pass array from controller to middleware Slim 3 PHP
我正在尝试将包含数据的数组传递给中间件并根据 Accept
HTTP header.
对其进行格式化
控制器从 db 获取数据并将其传递给响应 object。响应 object write()
方法只接受字符串:
public function getData(Request $request, Response $response): Response {
return $response->write($this->getUsers());
# This line of code should be fixed
}
中间件应该得到响应并正确格式化:
public function __invoke(Request $request, Response $response, callable $next) {
$response = $next($request, $response);
$body = $response->getBody();
switch ($request->getHeader('Accept')) {
case 'application/json':
return $response->withJson($body);
break;
case 'application/xml':
# Building an XML with the data
$newResponse = new \Slim\Http\Response();
return $newResponse->write($xml)->withHeader('Content-type', 'application/xml');
break;
case 'text/html':
# Building a HTML list with the data
$newResponse = new \Slim\Http\Response();
return $newResponse->write($list)->withHeader('Content-type', 'text/html;charset=utf-8');
break;
}
}
我有几条路线的行为类似:
$app->get('/api/users', 'UsersController:getUsers')->add($formatDataMiddleware);
$app->get('/api/products', 'UsersController:getProducts')->add($formatDataMiddleware);
通过使用中间件,我可以以声明的方式添加此类功能,从而使我的控制器保持精简。
如何将原始数据数组传递给响应并实现此模式?
Response
-Object 不提供这种功能,也没有一些扩展来做到这一点。所以需要调整Response-Class
class MyResponse extends \Slim\Http\Response {
private $data;
public function getData() {
return $this->data;
}
public function withData($data) {
$clone = clone $this;
$clone->data = $data;
return $clone;
}
}
然后您需要将新的 Response 添加到 Container
$container = $app->getContainer();
$container['response'] = function($container) { // this stuff is the default from slim
$headers = new Headers(['Content-Type' => 'text/html; charset=UTF-8']);
$response = new MyResponse(200, $headers); // <-- adjust that to the new class
return $response->withProtocolVersion($container->get('settings')['httpVersion']);
}
现在将响应类型更改为 MyResponse
并使用 withData
方法
public function getData(Request $request, \MyResponse $response): Response {
return $response->withData($this->getUsers());
}
最后你可以使用getData
方法并使用它的值并在中间件内部处理它。
public function __invoke(Request $request, \MyResponse $response, callable $next) {
$response = $next($request, $response);
$data = $response->getData();
// [..]
}
这就是您问题的答案。在我看来,一个更好的解决方案是一个助手 class 来完成您的中间件所做的事情,然后您可以这样做:
public function getData(Request $request, Response $response): Response {
$data = $this->getUsers();
return $this->helper->formatOutput($request, $response, $data);
}
为此,已经有一个库用于:rka-content-type-renderer
我正在尝试将包含数据的数组传递给中间件并根据 Accept
HTTP header.
对其进行格式化
控制器从 db 获取数据并将其传递给响应 object。响应 object write()
方法只接受字符串:
public function getData(Request $request, Response $response): Response {
return $response->write($this->getUsers());
# This line of code should be fixed
}
中间件应该得到响应并正确格式化:
public function __invoke(Request $request, Response $response, callable $next) {
$response = $next($request, $response);
$body = $response->getBody();
switch ($request->getHeader('Accept')) {
case 'application/json':
return $response->withJson($body);
break;
case 'application/xml':
# Building an XML with the data
$newResponse = new \Slim\Http\Response();
return $newResponse->write($xml)->withHeader('Content-type', 'application/xml');
break;
case 'text/html':
# Building a HTML list with the data
$newResponse = new \Slim\Http\Response();
return $newResponse->write($list)->withHeader('Content-type', 'text/html;charset=utf-8');
break;
}
}
我有几条路线的行为类似:
$app->get('/api/users', 'UsersController:getUsers')->add($formatDataMiddleware);
$app->get('/api/products', 'UsersController:getProducts')->add($formatDataMiddleware);
通过使用中间件,我可以以声明的方式添加此类功能,从而使我的控制器保持精简。
如何将原始数据数组传递给响应并实现此模式?
Response
-Object 不提供这种功能,也没有一些扩展来做到这一点。所以需要调整Response-Class
class MyResponse extends \Slim\Http\Response {
private $data;
public function getData() {
return $this->data;
}
public function withData($data) {
$clone = clone $this;
$clone->data = $data;
return $clone;
}
}
然后您需要将新的 Response 添加到 Container
$container = $app->getContainer();
$container['response'] = function($container) { // this stuff is the default from slim
$headers = new Headers(['Content-Type' => 'text/html; charset=UTF-8']);
$response = new MyResponse(200, $headers); // <-- adjust that to the new class
return $response->withProtocolVersion($container->get('settings')['httpVersion']);
}
现在将响应类型更改为 MyResponse
并使用 withData
方法
public function getData(Request $request, \MyResponse $response): Response {
return $response->withData($this->getUsers());
}
最后你可以使用getData
方法并使用它的值并在中间件内部处理它。
public function __invoke(Request $request, \MyResponse $response, callable $next) {
$response = $next($request, $response);
$data = $response->getData();
// [..]
}
这就是您问题的答案。在我看来,一个更好的解决方案是一个助手 class 来完成您的中间件所做的事情,然后您可以这样做:
public function getData(Request $request, Response $response): Response {
$data = $this->getUsers();
return $this->helper->formatOutput($request, $response, $data);
}
为此,已经有一个库用于:rka-content-type-renderer