Skip to content

Commit

Permalink
Adding collection schema to methods that use openApiPaginator (#563)
Browse files Browse the repository at this point in the history
  • Loading branch information
MasaKni authored Feb 7, 2025
1 parent 75ceab8 commit d8c2792
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 19 deletions.
9 changes: 8 additions & 1 deletion src/Lib/Operation/OperationResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

namespace SwaggerBake\Lib\Operation;

use Cake\Utility\Inflector;
use ReflectionClass;
use ReflectionMethod;
use SwaggerBake\Lib\Attribute\AttributeFactory;
use SwaggerBake\Lib\Attribute\OpenApiPaginator;
use SwaggerBake\Lib\Attribute\OpenApiResponse;
use SwaggerBake\Lib\Attribute\OpenApiSchema;
use SwaggerBake\Lib\Attribute\OpenApiSchemaProperty;
Expand All @@ -21,6 +23,7 @@
use SwaggerBake\Lib\OpenApi\Xml as OpenApiXml;
use SwaggerBake\Lib\Route\RouteDecorator;
use SwaggerBake\Lib\Swagger;
use UnexpectedValueException;

/**
* Builds OpenAPI Operation Responses for CRUD actions and controller actions annotated with SwagResponseSchema
Expand Down Expand Up @@ -100,7 +103,6 @@ private function assignFromAttributes(): void
continue;
}

$response->pushContent(new Content($mimeType, ''));
$this->operation->pushResponse($response);
}
}
Expand Down Expand Up @@ -407,6 +409,11 @@ private function assignDefaultResponses(): void
$schema->setXml((new OpenApiXml())->setName('response'));
}

if (isset($this->refMethod) && !empty($this->refMethod->getAttributes(OpenApiPaginator::class))) {
$schema = Inflector::singularize($this->route->getController() ?? throw new UnexpectedValueException());
$schema = $this->getMimeTypeSchema($mimeType, 'array', '#/components/schemas/' . $schema);
}

$response->pushContent(new Content($mimeType, $schema));
}

Expand Down
5 changes: 3 additions & 2 deletions tests/TestCase/Lib/Model/ModelScannerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@ class ModelScannerTest extends TestCase

private array $config;

private Router $router;

public function setUp(): void
{
parent::setUp();

$router = new Router();
Router::createRouteBuilder('/')->scope('/', function (RouteBuilder $builder) {
$builder->setExtensions(['json']);
$builder->resources('Employees');
});

$this->router = $router;
$this->router = new Router();

$this->config = [
'prefix' => '/',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public function test_all_attributes_in_one(): void
$operation = $operationQueryParam->getOperationWithQueryParameters();

$parameters = $operation->getParameters();

$this->assertCount(11, $parameters);
}

Expand Down
78 changes: 64 additions & 14 deletions tests/TestCase/Lib/Operation/OperationResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\TestSuite\PHPUnitConsecutiveTrait;
use Cake\TestSuite\TestCase;
use SwaggerBake\Lib\Attribute\OpenApiPaginator;
use SwaggerBake\Lib\Attribute\OpenApiResponse;
use SwaggerBake\Lib\Configuration;
use SwaggerBake\Lib\SwaggerFactory;
Expand All @@ -19,6 +21,7 @@
class OperationResponseTest extends TestCase
{
use ReflectionAttributeTrait;
use PHPUnitConsecutiveTrait;

/**
* @var string[]
Expand All @@ -44,7 +47,8 @@ public function setUp(): void
'delete',
'noResponsesDefined',
'textPlain',
'options'
'options',
'list'
],
'map' => [
'noResponsesDefined' => [
Expand All @@ -61,14 +65,19 @@ public function setUp(): void
'method' => ['options'],
'action' => 'options',
'path' => 'options'
],
'list' => [
'method' => 'get',
'action' => 'customGet',
'path' => 'custom-get'
]
]
]);
});

$this->config = new Configuration([
'prefix' => '/',
'yml' => '/config/swagger-bare-bones.yml',
'yml' => '/config/swagger-with-generic-collection.yml',
'json' => '/webroot/swagger.json',
'webPath' => '/swagger.json',
'hotReload' => false,
Expand Down Expand Up @@ -172,13 +181,17 @@ public function test_add_operation_with_no_response_defined(): void
$route = $this->routes['employees:add'];

$mockReflectionMethod = $this->createPartialMock(\ReflectionMethod::class, ['getAttributes']);
$mockReflectionMethod->expects($this->once())
->method(
'getAttributes'
$mockReflectionMethod->expects($this->exactly(2))
->method('getAttributes')
->with(
...$this->withConsecutive(
[OpenApiResponse::class],
[OpenApiPaginator::class]
)
)
->with(OpenApiResponse::class)
->will(
$this->returnValue([])
->willReturnOnConsecutiveCalls(
[],
[]
);

$operationResponse = new OperationResponse(
Expand Down Expand Up @@ -232,13 +245,17 @@ public function test_no_response_defined(): void
$route = $this->routes['employees:noresponsedefined'];

$mockReflectionMethod = $this->createPartialMock(\ReflectionMethod::class, ['getAttributes']);
$mockReflectionMethod->expects($this->once())
->method(
'getAttributes'
$mockReflectionMethod->expects($this->exactly(2))
->method('getAttributes')
->with(
...$this->withConsecutive(
[OpenApiResponse::class],
[OpenApiPaginator::class]
)
)
->with(OpenApiResponse::class)
->will(
$this->returnValue([])
->willReturnOnConsecutiveCalls(
[],
[]
);

$operationResponse = new OperationResponse(
Expand Down Expand Up @@ -390,6 +407,39 @@ public function test_http_options(): void
$this->assertNotEmpty($operationResponse->getOperationWithResponses()->getResponseByCode('200'));
}

public function test_custom_get_method_with_collection_response(): void
{
$route = $this->routes['employees:customget'];

$mockReflectionMethod = $this->mockReflectionMethod(OpenApiResponse::class, [
'statusCode' => '200',
'schemaType' => 'array',
'ref' => '#/components/schema/Employee',
]);

$operationResponse = new OperationResponse(
$this->mockSwagger('getSchemaByName', 'Employee'),
$this->config,
new Operation('employees:customget', 'get'),
$route,
null,
$mockReflectionMethod
);

$operation = $operationResponse->getOperationWithResponses();
$response = $operation->getResponseByCode('200');
$this->assertNotEmpty($response);

$content = $response->getContentByMimeType('application/json');
$this->assertNotEmpty($content);
$this->assertNotEmpty($content->getSchema());

/** @var Schema $schema */
$schema = $content->getSchema();
$this->assertEquals('array', $schema->getType());
$this->assertEquals('#/components/schema/Employee', $schema->getItems()['$ref']);
}

/**
* Builds a partial mock of Swagger.
*
Expand Down
2 changes: 0 additions & 2 deletions tests/test_app/src/Controller/EmployeesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use SwaggerBake\Lib\Attribute\OpenApiResponse;
use SwaggerBake\Lib\Attribute\OpenApiSecurity;
use SwaggerBake\Lib\Extension\CakeSearch\Attribute\OpenApiSearch;
use SwaggerBake\Test\TestCase\Lib\Attribute\OpenApiDtoTest;
use SwaggerBakeTest\App\Dto\CustomResponseSchema;
use SwaggerBakeTest\App\Dto\CustomResponseSchemaPublic;
use SwaggerBakeTest\App\Dto\EmployeeDataRequest;
Expand Down Expand Up @@ -138,7 +137,6 @@ public function delete($id): void
#[OpenApiQueryParam(name: 'queryParamName', type: "string", isRequired: false)]
#[OpenApiHeader(name: 'X-HEAD-ATTRIBUTE', type: 'string', isRequired: true)]
#[OpenApiPaginator]
#[OpenApiResponse(schemaType: 'object', description: "hello world")]
public function customGet(): void
{

Expand Down

0 comments on commit d8c2792

Please sign in to comment.