Skip to content

Commit f626998

Browse files
committed
review
1 parent 01846bd commit f626998

File tree

3 files changed

+241
-218
lines changed

3 files changed

+241
-218
lines changed

src/Metadata/Resource/Factory/MetadataCollectionFactoryTrait.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
namespace ApiPlatform\Metadata\Resource\Factory;
1515

1616
use ApiPlatform\Metadata\ApiResource;
17-
use ApiPlatform\Metadata\Exception\InvalidArgumentException;
18-
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
1917
use ApiPlatform\Metadata\Exception\RuntimeException;
2018
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
2119
use ApiPlatform\Metadata\HttpOperation;
@@ -90,13 +88,6 @@ private function buildResourceOperations(array $metadataCollection, string $reso
9088
foreach ($resource->getOperations() ?? new Operations() as $operation) {
9189
[$key, $operation] = $this->getOperationWithDefaults($resource, $operation);
9290
$operations[$key] = $operation;
93-
if (null !== $operation->getErrors()) {
94-
foreach ($operation->getErrors() as $error) {
95-
if (!is_a($error, ProblemExceptionInterface::class, true)) {
96-
throw new InvalidArgumentException(\sprintf('The error class "%s" does not implement "%s". Did you forget a use statement?', $error, ProblemExceptionInterface::class));
97-
}
98-
}
99-
}
10091
}
10192
if ($operations) {
10293
$resource = $resource->withOperations(new Operations($operations));

src/OpenApi/Factory/OpenApiFactory.php

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use ApiPlatform\Metadata\ApiResource;
2121
use ApiPlatform\Metadata\CollectionOperationInterface;
2222
use ApiPlatform\Metadata\Error;
23+
use ApiPlatform\Metadata\Exception\OperationNotFoundException;
2324
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
2425
use ApiPlatform\Metadata\Exception\ResourceClassNotFoundException;
2526
use ApiPlatform\Metadata\HeaderParameterInterface;
@@ -39,6 +40,7 @@
3940
use ApiPlatform\OpenApi\Model\MediaType;
4041
use ApiPlatform\OpenApi\Model\OAuthFlow;
4142
use ApiPlatform\OpenApi\Model\OAuthFlows;
43+
use ApiPlatform\OpenApi\Model\Operation;
4244
use ApiPlatform\OpenApi\Model\Parameter;
4345
use ApiPlatform\OpenApi\Model\PathItem;
4446
use ApiPlatform\OpenApi\Model\Paths;
@@ -172,15 +174,15 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
172174

173175
if ($openapiAttribute instanceof Webhook) {
174176
$pathItem = $openapiAttribute->getPathItem() ?: new PathItem();
175-
$openapiOperation = $pathItem->{'get'.ucfirst(strtolower($method))}() ?: new Model\Operation();
177+
$openapiOperation = $pathItem->{'get'.ucfirst(strtolower($method))}() ?: new Operation();
176178
} elseif (!\is_object($openapiAttribute)) {
177-
$openapiOperation = new Model\Operation();
179+
$openapiOperation = new Operation();
178180
} else {
179181
$openapiOperation = $openapiAttribute;
180182
}
181183

182184
// Complete with defaults
183-
$openapiOperation = new Model\Operation(
185+
$openapiOperation = new Operation(
184186
operationId: null !== $openapiOperation->getOperationId() ? $openapiOperation->getOperationId() : $this->normalizeOperationName($operationName),
185187
tags: null !== $openapiOperation->getTags() ? $openapiOperation->getTags() : [$operation->getShortName() ?: $resourceShortName],
186188
responses: null !== $openapiOperation->getResponses() ? $openapiOperation->getResponses() : [],
@@ -273,48 +275,10 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
273275
$openapiOperation = $openapiOperation->withParameters($openapiParameters);
274276
$existingResponses = $openapiOperation->getResponses() ?: [];
275277
$overrideResponses = $operation->getExtraProperties()[self::OVERRIDE_OPENAPI_RESPONSES] ?? $this->openApiOptions->getOverrideResponses();
276-
if ($operation instanceof HttpOperation && null !== $operation->getErrors()) {
277-
foreach ($operation->getErrors() as $error) {
278-
$status = null;
279-
$description = null;
280-
try {
281-
/** @var ProblemExceptionInterface $exception */
282-
$exception = (new \ReflectionClass($error))->newInstanceWithoutConstructor();
283-
$status = $exception->getStatus();
284-
$description = $exception->getTitle();
285-
} catch (\ReflectionException) {
286-
}
287-
288-
try {
289-
$errorOperation = $this->resourceMetadataFactory->create($error)->getOperation();
290-
if (!is_a($errorOperation, Error::class)) {
291-
$this->logger?->warning(\sprintf('The error class %s is not an ErrorResource', $error));
292-
continue;
293-
}
294-
$status ??= $errorOperation->getStatus();
295-
$description ??= $errorOperation->getDescription();
296-
} catch (ResourceClassNotFoundException) {
297-
$this->logger?->warning(\sprintf('The error class %s is not an ErrorResource', $error));
298-
continue;
299-
}
300-
301-
if (!$status) {
302-
$this->logger?->error(\sprintf(
303-
'The error class %s has no status defined, please either implement ProblemExceptionInterface, or make it an ErrorResource with a status',
304-
$error));
305-
continue;
306-
}
307-
308-
$operationErrorSchemas = [];
309-
foreach ($responseMimeTypes as $operationFormat) {
310-
$operationErrorSchema = $this->jsonSchemaFactory->buildSchema($error, $operationFormat, Schema::TYPE_OUTPUT, null, $schema, null, $forceSchemaCollection);
311-
$operationErrorSchemas[$operationFormat] = $operationErrorSchema;
312-
$this->appendSchemaDefinitions($schemas, $operationErrorSchema->getDefinitions());
313-
}
314-
315-
$openapiOperation = $this->buildOpenApiResponse($existingResponses, $status, $description ?? '', $openapiOperation, $operation, $responseMimeTypes, $operationErrorSchemas, $resourceMetadataCollection);
316-
}
278+
if ($operation instanceof HttpOperation && null !== ($errors = $operation->getErrors())) {
279+
$openapiOperation = $this->addOperationErrors($openapiOperation, $errors, $responseMimeTypes, $resourceMetadataCollection, $schema, $schemas);
317280
}
281+
318282
if ($overrideResponses || !$existingResponses) {
319283
// Create responses
320284
switch ($method) {
@@ -390,7 +354,7 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
390354
}
391355
}
392356

393-
private function buildOpenApiResponse(array $existingResponses, int|string $status, string $description, ?Model\Operation $openapiOperation = null, ?HttpOperation $operation = null, ?array $responseMimeTypes = null, ?array $operationOutputSchemas = null, ?ResourceMetadataCollection $resourceMetadataCollection = null): Model\Operation
357+
private function buildOpenApiResponse(array $existingResponses, int|string $status, string $description, ?Operation $openapiOperation = null, ?HttpOperation $operation = null, ?array $responseMimeTypes = null, ?array $operationOutputSchemas = null, ?ResourceMetadataCollection $resourceMetadataCollection = null): Operation
394358
{
395359
if (isset($existingResponses[$status])) {
396360
return $openapiOperation;
@@ -421,6 +385,9 @@ private function buildContent(array $responseMimeTypes, array $operationSchemas)
421385
return $content;
422386
}
423387

388+
/**
389+
* @return array[array<string, string>, array<string, string>]
390+
*/
424391
private function getMimeTypes(HttpOperation $operation): array
425392
{
426393
$requestFormats = $operation->getInputFormats() ?: [];
@@ -432,6 +399,11 @@ private function getMimeTypes(HttpOperation $operation): array
432399
return [$requestMimeTypes, $responseMimeTypes];
433400
}
434401

402+
/**
403+
* @param array<string, string[]> $responseFormats
404+
*
405+
* @return array<string, string>
406+
*/
435407
private function flattenMimeTypes(array $responseFormats): array
436408
{
437409
$responseMimeTypes = [];
@@ -698,7 +670,7 @@ private function appendSchemaDefinitions(\ArrayObject $schemas, \ArrayObject $de
698670
/**
699671
* @return array{0: int, 1: Parameter}|null
700672
*/
701-
private function hasParameter(Model\Operation $operation, Parameter $parameter): ?array
673+
private function hasParameter(Operation $operation, Parameter $parameter): ?array
702674
{
703675
foreach ($operation->getParameters() as $key => $existingParameter) {
704676
if ($existingParameter->getName() === $parameter->getName() && $existingParameter->getIn() === $parameter->getIn()) {
@@ -738,4 +710,61 @@ private function mergeParameter(Parameter $actual, Parameter $defined): Paramete
738710

739711
return $actual;
740712
}
713+
714+
/**
715+
* @param string[] $errors
716+
* @param array<string, string> $responseMimeTypes
717+
*/
718+
private function addOperationErrors(Operation $operation, array $errors, array $responseMimeTypes, ResourceMetadataCollection $resourceMetadataCollection, Schema $schema, \ArrayObject $schemas): Operation
719+
{
720+
$existingResponses = null;
721+
foreach ($errors as $error) {
722+
if (!is_a($error, ProblemExceptionInterface::class, true)) {
723+
$this->logger?->warning(\sprintf('The error class "%s" does not implement "%s". Did you forget a use statement?', $error, ProblemExceptionInterface::class));
724+
}
725+
726+
$status = null;
727+
$description = null;
728+
try {
729+
/** @var ProblemExceptionInterface */
730+
$exception = (new \ReflectionClass($error))->newInstanceWithoutConstructor();
731+
$status = $exception->getStatus();
732+
$description = $exception->getTitle();
733+
} catch (\ReflectionException) {
734+
}
735+
736+
try {
737+
$errorOperation = $this->resourceMetadataFactory->create($error)->getOperation();
738+
if (!is_a($errorOperation, Error::class)) {
739+
$this->logger?->warning(\sprintf('The error class %s is not an ErrorResource', $error));
740+
continue;
741+
}
742+
/* @var Error $errorOperation */
743+
$status ??= $errorOperation->getStatus();
744+
$description ??= $errorOperation->getDescription();
745+
} catch (ResourceClassNotFoundException|OperationNotFoundException) {
746+
$this->logger?->warning(\sprintf('The error class %s is not an ErrorResource', $error));
747+
continue;
748+
}
749+
750+
if (!$status) {
751+
$this->logger?->error(\sprintf(
752+
'The error class %s has no status defined, please either implement ProblemExceptionInterface, or make it an ErrorResource with a status',
753+
$error
754+
));
755+
continue;
756+
}
757+
758+
$operationErrorSchemas = [];
759+
foreach ($responseMimeTypes as $operationFormat) {
760+
$operationErrorSchema = $this->jsonSchemaFactory->buildSchema($error, $operationFormat, Schema::TYPE_OUTPUT, null, $schema);
761+
$operationErrorSchemas[$operationFormat] = $operationErrorSchema;
762+
$this->appendSchemaDefinitions($schemas, $operationErrorSchema->getDefinitions());
763+
}
764+
765+
$operation = $this->buildOpenApiResponse($existingResponses ??= $operation->getResponses() ?: [], $status, $description ?? '', $operation, $errorOperation, $responseMimeTypes, $operationErrorSchemas, $resourceMetadataCollection);
766+
}
767+
768+
return $operation;
769+
}
741770
}

0 commit comments

Comments
 (0)