Skip to content

Commit 71bebbe

Browse files
author
Bernhard Schmitt
committed
Implement generic PseudoEnumProvider
1 parent 3d94507 commit 71bebbe

12 files changed

Lines changed: 209 additions & 54 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php declare(strict_types=1);
2+
namespace PackageFactory\AtomicFusion\PresentationObjects\Application;
3+
4+
/*
5+
* This file is part of the PackageFactory.AtomicFusion.PresentationObjects package.
6+
*/
7+
8+
use Neos\ContentRepository\Domain\Model\NodeInterface;
9+
use Neos\ContentRepository\Domain\Model\NodeType;
10+
use Neos\ContentRepository\NodeTypePostprocessor\NodeTypePostprocessorInterface;
11+
use Neos\Flow\Annotations as Flow;
12+
use Neos\Flow\I18n\Translator;
13+
use Neos\Neos\Service\DataSource\AbstractDataSource;
14+
use Neos\Eel\ProtectedContextAwareInterface;
15+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\PseudoEnumInterface;
16+
17+
class PseudoEnumProvider extends AbstractDataSource implements ProtectedContextAwareInterface, NodeTypePostprocessorInterface
18+
{
19+
/**
20+
* @Flow\Inject
21+
* @var Translator
22+
*/
23+
protected $translator;
24+
25+
/**
26+
* @var string
27+
*/
28+
protected static $identifier = 'packagefactory-atomicfusion-presentationobjects-enumcases';
29+
30+
public function getData(NodeInterface $node = null, array $arguments = []): array
31+
{
32+
if (!isset($arguments['enumName'])) {
33+
throw new \InvalidArgumentException('Argument "enumName" must be provided.', 1625297174);
34+
}
35+
$this->validateEnumName($arguments['enumName']);
36+
$options = [];
37+
foreach ($this->getCases($arguments['enumName']) as $value) {
38+
$options[$value]['label'] = $this->getLabel($arguments['enumName'], $value);
39+
}
40+
41+
return $options;
42+
}
43+
44+
public function process(NodeType $nodeType, array &$configuration, array $options)
45+
{
46+
if (!isset($options['enumName'])) {
47+
throw new \InvalidArgumentException('Option "enumName" must be provided.', 1625298032);
48+
}
49+
$this->validateEnumName($options['enumName']);
50+
$cases = $this->getCases($options['enumName']);
51+
foreach ($options['propertyNames'] as $propertyName) {
52+
foreach ($cases as $case) {
53+
$configuration['properties'][$propertyName]['ui']['inspector']['editorOptions']['values'][$case] = [
54+
'label' => $this->getLabel($options['enumName'], (string)$case)
55+
];
56+
}
57+
}
58+
}
59+
60+
private function getLabel(string $enumName, string $value): string
61+
{
62+
list($packageKey, $componentName) = explode('/Presentation/', $enumName);
63+
$pivot = \mb_strrpos($componentName, '/');
64+
$componentNamespace = \mb_substr($packageKey, 0 , $pivot);
65+
$enumShort = lcfirst(\mb_substr($packageKey, $pivot+1));
66+
67+
return $this->translator->translateById(
68+
$enumShort . '.' . $value,
69+
[],
70+
null,
71+
null,
72+
\str_replace('/', '.', $componentNamespace),
73+
\str_replace('/', '.', $packageKey)
74+
) ?: $value;
75+
}
76+
77+
/**
78+
* @param class-string<mixed> $enumName
79+
* @return array|string[]|int[]
80+
*/
81+
public function getCases(string $enumName): array
82+
{
83+
return array_map(function (PseudoEnumInterface $case) {
84+
return $case->getValue();
85+
}, $enumName::cases());
86+
}
87+
88+
private function validateEnumName(string $enumName): void
89+
{
90+
if (!class_exists($enumName)) {
91+
throw new \InvalidArgumentException('Given enum "' . $enumName . '" does not exist.', 1625297031);
92+
}
93+
if (!in_array(PseudoEnumInterface::class, class_implements($enumName))) {
94+
throw new \InvalidArgumentException('Given enum "' . $enumName . '" does not implement the required ' . PseudoEnumInterface::class, 1625297122);
95+
}
96+
}
97+
98+
public function allowsCallOfMethod($methodName): bool
99+
{
100+
return true;
101+
}
102+
}

Classes/Domain/Component/PropType/IsEnum.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
use Neos\Flow\Annotations as Flow;
9-
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\EnumInterface;
9+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\PseudoEnumInterface;
1010

1111
/**
1212
* The specification for enum classes
@@ -17,6 +17,6 @@ final class IsEnum
1717
public static function isSatisfiedByClassName(string $className): bool
1818
{
1919
return class_exists($className)
20-
&& is_subclass_of($className, EnumInterface::class);
20+
&& is_subclass_of($className, PseudoEnumInterface::class);
2121
}
2222
}

Classes/Domain/Enum/EnumInterface.php

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types=1);
2+
namespace PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum;
3+
4+
/*
5+
* This file is part of the PackageFactory.AtomicFusion.PresentationObjects package
6+
*/
7+
8+
use Neos\Flow\Annotations as Flow;
9+
10+
/**
11+
* The interface to be implemented by pseudo enums
12+
*
13+
* See https://stitcher.io/blog/php-enums
14+
*/
15+
interface PseudoEnumInterface
16+
{
17+
/**
18+
* @return array<PseudoEnumInterface>
19+
*/
20+
public static function cases(): array;
21+
22+
/**
23+
* @return int|string
24+
*/
25+
public function getValue();
26+
}

Tests/Unit/Domain/Component/ComponentNameTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function classNameProvider(): array
9090
new ComponentName($packageKey, FusionNamespace::fromString('Custom.Type'), 'MyComponent')
9191
],
9292
[
93-
'Vendor\Site\Presentation\Component\MyNewComponent\MyStringEnum',
93+
'Vendor\Site\Presentation\Component\MyNewComponent\MyStringPseudoEnum',
9494
new ComponentName($packageKey, FusionNamespace::fromString('Component'), 'MyStringEnum')
9595
],
9696
[

Tests/Unit/Domain/Component/PropType/EnumPropTypeTest.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* This file is part of the PackageFactory.AtomicFusion.PresentationObjects package
66
*/
77

8-
use Vendor\Site\Presentation\Component\MyNewComponent\MyStringEnum;
8+
use Vendor\Site\Presentation\Component\MyNewComponent\MyStringPseudoEnum;
99
use Neos\Flow\Tests\UnitTestCase;
1010
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType\EnumPropType;
1111
use PHPUnit\Framework\Assert;
@@ -33,11 +33,11 @@ public function simpleNameProvider(): array
3333
{
3434
return [
3535
[
36-
new EnumPropType(MyStringEnum::class, false),
36+
new EnumPropType(MyStringPseudoEnum::class, false),
3737
'MyStringEnum'
3838
],
3939
[
40-
new EnumPropType(MyStringEnum::class, true),
40+
new EnumPropType(MyStringPseudoEnum::class, true),
4141
'MyStringEnum'
4242
]
4343
];
@@ -61,12 +61,12 @@ public function useStatementProvider(): array
6161
{
6262
return [
6363
[
64-
new EnumPropType(MyStringEnum::class, false),
64+
new EnumPropType(MyStringPseudoEnum::class, false),
6565
'use Vendor\Site\Presentation\Component\MyNewComponent\MyStringEnum;
6666
'
6767
],
6868
[
69-
new EnumPropType(MyStringEnum::class, true),
69+
new EnumPropType(MyStringPseudoEnum::class, true),
7070
'use Vendor\Site\Presentation\Component\MyNewComponent\MyStringEnum;
7171
'
7272
]
@@ -91,11 +91,11 @@ public function typeProvider(): array
9191
{
9292
return [
9393
[
94-
new EnumPropType(MyStringEnum::class, false),
94+
new EnumPropType(MyStringPseudoEnum::class, false),
9595
'MyStringEnum'
9696
],
9797
[
98-
new EnumPropType(MyStringEnum::class, true),
98+
new EnumPropType(MyStringPseudoEnum::class, true),
9999
'?MyStringEnum'
100100
]
101101
];
@@ -119,11 +119,11 @@ public function styleGuideValueProvider(): array
119119
{
120120
return [
121121
[
122-
new EnumPropType(MyStringEnum::class, false),
122+
new EnumPropType(MyStringPseudoEnum::class, false),
123123
'= \'myValue\''
124124
],
125125
[
126-
new EnumPropType(MyStringEnum::class, true),
126+
new EnumPropType(MyStringPseudoEnum::class, true),
127127
'= \'myValue\''
128128
]
129129
];

Tests/Unit/Domain/Component/PropType/PropTypeFactoryTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ public function validInputStringProvider(): array
124124
[
125125
$componentName,
126126
'MyStringEnum',
127-
new EnumPropType('Vendor\\Site\\Presentation\\Component\\MyNewComponent\\MyStringEnum', false)
127+
new EnumPropType('Vendor\\Site\\Presentation\\Component\\MyNewComponent\\MyStringPseudoEnum', false)
128128
],
129129
[
130130
$componentName,
131131
'?MyStringEnum',
132-
new EnumPropType('Vendor\\Site\\Presentation\\Component\\MyNewComponent\\MyStringEnum', true)
132+
new EnumPropType('Vendor\\Site\\Presentation\\Component\\MyNewComponent\\MyStringPseudoEnum', true)
133133
],
134134
[
135135
$componentName,
@@ -298,13 +298,13 @@ public function validReflectionPropertyProvider(): array
298298
case 'enumProp':
299299
$reflectionPropertyCases[] = [
300300
$reflectionProperty,
301-
new EnumPropType('Vendor\Site\Presentation\Component\MyNewComponent\MyStringEnum', false)
301+
new EnumPropType('Vendor\Site\Presentation\Component\MyNewComponent\MyStringPseudoEnum', false)
302302
];
303303
break;
304304
case 'nullableEnumProp':
305305
$reflectionPropertyCases[] = [
306306
$reflectionProperty,
307-
new EnumPropType('Vendor\Site\Presentation\Component\MyNewComponent\MyStringEnum', true)
307+
new EnumPropType('Vendor\Site\Presentation\Component\MyNewComponent\MyStringPseudoEnum', true)
308308
];
309309
break;
310310
case 'componentProp':

Tests/Unit/Fixtures/Site/Presentation/Component/Headline/HeadlineLook.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,30 @@
66
*/
77

88
use Neos\Flow\Annotations as Flow;
9-
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\EnumInterface;
9+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\PseudoEnumInterface;
1010

1111
/**
1212
* HeadlineLook enum for test purposes
1313
* @Flow\Proxy(false)
1414
*/
15-
final class HeadlineLook implements EnumInterface
15+
final class HeadlineLook implements PseudoEnumInterface
1616
{
1717
private string $value;
1818

19-
public static function getValues(): array
19+
private function __construct(string $value)
20+
{
21+
$this->value = $value;
22+
}
23+
24+
public static function cases(): array
2025
{
2126
return [
22-
'large'
27+
new self('large')
2328
];
2429
}
30+
31+
public function getValue(): string
32+
{
33+
return $this->value;
34+
}
2535
}

Tests/Unit/Fixtures/Site/Presentation/Component/Headline/HeadlineType.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,30 @@
66
*/
77

88
use Neos\Flow\Annotations as Flow;
9-
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\EnumInterface;
9+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\PseudoEnumInterface;
1010

1111
/**
1212
* HeadlineType enum for test purposes
1313
* @Flow\Proxy(false)
1414
*/
15-
final class HeadlineType implements EnumInterface
15+
final class HeadlineType implements PseudoEnumInterface
1616
{
1717
private string $value;
1818

19-
public static function getValues(): array
19+
private function __construct(string $value)
20+
{
21+
$this->value = $value;
22+
}
23+
24+
public static function cases(): array
2025
{
2126
return [
22-
'h1'
27+
new self('h1')
2328
];
2429
}
30+
31+
public function getValue(): string
32+
{
33+
return $this->value;
34+
}
2535
}

Tests/Unit/Fixtures/Site/Presentation/Component/MyNewComponent/MyIntEnum.php renamed to Tests/Unit/Fixtures/Site/Presentation/Component/MyNewComponent/MyIntPseudoEnum.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,33 @@
66
*/
77

88
use Neos\Flow\Annotations as Flow;
9-
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\EnumInterface;
9+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Enum\PseudoEnumInterface;
1010

1111
/**
1212
* Dummy int enum for test purposes
1313
* @Flow\Proxy(false)
1414
*/
15-
final class MyIntEnum implements EnumInterface
15+
final class MyIntPseudoEnum implements PseudoEnumInterface
1616
{
1717
private int $value;
1818

19-
public static function getValues(): array
19+
private function __construct(int $value)
20+
{
21+
$this->value = $value;
22+
}
23+
24+
/**
25+
* @return array<MyIntPseudoEnum>
26+
*/
27+
public static function cases(): array
2028
{
2129
return [
22-
42
30+
new self(42)
2331
];
2432
}
33+
34+
public function getValue(): int
35+
{
36+
return $this->value;
37+
}
2538
}

0 commit comments

Comments
 (0)