Skip to content

Commit 5f11d6c

Browse files
committed
Improve SchemaFactory performances
1 parent baecd8e commit 5f11d6c

File tree

5 files changed

+64
-7
lines changed

5 files changed

+64
-7
lines changed

src/JsonSchema/SchemaFactory.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public function buildSchema(string $className, string $format = 'json', string $
8080
}
8181

8282
$version = $schema->getVersion();
83-
$definitionName = $this->buildDefinitionName($className, $format, $type, $operationType, $operationName, $serializerContext);
83+
$definitionName = $this->buildDefinitionName($className, $format, $inputOrOutputClass, $resourceMetadata, $serializerContext);
8484

8585
if (null === $operationType || null === $operationName) {
8686
$method = Schema::TYPE_INPUT === $type ? 'POST' : 'GET';
@@ -104,6 +104,11 @@ public function buildSchema(string $className, string $format = 'json', string $
104104
}
105105
}
106106

107+
$refOnly = \func_num_args() > 8 ? func_get_arg(8) : false;
108+
if ($refOnly) {
109+
return $schema;
110+
}
111+
107112
$definitions = $schema->getDefinitions();
108113
if (isset($definitions[$definitionName])) {
109114
// Already computed
@@ -239,10 +244,8 @@ private function buildPropertySchema(Schema $schema, string $definitionName, str
239244
$schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = $propertySchema;
240245
}
241246

242-
private function buildDefinitionName(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?array $serializerContext = null): string
247+
private function buildDefinitionName(string $className, string $format = 'json', ?string $inputOrOutputClass = null, ?ResourceMetadata $resourceMetadata = null, ?array $serializerContext = null): string
243248
{
244-
[$resourceMetadata, $serializerContext,, $inputOrOutputClass] = $this->getMetadata($className, $type, $operationType, $operationName, $serializerContext);
245-
246249
$prefix = $resourceMetadata ? $resourceMetadata->getShortName() : (new \ReflectionClass($className))->getShortName();
247250
if (null !== $inputOrOutputClass && $className !== $inputOrOutputClass) {
248251
$parts = explode('\\', $inputOrOutputClass);

src/JsonSchema/SchemaFactoryInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ interface SchemaFactoryInterface
2525
/**
2626
* Builds the JSON Schema document corresponding to the given PHP class.
2727
*/
28-
public function buildSchema(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false): Schema;
28+
public function buildSchema(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false, /* bool $refOnly = false */): Schema;
2929
}

src/JsonSchema/TypeFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ private function getClassType(?string $className, string $format, ?bool $readabl
142142
throw new \LogicException('The schema factory must be injected by calling the "setSchemaFactory" method.');
143143
}
144144

145-
$subSchema = $this->schemaFactory->buildSchema($className, $format, Schema::TYPE_OUTPUT, null, null, $subSchema, $serializerContext);
145+
$subSchema = $this->schemaFactory->buildSchema($className, $format, Schema::TYPE_OUTPUT, null, null, $subSchema, $serializerContext, false, true); // @phpstan-ignore-line
146146

147147
return ['$ref' => $subSchema['$ref']];
148148
}

tests/JsonSchema/SchemaFactoryTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,58 @@ public function testBuildSchemaForOperationWithOverriddenSerializerGroups(): voi
156156
$this->assertArrayHasKey('type', $definitions[$rootDefinitionKey]['properties']['description']);
157157
$this->assertSame('string', $definitions[$rootDefinitionKey]['properties']['description']['type']);
158158
}
159+
160+
public function testBuildSchemaOnlyRef(): void
161+
{
162+
$typeFactoryProphecy = $this->prophesize(TypeFactoryInterface::class);
163+
$typeFactoryProphecy->getType(Argument::allOf(
164+
Argument::type(Type::class),
165+
Argument::which('getBuiltinType', Type::BUILTIN_TYPE_STRING)
166+
), Argument::cetera())->willReturn([
167+
'type' => 'string',
168+
]);
169+
170+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
171+
$resourceMetadataFactoryProphecy->create(OverriddenOperationDummy::class)->willReturn(new ResourceMetadata((new \ReflectionClass(OverriddenOperationDummy::class))->getShortName(), null, null, [
172+
'put' => [
173+
'normalization_context' => [
174+
'groups' => 'overridden_operation_dummy_put',
175+
AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
176+
],
177+
'validation_groups' => ['validation_groups_dummy_put'],
178+
],
179+
], [], [
180+
'normalization_context' => [
181+
'groups' => 'overridden_operation_dummy_read',
182+
],
183+
]));
184+
185+
$serializerGroup = 'overridden_operation_dummy_put';
186+
$validationGroups = 'validation_groups_dummy_put';
187+
188+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
189+
$propertyNameCollectionFactoryProphecy->create(OverriddenOperationDummy::class, Argument::allOf(
190+
Argument::type('array'),
191+
Argument::allOf(Argument::withEntry('serializer_groups', [$serializerGroup]), Argument::withEntry('validation_groups', [$validationGroups]))
192+
))->willReturn(new PropertyNameCollection(['alias', 'description']));
193+
194+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
195+
$propertyMetadataFactoryProphecy->create(OverriddenOperationDummy::class, 'alias', Argument::allOf(
196+
Argument::type('array'),
197+
Argument::allOf(Argument::withEntry('serializer_groups', [$serializerGroup]), Argument::withEntry('validation_groups', [$validationGroups]))
198+
))->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), null, true));
199+
$propertyMetadataFactoryProphecy->create(OverriddenOperationDummy::class, 'description', Argument::allOf(
200+
Argument::type('array'),
201+
Argument::allOf(Argument::withEntry('serializer_groups', [$serializerGroup]), Argument::withEntry('validation_groups', [$validationGroups]))
202+
))->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), null, true));
203+
204+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
205+
$resourceClassResolverProphecy->isResourceClass(OverriddenOperationDummy::class)->willReturn(true);
206+
207+
$schemaFactory = new SchemaFactory($typeFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), $propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal());
208+
$resultSchema = $schemaFactory->buildSchema(OverriddenOperationDummy::class, 'json', Schema::TYPE_OUTPUT, OperationType::ITEM, 'put', null, [], false, true);
209+
210+
$this->assertSame('#/definitions/OverriddenOperationDummy', $resultSchema['$ref']);
211+
$this->assertCount(0, $resultSchema->getDefinitions());
212+
}
159213
}

tests/JsonSchema/TypeFactoryTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ public function testGetClassType(): void
372372
{
373373
$schemaFactoryProphecy = $this->prophesize(SchemaFactoryInterface::class);
374374

375-
$schemaFactoryProphecy->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, null, null, Argument::type(Schema::class), ['foo' => 'bar'])->will(function (array $args) {
375+
$schemaFactoryProphecy->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, null, null, Argument::type(Schema::class), ['foo' => 'bar'], false, true)->will(function (array $args) {
376376
$args[5]['$ref'] = 'ref';
377377

378378
return $args[5];

0 commit comments

Comments
 (0)