Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
67 / 67 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
1 / 1 |
PolymorphicEntitySchemaProvider | |
100.00% |
67 / 67 |
|
100.00% |
4 / 4 |
12 | |
100.00% |
1 / 1 |
supports | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
fillInDiscriminator | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
addDisplaySchemaFor | |
100.00% |
28 / 28 |
|
100.00% |
1 / 1 |
4 | |||
addCreationSchemaFor | |
100.00% |
28 / 28 |
|
100.00% |
1 / 1 |
4 |
1 | <?php |
2 | namespace Apie\SchemaGenerator\SchemaProviders; |
3 | |
4 | use Apie\Core\Entities\PolymorphicEntityInterface; |
5 | use Apie\Core\Other\DiscriminatorMapping; |
6 | use Apie\SchemaGenerator\Builders\ComponentsBuilder; |
7 | use Apie\SchemaGenerator\Interfaces\SchemaProvider; |
8 | use cebe\openapi\spec\Components; |
9 | use cebe\openapi\spec\Discriminator; |
10 | use cebe\openapi\spec\Reference; |
11 | use cebe\openapi\spec\Schema; |
12 | use ReflectionClass; |
13 | |
14 | /** |
15 | * @implements SchemaProvider<PolymorphicEntityInterface> |
16 | */ |
17 | class PolymorphicEntitySchemaProvider implements SchemaProvider |
18 | { |
19 | public function supports(ReflectionClass $class): bool |
20 | { |
21 | if (!$class->implementsInterface(PolymorphicEntityInterface::class)) { |
22 | return false; |
23 | } |
24 | $method = $class->getMethod('getDiscriminatorMapping'); |
25 | return $method->getDeclaringClass()->name === $class->name && !$method->isAbstract(); |
26 | } |
27 | |
28 | private function fillInDiscriminator(Schema $schema, string $propertyName, string $propertyValue): void |
29 | { |
30 | $properties = $schema->properties ?? []; |
31 | $properties[$propertyName] = new Schema([ |
32 | 'type' => 'string', |
33 | 'enum' => [$propertyValue], |
34 | 'nullable' => false, |
35 | ]); |
36 | $schema->properties = $properties; |
37 | } |
38 | |
39 | public function addDisplaySchemaFor( |
40 | ComponentsBuilder $componentsBuilder, |
41 | string $componentIdentifier, |
42 | ReflectionClass $class, |
43 | bool $nullable = false |
44 | ): Components { |
45 | $relations = []; |
46 | $method = $class->getMethod('getDiscriminatorMapping'); |
47 | /** @var DiscriminatorMapping */ |
48 | $discriminatorMapping = $method->invoke(null); |
49 | |
50 | foreach ($discriminatorMapping->getConfigs() as $config) { |
51 | $key = $config->getDiscriminator(); |
52 | $value = $componentsBuilder->addDisplaySchemaFor($config->getClassName(), $discriminatorMapping->getPropertyName(), nullable: $nullable); |
53 | assert($value instanceof Reference); |
54 | $relations[$key] = $value; |
55 | $schema = $componentsBuilder->getSchemaForReference($value); |
56 | if ($schema) { |
57 | $this->fillInDiscriminator($schema, $discriminatorMapping->getPropertyName(), $config->getDiscriminator()); |
58 | } |
59 | } |
60 | $schema = new Schema([ |
61 | 'type' => 'object', |
62 | 'oneOf' => array_values($relations), |
63 | 'discriminator' => new Discriminator([ |
64 | 'propertyName' => $discriminatorMapping->getPropertyName(), |
65 | 'mapping' => array_map( |
66 | function (Reference $ref) { |
67 | return $ref->getReference(); |
68 | }, |
69 | $relations |
70 | ), |
71 | ]), |
72 | ]); |
73 | if ($nullable) { |
74 | $schema->nullable = true; |
75 | } |
76 | |
77 | $componentsBuilder->setSchema($componentIdentifier, $schema); |
78 | return $componentsBuilder->getComponents(); |
79 | } |
80 | |
81 | public function addCreationSchemaFor( |
82 | ComponentsBuilder $componentsBuilder, |
83 | string $componentIdentifier, |
84 | ReflectionClass $class, |
85 | bool $nullable = false |
86 | ): Components { |
87 | $relations = []; |
88 | $method = $class->getMethod('getDiscriminatorMapping'); |
89 | /** @var DiscriminatorMapping */ |
90 | $discriminatorMapping = $method->invoke(null); |
91 | foreach ($discriminatorMapping->getConfigs() as $config) { |
92 | $key = $config->getDiscriminator(); |
93 | $value = $componentsBuilder->addCreationSchemaFor($config->getClassName(), $discriminatorMapping->getPropertyName()); |
94 | assert($value instanceof Reference); |
95 | $relations[$key] = $value; |
96 | $schema = $componentsBuilder->getSchemaForReference($value); |
97 | if ($schema) { |
98 | $this->fillInDiscriminator($schema, $discriminatorMapping->getPropertyName(), $config->getDiscriminator()); |
99 | } |
100 | } |
101 | $schema = new Schema([ |
102 | 'type' => 'object', |
103 | 'oneOf' => array_values($relations), |
104 | 'discriminator' => new Discriminator([ |
105 | 'propertyName' => $discriminatorMapping->getPropertyName(), |
106 | 'mapping' => array_map( |
107 | function (Reference $ref) { |
108 | return $ref->getReference(); |
109 | }, |
110 | $relations |
111 | ), |
112 | ]), |
113 | ]); |
114 | if ($nullable) { |
115 | $schema->nullable = true; |
116 | } |
117 | |
118 | $componentsBuilder->setSchema($componentIdentifier, $schema); |
119 | return $componentsBuilder->getComponents(); |
120 | } |
121 | } |