From 6d00b3ed4c651729fb9c4c12b61fd67ac93f7da4 Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Tue, 12 Sep 2023 21:54:17 +0200 Subject: [PATCH 1/5] FEATURE: Implement EditPreviewModes for Neos 9 with the new CR Since nodes have no context in Neos 9 the edit preview mode cannot be decided by asking the node any more. This change renovates the `UserInterfaceMode` and the `UserInterfaceModeService` to use php 8 value objects. The UserInterfaceMode object is then added as globalValue `userInterfaceMode` to the `Neos\Neos\FusionView`. The uses of the following fusion expressions have to be adjusted as follows: - `node.context.live` - `!renderingMode.isEdit` - `node.context.currentRenderingMode.edit` - `renderingMode.isEdit` - `node.context.currentRenderingMode.preview` - `renderingMode.isPreview` - `node.context.currentRenderingMode.name` - `renderingMode.name` Resolves: #4086 --- .../Controller/Frontend/NodeController.php | 17 +- .../Classes/Domain/Model/RenderingMode.php | 71 +++++++ .../Domain/Model/UserInterfaceMode.php | 187 ------------------ .../Domain/Service/RenderingModeService.php | 100 ++++++++++ .../Service/UserInterfaceModeService.php | 121 ------------ .../Classes/Fusion/Helper/NodeHelper.php | 5 + .../Classes/View/FusionExceptionView.php | 7 +- Neos.Neos/Classes/View/FusionView.php | 14 +- Neos.Neos/Configuration/Settings.yaml | 7 +- .../Override/GlobalCacheIdentifiers.fusion | 2 +- .../Prototypes/ContentCollection.fusion | 2 +- .../Prototypes/ContentElementWrapping.fusion | 1 + .../Private/Fusion/Prototypes/Editable.fusion | 5 +- .../Fusion/Prototypes/FallbackNode.fusion | 2 +- .../Private/Fusion/Prototypes/Page.fusion | 2 +- .../Resources/Private/Fusion/RootCase.fusion | 5 +- 16 files changed, 220 insertions(+), 328 deletions(-) create mode 100644 Neos.Neos/Classes/Domain/Model/RenderingMode.php delete mode 100644 Neos.Neos/Classes/Domain/Model/UserInterfaceMode.php create mode 100644 Neos.Neos/Classes/Domain/Service/RenderingModeService.php delete mode 100644 Neos.Neos/Classes/Domain/Service/UserInterfaceModeService.php diff --git a/Neos.Neos/Classes/Controller/Frontend/NodeController.php b/Neos.Neos/Classes/Controller/Frontend/NodeController.php index f529f9f3844..c8e776c035f 100644 --- a/Neos.Neos/Classes/Controller/Frontend/NodeController.php +++ b/Neos.Neos/Classes/Controller/Frontend/NodeController.php @@ -36,6 +36,7 @@ use Neos\Flow\Session\SessionInterface; use Neos\Flow\Utility\Now; use Neos\Neos\Domain\Service\NodeSiteResolvingService; +use Neos\Neos\Domain\Service\RenderingModeService; use Neos\Neos\FrontendRouting\Exception\InvalidShortcutException; use Neos\Neos\FrontendRouting\Exception\NodeNotFoundException; use Neos\Neos\FrontendRouting\NodeAddress; @@ -108,8 +109,12 @@ class NodeController extends ActionController */ protected $nodeSiteResolvingService; + #[Flow\Inject] + protected RenderingModeService $renderingModeService; + /** * @param string $node Legacy name for backwards compatibility of route components + * @param string $renderingModeName Name of the user interface mode to use * @throws NodeNotFoundException * @throws \Neos\Flow\Mvc\Exception\StopActionException * @throws \Neos\Flow\Mvc\Exception\UnsupportedRequestTypeException @@ -120,8 +125,14 @@ class NodeController extends ActionController * with unsafe requests from widgets or plugins that are rendered on the node * - For those the CSRF token is validated on the sub-request, so it is safe to be skipped here */ - public function previewAction(string $node): void + public function previewAction(string $node, string $renderingModeName = null): void { + if (is_null($renderingModeName)) { + $renderingMode = $this->renderingModeService->findByCurrentUser(); + } else { + $renderingMode = $this->renderingModeService->findByName($renderingModeName); + } + $visibilityConstraints = VisibilityConstraints::frontend(); if ($this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess')) { $visibilityConstraints = VisibilityConstraints::withoutRestrictions(); @@ -161,6 +172,8 @@ public function previewAction(string $node): void $this->handleShortcutNode($nodeAddress, $contentRepository); } + $this->view->setOption('renderingModeName', $renderingMode->name); + $this->view->assignMultiple([ 'value' => $nodeInstance, 'site' => $site, @@ -234,6 +247,8 @@ public function showAction(string $node, bool $showInvisible = false): void $this->handleShortcutNode($nodeAddress, $contentRepository); } + $this->view->setOption('renderingModeName', 'frontend'); + $this->view->assignMultiple([ 'value' => $nodeInstance, 'site' => $site, diff --git a/Neos.Neos/Classes/Domain/Model/RenderingMode.php b/Neos.Neos/Classes/Domain/Model/RenderingMode.php new file mode 100644 index 00000000000..19a78934b73 --- /dev/null +++ b/Neos.Neos/Classes/Domain/Model/RenderingMode.php @@ -0,0 +1,71 @@ + $options + */ + public function __construct( + public readonly string $name, + public readonly bool $isEdit, + public readonly bool $isPreview, + public readonly string $title, + public readonly string $fusionPath, + public readonly array $options + ) { + } + + /** + * Creates an UserInterfaceMode object by configuration + * + * @param string $modeName + * @param array $configuration + */ + public static function createFromConfiguration(string $modeName, array $configuration): RenderingMode + { + $mode = new RenderingMode( + $modeName, + $configuration['isEditingMode'] ?? false, + $configuration['isPreviewMode'] ?? false, + $configuration['title'] ?? $modeName, + $configuration['fusionRenderingPath'] ?? '', + $configuration['options'] ?? [], + ); + return $mode; + } + + /** + * Creates the live User interface mode + */ + public static function createFrontend(): RenderingMode + { + return new RenderingMode( + 'frontend', + false, + false, + 'Frontend', + '', + [] + ); + } +} diff --git a/Neos.Neos/Classes/Domain/Model/UserInterfaceMode.php b/Neos.Neos/Classes/Domain/Model/UserInterfaceMode.php deleted file mode 100644 index 50e24d461ad..00000000000 --- a/Neos.Neos/Classes/Domain/Model/UserInterfaceMode.php +++ /dev/null @@ -1,187 +0,0 @@ - - */ - protected $options; - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param string $name - * @return void - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * @return boolean - */ - public function isPreview() - { - return $this->preview; - } - - /** - * @param boolean $preview - * @return void - */ - public function setPreview($preview) - { - $this->preview = $preview; - } - - /** - * @return boolean - */ - public function isEdit() - { - return $this->edit; - } - - /** - * @param boolean $edit - * @return void - */ - public function setEdit($edit) - { - $this->edit = $edit; - } - - /** - * @return string - */ - public function getFusionPath() - { - return $this->fusionPath; - } - - /** - * @param string $fusionPath - * @return void - */ - public function setFusionPath($fusionPath) - { - $this->fusionPath = $fusionPath; - } - - /** - * @return string - */ - public function getTitle() - { - return $this->title; - } - - /** - * @param string $title - * @return void - */ - public function setTitle($title) - { - $this->title = $title; - } - - /** - * @return array - */ - public function getOptions() - { - return $this->options; - } - - public function getOptionByPath(string $path): mixed - { - return ObjectAccess::getPropertyPath($this->options, $path); - } - - /** - * @param array $options - */ - public function setOptions(array $options): void - { - $this->options = $options; - } - - /** - * Creates an UserInterfaceMode object by configuration - * - * @param string $modeName - * @param array $configuration - */ - public static function createByConfiguration($modeName, array $configuration): self - { - $mode = new self(); - $mode->setName($modeName); - $mode->setPreview($configuration['isPreviewMode']); - $mode->setEdit($configuration['isEditingMode']); - $mode->setTitle($configuration['title']); - - if (isset($configuration['fusionRenderingPath'])) { - $mode->setFusionPath($configuration['fusionRenderingPath']); - } else { - $mode->setFusionPath(''); - } - - if (isset($configuration['options']) && is_array($configuration['options'])) { - $mode->setOptions($configuration['options']); - } - - return $mode; - } -} diff --git a/Neos.Neos/Classes/Domain/Service/RenderingModeService.php b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php new file mode 100644 index 00000000000..c4735309552 --- /dev/null +++ b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php @@ -0,0 +1,100 @@ + + */ + protected $editPreviewModes; + + /** + * @Flow\InjectConfiguration(path="userInterface.defaultEditPreviewMode", package="Neos.Neos") + * @var string + */ + protected $defaultEditPreviewMode; + + /** + * Get the current rendering mode. + * Will return a live mode when not in backend. + */ + public function findByCurrentUser(): RenderingMode + { + if ( + $this->userService->getBackendUser() === null + || !$this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess') + ) { + return RenderingMode::createFrontend(); + } + + $modeName = $this->userService->getUserPreference('contentEditing.editPreviewMode'); + if ($modeName === null) { + $modeName = $this->defaultEditPreviewMode; + } + + return $this->findByName($modeName); + } + + /** + * Returns the default rendering mode. + */ + public function findDefault(): RenderingMode + { + return $this->findByName($this->defaultEditPreviewMode); + } + + /** + * Finds an rendering mode by name. + */ + public function findByName(string $modeName): RenderingMode + { + if ($modeName === 'frontend') { + return RenderingMode::createFrontend(); + } + if (isset($this->editPreviewModes[$modeName])) { + return RenderingMode::createFromConfiguration($modeName, $this->editPreviewModes[$modeName]); + } + throw new Exception( + 'The requested interface render mode "' . $modeName . '" is not configured.' + . ' Please make sure it exists as key in the Settings path "Neos.Neos.Interface.editPreviewModes".', + 1427715962 + ); + } +} diff --git a/Neos.Neos/Classes/Domain/Service/UserInterfaceModeService.php b/Neos.Neos/Classes/Domain/Service/UserInterfaceModeService.php deleted file mode 100644 index 9a56be5731e..00000000000 --- a/Neos.Neos/Classes/Domain/Service/UserInterfaceModeService.php +++ /dev/null @@ -1,121 +0,0 @@ - - */ - protected $editPreviewModes; - - /** - * @Flow\InjectConfiguration(path="userInterface.defaultEditPreviewMode", package="Neos.Neos") - * @var string - */ - protected $defaultEditPreviewMode; - - /** - * Get the current rendering mode (editPreviewMode). - * Will return a live mode when not in backend. - * - * @return UserInterfaceMode - */ - public function findModeByCurrentUser() - { - if ( - $this->userService->getBackendUser() === null - || !$this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess') - ) { - return $this->findModeByName('live'); - } - - $editPreviewMode = $this->userService->getUserPreference('contentEditing.editPreviewMode'); - if ($editPreviewMode === null) { - $editPreviewMode = $this->defaultEditPreviewMode; - } - - return $this->findModeByName($editPreviewMode); - } - - /** - * Returns the default rendering mode. - * - * @return UserInterfaceMode - */ - public function findDefaultMode() - { - $mode = $this->findModeByName($this->defaultEditPreviewMode); - - return $mode; - } - - /** - * Finds an rendering mode by name. - * - * @param string $modeName - * @return UserInterfaceMode - * @throws Exception - */ - public function findModeByName($modeName) - { - if (isset($this->editPreviewModes[$modeName])) { - if ($this->editPreviewModes[$modeName] instanceof UserInterfaceMode) { - $mode = $this->editPreviewModes[$modeName]; - } elseif (is_array($this->editPreviewModes[$modeName])) { - $mode = UserInterfaceMode::createByConfiguration($modeName, $this->editPreviewModes[$modeName]); - $this->editPreviewModes[$modeName] = $mode; - } else { - throw new Exception( - 'The requested interface render mode "' . $modeName . '" is not configured correctly.' - . ' Please make sure it is fully configured.', - 1427716331 - ); - } - } else { - throw new Exception( - 'The requested interface render mode "' . $modeName . '" is not configured.' - . ' Please make sure it exists as key in the Settings path "Neos.Neos.Interface.editPreviewModes".', - 1427715962 - ); - } - - return $mode; - } -} diff --git a/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php b/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php index aeecab5d191..0b3826d337f 100644 --- a/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php +++ b/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php @@ -95,6 +95,11 @@ public function labelForNode(Node $node): NodeLabelToken return new NodeLabelToken($node); } + /** + * @param Node $node + * @return bool + * @deprecated Remove before Neos 9.0 !!! Use ${userInterfaceMode.isEdit || userInterfaceMode.isPreview} instead + */ public function inBackend(Node $node): bool { $contentRepository = $this->contentRepositoryRegistry->get($node->subgraphIdentity->contentRepositoryId); diff --git a/Neos.Neos/Classes/View/FusionExceptionView.php b/Neos.Neos/Classes/View/FusionExceptionView.php index c9b3c4262fb..38e56f23d6b 100644 --- a/Neos.Neos/Classes/View/FusionExceptionView.php +++ b/Neos.Neos/Classes/View/FusionExceptionView.php @@ -38,6 +38,7 @@ use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\FusionService; use Neos\Neos\Domain\Service\SiteNodeUtility; +use Neos\Neos\Domain\Service\RenderingModeService; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; class FusionExceptionView extends AbstractView @@ -87,6 +88,9 @@ class FusionExceptionView extends AbstractView #[Flow\Inject] protected ContentRepositoryRegistry $contentRepositoryRegistry; + #[Flow\Inject] + protected RenderingModeService $userInterfaceModeService; + /** * @return string * @throws \Neos\Flow\I18n\Exception\InvalidLocaleIdentifierException @@ -199,7 +203,8 @@ protected function getFusionRuntime( $fusionConfiguration = $this->fusionService->createFusionConfigurationFromSite($site); $fusionGlobals = FusionGlobals::fromArray([ - 'request' => $this->controllerContext->getRequest() + 'request' => $this->controllerContext->getRequest(), + 'renderingModeName' => 'frontend' ]); $this->fusionRuntime = $this->runtimeFactory->createFromConfiguration( $fusionConfiguration, diff --git a/Neos.Neos/Classes/View/FusionView.php b/Neos.Neos/Classes/View/FusionView.php index 8264acdd06e..ba06676b7af 100644 --- a/Neos.Neos/Classes/View/FusionView.php +++ b/Neos.Neos/Classes/View/FusionView.php @@ -27,6 +27,7 @@ use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\FusionService; use Neos\Neos\Domain\Service\SiteNodeUtility; +use Neos\Neos\Domain\Service\RenderingModeService; use Neos\Neos\Exception; use Psr\Http\Message\ResponseInterface; @@ -49,6 +50,9 @@ class FusionView extends AbstractView #[Flow\Inject] protected SiteRepository $siteRepository; + #[Flow\Inject] + protected RenderingModeService $renderingModeService; + /** * @Flow\Inject * @var ContentRepositoryRegistry @@ -96,6 +100,11 @@ public function render(): string|ResponseInterface null, 'Flag to enable content caching inside Fusion (overriding the global setting).', 'boolean' + ], + 'renderingModeName' => [ + 'frontend', + 'Name of the user interface mode to use', + 'string' ] ]; @@ -229,8 +238,11 @@ protected function getFusionRuntime(Node $currentSiteNode) $site = $this->siteRepository->findSiteBySiteNode($currentSiteNode); $fusionConfiguration = $this->fusionService->createFusionConfigurationFromSite($site); + $renderingMode = $this->renderingModeService->findByName($this->getOption('renderingModeName')); + $fusionGlobals = FusionGlobals::fromArray([ - 'request' => $this->controllerContext->getRequest() + 'request' => $this->controllerContext->getRequest(), + 'renderingMode' => $renderingMode ]); $this->fusionRuntime = $this->runtimeFactory->createFromConfiguration( $fusionConfiguration, diff --git a/Neos.Neos/Configuration/Settings.yaml b/Neos.Neos/Configuration/Settings.yaml index 6becebb2d32..32117df22fc 100755 --- a/Neos.Neos/Configuration/Settings.yaml +++ b/Neos.Neos/Configuration/Settings.yaml @@ -271,12 +271,7 @@ Neos: defaultEditPreviewMode: inPlace editPreviewModes: - # Live mode is only configured here for consistency. You shouldn't change it. - live: - isEditingMode: false - isPreviewMode: false - fusionRenderingPath: '' - title: Live + # the "frontend" renderingMode is hardcoded internally and cannot be modified inPlace: isEditingMode: true isPreviewMode: false diff --git a/Neos.Neos/Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion b/Neos.Neos/Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion index 6e5417ac858..fc741bf792f 100644 --- a/Neos.Neos/Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion @@ -6,5 +6,5 @@ prototype(Neos.Fusion:GlobalCacheIdentifiers) { workspaceChain = ${Array.join(Array.keys(Neos.Caching.getWorkspaceChain(documentNode)), ',')} workspaceChain.@if.has = ${!!documentNode} - editPreviewMode = ${editPreviewMode} + renderingMode = ${renderingMode.name} } diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCollection.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCollection.fusion index 995e421037b..2cd673451ce 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCollection.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCollection.fusion @@ -27,7 +27,7 @@ prototype(Neos.Neos:ContentCollection) < prototype(Neos.Fusion:Tag) { attributes { class.@process.collectionClass = ${Array.push(value, 'neos-contentcollection')} data-__neos-insertion-anchor = true - data-__neos-insertion-anchor.@if.onlyRenderInBackend = ${Neos.Node.inBackend(documentNode) && node.context.currentRenderingMode.edit} + data-__neos-insertion-anchor.@if.onlyRenderInBackend = ${renderingMode.isEdit} } # Doesn't need to be set, if the node is a content collection. diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentElementWrapping.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentElementWrapping.fusion index f8f6553aee6..395eb95b8c4 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentElementWrapping.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentElementWrapping.fusion @@ -5,6 +5,7 @@ # prototype(Neos.Neos:ContentElementWrapping) { @class = 'Neos\\Neos\\Fusion\\ContentElementWrappingImplementation' + @if.inEditMode = ${renderingMode.isEdit} node = ${node} value = ${value} # Additional attributes in the form '': '' that will be rendered in the ContentElementWrapping diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/Editable.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/Editable.fusion index 9693c1d04dd..dcfc63bc311 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/Editable.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/Editable.fusion @@ -12,10 +12,7 @@ prototype(Neos.Neos:Editable) < prototype(Neos.Fusion:Component) { renderer = Neos.Fusion:Case { editable { - // TODO: add props.node.context.currentRenderingMode.edit - // condition = ${Neos.Node.inBackend(props.node) && props.node.context.currentRenderingMode.edit} - condition = ${Neos.Node.inBackend(props.node)} - + condition = ${renderingMode.isEdit} renderer = Neos.Fusion:Tag { tagName = ${props.block ? 'div' : 'span'} content = ${q(props.node).property(props.property)} diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion index c2126858f69..f82b10bca43 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion @@ -1,4 +1,4 @@ prototype(Neos.Neos:FallbackNode) < prototype(Neos.Neos:Content) { templatePath = 'resource://Neos.Neos/Private/Templates/FusionObjects/FallbackNode.html' - @if.onlyRenderInBackend = ${Neos.Node.inBackend(node)} + @if.onlyRenderInBackend = ${renderingMode.isEdit || renderingMode.isPreview} } diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion index e519e01980d..59216dc14a1 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion @@ -64,7 +64,7 @@ prototype(Neos.Neos:Page) < prototype(Neos.Fusion:Http.Message) { tagName = 'body' omitClosingTag = true attributes.class.@process.addNeosBackendClass = ${Array.push(value, 'neos-backend')} - attributes.class.@process.addNeosBackendClass.@if.onlyRenderWhenNotInLiveWorkspace = ${Neos.Node.inBackend(documentNode)} + attributes.class.@process.addNeosBackendClass.@if.onlyRenderWhenNotInLiveWorkspace = ${renderingMode.isEdit} } # Content of the body tag. To be defined by the integrator. diff --git a/Neos.Neos/Resources/Private/Fusion/RootCase.fusion b/Neos.Neos/Resources/Private/Fusion/RootCase.fusion index cd1cf2a84f7..957c8d4fd18 100644 --- a/Neos.Neos/Resources/Private/Fusion/RootCase.fusion +++ b/Neos.Neos/Resources/Private/Fusion/RootCase.fusion @@ -17,9 +17,8 @@ root { editPreviewMode { @position = 'end 9996' - possibleEditPreviewModePath = ${documentNode.context.currentRenderingMode.fusionPath} - condition = ${Neos.Node.inBackend(documentNode) && this.possibleEditPreviewModePath != null && this.possibleEditPreviewModePath != ''} - renderPath = ${'/' + this.possibleEditPreviewModePath} + condition = ${(renderingMode.isEdit || renderingMode.isPreview) && renderingMode.fusionPath} + renderPath = ${'/' + renderingMode.fusionPath} } format { From 70d21791135ac43d50a75134a4e5c0184526e9af Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Fri, 15 Sep 2023 20:43:19 +0200 Subject: [PATCH 2/5] TASK: Introduce constant `RenderingMode::FRONTEND` for system integrated rendering mode --- .../Controller/Frontend/NodeController.php | 3 ++- .../Classes/Domain/Model/RenderingMode.php | 17 +++++++++++++---- .../Domain/Service/RenderingModeService.php | 4 ++-- Neos.Neos/Classes/View/FusionExceptionView.php | 3 ++- Neos.Neos/Classes/View/FusionView.php | 3 ++- Neos.Neos/Configuration/Settings.yaml | 3 ++- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Neos.Neos/Classes/Controller/Frontend/NodeController.php b/Neos.Neos/Classes/Controller/Frontend/NodeController.php index c8e776c035f..26571bf01c4 100644 --- a/Neos.Neos/Classes/Controller/Frontend/NodeController.php +++ b/Neos.Neos/Classes/Controller/Frontend/NodeController.php @@ -35,6 +35,7 @@ use Neos\Flow\Security\Context as SecurityContext; use Neos\Flow\Session\SessionInterface; use Neos\Flow\Utility\Now; +use Neos\Neos\Domain\Model\RenderingMode; use Neos\Neos\Domain\Service\NodeSiteResolvingService; use Neos\Neos\Domain\Service\RenderingModeService; use Neos\Neos\FrontendRouting\Exception\InvalidShortcutException; @@ -247,7 +248,7 @@ public function showAction(string $node, bool $showInvisible = false): void $this->handleShortcutNode($nodeAddress, $contentRepository); } - $this->view->setOption('renderingModeName', 'frontend'); + $this->view->setOption('renderingModeName', RenderingMode::FRONTEND); $this->view->assignMultiple([ 'value' => $nodeInstance, diff --git a/Neos.Neos/Classes/Domain/Model/RenderingMode.php b/Neos.Neos/Classes/Domain/Model/RenderingMode.php index 19a78934b73..389f23c1f2f 100644 --- a/Neos.Neos/Classes/Domain/Model/RenderingMode.php +++ b/Neos.Neos/Classes/Domain/Model/RenderingMode.php @@ -14,7 +14,7 @@ namespace Neos\Neos\Domain\Model; -use Neos\Utility\ObjectAccess; +use Neos\Neos\Domain\Exception; /** * Describes the mode in which the Neos interface is rendering currently, @@ -22,6 +22,8 @@ */ class RenderingMode { + public const FRONTEND = 'frontend'; + /** * @param array $options */ @@ -36,13 +38,20 @@ public function __construct( } /** - * Creates an UserInterfaceMode object by configuration + * Creates a rendering mode from its configuration * * @param string $modeName * @param array $configuration */ public static function createFromConfiguration(string $modeName, array $configuration): RenderingMode { + if ($modeName === RenderingMode::FRONTEND) { + throw new Exception( + 'Cannot instantiate system rendering mode "frontend" from configuration.' + . ' Please use RenderingMode::createFrontend().', + 1694802951840 + ); + } $mode = new RenderingMode( $modeName, $configuration['isEditingMode'] ?? false, @@ -55,12 +64,12 @@ public static function createFromConfiguration(string $modeName, array $configur } /** - * Creates the live User interface mode + * Creates the system integrated rendering mode 'frontend' */ public static function createFrontend(): RenderingMode { return new RenderingMode( - 'frontend', + RenderingMode::FRONTEND, false, false, 'Frontend', diff --git a/Neos.Neos/Classes/Domain/Service/RenderingModeService.php b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php index c4735309552..296362aaf4c 100644 --- a/Neos.Neos/Classes/Domain/Service/RenderingModeService.php +++ b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php @@ -85,14 +85,14 @@ public function findDefault(): RenderingMode */ public function findByName(string $modeName): RenderingMode { - if ($modeName === 'frontend') { + if ($modeName === RenderingMode::FRONTEND) { return RenderingMode::createFrontend(); } if (isset($this->editPreviewModes[$modeName])) { return RenderingMode::createFromConfiguration($modeName, $this->editPreviewModes[$modeName]); } throw new Exception( - 'The requested interface render mode "' . $modeName . '" is not configured.' + 'The requested rendering mode "' . $modeName . '" is not configured.' . ' Please make sure it exists as key in the Settings path "Neos.Neos.Interface.editPreviewModes".', 1427715962 ); diff --git a/Neos.Neos/Classes/View/FusionExceptionView.php b/Neos.Neos/Classes/View/FusionExceptionView.php index 38e56f23d6b..5176990ff4b 100644 --- a/Neos.Neos/Classes/View/FusionExceptionView.php +++ b/Neos.Neos/Classes/View/FusionExceptionView.php @@ -35,6 +35,7 @@ use Neos\Fusion\Core\Runtime as FusionRuntime; use Neos\Fusion\Core\RuntimeFactory; use Neos\Fusion\Exception\RuntimeException; +use Neos\Neos\Domain\Model\RenderingMode; use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\FusionService; use Neos\Neos\Domain\Service\SiteNodeUtility; @@ -204,7 +205,7 @@ protected function getFusionRuntime( $fusionGlobals = FusionGlobals::fromArray([ 'request' => $this->controllerContext->getRequest(), - 'renderingModeName' => 'frontend' + 'renderingModeName' => RenderingMode::FRONTEND ]); $this->fusionRuntime = $this->runtimeFactory->createFromConfiguration( $fusionConfiguration, diff --git a/Neos.Neos/Classes/View/FusionView.php b/Neos.Neos/Classes/View/FusionView.php index ba06676b7af..e9c2ba43ab7 100644 --- a/Neos.Neos/Classes/View/FusionView.php +++ b/Neos.Neos/Classes/View/FusionView.php @@ -24,6 +24,7 @@ use Neos\Fusion\Core\Runtime; use Neos\Fusion\Core\RuntimeFactory; use Neos\Fusion\Exception\RuntimeException; +use Neos\Neos\Domain\Model\RenderingMode; use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\FusionService; use Neos\Neos\Domain\Service\SiteNodeUtility; @@ -102,7 +103,7 @@ public function render(): string|ResponseInterface 'boolean' ], 'renderingModeName' => [ - 'frontend', + RenderingMode::FRONTEND, 'Name of the user interface mode to use', 'string' ] diff --git a/Neos.Neos/Configuration/Settings.yaml b/Neos.Neos/Configuration/Settings.yaml index 32117df22fc..16a96abe01f 100755 --- a/Neos.Neos/Configuration/Settings.yaml +++ b/Neos.Neos/Configuration/Settings.yaml @@ -271,7 +271,8 @@ Neos: defaultEditPreviewMode: inPlace editPreviewModes: - # the "frontend" renderingMode is hardcoded internally and cannot be modified + # the system integrated rendering mode "frontend" cannot be configured + # frontend: {} inPlace: isEditingMode: true isPreviewMode: false From e2c6f5e27c9690611fc0c562c648a0f9c335a87e Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Fri, 15 Sep 2023 20:47:11 +0200 Subject: [PATCH 3/5] TASK: RenderingModeService instances runtime cache --- .../Domain/Service/RenderingModeService.php | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Neos.Neos/Classes/Domain/Service/RenderingModeService.php b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php index 296362aaf4c..9930e4d26aa 100644 --- a/Neos.Neos/Classes/Domain/Service/RenderingModeService.php +++ b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php @@ -51,6 +51,11 @@ class RenderingModeService */ protected $defaultEditPreviewMode; + /** + * @var array + */ + private array $instances = []; + /** * Get the current rendering mode. * Will return a live mode when not in backend. @@ -85,16 +90,14 @@ public function findDefault(): RenderingMode */ public function findByName(string $modeName): RenderingMode { - if ($modeName === RenderingMode::FRONTEND) { - return RenderingMode::createFrontend(); - } - if (isset($this->editPreviewModes[$modeName])) { - return RenderingMode::createFromConfiguration($modeName, $this->editPreviewModes[$modeName]); - } - throw new Exception( - 'The requested rendering mode "' . $modeName . '" is not configured.' + return $this->instances[$modeName] ??= match (true) { + $modeName === RenderingMode::FRONTEND => RenderingMode::createFrontend(), + isset($this->editPreviewModes[$modeName]) => RenderingMode::createFromConfiguration($modeName, $this->editPreviewModes[$modeName]), + default => throw new Exception( + 'The requested rendering mode "' . $modeName . '" is not configured.' . ' Please make sure it exists as key in the Settings path "Neos.Neos.Interface.editPreviewModes".', - 1427715962 - ); + 1427715962 + ) + }; } } From 0463da99b0e8128ba1090ee77bcb325fff271dcb Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Fri, 15 Sep 2023 20:53:02 +0200 Subject: [PATCH 4/5] TASK: Remove half-baked solution of session independent preview's Otherwise, this feature would only work for this one page, successive links will currently not have that query param added - the linking service still needs to learn this, but we delay this for another time. --- .../Classes/Controller/Frontend/NodeController.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Neos.Neos/Classes/Controller/Frontend/NodeController.php b/Neos.Neos/Classes/Controller/Frontend/NodeController.php index 26571bf01c4..d7ef5446465 100644 --- a/Neos.Neos/Classes/Controller/Frontend/NodeController.php +++ b/Neos.Neos/Classes/Controller/Frontend/NodeController.php @@ -115,7 +115,6 @@ class NodeController extends ActionController /** * @param string $node Legacy name for backwards compatibility of route components - * @param string $renderingModeName Name of the user interface mode to use * @throws NodeNotFoundException * @throws \Neos\Flow\Mvc\Exception\StopActionException * @throws \Neos\Flow\Mvc\Exception\UnsupportedRequestTypeException @@ -126,13 +125,10 @@ class NodeController extends ActionController * with unsafe requests from widgets or plugins that are rendered on the node * - For those the CSRF token is validated on the sub-request, so it is safe to be skipped here */ - public function previewAction(string $node, string $renderingModeName = null): void + public function previewAction(string $node): void { - if (is_null($renderingModeName)) { - $renderingMode = $this->renderingModeService->findByCurrentUser(); - } else { - $renderingMode = $this->renderingModeService->findByName($renderingModeName); - } + // @todo add $renderingModeName as parameter and append it for successive links again as get parameter to node uris + $renderingMode = $this->renderingModeService->findByCurrentUser(); $visibilityConstraints = VisibilityConstraints::frontend(); if ($this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess')) { From 5639b6b716a23bac478b9dc50b008ef6537974fc Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Sat, 16 Sep 2023 16:41:12 +0200 Subject: [PATCH 5/5] TASK: Optimize runtime cache for RenderingModes for readability --- .../Domain/Service/RenderingModeService.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Neos.Neos/Classes/Domain/Service/RenderingModeService.php b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php index 9930e4d26aa..5f63b9f313b 100644 --- a/Neos.Neos/Classes/Domain/Service/RenderingModeService.php +++ b/Neos.Neos/Classes/Domain/Service/RenderingModeService.php @@ -90,14 +90,20 @@ public function findDefault(): RenderingMode */ public function findByName(string $modeName): RenderingMode { - return $this->instances[$modeName] ??= match (true) { - $modeName === RenderingMode::FRONTEND => RenderingMode::createFrontend(), - isset($this->editPreviewModes[$modeName]) => RenderingMode::createFromConfiguration($modeName, $this->editPreviewModes[$modeName]), - default => throw new Exception( + if ($instance = $this->instances[$modeName] ?? null) { + return $instance; + } + if ($modeName === RenderingMode::FRONTEND) { + $this->instances[$modeName] = RenderingMode::createFrontend(); + } elseif (isset($this->editPreviewModes[$modeName])) { + $this->instances[$modeName] = RenderingMode::createFromConfiguration($modeName, $this->editPreviewModes[$modeName]); + } else { + throw new Exception( 'The requested rendering mode "' . $modeName . '" is not configured.' . ' Please make sure it exists as key in the Settings path "Neos.Neos.Interface.editPreviewModes".', 1427715962 - ) - }; + ); + } + return $this->instances[$modeName]; } }