diff --git a/features/bootstrap/SwaggerContext.php b/features/bootstrap/SwaggerContext.php index 1d4a96cfce2..3fab0f438a5 100644 --- a/features/bootstrap/SwaggerContext.php +++ b/features/bootstrap/SwaggerContext.php @@ -60,6 +60,20 @@ public function assertTheSwaggerClassNotExist($className) } } + /** + * @Then the Swagger path ":arg1" exist + */ + public function assertThePathExist($path) + { + try { + \PHPUnit_Framework_Assert::assertTrue($this->assertSwaggerPath($path)); + + throw new \PHPUnit_Framework_ExpectationFailedException(sprintf('The path "%s" exist.', $path)); + } catch (\Exception $exception) { + // an exception must be catched + } + } + /** * @Then the value of the node ":node" of the Swagger class ":class" is ":value" */ @@ -191,6 +205,21 @@ private function getProperties(string $className) : stdClass return empty($classInfos->{'properties'}) ? $classInfos->{'properties'} : new stdClass(); } + private function assertSwaggerPath(string $expectedPath, bool $getOperation = false): bool + { + $json = $this->getLastJsonResponse(); + $validPath = false; + if (isset($json->{'paths'}) && $getOperation) { + foreach ($json->{'paths'} as $classTitle => $classPath) { + if ($expectedPath === $classPath) { + return true; + } + } + } + + return $validPath; + } + private function getClassInfos(string $className, bool $getOperation = false) : stdClass { $json = $this->getLastJsonResponse(); diff --git a/features/swagger/doc.feature b/features/swagger/doc.feature index bb022b94be2..d27b69b0d90 100644 --- a/features/swagger/doc.feature +++ b/features/swagger/doc.feature @@ -24,6 +24,7 @@ Feature: Documentation support And the Swagger class "ThirdLevel" exist And the Swagger class "ParentDummy" not exist And the Swagger class "UnknownDummy" not exist + And the Swagger path "/override/swagger" exist # Properties And "id" property doesn't exist for the Swagger class "Dummy" And "name" property is required for Swagger class "Dummy" diff --git a/src/Swagger/ApiDocumentationBuilder.php b/src/Swagger/ApiDocumentationBuilder.php index b6682c87b2b..8cd6c3ba141 100644 --- a/src/Swagger/ApiDocumentationBuilder.php +++ b/src/Swagger/ApiDocumentationBuilder.php @@ -76,13 +76,15 @@ public function getApiDocumentation() : array { $classes = []; $operation = []; - + $customOperations = []; $itemOperationsDocs = []; $definitions = []; foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) { $operation['item'] = []; $operation['collection'] = []; + $customOperations['item'] = []; + $customOperations['collection'] = []; $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); $shortName = $resourceMetadata->getShortName(); @@ -146,25 +148,57 @@ public function getApiDocumentation() : array if ($operations = $resourceMetadata->getItemOperations()) { foreach ($operations as $operationName => $itemOperation) { - $swaggerOperation = $this->getSwaggerOperation($resourceClass, $resourceMetadata, $operationName, $itemOperation, $prefixedShortName, false, $definitions); + $method = $this->operationMethodResolver->getItemOperationMethod($resourceClass, $operationName); + $swaggerOperation = $this->getSwaggerOperation($resourceClass, $resourceMetadata, $operationName, $itemOperation, $prefixedShortName, false, $definitions, $method); $operation['item'] = array_merge($operation['item'], $swaggerOperation); + if ($operationName !== strtolower($method)) { + $customOperations['item'][] = $operationName; + } } } if ($operations = $resourceMetadata->getCollectionOperations()) { foreach ($operations as $operationName => $collectionOperation) { - $swaggerOperation = $this->getSwaggerOperation($resourceClass, $resourceMetadata, $operationName, $collectionOperation, $prefixedShortName, true, $definitions); + $method = $this->operationMethodResolver->getCollectionOperationMethod($resourceClass, $operationName); + $swaggerOperation = $this->getSwaggerOperation($resourceClass, $resourceMetadata, $operationName, $collectionOperation, $prefixedShortName, true, $definitions, $method); $operation['collection'] = array_merge($operation['collection'], $swaggerOperation); + if ($operationName !== strtolower($method)) { + $customOperations['collection'][] = $operationName; + } } } - try { $resourceClassIri = $this->iriConverter->getIriFromResourceClass($resourceClass); $itemOperationsDocs[$resourceClassIri] = $operation['collection']; + if (!empty($customOperations['collection'])) { + foreach ($customOperations['collection'] as $customOperation) { + $path = $resourceMetadata->getCollectionOperationAttribute($customOperation, 'path'); + if (null !== $path) { + $method = $this->operationMethodResolver->getCollectionOperationMethod($resourceClass, $customOperation); + $customSwaggerOperation = $this->getSwaggerOperation($resourceClass, $resourceMetadata, $customOperation, [$method], $prefixedShortName, true, $definitions, $method); + + $itemOperationsDocs[$path] = $customSwaggerOperation; + } + } + } + + $resourceClassIri .= '/{id}'; $itemOperationsDocs[$resourceClassIri] = $operation['item']; + + if (!empty($customOperations['item'])) { + foreach ($customOperations['item'] as $customOperation) { + $path = $resourceMetadata->getItemOperationAttribute($customOperation, 'path'); + if (null !== $path) { + $method = $this->operationMethodResolver->getItemOperationMethod($resourceClass, $customOperation); + $customSwaggerOperation = $this->getSwaggerOperation($resourceClass, $resourceMetadata, $customOperation, [$method], $prefixedShortName, true, $definitions, $method); + + $itemOperationsDocs[$path] = $customSwaggerOperation; + } + } + } } catch (InvalidArgumentException $e) { } @@ -191,14 +225,8 @@ public function getApiDocumentation() : array /** * Gets and populates if applicable a Swagger operation. */ - private function getSwaggerOperation(string $resourceClass, ResourceMetadata $resourceMetadata, string $operationName, array $operation, string $prefixedShortName, bool $collection, array $properties) : array + private function getSwaggerOperation(string $resourceClass, ResourceMetadata $resourceMetadata, string $operationName, array $operation, string $prefixedShortName, bool $collection, array $properties, string $method) : array { - if ($collection) { - $method = $this->operationMethodResolver->getCollectionOperationMethod($resourceClass, $operationName); - } else { - $method = $this->operationMethodResolver->getItemOperationMethod($resourceClass, $operationName); - } - $methodSwagger = strtolower($method); $swaggerOperation = $operation['swagger_context'] ?? []; $shortName = $resourceMetadata->getShortName(); diff --git a/tests/Fixtures/TestBundle/Entity/OverriddenOperationDummy.php b/tests/Fixtures/TestBundle/Entity/OverriddenOperationDummy.php index 890bba60a5b..ac1bd048ed2 100644 --- a/tests/Fixtures/TestBundle/Entity/OverriddenOperationDummy.php +++ b/tests/Fixtures/TestBundle/Entity/OverriddenOperationDummy.php @@ -27,7 +27,19 @@ * "normalization_context"={"groups"={"overridden_operation_dummy_read"}}, * "denormalization_context"={"groups"={"overridden_operation_dummy_write"}} * }, + * collectionOperations={ + * + * "get"={"method"="GET"}, + * "post"={"method"="POST"}, + * "swagger"= { + * "path"="/override/swagger", + * "method"="GET", + * } + * }, * itemOperations={ + * "swagger"= { + * "method"="GET", + * }, * "get"={ * "method"="GET", * "normalization_context"={"groups"={"overridden_operation_dummy_get"}},