Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
48 / 48 |
|
100.00% |
6 / 6 |
CRAP | |
100.00% |
1 / 1 |
PolymorphicEntityStrategy | |
100.00% |
48 / 48 |
|
100.00% |
6 / 6 |
28 | |
100.00% |
1 / 1 |
supports | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModificationMetadata | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
7 | |||
getCreationMetadata | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
8 | |||
getResultMetadata | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
8 | |||
mergeChildClass | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | namespace Apie\Core\Metadata\Strategy; |
3 | |
4 | use Apie\Core\Context\ApieContext; |
5 | use Apie\Core\Context\MetadataFieldHashmap; |
6 | use Apie\Core\Entities\PolymorphicEntityInterface; |
7 | use Apie\Core\Metadata\CompositeMetadata; |
8 | use Apie\Core\Metadata\Fields\DiscriminatorColumn; |
9 | use Apie\Core\Metadata\Fields\FieldInterface; |
10 | use Apie\Core\Metadata\Fields\OptionalField; |
11 | use Apie\Core\Metadata\Fields\StaticDiscriminatorColumn; |
12 | use Apie\Core\Metadata\StrategyInterface; |
13 | use Apie\Core\Other\DiscriminatorConfig; |
14 | use Apie\Core\Other\DiscriminatorMapping; |
15 | use Apie\Core\Utils\EntityUtils; |
16 | use ReflectionClass; |
17 | |
18 | final class PolymorphicEntityStrategy implements StrategyInterface |
19 | { |
20 | public static function supports(ReflectionClass $class): bool |
21 | { |
22 | return EntityUtils::isPolymorphicEntity($class); |
23 | } |
24 | |
25 | /** |
26 | * @param ReflectionClass<PolymorphicEntityInterface> $class |
27 | */ |
28 | public function __construct(private ReflectionClass $class) |
29 | { |
30 | } |
31 | |
32 | public function getModificationMetadata(ApieContext $context): CompositeMetadata |
33 | { |
34 | $list = []; |
35 | |
36 | $class = $this->class; |
37 | |
38 | while ($class) { |
39 | $method = $class->getMethod('getDiscriminatorMapping'); |
40 | if (!$method->isAbstract() && $method->getDeclaringClass()->name === $class->name) { |
41 | /** @var DiscriminatorMapping $mapping */ |
42 | $mapping = $method->invoke(null); |
43 | foreach ($mapping->getConfigs() as $config) { |
44 | if ($method->getDeclaringClass()->name === $this->class->name || $config->getClassName() === $this->class->name) { |
45 | $this->mergeChildClass($context, $config, $list, 'getModificationMetadata'); |
46 | } |
47 | } |
48 | } |
49 | $class = $class->getParentClass(); |
50 | } |
51 | |
52 | return new CompositeMetadata(new MetadataFieldHashmap($list), $this->class); |
53 | } |
54 | |
55 | public function getCreationMetadata(ApieContext $context): CompositeMetadata |
56 | { |
57 | /** @var array<string, FieldInterface> $list */ |
58 | $list = []; |
59 | |
60 | $class = $this->class; |
61 | |
62 | while ($class) { |
63 | $method = $class->getMethod('getDiscriminatorMapping'); |
64 | if (!$method->isAbstract() && $method->getDeclaringClass()->name === $class->name) { |
65 | /** @var DiscriminatorMapping $mapping */ |
66 | $mapping = $method->invoke(null); |
67 | $list[$mapping->getPropertyName()] = new DiscriminatorColumn($mapping); |
68 | foreach ($mapping->getConfigs() as $config) { |
69 | if ($method->getDeclaringClass()->name === $this->class->name || $config->getClassName() === $this->class->name) { |
70 | $this->mergeChildClass($context, $config, $list, 'getCreationMetadata'); |
71 | } |
72 | } |
73 | } |
74 | $class = $class->getParentClass(); |
75 | } |
76 | foreach (EntityUtils::getDiscriminatorValues($this->class) as $propertyName => $discriminatorValue) { |
77 | $list[$propertyName] = new StaticDiscriminatorColumn($discriminatorValue); |
78 | } |
79 | |
80 | return new CompositeMetadata(new MetadataFieldHashmap($list), $this->class); |
81 | } |
82 | |
83 | public function getResultMetadata(ApieContext $context): CompositeMetadata |
84 | { |
85 | /** @var array<string, FieldInterface> $list */ |
86 | $list = []; |
87 | |
88 | $class = $this->class; |
89 | |
90 | while ($class) { |
91 | $method = $class->getMethod('getDiscriminatorMapping'); |
92 | if (!$method->isAbstract() && $method->getDeclaringClass()->name === $class->name) { |
93 | /** @var DiscriminatorMapping $mapping */ |
94 | $mapping = $method->invoke(null); |
95 | $list[$mapping->getPropertyName()] = new DiscriminatorColumn($mapping); |
96 | foreach ($mapping->getConfigs() as $config) { |
97 | if ($method->getDeclaringClass()->name === $this->class->name || $config->getClassName() === $this->class->name) { |
98 | $this->mergeChildClass($context, $config, $list, 'getResultMetadata'); |
99 | } |
100 | } |
101 | } |
102 | $class = $class->getParentClass(); |
103 | } |
104 | foreach (EntityUtils::getDiscriminatorValues($this->class) as $propertyName => $discriminatorValue) { |
105 | $list[$propertyName] = new StaticDiscriminatorColumn($discriminatorValue); |
106 | } |
107 | |
108 | return new CompositeMetadata(new MetadataFieldHashmap($list), $this->class); |
109 | } |
110 | |
111 | /** |
112 | * @param array<string, FieldInterface> $list |
113 | */ |
114 | private function mergeChildClass( |
115 | ApieContext $context, |
116 | DiscriminatorConfig $config, |
117 | array& $list, |
118 | string $method |
119 | ): void { |
120 | $refl = new ReflectionClass($config->getClassName()); |
121 | $tmp = new RegularObjectStrategy($refl); |
122 | $mapping = $tmp->$method($context); |
123 | foreach ($mapping->getHashmap() as $propertyName => $declaration) { |
124 | /** @var string $propertyName */ |
125 | if (isset($list[$propertyName])) { |
126 | $list[$propertyName] = new OptionalField($declaration, $list[$propertyName]); |
127 | } else { |
128 | $list[$propertyName] = new OptionalField($declaration); |
129 | } |
130 | } |
131 | } |
132 | } |