Skip to content

Commit 239155c

Browse files
committed
redirect merged schemas
1 parent d66b130 commit 239155c

File tree

6 files changed

+307
-179
lines changed

6 files changed

+307
-179
lines changed

src/Model/SchemaDefinition/JsonSchema.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,26 @@
1111
*/
1212
class JsonSchema
1313
{
14+
private const SCHEMA_SIGNATURE_RELEVANT_FIELDS = [
15+
'type',
16+
'properties',
17+
'$ref',
18+
'allOf',
19+
'anyOf',
20+
'oneOf',
21+
'not',
22+
'if',
23+
'then',
24+
'else',
25+
'additionalProperties',
26+
'required',
27+
'propertyNames',
28+
'minProperties',
29+
'maxProperties',
30+
'dependencies',
31+
'patternProperties',
32+
];
33+
1434
/** @var array */
1535
protected $json;
1636
/** @var string */
@@ -36,6 +56,19 @@ public function getJson(): array
3656
return $this->json;
3757
}
3858

59+
/**
60+
* create the signature from all fields which are directly relevant for the created object. Additional fields
61+
* can be ignored as the resulting code will be identical
62+
*/
63+
public function getSignature(): string
64+
{
65+
return md5(
66+
json_encode(
67+
array_intersect_key($this->json, array_fill_keys(self::SCHEMA_SIGNATURE_RELEVANT_FIELDS, null))
68+
)
69+
);
70+
}
71+
3972
/**
4073
* @param array $json
4174
*

src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php

Lines changed: 6 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
*/
3434
abstract class AbstractComposedValueProcessor extends AbstractValueProcessor
3535
{
36-
/** @var PropertyInterface[] */
37-
private static $generatedMergedProperties = [];
3836
/** @var bool */
3937
private $rootLevelComposition;
4038
/** @var PropertyInterface|null */
@@ -85,7 +83,12 @@ function () use (&$resolvedCompositions, $property, $compositionProperties, $pro
8583

8684
$this->mergedProperty = !$this->rootLevelComposition
8785
&& $this instanceof MergedComposedPropertiesInterface
88-
? $this->createMergedProperty($property, $compositionProperties, $propertySchema)
86+
? $this->schemaProcessor->createMergedProperty(
87+
$this->schema,
88+
$property,
89+
$compositionProperties,
90+
$propertySchema
91+
)
8992
: null;
9093
}
9194
}
@@ -209,138 +212,6 @@ static function (CompositionPropertyDecorator $property): string {
209212
}
210213
}
211214

212-
/**
213-
* Gather all nested object properties and merge them together into a single merged property
214-
*
215-
* @param PropertyInterface $property
216-
* @param CompositionPropertyDecorator[] $compositionProperties
217-
* @param JsonSchema $propertySchema
218-
*
219-
* @return PropertyInterface|null
220-
*
221-
* @throws SchemaException
222-
*/
223-
private function createMergedProperty(
224-
PropertyInterface $property,
225-
array $compositionProperties,
226-
JsonSchema $propertySchema
227-
): ?PropertyInterface {
228-
$redirectToProperty = $this->redirectMergedProperty($compositionProperties);
229-
if ($redirectToProperty === null || $redirectToProperty instanceof PropertyInterface) {
230-
if ($redirectToProperty) {
231-
$property->addTypeHintDecorator(new CompositionTypeHintDecorator($redirectToProperty));
232-
}
233-
234-
return $redirectToProperty;
235-
}
236-
237-
$mergedClassName = $this->schemaProcessor
238-
->getGeneratorConfiguration()
239-
->getClassNameGenerator()
240-
->getClassName(
241-
$property->getName(),
242-
$propertySchema,
243-
true,
244-
$this->schemaProcessor->getCurrentClassName()
245-
);
246-
247-
// check if the merged property already has been generated
248-
if (isset(self::$generatedMergedProperties[$mergedClassName])) {
249-
return self::$generatedMergedProperties[$mergedClassName];
250-
}
251-
252-
$mergedPropertySchema = new Schema($this->schema->getClassPath(), $mergedClassName, $propertySchema);
253-
254-
$mergedProperty = new Property(
255-
'MergedProperty',
256-
new PropertyType($mergedClassName),
257-
$mergedPropertySchema->getJsonSchema()
258-
);
259-
260-
self::$generatedMergedProperties[$mergedClassName] = $mergedProperty;
261-
262-
$this->transferPropertiesToMergedSchema($mergedPropertySchema, $compositionProperties);
263-
264-
$this->schemaProcessor->generateClassFile(
265-
$this->schemaProcessor->getCurrentClassPath(),
266-
$mergedClassName,
267-
$mergedPropertySchema
268-
);
269-
270-
$property->addTypeHintDecorator(new CompositionTypeHintDecorator($mergedProperty));
271-
272-
return $mergedProperty
273-
->addDecorator(
274-
new ObjectInstantiationDecorator($mergedClassName, $this->schemaProcessor->getGeneratorConfiguration())
275-
)
276-
->setNestedSchema($mergedPropertySchema);
277-
}
278-
279-
/**
280-
* Check if multiple $compositionProperties contain nested schemas. Only in this case a merged property must be
281-
* created. If no nested schemas are detected null will be returned. If only one $compositionProperty contains a
282-
* nested schema the $compositionProperty will be used as a replacement for the merged property.
283-
*
284-
* Returns false if a merged property must be created.
285-
*
286-
* @param CompositionPropertyDecorator[] $compositionProperties
287-
*
288-
* @return PropertyInterface|null|false
289-
*/
290-
private function redirectMergedProperty(array $compositionProperties)
291-
{
292-
$redirectToProperty = null;
293-
foreach ($compositionProperties as $property) {
294-
if ($property->getNestedSchema()) {
295-
if ($redirectToProperty !== null) {
296-
return false;
297-
}
298-
299-
$redirectToProperty = $property;
300-
}
301-
}
302-
303-
return $redirectToProperty;
304-
}
305-
306-
/**
307-
* @param Schema $mergedPropertySchema
308-
* @param PropertyInterface[] $compositionProperties
309-
*/
310-
private function transferPropertiesToMergedSchema(Schema $mergedPropertySchema, array $compositionProperties): void
311-
{
312-
foreach ($compositionProperties as $property) {
313-
if (!$property->getNestedSchema()) {
314-
continue;
315-
}
316-
317-
$property->getNestedSchema()->onAllPropertiesResolved(
318-
function () use ($property, $mergedPropertySchema): void {
319-
foreach ($property->getNestedSchema()->getProperties() as $nestedProperty) {
320-
$mergedPropertySchema->addProperty(
321-
// don't validate fields in merged properties. All fields were validated before
322-
// corresponding to the defined constraints of the composition property.
323-
(clone $nestedProperty)->filterValidators(static function (): bool {
324-
return false;
325-
})
326-
);
327-
328-
// the parent schema needs to know about all imports of the nested classes as all properties
329-
// of the nested classes are available in the parent schema (combined schema merging)
330-
$this->schema->addNamespaceTransferDecorator(
331-
new SchemaNamespaceTransferDecorator($property->getNestedSchema())
332-
);
333-
}
334-
335-
// make sure the merged schema knows all imports of the parent schema
336-
$mergedPropertySchema->addNamespaceTransferDecorator(
337-
new SchemaNamespaceTransferDecorator($this->schema)
338-
);
339-
}
340-
);
341-
}
342-
}
343-
344215
/**
345216
* @param int $composedElements The amount of elements which are composed together
346217
*

0 commit comments

Comments
 (0)