将数组从控制器传递到中间件Slim 3 PHP

时间:2017-04-14 02:00:49

标签: php rest api slim middleware

我正在尝试将包含数据的数组传递给中间件,并根据Accept HTTP标头对其进行格式化。
控制器从db获取数据并将其传递给响应对象。响应对象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);

通过使用中间件,我可以以声明的方式添加这些功能,保持我的控制器很薄。

如何将原始数据数组传递给响应并实现此模式?

1 个答案:

答案 0 :(得分:1)

Response - 对象不提供此功能,也没有一些扩展来执行此操作。所以你需要调整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;
    }
}

然后您需要将新响应添加到容器

$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();
    // [..]
}

这就是你问题的答案。在我看来,一个更好的解决方案是帮助类,它可以完成你的中间件所做的事情,然后就可以这样:

public function getData(Request $request, Response $response): Response {
    $data = $this->getUsers();        
    return $this->helper->formatOutput($request, $response, $data);
}

为此,已有一个lib:rka-content-type-renderer