From 9e281f9fdf8490bc409038acb2f250728fb3c614 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:20:15 +0100 Subject: [PATCH 1/2] TASK: Add documentation how work with psr responses in controller --- Neos.Flow/Classes/Mvc/ActionResponse.php | 33 ++++++++++++++++++- .../Mvc/Controller/AbstractController.php | 12 +++++++ Neos.Flow/Classes/Mvc/View/JsonView.php | 11 ++++++- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Neos.Flow/Classes/Mvc/ActionResponse.php b/Neos.Flow/Classes/Mvc/ActionResponse.php index da68121c92..1600075a9f 100644 --- a/Neos.Flow/Classes/Mvc/ActionResponse.php +++ b/Neos.Flow/Classes/Mvc/ActionResponse.php @@ -28,7 +28,16 @@ * via `$this->response` {@see AbstractController::$response} and pass it along to places. * But this behaviour is deprecated! * - * Instead, you can directly return a PSR repose {@see \GuzzleHttp\Psr7\Response} from a controller: + * Instead of modifying the repose via $this->response like + * + * - $this->response->addHttpHeader + * - $this->response->setHttpHeader + * - $this->response->setContentType + * - $this->response->setStatusCode + * + * you can directly return a PSR repose {@see \GuzzleHttp\Psr7\Response} from a controller. + * + * *set status code and contents and additional header:* * * ```php * public function myAction() @@ -38,6 +47,28 @@ * } * ``` * + * *modify a view response with additional header:* + * + * ```php + * public function myAction() + * { + * $response = $this->view->render(); + * if (!$response instanceof Response) { + * $response = new Response(body: $response); + * } + * return $response->withAddedHeader('X-My-Header', 'foo'); + * } + * ``` + * + * *render json without using the legacy json view:* + * + * ```php + * public function myAction() + * { + * return new Response(body: json_encode($data, JSON_THROW_ON_ERROR), headers: ['Content-Type' => 'application/json']); + * } + * ``` + * * @deprecated with Flow 9 * @Flow\Proxy(false) */ diff --git a/Neos.Flow/Classes/Mvc/Controller/AbstractController.php b/Neos.Flow/Classes/Mvc/Controller/AbstractController.php index 020bee1106..a83daa4240 100644 --- a/Neos.Flow/Classes/Mvc/Controller/AbstractController.php +++ b/Neos.Flow/Classes/Mvc/Controller/AbstractController.php @@ -11,6 +11,7 @@ * source code. */ +use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Utils; use Neos\Error\Messages as Error; use Neos\Flow\Annotations as Flow; @@ -63,6 +64,17 @@ abstract class AbstractController implements ControllerInterface /** * The legacy response which will is provide by this action controller + * + * Legacy ways to modify a repose: + * + * - $this->response->addHttpHeader + * - $this->response->setHttpHeader + * - $this->response->setContentType + * - $this->response->setStatusCode + * + * Please return a new {@see Response} instead from your controller action. + * Documentation to adjust your code is provided in {@see ActionResponse}. + * * @var ActionResponse * @deprecated with Flow 9 {@see ActionResponse} */ diff --git a/Neos.Flow/Classes/Mvc/View/JsonView.php b/Neos.Flow/Classes/Mvc/View/JsonView.php index 6935c669cf..a614500bee 100644 --- a/Neos.Flow/Classes/Mvc/View/JsonView.php +++ b/Neos.Flow/Classes/Mvc/View/JsonView.php @@ -23,7 +23,16 @@ /** * A JSON view * - * @deprecated please use json_encode instead + * please return a new response instead in your controller and set the Content-Type to application/json + * + * ```php + * public function myAction() + * { + * return new Response(body: json_encode($data, JSON_THROW_ON_ERROR), headers: ['Content-Type' => 'application/json']); + * } + * ``` + * + * @deprecated with Flow 9.0 please use the native json_encode instead, without relying on the flow object conversion magic */ class JsonView extends AbstractView { From 2ea87da6f38729a5771c60f73084f4fd061e9273 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:29:43 +0100 Subject: [PATCH 2/2] TASK: Inline ActionController::renderView and document behaviour change The behaviour change of not merging the views full psr response with the previously available legacy response is a combination of the changes - https://github.com/neos/flow-development-collection/pull/3286 - https://github.com/neos/flow-development-collection/pull/3311 --- .../Mvc/Controller/ActionController.php | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/Neos.Flow/Classes/Mvc/Controller/ActionController.php b/Neos.Flow/Classes/Mvc/Controller/ActionController.php index 55e16ba634..1c933828b4 100644 --- a/Neos.Flow/Classes/Mvc/Controller/ActionController.php +++ b/Neos.Flow/Classes/Mvc/Controller/ActionController.php @@ -11,10 +11,11 @@ * source code. */ +use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Utils; +use Neos\Error\Messages as Error; use Neos\Error\Messages\Result; use Neos\Flow\Annotations as Flow; -use Neos\Error\Messages as Error; use Neos\Flow\Log\ThrowableStorageInterface; use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Flow\Mvc\ActionRequest; @@ -36,7 +37,6 @@ use Neos\Flow\Reflection\ReflectionService; use Neos\Utility\TypeHandling; use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; use Psr\Log\LoggerInterface; /** @@ -563,7 +563,15 @@ protected function callActionMethod(ActionRequest $request, Arguments $arguments } if ($actionResult === null && $this->view instanceof ViewInterface) { - return $this->renderView($httpResponse); + $result = $this->view->render(); + + if ($result instanceof Response) { + // merging of the $httpResponse (previously $this->response) was previously done to a limited extend via the use of replaceHttpResponse. + // With Flow 9 the returned response will overrule any changes made to $this->response as there is no clear way to merge them. + return $result; + } + + return $httpResponse->withBody($result); } return $httpResponse->withBody(Utils::streamFor($actionResult)); @@ -828,20 +836,4 @@ protected function getErrorFlashMessage() { return new Error\Error('An error occurred while trying to call %1$s->%2$s()', null, [get_class($this), $this->actionMethodName]); } - - /** - * Renders the view and returns the psr response. - * - * If a stream is returned it will be applied (to the most likely empty response) which was previously available as $this->response. - */ - protected function renderView(ResponseInterface $httpResponse): ResponseInterface - { - $result = $this->view->render(); - - if ($result instanceof StreamInterface) { - return $httpResponse->withBody($result); - } - - return $result; - } }