From 04697a1704c04557db9c1e9d6a88959f4f477873 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Fri, 18 Jul 2025 12:02:01 +0200 Subject: [PATCH] feat: Ajoute la documentation API avec NelmioApiDocBundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ce commit ajoute la prise en charge de la documentation API en utilisant NelmioApiDocBundle. Les modifications suivantes ont été apportées : - Installation de NelmioApiDocBundle via Composer. - Ajout des configurations nécessaires pour NelmioApiDocBundle. - Création d'un contrôleur API public de base avec des annotations OpenAPI. - Mise à jour de la configuration des routes pour inclure la documentation Swagger UI. - Ajout de styles SCSS personnalisés pour améliorer l'apparence de Swagger UI. - Mise à jour du fichier sitemap pour inclure les routes de documentation API. - Configuration de symfony.lock pour la version de nelmio. --- assets/api.js | 1 + assets/api.scss | 16 + composer.json | 1 + composer.lock | 327 ++++++++++++++---- config/bundles.php | 1 + config/packages/nelmio_api_doc.yaml | 26 ++ config/routes.yaml | 6 +- config/routes/nelmio_api_doc.yaml | 12 + src/Controller/Api/Public/RootController.php | 72 ++++ src/EventListener/SitemapSubscriber.php | 8 +- symfony.lock | 13 + .../SwaggerUi/index.html.twig | 12 + 12 files changed, 433 insertions(+), 62 deletions(-) create mode 100644 assets/api.js create mode 100644 assets/api.scss create mode 100644 config/packages/nelmio_api_doc.yaml create mode 100644 config/routes/nelmio_api_doc.yaml create mode 100644 src/Controller/Api/Public/RootController.php create mode 100644 templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig diff --git a/assets/api.js b/assets/api.js new file mode 100644 index 0000000..b348bb6 --- /dev/null +++ b/assets/api.js @@ -0,0 +1 @@ +import './api.scss' diff --git a/assets/api.scss b/assets/api.scss new file mode 100644 index 0000000..a996621 --- /dev/null +++ b/assets/api.scss @@ -0,0 +1,16 @@ +header { + &:before { + background: purple; + } +} + +.title{ + color: purple !important; +} + +.opblock-summary-method{ + background: purple !important; +} +.opblock-section-header{ + background: #f8adf8 !important; +} diff --git a/composer.json b/composer.json index 3388879..64c2a19 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "liip/imagine-bundle": "^2.13", "minishlink/web-push": "^9.0", "mittwald/vault-php": "^3.0", + "nelmio/api-doc-bundle": "^5.4", "nelmio/cors-bundle": "^2.5", "phpdocumentor/reflection-docblock": "^5.6.2", "phpstan/phpdoc-parser": "^2.2", diff --git a/composer.lock b/composer.lock index ecf056e..383cdb0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7271bea1fd76a2d50dba48bc7d223135", + "content-hash": "a38b1e9f2490861aa3e6aee97fa1ff63", "packages": [ { "name": "aws/aws-crt-php", @@ -2905,6 +2905,129 @@ }, "time": "2024-09-04T18:46:31+00:00" }, + { + "name": "nelmio/api-doc-bundle", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nelmio/NelmioApiDocBundle.git", + "reference": "49098f9e3f5e7a466b95b1d108d45857ba533c96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/49098f9e3f5e7a466b95b1d108d45857ba533c96", + "reference": "49098f9e3f5e7a466b95b1d108d45857ba533c96", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "phpdocumentor/reflection-docblock": "^5.0", + "phpdocumentor/type-resolver": "^1.8.2", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "psr/container": "^1.0 || ^2.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/config": "^6.4 || ^7.1", + "symfony/console": "^6.4 || ^7.1", + "symfony/dependency-injection": "^6.4 || ^7.1", + "symfony/deprecation-contracts": "^2.1 || ^3", + "symfony/framework-bundle": "^6.4 || ^7.1", + "symfony/http-foundation": "^6.4 || ^7.1", + "symfony/http-kernel": "^6.4 || ^7.1", + "symfony/options-resolver": "^6.4 || ^7.1", + "symfony/property-info": "^6.4 || ^7.1", + "symfony/routing": "^6.4 || ^7.1", + "zircote/swagger-php": "^4.11.1 || ^5.0" + }, + "conflict": { + "zircote/swagger-php": "4.8.7" + }, + "require-dev": { + "api-platform/core": "^3.2", + "friendsofphp/php-cs-fixer": "^3.52", + "friendsofsymfony/rest-bundle": "^3.2.0", + "jms/serializer": "^3.32", + "jms/serializer-bundle": "^5.5", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-phpunit": "^1.3", + "phpstan/phpstan-strict-rules": "^1.5", + "phpstan/phpstan-symfony": "^1.3", + "phpunit/phpunit": "^10.5", + "symfony/asset": "^6.4 || ^7.1", + "symfony/browser-kit": "^6.4 || ^7.1", + "symfony/cache": "^6.4 || ^7.1", + "symfony/dom-crawler": "^6.4 || ^7.1", + "symfony/expression-language": "^6.4 || ^7.1", + "symfony/finder": "^6.4 || ^7.1", + "symfony/form": "^6.4 || ^7.1", + "symfony/phpunit-bridge": "^6.4 || ^7.1", + "symfony/property-access": "^6.4 || ^7.1", + "symfony/security-csrf": "^6.4 || ^7.1", + "symfony/security-http": "^6.4 || ^7.1", + "symfony/serializer": "^6.4 || ^7.1", + "symfony/stopwatch": "^6.4 || ^7.1", + "symfony/templating": "^6.4 || ^7.1", + "symfony/translation": "^6.4 || ^7.1", + "symfony/twig-bundle": "^6.4 || ^7.1", + "symfony/uid": "^6.4 || ^7.1", + "symfony/validator": "^6.4 || ^7.1", + "willdurand/hateoas-bundle": "^2.7", + "willdurand/negotiation": "^3.0" + }, + "suggest": { + "api-platform/core": "For using an API oriented framework.", + "friendsofsymfony/rest-bundle": "For using the parameters annotations.", + "jms/serializer-bundle": "For describing your models.", + "symfony/asset": "For using the Swagger UI.", + "symfony/cache": "For using a PSR-6 compatible cache implementation with the API doc generator.", + "symfony/form": "For describing your form type models.", + "symfony/monolog-bundle": "For using a PSR-3 compatible logger implementation with the API PHP describer.", + "symfony/security-csrf": "For using csrf protection tokens in forms.", + "symfony/serializer": "For describing your models.", + "symfony/twig-bundle": "For using the Swagger UI.", + "symfony/validator": "For describing the validation constraints in your models.", + "willdurand/hateoas-bundle": "For extracting HATEOAS metadata." + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-4.x": "4.x-dev", + "dev-5.x": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Nelmio\\ApiDocBundle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://github.com/nelmio/NelmioApiDocBundle/contributors" + } + ], + "description": "Generates documentation for your REST API from attributes", + "keywords": [ + "api", + "doc", + "documentation", + "rest" + ], + "support": { + "issues": "https://github.com/nelmio/NelmioApiDocBundle/issues", + "source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://github.com/DjordyKoert", + "type": "github" + } + ], + "time": "2025-06-26T15:03:21+00:00" + }, { "name": "nelmio/cors-bundle", "version": "2.5.0", @@ -2967,6 +3090,64 @@ }, "time": "2024-06-24T21:25:28+00:00" }, + { + "name": "nikic/php-parser", + "version": "v5.5.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + }, + "time": "2025-05-31T08:24:38+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -10324,6 +10505,92 @@ "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, "time": "2022-06-03T18:03:27+00:00" + }, + { + "name": "zircote/swagger-php", + "version": "5.1.4", + "source": { + "type": "git", + "url": "https://github.com/zircote/swagger-php.git", + "reference": "471f2e7c24c9508a2ee08df245cab64b62dbf721" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/471f2e7c24c9508a2ee08df245cab64b62dbf721", + "reference": "471f2e7c24c9508a2ee08df245cab64b62dbf721", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/php-parser": "^4.19 || ^5.0", + "php": ">=7.4", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/deprecation-contracts": "^2 || ^3", + "symfony/finder": "^5.0 || ^6.0 || ^7.0", + "symfony/yaml": "^5.0 || ^6.0 || ^7.0" + }, + "conflict": { + "symfony/process": ">=6, <6.4.14" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11", + "doctrine/annotations": "^2.0", + "friendsofphp/php-cs-fixer": "^3.62.0", + "phpstan/phpstan": "^1.6 || ^2.0", + "phpunit/phpunit": "^9.0", + "rector/rector": "^1.0 || ^2.0", + "vimeo/psalm": "^4.30 || ^5.0" + }, + "suggest": { + "doctrine/annotations": "^2.0" + }, + "bin": [ + "bin/openapi" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "OpenApi\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Robert Allen", + "email": "zircote@gmail.com" + }, + { + "name": "Bob Fanger", + "email": "bfanger@gmail.com", + "homepage": "https://bfanger.nl" + }, + { + "name": "Martin Rademacher", + "email": "mano@radebatz.net", + "homepage": "https://radebatz.net" + } + ], + "description": "Generate interactive documentation for your RESTful API using PHP attributes (preferred) or PHPDoc annotations", + "homepage": "https://github.com/zircote/swagger-php", + "keywords": [ + "api", + "json", + "rest", + "service discovery" + ], + "support": { + "issues": "https://github.com/zircote/swagger-php/issues", + "source": "https://github.com/zircote/swagger-php/tree/5.1.4" + }, + "time": "2025-07-15T23:54:13+00:00" } ], "packages-dev": [ @@ -10517,64 +10784,6 @@ ], "time": "2025-07-05T12:25:42+00:00" }, - { - "name": "nikic/php-parser", - "version": "v5.5.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" - }, - "time": "2025-05-31T08:24:38+00:00" - }, { "name": "phar-io/manifest", "version": "2.0.4", diff --git a/config/bundles.php b/config/bundles.php index 8781dbc..601f426 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -18,4 +18,5 @@ return [ Presta\SitemapBundle\PrestaSitemapBundle::class => ['all' => true], Sentry\SentryBundle\SentryBundle::class => ['prod' => true], Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true], + Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true], ]; diff --git a/config/packages/nelmio_api_doc.yaml b/config/packages/nelmio_api_doc.yaml new file mode 100644 index 0000000..a773b39 --- /dev/null +++ b/config/packages/nelmio_api_doc.yaml @@ -0,0 +1,26 @@ +nelmio_api_doc: + documentation: + servers: + - url: https://api.esy-web.dev/ + description: Main Api Server + - url: https://esyweb.local/ + description: Local server + info: + title: Esy-Web Api + description: Doc for Esy-Web Api + version: 1.0.0 + components: + securitySchemes: + EsyKeyAuth: + type: apiKey + in: header + name: Esy-Key + description: > + API key required to access the API. + Please contact contact.s.com@siteconseil.fr to request access. + Must be a client. + security: + - EsyKeyAuth: [] + areas: + path_patterns: + - ^/api/public diff --git a/config/routes.yaml b/config/routes.yaml index 5fac09d..70ba39e 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -6,6 +6,10 @@ controllers: type: attribute - +app.swagger_ui: + path: /api/doc + methods: GET + defaults: { _controller: nelmio_api_doc.controller.swagger_ui } + presta_sitemap: resource: "@PrestaSitemapBundle/config/routing.yml" diff --git a/config/routes/nelmio_api_doc.yaml b/config/routes/nelmio_api_doc.yaml new file mode 100644 index 0000000..364b4af --- /dev/null +++ b/config/routes/nelmio_api_doc.yaml @@ -0,0 +1,12 @@ +# Expose your documentation as JSON swagger compliant +app.swagger: + path: /api/doc.json + methods: GET + defaults: { _controller: nelmio_api_doc.controller.swagger } + +## Requires the Asset component and the Twig bundle +## $ composer require twig asset +#app.swagger_ui: +# path: /api/doc +# methods: GET +# defaults: { _controller: nelmio_api_doc.controller.swagger_ui } diff --git a/src/Controller/Api/Public/RootController.php b/src/Controller/Api/Public/RootController.php new file mode 100644 index 0000000..a97a75b --- /dev/null +++ b/src/Controller/Api/Public/RootController.php @@ -0,0 +1,72 @@ + 'Welcome to the public API endpoint!', + 'status' => 'success', + ]; + + return $this->json($data); + } + #[Route('/api/public/quote', name: 'api_public_quote', methods: ['GET'])] + #[OA\Get( + path: '/api/public/quote', + description: 'Form quote access api', + summary: 'Form quote access api', + parameters: [ + new OA\Parameter( + name: 'Accept', + description: 'Accepted response content type', + in: 'header', + required: true, + schema: new OA\Schema(type: 'string', enum: ['text/html']) + ) + ], + responses: [ + new OA\Response( + response: 200, + description: 'Form for api quote', + content: new OA\MediaType( + mediaType: 'text/html', + ) + ) + ] + )] + #[Security(name: '')] + public function quote(): Response + { + return new JsonResponse([]); + } +} diff --git a/src/EventListener/SitemapSubscriber.php b/src/EventListener/SitemapSubscriber.php index 6bd86ad..4e3a431 100644 --- a/src/EventListener/SitemapSubscriber.php +++ b/src/EventListener/SitemapSubscriber.php @@ -20,7 +20,11 @@ class SitemapSubscriber implements EventSubscriberInterface { $urlContainer = $sitemapPopulateEvent->getUrlContainer(); $urlGenerator = $sitemapPopulateEvent->getUrlGenerator(); - $pathMenuItem = new UrlConcrete($urlGenerator->generate('app_login', [], UrlGeneratorInterface::ABSOLUTE_URL)); - $urlContainer->addUrl($pathMenuItem, 'main'); + + + $pathMenuItemApiDoc = new UrlConcrete($urlGenerator->generate('app.swagger_ui', [], UrlGeneratorInterface::ABSOLUTE_URL)); + $urlContainer->addUrl($pathMenuItemApiDoc,'api'); + $pathMenuItemApiDocQuote = new UrlConcrete($urlGenerator->generate('api_public_quote', [], UrlGeneratorInterface::ABSOLUTE_URL)); + $urlContainer->addUrl($pathMenuItemApiDocQuote,'api'); } } diff --git a/symfony.lock b/symfony.lock index 62c02e5..e82afdc 100644 --- a/symfony.lock +++ b/symfony.lock @@ -64,6 +64,19 @@ "config/routes/liip_imagine.yaml" ] }, + "nelmio/api-doc-bundle": { + "version": "5.4", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "3.0", + "ref": "c8e0c38e1a280ab9e37587a8fa32b251d5bc1c94" + }, + "files": [ + "config/packages/nelmio_api_doc.yaml", + "config/routes/nelmio_api_doc.yaml" + ] + }, "nelmio/cors-bundle": { "version": "2.5", "recipe": { diff --git a/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig b/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig new file mode 100644 index 0000000..1fde332 --- /dev/null +++ b/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig @@ -0,0 +1,12 @@ +{% extends '@!NelmioApiDoc/SwaggerUi/index.html.twig' %} + +{% block javascripts %} + {{ parent() }} + {{ vite_asset('api.js',[]) }} +{% endblock %} +{# Import your own script #} +{% block header %} + +{% endblock %}