stfalcon-studio/swagger-bundle
A Symfony bundle that integrates swagger-php to generate OpenAPI/Swagger documentation from PHP annotations, helping keep API specs in sync with your code and exposing interactive docs for your endpoints.
What this package is: stfalcon-studio/SwaggerBundle is a thin Symfony bundle wrapping zircote/swagger-php. It registers the OpenAPI scanner as a service, exposes config for scan paths/excludes, and serves the generated document (JSON/YAML) from a route.
Reality check before you install: this is a Symfony bundle. It requires symfony/framework-bundle, which Laravel does not use (Laravel ships individual Symfony components, not the FrameworkBundle, and has no bundle/kernel registration). You cannot composer require this into a Laravel app. If you're in Laravel, use zircote/swagger-php directly behind an Artisan command + route — the workflow below transfers almost 1:1. If you're assessing it for a Symfony service in your estate, continue.
Minimal steps (Symfony host app):
composer require stfalcon-studio/swagger-bundle:^2.0 — v2 requires Symfony 8 components and therefore PHP 8.4+.config/bundles.php.config/packages/swagger.yaml with your scan directories (read the bundle's DependencyInjection/Configuration.php first — it is the authoritative config surface, not the README).#[OA\Info] plus a single #[OA\Get].First use case: don't document the whole API. Get one controller + a global #[OA\Info] block producing a valid document, wire that JSON into Swagger UI / Redoc / Scalar, then expand. A valid tiny document beats a broken comprehensive one.
Where to look first, in order: Configuration.php → the bundle's routing file → the scanner service definition → README. The README on this project historically lags the config, so trust the code.
Attribute-first, one source of truth. swagger-php 4/5 uses PHP 8 attributes (#[OA\Get], #[OA\Schema], #[OA\Property]). Keep operation attributes on controller actions and schema attributes on DTOs; never duplicate a schema inline in a controller.
Centralise document metadata. Put #[OA\Info], #[OA\Servers], and #[OA\SecurityScheme] on a single empty "bootstrap" class rather than scattering them. It makes environment-specific servers values easy to swap per env.
Reuse schemas by reference. Annotate DTOs/entities with #[OA\Schema] and reference them with ref: '#/components/schemas/Foo'. This is the difference between a maintainable spec and 400 lines of duplicated JSON.
Be explicit about scan paths. Scan src/Controller and your DTO namespace; exclude Entity, Migrations, Tests, vendor. Blanket-scanning src/ is the #1 cause of slow and noisy generation.
Generate at build time, not request time. For anything beyond dev, dump the document in CI or on deploy and serve the artifact statically:
php bin/console <bundle-dump-command> --format=json > public/openapi.json
# Laravel equivalent: php artisan openapi:generate > storage/app/openapi.json
Validate in CI. Run the dump command, then spectral lint or openapi-generator validate against the output. A broken attribute throws during the scan — make that fail the build, not the staging docs page.
Contract-test against it. league/openapi-psr7-validator or php-openapi in a feature test lets you assert real responses match the documented schema. This is where the doc earns its keep.
Feed a UI, don't build one. Point Swagger UI / Redoc / Scalar at the generated JSON. Only reach for nelmio/api-doc-bundle if you want the UI bundled and versioned with the spec.
v2.0.0 is a compatibility-only major. The entire release is one PR: "Switch to Symfony 8.0." No new features, no documented behavioural changes. Treat it as a constraint bump — the risk is in Composer resolution, not in runtime behaviour.
Symfony 8 means PHP 8.4+. Check your Docker base image, CI matrix, and static-analysis config before you bump. A failed platform requirement surfaces as an opaque Composer error.
It's a hard cut, not a deprecation. There is no deprecation layer bridging 1.x and 2.x — Composer will simply refuse to install. To find what's blocking you:
composer why-not stfalcon-studio/swagger-bundle 2.0.0
That usually names another bundle still pinned to symfony/framework-bundle: ^6|^7. You cannot partially upgrade Symfony, so v2.0.0 is gated on the whole app moving to Symfony 8.
Stay on 1.1.1 if you're on Symfony 6.4 or 7.x. Pin ^1.1 explicitly and assume security/compat fixes are not backported to a branch the maintainer has moved past — this project's release cadence is low.
Check the swagger-php constraint, not just Symfony's. The release notes don't mention the transitive zircote/swagger-php range. Diff composer.json between 1.1.1 and 2.0.0 before upgrading. If the bump pulls swagger-php 5, your docblock annotations (@OA\...) stop working entirely — they're removed in favour of attributes. That migration is far larger than the Symfony bump and should be planned separately.
The docs route is unauthenticated by default. Gate it behind a firewall, or disable the route in prod via a when@prod config block. An internal API spec is a useful map for an attacker.
A malformed attribute breaks the docs endpoint, not the app. Errors surface during the scan, so the application boots fine and only the docs page 500s. Always run generation as a CI step so failures are loud.
Generated JSON is not order-stable. Sort paths and components.schemas before committing snapshots, or every PR diff becomes noise and reviewers stop reading it.
Extension points, in order of preference: swagger-php Processor/Analyser classes to post-process the document → overriding the bundle's route/controller → config → forking. Processors are the intended hook for things like stripping internal endpoints or injecting version numbers.
Don't wait for Laravel support. The v2.0.0 direction — tightening to a single Symfony major — makes a framework-agnostic release less likely, not more. In Laravel, budget for zircote/swagger-php plus ~50 lines of Artisan command and a route; that has no framework upgrade cliff attached.
How can I help you explore Laravel packages today?