Skip to content

Commit c44bf5b

Browse files
committed
fix: Fix Api Docs generic type detection + add test
1 parent 23ad6c0 commit c44bf5b

22 files changed

+121
-67
lines changed

.env.dist .env

File renamed without changes.

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
.idea
2-
.env
2+
.env.local

.gitlab-ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ stages:
1313
- cleanup
1414

1515
variables:
16-
DOCKER_IMAGE: docker:26.1
17-
DOCKER_DIND_IMAGE: docker:26.1-dind-rootless
16+
DOCKER_IMAGE: docker:27.1
17+
DOCKER_DIND_IMAGE: docker:27.1-dind-rootless
1818
PHP_VERSION: '8.3'
1919
PHP_DOCKER_RELEASE: 'bookworm'
2020

bin/publish-package.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ checkout_subtree () {
2323
}
2424

2525
cleanup () {
26-
# Delete the tag locally to avoid conflicts
27-
git tag -d ${PACKAGE_VERSION}
2826
git checkout origin/${CI_COMMIT_REF_NAME}
2927
git branch -D ${TEMP_BRANCH}
3028
}
@@ -36,6 +34,9 @@ publish_tag () {
3634
git tag -a ${PACKAGE_VERSION} -m "Version ${PACKAGE_VERSION}"
3735
git push -f ${PACKAGE} refs/tags/${PACKAGE_VERSION}:refs/tags/${PACKAGE_VERSION}
3836

37+
# Delete the tag locally to avoid conflicts
38+
git tag -d ${PACKAGE_VERSION}
39+
3940
cleanup
4041
}
4142

docker/php-cli/run.sh

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#!/bin/bash -e
22

3-
cp -n .env.dist .env
43
source .env
54

5+
if [ -f .env.local ]; then
6+
source .env.local
7+
fi
8+
69
DIRECTORY="${1:-packages}"
710

811
docker build --build-arg PHP_VERSION=${PHP_VERSION} \

packages/api-documentation-bundle/composer.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "fusonic/api-documentation-bundle",
33
"license": "MIT",
4-
"version": "0.1.0",
4+
"version": "0.1.1",
55
"description": "Symfony bundle for automated documentation with NelmioApiDocBundle.",
66
"type": "symfony-bundle",
77
"authors": [
@@ -32,14 +32,15 @@
3232
"phpstan/phpstan-strict-rules": "^1.6",
3333
"phpstan/phpstan-symfony": "^1.4",
3434
"phpunit/phpunit": "^11.2",
35+
"symfony/serializer": "^5.4 || ^6.0 || ^7.0",
3536
"symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0",
3637
"symfony/test-pack": "^1.0",
3738
"symfony/yaml": "^5.4 || ^6.0 || ^7.0",
3839
"tomasvotruba/type-coverage": "^0.3"
3940
},
4041
"require": {
4142
"php": ">=8.2",
42-
"nelmio/api-doc-bundle": "^4.11",
43+
"nelmio/api-doc-bundle": "^4.29",
4344
"symfony/config": "^5.4 || ^6.0 || ^7.0",
4445
"symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0",
4546
"symfony/dom-crawler": "^5.4 || ^6.0 || ^7.0",

packages/api-documentation-bundle/src/AnnotationBuilder/AnnotationBuilder.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ final class AnnotationBuilder
3232
public function __construct(
3333
private readonly DocumentedRoute $route,
3434
private readonly \ReflectionMethod $method,
35-
private readonly ?\ReflectionClass $requestObjectReflectionClass
35+
private readonly ?\ReflectionClass $requestObjectReflectionClass,
3636
) {
3737
$this->propertyExtractor = new PropertyExtractor();
3838

packages/api-documentation-bundle/src/AnnotationBuilder/PropertyExtractor.php

-4
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ public function extractMethodReturnType(\ReflectionMethod $method): ?Type
5656

5757
public function extractCollectionReturnType(Type $returnType): ?Type
5858
{
59-
if (!$returnType->isCollection()) {
60-
return null;
61-
}
62-
6359
$collectionTypes = $returnType->getCollectionValueTypes();
6460

6561
if (\count($collectionTypes) > 0) {

packages/api-documentation-bundle/src/Attribute/DocumentedRoute.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function __construct(
4141
private readonly ?string $output = null,
4242
private readonly ?bool $outputIsCollection = null,
4343
private readonly ?int $statusCode = null,
44-
private readonly ?string $description = null
44+
private readonly ?string $description = null,
4545
) {
4646
parent::__construct(
4747
path: $path,

packages/api-documentation-bundle/tests/App/Controller/TestController.php

+10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Fusonic\ApiDocumentationBundle\Attribute\DocumentedRoute;
1313
use Fusonic\ApiDocumentationBundle\Tests\App\FromRequest;
1414
use Fusonic\ApiDocumentationBundle\Tests\App\Request\TestRequest;
15+
use Fusonic\ApiDocumentationBundle\Tests\App\Response\TestGenericResponse;
1516
use Fusonic\ApiDocumentationBundle\Tests\App\Response\TestResponse;
1617
use OpenApi\Attributes as OA;
1718
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -71,6 +72,15 @@ public function testAnnotationCustomReturnTypeArray(#[FromRequest] TestRequest $
7172
return [new TestResponse($query->id)];
7273
}
7374

75+
/**
76+
* @return TestGenericResponse<TestResponse>
77+
*/
78+
#[DocumentedRoute(path: '/test-generic-return-type/{id}', methods: ['GET'])]
79+
public function testGenericReturnType(#[FromRequest] TestRequest $query): TestGenericResponse
80+
{
81+
return new TestGenericResponse([new TestResponse($query->id)]);
82+
}
83+
7484
#[DocumentedRoute(path: '/test-combined-attributes/{id}', methods: ['POST'], description: 'Object found')]
7585
#[OA\Response(response: 404, description: 'Object was not found.')]
7686
public function testCombinedAttributes(#[FromRequest] TestRequest $query): TestResponse
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* Copyright (c) Fusonic GmbH. All rights reserved.
5+
* Licensed under the MIT License. See LICENSE file in the project root for license information.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Fusonic\ApiDocumentationBundle\Tests\App\Response;
11+
12+
use Symfony\Component\Serializer\Attribute\Ignore;
13+
14+
/**
15+
* @template T
16+
*/
17+
class TestGenericResponse
18+
{
19+
/**
20+
* @var array<T>
21+
*/
22+
#[Ignore]
23+
private array $data;
24+
25+
/**
26+
* @param array<T> $data
27+
*/
28+
public function __construct(array $data)
29+
{
30+
$this->data = $data;
31+
}
32+
33+
/**
34+
* @return array<T>
35+
*/
36+
public function getData(): array
37+
{
38+
return $this->data;
39+
}
40+
}

packages/api-documentation-bundle/tests/NelmioApiDocsTest.php

+46-43
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
1313
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
1414
use Symfony\Component\HttpFoundation\Response;
15-
use Symfony\Component\HttpKernel\Kernel;
1615

1716
final class NelmioApiDocsTest extends WebTestCase
1817
{
@@ -50,6 +49,7 @@ public function testGetJsonDocs(): void
5049
$this->verifyReturnTypeRoute('/test-return-type/{id}', $content);
5150
$this->verifyBuiltinReturnTypeRoute('/test-builtin-return-type/{id}', $content);
5251
$this->verifyAnnotationBuiltinArrayReturnTypeRoute('/annotation-builtin-type-array/{id}', $content);
52+
$this->verifyAnnotationGenericReturnTypeRoute('/test-generic-return-type/{id}', $content);
5353
$this->verifyAnnotationCustomArrayReturnTypeRoute('/test-annotation-custom-return-type/{id}', $content);
5454
$this->verifyPostRouteWithTag('/test-post-route-with-tag/{id}', $content);
5555
$this->verifyCombinedAttributesRoute('/test-combined-attributes/{id}', $content);
@@ -58,56 +58,32 @@ public function testGetJsonDocs(): void
5858
$this->verifyVoidReturnType('/test-void-return-type', $content);
5959

6060
self::assertArrayHasKey('components', $content);
61-
62-
if (Kernel::VERSION_ID < 70000) {
63-
self::assertSame([
64-
'schemas' => [
65-
'TestRequest' => [
66-
'properties' => [
67-
'id' => [
68-
'type' => 'integer',
69-
],
70-
],
71-
'type' => 'object',
61+
self::assertSame([
62+
'schemas' => [
63+
'TestRequest' => [
64+
'required' => [
65+
'id',
7266
],
73-
'TestResponse' => [
74-
'properties' => [
75-
'id' => [
76-
'type' => 'integer',
77-
],
67+
'properties' => [
68+
'id' => [
69+
'type' => 'integer',
7870
],
79-
'type' => 'object',
8071
],
72+
'type' => 'object',
8173
],
82-
], $content['components']);
83-
} else {
84-
self::assertSame([
85-
'schemas' => [
86-
'TestRequest' => [
87-
'required' => [
88-
'id',
89-
],
90-
'properties' => [
91-
'id' => [
92-
'type' => 'integer',
93-
],
94-
],
95-
'type' => 'object',
74+
'TestResponse' => [
75+
'required' => [
76+
'id',
9677
],
97-
'TestResponse' => [
98-
'required' => [
99-
'id',
100-
],
101-
'properties' => [
102-
'id' => [
103-
'type' => 'integer',
104-
],
78+
'properties' => [
79+
'id' => [
80+
'type' => 'integer',
10581
],
106-
'type' => 'object',
10782
],
83+
'type' => 'object',
10884
],
109-
], $content['components']);
110-
}
85+
],
86+
], $content['components']);
11187
}
11288

11389
/**
@@ -260,6 +236,33 @@ private function verifyBuiltinReturnTypeRoute(string $path, array $content): voi
260236
], $content['paths'][$path]['get']['responses']);
261237
}
262238

239+
/**
240+
* @param array<string, mixed> $content
241+
*/
242+
private function verifyAnnotationGenericReturnTypeRoute(string $path, array $content): void
243+
{
244+
$this->verifyTestRequestObjectQuery($path, $content);
245+
246+
self::assertArrayHasKey('responses', $content['paths'][$path]['get']);
247+
self::assertCount(1, $content['paths'][$path]['get']['responses']);
248+
249+
self::assertSame([
250+
200 => [
251+
'description' => 'get TestResponse collection',
252+
'content' => [
253+
'application/json' => [
254+
'schema' => [
255+
'type' => 'array',
256+
'items' => [
257+
'$ref' => '#/components/schemas/TestResponse',
258+
],
259+
],
260+
],
261+
],
262+
],
263+
], $content['paths'][$path]['get']['responses']);
264+
}
265+
263266
/**
264267
* @param array<string, mixed> $content
265268
*/

packages/csv-reader/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "fusonic/csv-reader",
33
"license": "MIT",
4-
"version": "0.5.0",
4+
"version": "0.5.1",
55
"description": "Map data from CSV files to typed PHP models.",
66
"type": "library",
77
"authors": [

packages/csv-reader/src/Mapping/MappingInfo.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ abstract class MappingInfo
1616
{
1717
protected function __construct(
1818
private string $targetType,
19-
private int $sourceIndex
19+
private int $sourceIndex,
2020
) {
2121
}
2222

packages/csv-reader/src/Mapping/MethodMappingInfo.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class MethodMappingInfo extends MappingInfo
1717
public function __construct(
1818
string $targetType,
1919
private string $methodName,
20-
int $sourceIndex
20+
int $sourceIndex,
2121
) {
2222
parent::__construct($targetType, $sourceIndex);
2323
}

packages/csv-reader/src/Mapping/PropertyMappingInfo.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class PropertyMappingInfo extends MappingInfo
1717
public function __construct(
1818
string $targetType,
1919
private string $propertyName,
20-
int $sourceIndex
20+
int $sourceIndex,
2121
) {
2222
parent::__construct($targetType, $sourceIndex);
2323
}

packages/http-kernel-bundle/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "fusonic/http-kernel-bundle",
33
"description": "Symfony bundle with extensions for Symfony's HttpKernel",
4-
"version": "1.4.0",
4+
"version": "1.4.1",
55
"type": "library",
66
"license": "MIT",
77
"authors": [

packages/http-kernel-bundle/src/Exception/InvalidEnumException.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class InvalidEnumException extends \InvalidArgumentException
1717
public function __construct(
1818
public readonly string $enumClass,
1919
public readonly mixed $data,
20-
public readonly ?string $propertyPath
20+
public readonly ?string $propertyPath,
2121
) {
2222
parent::__construct(\sprintf('Invalid enum value for %s: %s', $enumClass, $data));
2323
}

packages/http-kernel-bundle/src/Normalizer/ConstraintViolationExceptionNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
final readonly class ConstraintViolationExceptionNormalizer implements NormalizerInterface
2424
{
2525
public function __construct(
26-
private NormalizerInterface $normalizer
26+
private NormalizerInterface $normalizer,
2727
) {
2828
}
2929

packages/http-kernel-bundle/src/Normalizer/DecoratedBackedEnumNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
final class DecoratedBackedEnumNormalizer implements NormalizerInterface, DenormalizerInterface
2323
{
2424
public function __construct(
25-
private readonly BackedEnumNormalizer $inner
25+
private readonly BackedEnumNormalizer $inner,
2626
) {
2727
}
2828

packages/http-kernel-bundle/src/Request/BodyParser/JsonRequestBodyParser.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public function __construct(
1818
/**
1919
* @var int<1, 512>
2020
*/
21-
private readonly int $maxJsonDepth = 512
21+
private readonly int $maxJsonDepth = 512,
2222
) {
2323
}
2424

packages/messenger-mailer-bundle/src/Middleware/AttachmentEmailMiddleware.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
class AttachmentEmailMiddleware implements MiddlewareInterface
2525
{
2626
public function __construct(
27-
private readonly EmailAttachmentHandlerInterface $handler
27+
private readonly EmailAttachmentHandlerInterface $handler,
2828
) {
2929
}
3030

0 commit comments

Comments
 (0)