Deprecation: #92784 - Extbase controller actions must return ResponseInterface¶
See forge#92784
Description¶
Until now, Extbase controller actions could return either nothing (void), null, a string, or an object that implements __toString()
.
From now on Extbase expects actions to return an instance of Psr\Http\Message\ResponseInterface
.
Impact¶
All actions that do not return an instance of Psr\Http\Message\ResponseInterface
trigger a PHP E_USER_DEPRECATED
error and will fail as of TYPO3 v12.
Affected Installations¶
All installations that use Extbase controller actions which don't return an instance of Psr\Http\Message\ResponseInterface
.
Migration¶
Since the core follows not only PSR-7 (https://www.php-fig.org/psr/psr-7/)
but also PSR-17 (https://www.php-fig.org/psr/psr-17/),
the PSR-17 factories should be used. Both the $responseFactory
as
well as the $streamFactory
are available in all extbase controllers.
The $responseFactory
can be used to create a blank response object
whose content and headers can be set freely. The content can therfore be
set using the $streamFactory
.
Example:
public function listAction(): ResponseInterface
{
$items = $this->itemRepository->findAll();
$this->view->assign('items', $items);
return $this->responseFactory->createResponse()
->withAddedHeader('Content-Type', 'text/html; charset=utf-8')
->withBody($this->streamFactory->createStream($this->view->render()));
}
This example only shows the most common use case. It causes html with a Content-Type: text/html
header and
http code 200 Ok
returned as the response to the client.
Tip
Using the factory is a clean architectural solution but it's a lot of new code when migration from returning nothing at all.
To ease the migration path, method htmlResponse(string $html = null)
has been introduced which allows for a quite small change.
When called without an argument, said method renders the current view.
public function listAction(): ResponseInterface
{
$items = $this->itemRepository->findAll();
$this->view->assign('items', $items);
return $this->htmlResponse();
}
Of course you are free to adjust this response object before returning it.
Example:
public function listAction(): ResponseInterface
{
$items = $this->itemRepository->findAll();
$this->view->assign('items', $items);
return $this->responseFactory
->createResponse()
->withHeader('Cache-Control', 'must-revalidate')
->withHeader('Content-Type', 'text/html; charset=utf-8')
->withStatus(200, 'Super ok!')
->withBody($this->streamFactory->createStream($this->view->render()));
}
Tip
To adjust the content of an already created PSR-7 response object,
$response->getBody()->write()
can be used.
Tip
Since Extbase uses PSR-7 responses, you should make yourself familiar with its API. Documentation and more information regarding PSR-7 responses can be found here: https://www.php-fig.org/psr/psr-7/#33-psrhttpmessageresponseinterface
In case you are using the JsonView
in your extbase controller, you may
want to ease the migration path with the new jsonResponse(string $json = null)
method. Similar to htmlResponse()
, this method creates a PSR-7 Response
with the Content-Type: application/json
header and http code 200 Ok
.
If argument $json
is omitted, the current view is rendered automatically.
Example:
public function listApiAction(): ResponseInterface
{
$items = $this->itemRepository->findAll();
$this->view->assign('value', [
'items' => $items
]);
return $this->jsonResponse();
}
Above example is equivalent to:
public function listApiAction(): ResponseInterface
{
$items = $this->itemRepository->findAll();
$this->view->assign('value', [
'items' => $items
]);
return $this->responseFactory
->createResponse()
->withHeader('Content-Type', 'application/json; charset=utf-8')
->withBody($this->streamFactory->createStream($this->view->render()));
}