Skip to content

Commit

Permalink
Improve openapi performances
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Mar 16, 2021
1 parent 127e0bf commit 7e7d6e2
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 15 deletions.
6 changes: 2 additions & 4 deletions src/JsonSchema/SchemaFactory.php
Expand Up @@ -80,7 +80,7 @@ public function buildSchema(string $className, string $format = 'json', string $
}

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

if (null === $operationType || null === $operationName) {
$method = Schema::TYPE_INPUT === $type ? 'POST' : 'GET';
Expand Down Expand Up @@ -239,10 +239,8 @@ private function buildPropertySchema(Schema $schema, string $definitionName, str
$schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = $propertySchema;
}

private function buildDefinitionName(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?array $serializerContext = null): string
private function buildDefinitionName(string $className, string $format = 'json', ?string $inputOrOutputClass = null, ?ResourceMetadata $resourceMetadata = null, ?array $serializerContext = null): string
{
[$resourceMetadata, $serializerContext,, $inputOrOutputClass] = $this->getMetadata($className, $type, $operationType, $operationName, $serializerContext);

$prefix = $resourceMetadata ? $resourceMetadata->getShortName() : (new \ReflectionClass($className))->getShortName();
if (null !== $inputOrOutputClass && $className !== $inputOrOutputClass) {
$parts = explode('\\', $inputOrOutputClass);
Expand Down
2 changes: 1 addition & 1 deletion src/JsonSchema/TypeFactory.php
Expand Up @@ -142,7 +142,7 @@ private function getClassType(?string $className, string $format, ?bool $readabl
throw new \LogicException('The schema factory must be injected by calling the "setSchemaFactory" method.');
}

$subSchema = $this->schemaFactory->buildSchema($className, $format, Schema::TYPE_OUTPUT, null, null, $subSchema, $serializerContext);
$subSchema = $this->schemaFactory->buildSchema($className, $format, Schema::TYPE_OUTPUT, null, null, $subSchema, $serializerContext, false);

return ['$ref' => $subSchema['$ref']];
}
Expand Down
27 changes: 18 additions & 9 deletions src/OpenApi/Factory/OpenApiFactory.php
Expand Up @@ -86,19 +86,19 @@ public function __invoke(array $context = []): OpenApi
$servers = '/' === $baseUrl || '' === $baseUrl ? [new Model\Server('/')] : [new Model\Server($baseUrl)];
$paths = new Model\Paths();
$links = [];
$schemas = [];
$schemas = new \ArrayObject();

foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) {
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
$resourceShortName = $resourceMetadata->getShortName();

// Items needs to be parsed first to be able to reference the lines from the collection operation
[$itemOperationLinks, $itemOperationSchemas] = $this->collectPaths($resourceMetadata, $resourceClass, OperationType::ITEM, $context, $paths, $links, $schemas);
$schemas += $itemOperationSchemas;
$this->appendSchemaDefinitions($schemas, $itemOperationSchemas);
[$collectionOperationLinks, $collectionOperationSchemas] = $this->collectPaths($resourceMetadata, $resourceClass, OperationType::COLLECTION, $context, $paths, $links, $schemas);

[$subresourceOperationLinks, $subresourceOperationSchemas] = $this->collectPaths($resourceMetadata, $resourceClass, OperationType::SUBRESOURCE, $context, $paths, $links, $schemas);
$schemas += $collectionOperationSchemas;
$this->appendSchemaDefinitions($schemas, $collectionOperationSchemas);
}

$securitySchemes = $this->getSecuritySchemes();
Expand All @@ -113,7 +113,7 @@ public function __invoke(array $context = []): OpenApi
$servers,
$paths,
new Model\Components(
new \ArrayObject($schemas),
$schemas,
new \ArrayObject(),
new \ArrayObject(),
new \ArrayObject(),
Expand All @@ -128,7 +128,7 @@ public function __invoke(array $context = []): OpenApi
/**
* @return array | array
*/
private function collectPaths(ResourceMetadata $resourceMetadata, string $resourceClass, string $operationType, array $context, Model\Paths $paths, array &$links, array $schemas = []): array
private function collectPaths(ResourceMetadata $resourceMetadata, string $resourceClass, string $operationType, array $context, Model\Paths $paths, array &$links, \ArrayObject $schemas): array
{
$resourceShortName = $resourceMetadata->getShortName();
$operations = OperationType::COLLECTION === $operationType ? $resourceMetadata->getCollectionOperations() : (OperationType::ITEM === $operationType ? $resourceMetadata->getItemOperations() : $this->subresourceOperationFactory->create($resourceClass));
Expand All @@ -155,12 +155,14 @@ private function collectPaths(ResourceMetadata $resourceMetadata, string $resour
$linkedOperationId = 'get'.ucfirst($resourceShortName).ucfirst(OperationType::ITEM);
$pathItem = $paths->getPath($path) ?: new Model\PathItem();
$forceSchemaCollection = OperationType::SUBRESOURCE === $operationType ? ($operation['collection'] ?? false) : false;
$schema = new Schema('openapi');
$schema->setDefinitions($schemas);

$operationOutputSchemas = [];
foreach ($responseMimeTypes as $operationFormat) {
$operationOutputSchema = $this->jsonSchemaFactory->buildSchema($resourceClass, $operationFormat, Schema::TYPE_OUTPUT, $operationType, $operationName, new Schema('openapi'), null, $forceSchemaCollection);
$schemas += $operationOutputSchema->getDefinitions()->getArrayCopy();
$operationOutputSchema = $this->jsonSchemaFactory->buildSchema($resourceClass, $operationFormat, Schema::TYPE_OUTPUT, $operationType, $operationName, $schema, null, $forceSchemaCollection);
$operationOutputSchemas[$operationFormat] = $operationOutputSchema;
$this->appendSchemaDefinitions($schemas, $operationOutputSchema->getDefinitions());
}

$parameters = [];
Expand Down Expand Up @@ -264,9 +266,9 @@ private function collectPaths(ResourceMetadata $resourceMetadata, string $resour
} elseif ('PUT' === $method || 'POST' === $method || 'PATCH' === $method) {
$operationInputSchemas = [];
foreach ($requestMimeTypes as $operationFormat) {
$operationInputSchema = $this->jsonSchemaFactory->buildSchema($resourceClass, $operationFormat, Schema::TYPE_INPUT, $operationType, $operationName, new Schema('openapi'), null, $forceSchemaCollection);
$schemas += $operationInputSchema->getDefinitions()->getArrayCopy();
$operationInputSchema = $this->jsonSchemaFactory->buildSchema($resourceClass, $operationFormat, Schema::TYPE_INPUT, $operationType, $operationName, $schema, null, $forceSchemaCollection);
$operationInputSchemas[$operationFormat] = $operationInputSchema;
$this->appendSchemaDefinitions($schemas, $operationInputSchema->getDefinitions());
}

$requestBody = new Model\RequestBody(sprintf('The %s %s resource', 'POST' === $method ? 'new' : 'updated', $resourceShortName), $this->buildContent($requestMimeTypes, $operationInputSchemas), true);
Expand Down Expand Up @@ -510,6 +512,13 @@ private function getSecuritySchemes(): array
return $securitySchemes;
}

private function appendSchemaDefinitions(\ArrayObject &$schemas, \ArrayObject $definitions): void
{
foreach ($definitions as $key => $value) {
$schemas[$key] = $value;
}
}

/**
* @var Model\Parameter[]
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/JsonSchema/TypeFactoryTest.php
Expand Up @@ -372,7 +372,7 @@ public function testGetClassType(): void
{
$schemaFactoryProphecy = $this->prophesize(SchemaFactoryInterface::class);

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

return $args[5];
Expand Down

0 comments on commit 7e7d6e2

Please sign in to comment.