Skip to content

Commit

Permalink
Merge pull request #4623 from mficzel/task/renderMenusWithoutFluid
Browse files Browse the repository at this point in the history
TASK: Render menu prototypes without fluid
  • Loading branch information
mhsdesign authored Oct 26, 2023
2 parents f61829f + 300f84f commit f271bd3
Show file tree
Hide file tree
Showing 19 changed files with 274 additions and 388 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
namespace Neos\ContentRepository\Core\SharedModel\Node;

use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes;

/**
* An immutable collection of NodeAggregateIds, indexed by their value
Expand Down Expand Up @@ -67,13 +68,10 @@ public static function fromJsonString(string $jsonString): self
return self::fromArray(\json_decode($jsonString, true));
}

/**
* @param Node[] $nodes
*/
public static function fromNodes(array $nodes): self
public static function fromNodes(Nodes $nodes): self
{
return self::fromArray(
array_map(fn(Node $node) => $node->nodeAggregateId, $nodes)
array_map(fn(Node $node) => $node->nodeAggregateId, iterator_to_array($nodes))
);
}

Expand All @@ -85,6 +83,11 @@ public function merge(self $other): self
));
}

public function contain(NodeAggregateId $nodeAggregateId): bool
{
return array_key_exists($nodeAggregateId->value, $this->nodeAggregateIds);
}

/**
* @return array<string,NodeAggregateId>
*/
Expand Down
6 changes: 6 additions & 0 deletions Neos.Fusion/Classes/Service/RenderAttributesTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ protected function renderAttributes(iterable $attributes, bool $allowEmpty = tru
foreach ($attributeValue as $attributeValuePart) {
if ($attributeValuePart instanceof \Stringable) {
$attributeValuePart = $attributeValuePart->__toString();
} elseif ($attributeValuePart instanceof \BackedEnum) {
$attributeValuePart = $attributeValuePart->value;
}
$joinedAttributeValue .= match (gettype($attributeValuePart)) {
'boolean', 'NULL' => '',
Expand All @@ -50,6 +52,10 @@ protected function renderAttributes(iterable $attributes, bool $allowEmpty = tru
};
}
$attributeValue = trim($joinedAttributeValue);
} elseif ($attributeValue instanceof \Stringable) {
$attributeValue = $attributeValue->__toString();
} elseif ($attributeValue instanceof \BackedEnum) {
$attributeValue = $attributeValue->value;
}
$encodedAttributeName = htmlspecialchars((string)$attributeName, ENT_COMPAT, 'UTF-8', false);
if ($attributeValue === true || $attributeValue === '') {
Expand Down
32 changes: 31 additions & 1 deletion Neos.Fusion/Tests/Unit/Service/HtmlAugmenterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ public function __toString() {
return "casted value";
}
}
enum BackedStringEnum: string {
case Example = "enum value";
}
');

/** @noinspection PhpUndefinedClassInspection */
$mockObject = new \ClassWithToStringMethod();
$mockEnum = \BackedStringEnum::Example;

return [
// object values with __toString method
Expand All @@ -61,7 +66,15 @@ public function __toString() {
'allowEmpty' => true,
'expectedResult' => '<div object="casted value"></div>'
],

// object values with BackendEnum value
[
'html' => '',
'attributes' => ['enum' => $mockEnum],
'fallbackTagName' => null,
'exclusiveAttributes' => null,
'allowEmpty' => true,
'expectedResult' => '<div enum="enum value"></div>'
],
// empty source
[
'html' => '',
Expand Down Expand Up @@ -344,6 +357,23 @@ public function __toString() {
'allowEmpty' => false,
'expectedResult' => '<p data-stringable="casted value">Stringable attribute</p>',
],
// Adding of Enum attributes
[
'html' => '<p>Enum attribute</p>',
'attributes' => ['data-enum' => $mockEnum],
'fallbackTagName' => null,
'exclusiveAttributes' => null,
'allowEmpty' => true,
'expectedResult' => '<p data-enum="enum value">Enum attribute</p>',
],
[
'html' => '<p>Enum attribute</p>',
'attributes' => ['data-enum' => $mockEnum],
'fallbackTagName' => null,
'exclusiveAttributes' => null,
'allowEmpty' => false,
'expectedResult' => '<p data-enum="enum value">Enum attribute</p>',
],
// Adding of array attributes
[
'html' => '<p>Array attribute</p>',
Expand Down
31 changes: 31 additions & 0 deletions Neos.Neos/Classes/Fusion/AbstractMenuItemsImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ abstract class AbstractMenuItemsImplementation extends AbstractFusionObject
*/
protected $renderHiddenInIndex;

/**
* Internal cache for the calculateItemStates property.
*
* @var boolean
*/
protected $calculateItemStates;

/**
* Rootline of all nodes from the current node to the site root node, keys are depth of nodes.
*
Expand All @@ -70,6 +77,19 @@ abstract class AbstractMenuItemsImplementation extends AbstractFusionObject
#[Flow\Inject]
protected ContentRepositoryRegistry $contentRepositoryRegistry;

/**
* Whether the active/current state of menu items is calculated on the server side.
* This has an effect on performance and caching
*/
public function isCalculateItemStatesEnabled(): bool
{
if ($this->calculateItemStates === null) {
$this->calculateItemStates = (bool)$this->fusionValue('calculateItemStates');
}

return $this->calculateItemStates;
}

/**
* Should nodes that have "hiddenInIndex" set still be visible in this menu.
*
Expand Down Expand Up @@ -169,4 +189,15 @@ protected function getCurrentNodeRootline(): array

return $this->currentNodeRootline;
}

protected function buildUri(Node $node): string
{
$this->runtime->pushContextArray([
'itemNode' => $node,
'documentNode' => $node,
]);
$uri = $this->runtime->render($this->path . '/itemUriRenderer');
$this->runtime->popContext();
return $uri;
}
}
26 changes: 26 additions & 0 deletions Neos.Neos/Classes/Fusion/DimensionMenuItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Neos\Neos\Fusion;

use Neos\ContentRepository\Core\Projection\ContentGraph\Node;

/**
* A menu item for dimension menus
* Compared to the default {@see MenuItem} it has no `menuLevel` property, but one for the `targetDimensions`
*/
final readonly class DimensionMenuItem
{
/**
* @param array<string,mixed>|null $targetDimensions
*/
public function __construct(
public ?Node $node,
public ?MenuItemState $state = null,
public ?string $label = null,
public ?array $targetDimensions = null,
public ?string $uri = null
) {
}
}
33 changes: 17 additions & 16 deletions Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function getDimension(): array

/**
* Builds the array of Menu items for this variant menu
* @return array<int,array<string,mixed>>
* @return array<int,DimensionMenuItem>
*/
protected function buildItems(): array
{
Expand Down Expand Up @@ -86,12 +86,13 @@ protected function buildItems(): array
$metadata = $this->determineMetadata($dimensionSpacePoint, $dimensionMenuItemsImplementationInternals);

if ($variant === null || !$this->isNodeHidden($variant)) {
$menuItems[] = [
'node' => $variant,
'state' => $this->calculateItemState($variant),
'label' => $this->determineLabel($variant, $metadata),
'targetDimensions' => $metadata
];
$menuItems[] = new DimensionMenuItem(
$variant,
$this->isCalculateItemStatesEnabled() ? $this->calculateItemState($variant) : null,
$this->determineLabel($variant, $metadata),
$metadata,
$variant ? $this->buildUri($variant) : null
);
}
}
}
Expand All @@ -100,15 +101,15 @@ protected function buildItems(): array
if ($contentDimensionIdentifierToLimitTo && $valuesToRestrictTo) {
$order = array_flip($valuesToRestrictTo);
usort($menuItems, function (
array $menuItemA,
array $menuItemB
DimensionMenuItem $menuItemA,
DimensionMenuItem $menuItemB
) use (
$order,
$contentDimensionIdentifierToLimitTo
) {
return (int)$order[$menuItemA['node']?->subgraphIdentity->dimensionSpacePoint->getCoordinate(
return (int)$order[$menuItemA->node?->subgraphIdentity->dimensionSpacePoint->getCoordinate(
$contentDimensionIdentifierToLimitTo
)] <=> (int)$order[$menuItemB['node']?->subgraphIdentity->dimensionSpacePoint->getCoordinate(
)] <=> (int)$order[$menuItemB->node?->subgraphIdentity->dimensionSpacePoint->getCoordinate(
$contentDimensionIdentifierToLimitTo
)];
});
Expand Down Expand Up @@ -218,19 +219,19 @@ protected function determineLabel(?Node $variant = null, array $metadata = []):
}
}

protected function calculateItemState(?Node $variant = null): string
protected function calculateItemState(?Node $variant = null): MenuItemState
{
if (is_null($variant)) {
return self::STATE_ABSENT;
return MenuItemState::ABSENT;
}

if ($variant === $this->currentNode) {
return self::STATE_CURRENT;
return MenuItemState::CURRENT;
}

return self::STATE_NORMAL;
return MenuItemState::NORMAL;
}


/**
* In some cases generalization of the other dimension values is feasible
* to find a dimension space point in which a variant can be resolved
Expand Down
57 changes: 8 additions & 49 deletions Neos.Neos/Classes/Fusion/MenuItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,60 +9,19 @@
/**
* A menu item
*/
final class MenuItem
final readonly class MenuItem
{
protected Node $node;

protected ?MenuItemState $state;

protected ?string $label;

protected int $menuLevel;

/**
* @var array<int,MenuItem>
*/
protected array $children;

protected ?string $uri;

/**
* @param array<int,MenuItem> $children
*/
public function __construct(
Node $node,
?MenuItemState $state = null,
?string $label = null,
int $menuLevel = 1,
array $children = [],
string $uri = null
public Node $node,
public ?MenuItemState $state = null,
public ?string $label = null,
public int $menuLevel = 1,
public array $children = [],
public ?string $uri = null
) {
$this->node = $node;
$this->state = $state;
$this->label = $label;
$this->menuLevel = $menuLevel;
$this->children = $children;
$this->uri = $uri;
}

public function getNode(): Node
{
return $this->node;
}

public function getState(): ?MenuItemState
{
return $this->state;
}

public function getLabel(): ?string
{
return $this->label;
}

public function getMenuLevel(): int
{
return $this->menuLevel;
}

/**
Expand All @@ -75,7 +34,7 @@ public function getChildren(): array

/**
* @return array<int,MenuItem>
* @deprecated Use getChildren instead
* @deprecated Use children instead
*/
public function getSubItems(): array
{
Expand Down
53 changes: 5 additions & 48 deletions Neos.Neos/Classes/Fusion/MenuItemState.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,10 @@
/**
* The menu item state value object
*/
final class MenuItemState
enum MenuItemState: string
{
public const STATE_NORMAL = 'normal';
public const STATE_CURRENT = 'current';
public const STATE_ACTIVE = 'active';
public const STATE_ABSENT = 'absent';

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

/**
* @param string $state
* @throws Exception\InvalidMenuItemStateException
*/
public function __construct(string $state)
{
if (
$state !== self::STATE_NORMAL
&& $state !== self::STATE_CURRENT
&& $state !== self::STATE_ACTIVE
&& $state !== self::STATE_ABSENT
) {
throw new Exception\InvalidMenuItemStateException(
'"' . $state . '" is no valid menu item state',
1519668881
);
}

$this->state = $state;
}


/**
* @return MenuItemState
*/
public static function normal(): MenuItemState
{
return new MenuItemState(self::STATE_NORMAL);
}

/**
* @return string
*/
public function __toString(): string
{
return $this->state;
}
case NORMAL = 'normal';
case CURRENT = 'current';
case ACTIVE = 'active';
case ABSENT = 'absent';
}
Loading

0 comments on commit f271bd3

Please sign in to comment.