Skip to content

Commit 3adf1d2

Browse files
author
Bernhard Schmitt
committed
WIP: Introduce UnionPropType
1 parent 904803f commit 3adf1d2

4 files changed

Lines changed: 226 additions & 39 deletions

File tree

Classes/Domain/Component/PropType/PropTypeFactory.php

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -77,46 +77,63 @@ public static function fromInputString(ComponentName $parentComponentName, strin
7777
public static function fromReflectionProperty(\ReflectionProperty $property): PropTypeInterface
7878
{
7979
if ($type = $property->getType()) {
80-
$nullable = $type->allowsNull();
81-
$typeString = ltrim((string)$type, '?');
82-
switch ($typeString) {
83-
case 'string':
84-
return new StringPropType($nullable);
85-
case 'int':
86-
return new IntPropType($nullable);
87-
case 'float':
88-
return new FloatPropType($nullable);
89-
case 'bool':
90-
return new BoolPropType($nullable);
91-
case UriInterface::class:
92-
case Uri::class:
93-
return new UriPropType($nullable);
94-
case ImageSourceInterface::class:
95-
return new ImageSourcePropType($nullable);
96-
case SlotInterface::class:
97-
return new SlotPropType($nullable);
98-
case StringLike::class:
99-
return new StringLikePropType($nullable);
100-
default:
101-
if (IsEnum::isSatisfiedByClassName($typeString)) {
102-
/** @phpstan-var class-string<mixed> $typeString */
103-
return new EnumPropType($typeString, $nullable);
104-
}
105-
if (IsComponent::isSatisfiedByClassName($typeString)) {
106-
/** @phpstan-var class-string<mixed> $typeString */
107-
$componentName = ComponentName::fromClassName($typeString);
108-
return new ComponentPropType($componentName, $nullable);
109-
}
110-
if (IsComponentArray::isSatisfiedByClassName($typeString)) {
111-
/** @phpstan-var class-string<mixed> $typeString */
112-
$componentName = ComponentName::fromClassName($typeString);
113-
return new ComponentArrayPropType($componentName);
80+
if ($type instanceof \ReflectionNamedType) {
81+
$nullable = $type->allowsNull();
82+
$typeString = ltrim((string)$type, '?');
83+
84+
return self::resolvePropTypeByTypeString($typeString, $nullable);
85+
} elseif ($type instanceof \ReflectionUnionType) {
86+
$nullable = $type->allowsNull();
87+
$propTypes = [];
88+
foreach ($type->getTypes() as $type) {
89+
if ($type->getName() !== 'null') {
90+
$propTypes[] = self::resolvePropTypeByTypeString($type->getName(), false);
11491
}
92+
}
93+
return new UnionPropType($nullable, ...$propTypes);
11594
}
116-
117-
throw PropTypeIsInvalid::becauseItIsNoKnownComponentValueOrPrimitive($typeString);
11895
}
11996

12097
throw PropTypeIsInvalid::becausePropertyIsNotTyped($property);
12198
}
99+
100+
private static function resolvePropTypeByTypeString(string $typeString, bool $nullable): PropTypeInterface
101+
{
102+
switch ($typeString) {
103+
case 'string':
104+
return new StringPropType($nullable);
105+
case 'int':
106+
return new IntPropType($nullable);
107+
case 'float':
108+
return new FloatPropType($nullable);
109+
case 'bool':
110+
return new BoolPropType($nullable);
111+
case UriInterface::class:
112+
case Uri::class:
113+
return new UriPropType($nullable);
114+
case ImageSourceInterface::class:
115+
return new ImageSourcePropType($nullable);
116+
case SlotInterface::class:
117+
return new SlotPropType($nullable);
118+
case StringLike::class:
119+
return new StringLikePropType($nullable);
120+
default:
121+
if (IsEnum::isSatisfiedByClassName($typeString)) {
122+
/** @phpstan-var class-string<mixed> $typeString */
123+
return new EnumPropType($typeString, $nullable);
124+
}
125+
if (IsComponent::isSatisfiedByClassName($typeString)) {
126+
/** @phpstan-var class-string<mixed> $typeString */
127+
$componentName = ComponentName::fromClassName($typeString);
128+
return new ComponentPropType($componentName, $nullable);
129+
}
130+
if (IsComponentArray::isSatisfiedByClassName($typeString)) {
131+
/** @phpstan-var class-string<mixed> $typeString */
132+
$componentName = ComponentName::fromClassName($typeString);
133+
return new ComponentArrayPropType($componentName);
134+
}
135+
}
136+
137+
throw PropTypeIsInvalid::becauseItIsNoKnownComponentValueOrPrimitive($typeString);
138+
}
122139
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PackageFactory.AtomicFusion.PresentationObjects package
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType;
10+
11+
use Neos\Flow\Annotations as Flow;
12+
13+
#[Flow\Proxy(false)]
14+
final class UnionPropType implements PropTypeInterface
15+
{
16+
/**
17+
* @var array<int,PropTypeInterface>
18+
*/
19+
public readonly array $propTypes;
20+
21+
public function __construct(
22+
private readonly bool $nullable,
23+
PropTypeInterface ...$propTypes
24+
) {
25+
$this->propTypes = $propTypes;
26+
}
27+
28+
public function isNullable(): bool
29+
{
30+
return $this->nullable;
31+
}
32+
33+
public function getSimpleName(): string
34+
{
35+
// not to be used, a special case should be used evaluating the child prop types
36+
return 'union';
37+
}
38+
39+
public function getUseStatement(): string
40+
{
41+
// not to be used, a special case should be used evaluating the child prop types
42+
return '';
43+
}
44+
45+
public function getType(): string
46+
{
47+
return implode(
48+
'|',
49+
array_map(
50+
fn (PropTypeInterface $propType): string => $propType->getType(),
51+
$this->propTypes
52+
)
53+
) . ($this->isNullable() ? '|null' : '');
54+
}
55+
56+
public function getStyleGuideValue(int $nestingLevel = 0): string
57+
{
58+
return '= \'\'';
59+
}
60+
61+
public function getDefinitionData(string $propName): string
62+
{
63+
return '
64+
<PackageFactory.AtomicFusion.PresentationObjects:Slot presentationObject={presentationObject.' . $propName . '}'
65+
. ($this->nullable ? ' @if={presentationObject.' . $propName . '}' : '') . ' />
66+
';
67+
}
68+
}

Classes/Domain/Component/Props.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType\PropTypeFactory;
1414
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType\PropTypeInterface;
1515
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType\PropTypeIsInvalid;
16+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType\UnionPropType;
1617

1718
/**
1819
* @Flow\Proxy(false)
@@ -109,9 +110,15 @@ public function renderUseStatements(): string
109110

110111
$statedTypes = [];
111112
foreach ($this as $propType) {
112-
if (!isset($statedTypes[$propType->getSimpleName()])) {
113-
$statedTypes[$propType->getSimpleName()] = true;
114-
$statements .= $propType->getUseStatement();
113+
$propTypesToBeRendered = $propType instanceof UnionPropType
114+
? $propType->propTypes
115+
: [$propType];
116+
117+
foreach ($propTypesToBeRendered as $propTypeToBeRendered) {
118+
if (!isset($statedTypes[$propTypeToBeRendered->getSimpleName()])) {
119+
$statedTypes[$propTypeToBeRendered->getSimpleName()] = true;
120+
$statements .= $propTypeToBeRendered->getUseStatement();
121+
}
115122
}
116123
}
117124

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PackageFactory.AtomicFusion.PresentationObjects package
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace PackageFactory\AtomicFusion\PresentationObjects\Tests\Unit\Domain\Component\PropType;
10+
11+
use Neos\Flow\Tests\UnitTestCase;
12+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\ComponentName;
13+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType\ComponentPropType;
14+
use PackageFactory\AtomicFusion\PresentationObjects\Domain\Component\PropType\UnionPropType;
15+
use PHPUnit\Framework\Assert;
16+
use Vendor\Shared\Presentation\Component\Text\Text;
17+
use Vendor\Site\Presentation\Component\MyComponent\MyComponent;
18+
19+
/**
20+
* Test cases for the Union PropType
21+
*/
22+
final class UnionPropTypeTest extends UnitTestCase
23+
{
24+
/**
25+
* @dataProvider typeProvider
26+
*/
27+
public function testGetType(UnionPropType $subject, string $expectedType): void
28+
{
29+
Assert::assertSame($expectedType, $subject->getType());
30+
}
31+
32+
/**
33+
* @return array<mixed>
34+
*/
35+
public function typeProvider(): array
36+
{
37+
return [
38+
[
39+
new UnionPropType(
40+
false,
41+
new ComponentPropType(ComponentName::fromClassName(MyComponent::class), false),
42+
new ComponentPropType(ComponentName::fromClassName(Text::class), false)
43+
),
44+
'MyComponent|Text'
45+
],
46+
[
47+
new UnionPropType(
48+
true,
49+
new ComponentPropType(ComponentName::fromClassName(MyComponent::class), false),
50+
new ComponentPropType(ComponentName::fromClassName(Text::class), false)
51+
),
52+
'MyComponent|Text|null'
53+
]
54+
];
55+
}
56+
57+
/**
58+
* @dataProvider definitionDataProvider
59+
*/
60+
public function testGetDefinitionData(UnionPropType $subject, string $propName, string $expectedStyleGuideValue): void
61+
{
62+
Assert::assertSame($expectedStyleGuideValue, $subject->getDefinitionData($propName));
63+
}
64+
65+
/**
66+
* @return array<mixed>
67+
*/
68+
public function definitionDataProvider(): array
69+
{
70+
return [
71+
[
72+
new UnionPropType(
73+
false,
74+
new ComponentPropType(ComponentName::fromClassName(MyComponent::class), false),
75+
new ComponentPropType(ComponentName::fromClassName(Text::class), false)
76+
),
77+
'myProperty',
78+
'
79+
<PackageFactory.AtomicFusion.PresentationObjects:Slot presentationObject={presentationObject.myProperty} />
80+
'
81+
],
82+
[
83+
new UnionPropType(
84+
true,
85+
new ComponentPropType(ComponentName::fromClassName(MyComponent::class), false),
86+
new ComponentPropType(ComponentName::fromClassName(Text::class), false)
87+
),
88+
'myProperty',
89+
'
90+
<PackageFactory.AtomicFusion.PresentationObjects:Slot presentationObject={presentationObject.myProperty} @if={presentationObject.myProperty} />
91+
'
92+
]
93+
];
94+
}
95+
}

0 commit comments

Comments
 (0)