Skip to content

Commit

Permalink
FEATURE: Implement EditPreviewModes for the new ui
Browse files Browse the repository at this point in the history
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` - `userInterfaceMode.live`
- `node.context.currentRenderingMode.edit` - `userInterfaceMode.edit`
- `node.context.currentRenderingMode.preview` - `userInterfaceMode.preview`
- `node.context.currentRenderingMode.name` - `userInterfaceMode.name`

Resolves: #4086
  • Loading branch information
mficzel committed Sep 12, 2023
1 parent 8cb03d5 commit 06ccf27
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 193 deletions.
15 changes: 14 additions & 1 deletion Neos.Neos/Classes/Controller/Frontend/NodeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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\UserInterfaceModeService;
use Neos\Neos\FrontendRouting\Exception\InvalidShortcutException;
use Neos\Neos\FrontendRouting\Exception\NodeNotFoundException;
use Neos\Neos\FrontendRouting\NodeAddress;
Expand Down Expand Up @@ -108,8 +109,12 @@ class NodeController extends ActionController
*/
protected $nodeSiteResolvingService;

#[Flow\Inject]
protected UserInterfaceModeService $userInterfaceModeService;

/**
* @param string $node Legacy name for backwards compatibility of route components
* @param string $uiModeName Name of the user interface mode to use
* @throws NodeNotFoundException
* @throws \Neos\Flow\Mvc\Exception\StopActionException
* @throws \Neos\Flow\Mvc\Exception\UnsupportedRequestTypeException
Expand All @@ -120,8 +125,12 @@ 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 $uiModeName = null): void
{
if (is_null($uiModeName)) {
$uiModeName = $this->userInterfaceModeService->findUserInterfaceModeNameByCurrentUser();
}

$visibilityConstraints = VisibilityConstraints::frontend();
if ($this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess')) {
$visibilityConstraints = VisibilityConstraints::withoutRestrictions();
Expand Down Expand Up @@ -161,6 +170,8 @@ public function previewAction(string $node): void
$this->handleShortcutNode($nodeAddress, $contentRepository);
}

$this->view->setOption('userInterfaceModeName', $uiModeName);

$this->view->assignMultiple([
'value' => $nodeInstance,
'site' => $site,
Expand Down Expand Up @@ -234,6 +245,8 @@ public function showAction(string $node, bool $showInvisible = false): void
$this->handleShortcutNode($nodeAddress, $contentRepository);
}

$this->view->setOption('userInterfaceModeName', 'live');

$this->view->assignMultiple([
'value' => $nodeInstance,
'site' => $site,
Expand Down
186 changes: 49 additions & 137 deletions Neos.Neos/Classes/Domain/Model/UserInterfaceMode.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,139 +23,36 @@
class UserInterfaceMode
{
/**
* @var string
*/
protected $name;

/**
* @var boolean
*/
protected $preview;

/**
* @var boolean
*/
protected $edit;

/**
* @var string
*/
protected $fusionPath;

/**
* @var string
*/
protected $title;

/**
* @var array<string,mixed>
*/
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
* @param array<string,mixed> $options
*/
public function setTitle($title)
{
$this->title = $title;
public function __construct(
public readonly string $name,
public readonly UserInterfaceModeType $type,
public readonly string $title,
public readonly string $fusionPath,
public readonly array $options
) {
if ($name == 'live' && $type != UserInterfaceModeType::Live) {
throw new \InvalidArgumentException('UserInterfaceMode "live" has to be live');
}
if ($name == 'live' && in_array($type, [UserInterfaceModeType::Edit, UserInterfaceModeType::Preview])) {
throw new \InvalidArgumentException('UserInterfaceMode "live" mode cannot be edit or preview mode');
}
}

/**
* @return array<string,mixed>
*/
public function getOptions()
public function isLive(): bool
{
return $this->options;
return $this->type === UserInterfaceModeType::Live;
}

public function getOptionByPath(string $path): mixed
public function isEdit(): bool
{
return ObjectAccess::getPropertyPath($this->options, $path);
return $this->type === UserInterfaceModeType::Edit;
}

/**
* @param array<string,mixed> $options
*/
public function setOptions(array $options): void
public function isPreview(): bool
{
$this->options = $options;
return $this->type === UserInterfaceModeType::Preview;
}

/**
Expand All @@ -164,24 +61,39 @@ public function setOptions(array $options): void
* @param string $modeName
* @param array<string,mixed> $configuration
*/
public static function createByConfiguration($modeName, array $configuration): self
public static function createByConfiguration(string $modeName, array $configuration): UserInterfaceMode
{
$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']);
if ($configuration['isEditingMode'] ?? false) {
$type = UserInterfaceModeType::Edit;
} elseif ($configuration['isPreviewMode'] ?? false) {
$type = UserInterfaceModeType::Preview;
} elseif ($modeName === 'live'){
$type = UserInterfaceModeType::Live;
} else {
$mode->setFusionPath('');
}

if (isset($configuration['options']) && is_array($configuration['options'])) {
$mode->setOptions($configuration['options']);
throw new \InvalidArgumentException(sprintf('Type of UserInterfaceMode "%s" could not be determined', $modeName));
}

$mode = new UserInterfaceMode(
$modeName,
$type,
$configuration['title'] ?? $modeName,
$configuration['fusionRenderingPath'] ?? '',
$configuration['options'] ?? [],
);
return $mode;
}

/**
* Creates the live User interface mode
*/
public static function createLive(): UserInterfaceMode
{
return new UserInterfaceMode(
'live',
UserInterfaceModeType::Live,
'Live',
'',
[]
);
}
}
24 changes: 24 additions & 0 deletions Neos.Neos/Classes/Domain/Model/UserInterfaceModeType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

declare(strict_types=1);

namespace Neos\Neos\Domain\Model;

use Neos\Utility\ObjectAccess;

enum UserInterfaceModeType: string
{
case Live = 'live';
case Edit = 'edit';
case Preview = 'preview';
}
51 changes: 15 additions & 36 deletions Neos.Neos/Classes/Domain/Service/UserInterfaceModeService.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,68 +54,47 @@ class UserInterfaceModeService
/**
* Get the current rendering mode (editPreviewMode).
* Will return a live mode when not in backend.
*
* @return UserInterfaceMode
*/
public function findModeByCurrentUser()
public function findUserInterfaceModeNameByCurrentUser(): string
{
if (
$this->userService->getBackendUser() === null
|| !$this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess')
) {
return $this->findModeByName('live');
return 'live';
}

$editPreviewMode = $this->userService->getUserPreference('contentEditing.editPreviewMode');
if ($editPreviewMode === null) {
$editPreviewMode = $this->defaultEditPreviewMode;
}

return $this->findModeByName($editPreviewMode);
return $editPreviewMode;
}

/**
* Returns the default rendering mode.
*
* @return UserInterfaceMode
*/
public function findDefaultMode()
public function findDefaultUserInterfaceMode(): string
{
$mode = $this->findModeByName($this->defaultEditPreviewMode);

return $mode;
return $this->defaultEditPreviewMode;
}

/**
* Finds an rendering mode by name.
*
* @param string $modeName
* @return UserInterfaceMode
* @throws Exception
*/
public function findModeByName($modeName)
public function findModeByName(string $modeName): UserInterfaceMode
{
if ($modeName === 'live') {
return UserInterfaceMode::createLive();
}
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 UserInterfaceMode::createByConfiguration($modeName, $this->editPreviewModes[$modeName]);
}

return $mode;
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
);
}
}
5 changes: 5 additions & 0 deletions Neos.Neos/Classes/Fusion/Helper/NodeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.edit || userInterfaceMode.preview} instead
*/
public function inBackend(Node $node): bool
{
$contentRepository = $this->contentRepositoryRegistry->get($node->subgraphIdentity->contentRepositoryId);
Expand Down
Loading

0 comments on commit 06ccf27

Please sign in to comment.