Skip to content

Commit

Permalink
Merge pull request #4738 from kitsunet/task/adjust-to-flow-changes
Browse files Browse the repository at this point in the history
TASK: WIP Adjust to Flow Controller changes
  • Loading branch information
kitsunet authored Sep 12, 2024
2 parents f738c2d + 55b7068 commit ad7b32f
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ jobs:
git -C ../${{ env.NEOS_FOLDER }} checkout -b build
composer config repositories.neos '{ "type": "path", "url": "../${{ env.NEOS_FOLDER }}", "options": { "symlink": false } }'
composer require --no-update neos/neos-development-collection:"dev-build as ${{ env.NEOS_BRANCH_ALIAS }}"
# enable this line to require a specific flow version for testing
# composer require --no-update neos/flow-development-collection:"dev-your-flow-branch-name as ${{ env.NEOS_BRANCH_ALIAS }}"
- name: Cache Composer packages
id: composer-cache
Expand Down
3 changes: 2 additions & 1 deletion Neos.Fusion/Classes/Core/Runtime.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Neos\Flow\Mvc\ActionRequest;
use Neos\Flow\Mvc\ActionResponse;
use Neos\Flow\Mvc\Exception\StopActionException;
use Neos\Flow\Mvc\Exception\ForwardException;
use Neos\Flow\ObjectManagement\ObjectManagerInterface;
use Neos\Flow\Security\Exception as SecurityException;
use Neos\Fusion\Core\Cache\RuntimeContentCache;
Expand Down Expand Up @@ -478,7 +479,7 @@ public function evaluate(string $fusionPath, $contextObject = null, string $beha
// fast path for expression or value
try {
return $this->evaluateExpressionOrValueInternal($fusionPath, $fusionConfiguration, $contextObject);
} catch (StopActionException | SecurityException | RuntimeException $exception) {
} catch (StopActionException | ForwardException | SecurityException | RuntimeException $exception) {
throw $exception;
} catch (\Exception $exception) {
return $this->handleRenderingException($fusionPath, $exception, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* source code.
*/

use GuzzleHttp\Psr7\Response;
use Neos\Flow\Exception;
use Neos\Flow\Mvc\Exception\StopActionException;
use Neos\Flow\Tests\UnitTestCase;
Expand Down Expand Up @@ -99,7 +100,7 @@ public function unpackRuntimeException()
public function neverHandleStopActionException()
{
$this->expectException(StopActionException::class);
$this->handler->handleRenderingException('path', new StopActionException());
$this->handler->handleRenderingException('path', StopActionException::createForResponse(new Response(), ''));
}


Expand Down
19 changes: 9 additions & 10 deletions Neos.Neos/Classes/Controller/Backend/ModuleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
namespace Neos\Neos\Controller\Backend;

use Neos\Flow\Annotations as Flow;
use Neos\Flow\Mvc\ActionResponse;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Flow\Mvc\Dispatcher;
use Neos\Flow\Security\Account;
Expand Down Expand Up @@ -109,19 +108,19 @@ public function indexAction(array $module)

$moduleRequest->setArgument('__moduleConfiguration', $moduleConfiguration);

$moduleResponse = new ActionResponse();
$moduleResponse = $this->dispatcher->dispatch($moduleRequest);

$this->dispatcher->dispatch($moduleRequest, $moduleResponse);
$moduleResponse->mergeIntoParentResponse($this->response);

if ($moduleResponse->getRedirectUri() !== null) {
$this->redirectToUri($moduleResponse->getRedirectUri(), 0, $moduleResponse->getStatusCode());
if ($moduleResponse->hasHeader('Location')) {
// Preserve redirects see b57d72aeeaa2e6da4d9c0a80363025fefd63d813
return $moduleResponse;
} elseif ($moduleRequest->getFormat() !== 'html') {
// Allow ajax request with json or similar dd7e5c99924bf1b8618775bec08cc4f2cb1a6d2a
// todo just return $moduleResponse and trust its content-type instead of inferring the requested content-type
$mediaType = MediaTypes::getMediaTypeFromFilename('file.' . $moduleRequest->getFormat());
if ($mediaType !== 'application/octet-stream') {
$this->controllerContext->getResponse()->setContentType($mediaType);
$moduleResponse = $moduleResponse->withHeader('Content-Type', $mediaType);
}
return $moduleResponse->getContent();
return $moduleResponse;
} else {
/** @var ?Account $authenticatedAccount */
$authenticatedAccount = $this->securityContext->getAccount();
Expand All @@ -131,7 +130,7 @@ public function indexAction(array $module)

$this->view->assignMultiple([
'moduleClass' => implode('-', $modules),
'moduleContents' => $moduleResponse->getContent(),
'moduleContents' => $moduleResponse->getBody()->getContents(),
'title' => $moduleRequest->hasArgument('title')
? $moduleRequest->getArgument('title')
: $moduleConfiguration['label'],
Expand Down
16 changes: 11 additions & 5 deletions Neos.Neos/Classes/Fusion/PluginImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,21 @@ public function evaluate(): string
$this->node = $currentContext['node'];
$this->documentNode = $currentContext['documentNode'];
$parentResponse = $this->runtime->getControllerContext()->getResponse();
$pluginResponse = new ActionResponse();
$this->dispatcher->dispatch($this->buildPluginRequest(), $pluginResponse);
$pluginResponse = $this->dispatcher->dispatch($this->buildPluginRequest());

// We need to make sure to not merge content up into the parent ActionResponse
// because that would break the Fusion HttpResponse.
$content = $pluginResponse->getContent();
$pluginResponse->setContent('');
$content = $pluginResponse->getBody()->getContents();

$pluginResponse->mergeIntoParentResponse($parentResponse);
// hacky, but part of the deal. We have to manipulate the global response to redirect for example.
// transfer possible headers that have been set dynamically
foreach ($pluginResponse->getHeaders() as $name => $values) {
$parentResponse->setHttpHeader($name, $values);
}
// if the status code is 200 we assume it's the default and will not overrule it
if ($pluginResponse->getStatusCode() !== 200) {
$parentResponse->setStatusCode($pluginResponse->getStatusCode());
}

return $content;
}
Expand Down
35 changes: 18 additions & 17 deletions Neos.Neos/Classes/Service/Controller/AbstractServiceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@

namespace Neos\Neos\Service\Controller;

use GuzzleHttp\Psr7\Response;
use Neos\ContentRepository\Core\SharedModel\User\UserId;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Exception as FlowException;
use Neos\Flow\Log\ThrowableStorageInterface;
use Neos\Flow\Log\Utility\LogEnvironment;
use Neos\Flow\Mvc\ActionRequest;
use Neos\Flow\Mvc\ActionResponse;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Flow\Mvc\Exception\ForwardException;
use Neos\Flow\Mvc\Exception\StopActionException;
use Neos\Neos\Controller\BackendUserTranslationTrait;
use Neos\Neos\Domain\Service\UserService;
use Psr\Http\Message\ResponseInterface;

/**
* Abstract Service Controller
Expand Down Expand Up @@ -84,36 +86,35 @@ protected function errorAction(): never
/**
* Catch exceptions while processing an exception and respond to JSON format
* TODO: This is an explicit exception handling that will be replaced by format-enabled exception handlers.
*
* @param ActionRequest $request The request object
* @param ActionResponse $response The response, modified by this handler
* @return void
* @throws StopActionException
* @throws \Exception
*/
public function processRequest(ActionRequest $request, ActionResponse $response)
public function processRequest(ActionRequest $request): ResponseInterface
{
try {
parent::processRequest($request, $response);
} catch (StopActionException $exception) {
$response = parent::processRequest($request);
} catch (StopActionException | ForwardException $exception) {
throw $exception;
} catch (\Exception $exception) {
if ($this->request->getFormat() !== 'json') {
throw $exception;
}
$exceptionData = $this->convertException($exception);
$response->setContentType('application/json');
if ($exception instanceof FlowException) {
$response->setStatusCode($exception->getStatusCode());
} else {
$response->setStatusCode(500);
}
$response->setContent(json_encode(['error' => $exceptionData], JSON_THROW_ON_ERROR));
$body = json_encode(['error' => $exceptionData], JSON_THROW_ON_ERROR);
$response = new Response(
status: $exception instanceof FlowException
? $exception->getStatusCode()
: 500,
headers: [
'Content-Type' => 'application/json'
],
body: $body
);
$this->logger->error(
$this->throwableStorage2->logThrowable($exception),
LogEnvironment::fromMethodName(__METHOD__)
);
}

return $response;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions Neos.Neos/Tests/Unit/Fusion/PluginImplementationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
* source code.
*/

use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Uri;
use Neos\Flow\Mvc\ActionRequest;
use Neos\Flow\Mvc\ActionResponse;
use Neos\Flow\Mvc\Controller\ControllerContext;
use Neos\Flow\Mvc\Dispatcher;
use Neos\Flow\Mvc\RequestInterface;
use Neos\Flow\Tests\UnitTestCase;
use Neos\Fusion\Core\Runtime;
use Neos\Neos\Fusion\PluginImplementation;
Expand Down Expand Up @@ -54,7 +54,7 @@ class PluginImplementationTest extends UnitTestCase
protected $mockHttpRequest;

/**
* @var MockObject|RequestInterface
* @var MockObject|ActionRequest
*/
protected $mockActionRequest;

Expand Down Expand Up @@ -132,8 +132,8 @@ public function evaluateSetHeaderIntoParent(string $message, array $input, array
$this->_setHeadersIntoResponse($parentResponse, $input['parent']);
$this->mockControllerContext->method('getResponse')->willReturn($parentResponse);

$this->mockDispatcher->method('dispatch')->willReturnCallback(function (ActionRequest $request, ActionResponse $response) use ($input) {
$this->_setHeadersIntoResponse($response, $input['plugin']);
$this->mockDispatcher->method('dispatch')->willReturnCallback(function (ActionRequest $request) use ($input) {
return new Response(headers: $input['plugin']);
});

$this->mockRuntime->expects($this->any())->method('getCurrentContext')->willReturn(['node' => null, 'documentNode' => null]);
Expand Down

0 comments on commit ad7b32f

Please sign in to comment.