Skip to content

Commit 0f03464

Browse files
author
Bernhard Schmitt
committed
Adjust documentation to explain usage of enums
1 parent 523b782 commit 0f03464

2 files changed

Lines changed: 234 additions & 1 deletion

File tree

Documentation/01_PresentationObjectsAndComponents.md

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
# 1. PresentationObjects and Components
1010

11-
> **Hint:** This section describes the manual creation of PresentationObjects and PresentationObject components. Both patterns can also be scaffolded by the [Kickstarter](./05_Kickstarter.md).
11+
> **Hint:** This section describes the manual creation of PresentationObjects, Pseudo-Enums and PresentationObject components. All these patterns can also be scaffolded by the [Kickstarter](./05_Kickstarter.md).
1212
1313
In this tutorial, we're going to write a PresentationObject for an image component. Our image consists of a `src`, an `alt` and an optional `title` property.
1414

@@ -139,6 +139,106 @@ myImage = Vendor.Site:Component.Image {
139139

140140
An exception will be thrown, if `someObject` does not implement `Vendor\Site\Presentation\Image\ImageInterface`.
141141

142+
## (Pseudo) Enums
143+
144+
It is recommended to model discrete values for presentation object properties as objects themselves.
145+
Since PHP does not support enums yet, this package provides an interface to be implemented by classes that behave similarly to enums.
146+
> **Hint:** For more information on enums in PHP, see https://stitcher.io/blog/php-enums
147+
148+
<small>*`EXAMPLE: Pseudo-enum`*<small>
149+
150+
Given we have a presentation object Headline with properties type and content.
151+
While content can be an arbitrary string, in our project by specification we only support h1-h3 as types for headlines.
152+
To prevent accidental use of h4 (or other tag names) for headlines, we model the headline type as a pseudo enum as follows:
153+
154+
```php
155+
<?php declare(strict_types=1);
156+
namespace Acme\Site\Presentation\Block\Headline;
157+
158+
use Neos\Flow\Annotations as Flow;
159+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\PseudoEnumInterface;
160+
161+
/**
162+
* @Flow\Proxy(false)
163+
*/
164+
final class HeadlineType implements PseudoEnumInterface
165+
{
166+
const TYPE_H1 = 'h1';
167+
const TYPE_H2 = 'h2';
168+
const TYPE_H3 = 'h3';
169+
170+
private string $value;
171+
172+
private function __construct(string $value)
173+
{
174+
$this->value = $value;
175+
}
176+
177+
public static function fromString(string $string): self
178+
{
179+
if ($string !== self::TYPE_H1 && $string !== self::TYPE_H2 && $string !== self::TYPE_H3) {
180+
throw HeadlineTypeIsInvalid::becauseItMustBeOneOfTheDefinedConstants($string);
181+
}
182+
183+
return new self($string);
184+
}
185+
186+
public static function h1(): self
187+
{
188+
return new self(self::TYPE_H1);
189+
}
190+
191+
public static function h2(): self
192+
{
193+
return new self(self::TYPE_H2);
194+
}
195+
196+
public static function h3(): self
197+
{
198+
return new self(self::TYPE_H3);
199+
}
200+
201+
/**
202+
* @return array|self[]
203+
*/
204+
public static function cases(): array
205+
{
206+
return [
207+
new self(self::TYPE_H1),
208+
new self(self::TYPE_H2),
209+
new self(self::TYPE_H3)
210+
];
211+
}
212+
213+
public function getValue(): string
214+
{
215+
return $this->value;
216+
}
217+
218+
public function __toString(): string
219+
{
220+
return $this->value;
221+
}
222+
}
223+
```
224+
225+
Now instead of having a string typed property in our headline, we can model it as follows:
226+
227+
```php
228+
<?php declare(strict_types=1);
229+
namespace Acme\Site\Presentation\Block\Headline;
230+
231+
interface HeadlineInterface
232+
{
233+
public function getType(): HeadlineType;
234+
235+
public function getContent(): string;
236+
}
237+
```
238+
239+
> **Hint:** Pseudo-enums can also be used in Neos' inspector select box editor. Please refer to [Integration Recipes](./04_IntegrationRecipes.md) to learn how it is done.
240+
241+
142242
---
143243

144244
<div align="center">

Documentation/04_IntegrationRecipes.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,139 @@ Resolves URIs with the special `asset://` and `node://` protocols.
8080
| $rawLinkUri | string | The string containing the URI | |
8181
| $subgraph | [ContentContext](https://github.com/neos/neos-development-collection/blob/master/Neos.Neos/Classes/Domain/Service/ContentContext.php) | A reference content context required to resolve `node://` URIs | |
8282

83+
## The EnumProvider
84+
85+
All pseudo-enums implementing the PseudoEnumInterface can be provided to the inspector or the Fusion runtime using the PseudoEnumProvider.
86+
This makes the enum itself the single source of discrete values a node or presentation object property may have, obsoleting value adjustments in Fusion, configuration etc.
87+
88+
As an example, we use the following pseudo-enum:
89+
90+
```php
91+
<?php declare(strict_types=1);
92+
namespace Acme\Site\Presentation\Block\Headline;
93+
94+
use Neos\Flow\Annotations as Flow;
95+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\PseudoEnumInterface;
96+
97+
/**
98+
* @Flow\Proxy(false)
99+
*/
100+
final class HeadlineType implements PseudoEnumInterface
101+
{
102+
const TYPE_H1 = 'h1';
103+
const TYPE_H2 = 'h2';
104+
const TYPE_H3 = 'h3';
105+
106+
private string $value;
107+
108+
private function __construct(string $value)
109+
{
110+
$this->value = $value;
111+
}
112+
113+
public static function h1(): self
114+
{
115+
return new self(self::TYPE_H1);
116+
}
117+
118+
public static function h2(): self
119+
{
120+
return new self(self::TYPE_H2);
121+
}
122+
123+
public static function h3(): self
124+
{
125+
return new self(self::TYPE_H3);
126+
}
127+
128+
/**
129+
* @return array|self[]
130+
*/
131+
public static function cases(): array
132+
{
133+
return [
134+
new self(self::TYPE_H1),
135+
new self(self::TYPE_H2),
136+
new self(self::TYPE_H3)
137+
];
138+
}
139+
140+
public function getValue(): string
141+
{
142+
return $this->value;
143+
}
144+
145+
public function __toString(): string
146+
{
147+
return $this->value;
148+
}
149+
}
150+
151+
```
152+
153+
### As a node type postprocessor
154+
155+
Due to cacheability and thus improved performance, it is recommended to use the EnumProvider's node type postprocessor capabilities to make the enum's cases available in the Inspector.
156+
157+
When we now declare our NodeType property, we do this as follows:
158+
159+
```yaml
160+
properties:
161+
headline:
162+
type: string
163+
ui:
164+
inspector:
165+
editor: Neos.Neos/Inspector/Editors/SelectBoxEditor
166+
editorOptions:
167+
values: []
168+
postprocessors:
169+
headline-types:
170+
postprocessor: PackageFactory\AtomicFusion\PresentationObjects\Application\PseudoEnumProvider
171+
postprocessorOptions:
172+
enumName: Acme\Site\Presentation\Block\Headline\HeadlineType
173+
propertyNames:
174+
- headline
175+
```
176+
177+
The initial values are left empty and will be completely populated by the postprocessor. While the postprocessor is the same for all enums, there are two configuration options available:
178+
* enumName: The enum's fully qualified PHP class name
179+
* propertyNames: A list of property names to apply this enum's values to
180+
181+
### As a data source
182+
183+
If for some reason the postprocessor does not suffice, there is also the possibility to use the provider as a data source.
184+
Be aware that though more flexible, data sources are called on each load of the inspector, impacting performance.
185+
The provider can be used as a data source as follows:
186+
187+
```yaml
188+
properties:
189+
headline:
190+
type: string
191+
ui:
192+
inspector:
193+
editor: Neos.Neos/Inspector/Editors/SelectBoxEditor
194+
editorOptions:
195+
dataSourceIdentifier: packagefactory-atomicfusion-presentationobjects-enumcases
196+
dataSourceAdditionalData:
197+
enumName: Acme\Site\Presentation\Block\Headline\HeadlineType
198+
```
199+
200+
### As an EEL helper
201+
202+
If you need the enum's values in Fusion, you can declare the provider as an EEL helper
203+
204+
```yaml
205+
Neos:
206+
Fusion:
207+
defaultContext:
208+
Enum: PackageFactory\AtomicFusion\PresentationObjects\Application\PseudoEnumProvider
209+
```
210+
and use it in Fusion to get the cases or values.
211+
```neosfusion
212+
cases = ${Enum.getCases('Acme\Site\Presentation\Block\Headline\HeadlineType')}
213+
values = ${Enum.getValues('Acme\Site\Presentation\Block\Headline\HeadlineType')}
214+
```
215+
83216
---
84217

85218
<div align="center">

0 commit comments

Comments
 (0)