Guide développeur Symfony
Le package Symfony est conçu autour des services. Injecte PdfFactory, appelle create() pour chaque document et utilise les builders Messenger pour la génération asynchrone. La fabrique peut vivre comme service du conteneur, car chaque appel renvoie un document neuf.
Utilise ce guide lorsque tu conçois des contrôleurs, des services, des handlers Messenger ou des points d’extension au niveau du bundle autour de nextpdf/symfony.
Frontière d’architecture
Section intitulée « Frontière d’architecture »| Couche | Propriétaire | Responsabilité | À ne pas mettre ici |
|---|---|---|---|
| Contrôleur | Application | Autorise la requête, collecte les entrées, renvoie un PdfResponse. | Mise en page PDF partagée entre les cas d’usage. |
| Service applicatif | Application | Charge les données du domaine et choisit un builder. | Logique du compilateur de conteneur Symfony. |
| Service builder | Application | Implémente PdfBuilderInterface pour construire des documents de façon synchrone ou via une file d’attente. | Objets de requête, gestionnaires d’entités ou contexte non sérialisable. |
| Bundle Symfony | nextpdf/symfony | Enregistre les services, l’arbre de configuration, la passe d’extension optionnelle, les helpers de réponse et les DTO Messenger. | Politique de stockage propre au tenant. |
| Moteur principal | nextpdf/nextpdf | Compose et sérialise le document. | Comportement de la réponse Symfony ou de Messenger. |
Cycle de vie à l’exécution
Section intitulée « Cycle de vie à l’exécution »| Étape | Comportement | Action du développeur |
|---|---|---|
| Démarrage du bundle | NextPdfBundle::build() enregistre la détection des extensions optionnelles. | Laisse Symfony découvrir le bundle ou enregistre-le dans bundles.php. |
| Chargement de la configuration | NextPdfExtension::load() traite la configuration nextpdf: et charge les définitions de services. | Garde la configuration explicite et adaptée à l’environnement. |
| Utilisation de la fabrique | PdfFactory::create() renvoie un nouveau document configuré. | Ne stocke aucun document dans des services. |
| Sortie du contrôleur | PdfResponse transforme un document terminé en réponse. | Utilise le helper plutôt que d’assembler manuellement les en-têtes. |
| Envoi via Messenger | GeneratePdfMessage transporte la classe du builder, le chemin de sortie et un contexte sérialisable. | Garde le contexte minimal et compatible avec des valeurs scalaires. |
| Traitement du message | GeneratePdfHandler résout le builder depuis un service locator et enregistre le document. | Rends les builders déterministes et idempotents. |
Structure applicative recommandée
Section intitulée « Structure applicative recommandée »| Chemin | Rôle |
|---|---|
src/Pdf/Builder/* | Services qui implémentent PdfBuilderInterface. |
src/Pdf/Data/* | Petits DTO ou tableaux utilisés comme contexte pour les builders. |
src/Pdf/Storage/* | Sélection de la racine de stockage et politique de nom de fichier de sortie. |
src/Controller/* | Points d’entrée de réponse synchrone. |
tests/Pdf/* | Tests des builders, des réponses, de Messenger et de la configuration. |
Préfère les services de builder aux fonctions utilitaires statiques. Ils se taguent, se décorent, se testent et s’utilisent facilement depuis Messenger.
<?php
namespace App\Pdf\Builder;
use NextPDF\Core\Document;use NextPDF\Symfony\Message\PdfBuilderInterface;
final readonly class InvoicePdfBuilder implements PdfBuilderInterface{ public function build(Document $document, array $context): Document { $document->setTitle((string) $context['title']) ->addPage() ->writeHtml((string) $context['html']);
return $document; }}Pattern de réponse synchrone
Section intitulée « Pattern de réponse synchrone »<?php
namespace App\Controller;
use App\Pdf\Builder\InvoicePdfBuilder;use NextPDF\Symfony\Http\PdfResponse;use NextPDF\Symfony\Service\PdfFactory;
final readonly class InvoiceController{ public function __invoke( PdfFactory $factory, InvoicePdfBuilder $builder, ) { $document = $builder->build($factory->create(), [ 'title' => 'Invoice 1234', 'html' => '<h1>Invoice 1234</h1>', ]);
return PdfResponse::download($document, 'invoice-1234.pdf'); }}Garde le contexte du contrôleur au minimum. Si un builder a besoin de nombreux objets du domaine, déplace l’orchestration dans un service applicatif et passe un DTO ou un tableau normalisé au builder.
Pattern Messenger
Section intitulée « Pattern Messenger »GeneratePdfMessage valide la classe du builder et le chemin de sortie avant l’envoi. Le handler valide à nouveau le chemin au moment de l’exécution.
<?php
use App\Pdf\Builder\InvoicePdfBuilder;use NextPDF\Symfony\Message\GeneratePdfMessage;
$bus->dispatch(new GeneratePdfMessage( builderClass: InvoicePdfBuilder::class, outputPath: $projectDir . '/var/pdfs/invoice-1234.pdf', builderContext: [ 'title' => 'Invoice 1234', 'html' => '<h1>Invoice 1234</h1>', ],));Ne place pas d’entités Doctrine, de flux ouverts, de closures, d’objets de requête ou d’objets de service dans builderContext.
Points d’extension
Section intitulée « Points d’extension »| Point d’extension | À utiliser pour | Contrainte |
|---|---|---|
Décoration du service PdfFactory | Appliquer les valeurs par défaut de l’application avant que les documents n’atteignent les contrôleurs. | Doit préserver la sémantique d’un document neuf. |
PdfBuilderInterface | Définir des builders de documents réutilisables ou destinés à la file d’attente. | Doit renvoyer un Document. |
OptionalExtensionPass | Activer des fonctionnalités Artisan ou Premium optionnelles au moment de la compilation. | La disponibilité est un état de compilation du conteneur, pas un état de requête. |
| Arbre de configuration Symfony | Valeurs par défaut, PDF/A, paramètres du renderer, signature, TSA, Messenger. | Une configuration invalide doit échouer pendant la construction du conteneur. |
Câblage du service GeneratePdfHandler | Restreindre les builders accessibles depuis les messages en file d’attente. | Le service locator ne doit exposer que les services de builder approuvés. |
Workflow de développement
Section intitulée « Workflow de développement »- Ajoute un service builder avec une entrée déterministe.
- Utilise
PdfFactory::create()dans un contrôleur ou un service. - Ajoute un test de réponse pour le nom de fichier, le type de contenu et les en-têtes.
- Enregistre le builder pour Messenger lorsque le même document doit être généré de façon asynchrone.
- Ajoute des tests de message invalide pour le nom de classe, le chemin de sortie et la forme du contexte.
- Ajoute un test de compilation du conteneur avec une configuration minimale et une configuration de production.
- Mesure le temps de rendu et la mémoire avec les mêmes réglages PHP qu’en production.
Gestion des échecs
Section intitulée « Gestion des échecs »| Échec | Où il doit être géré | Réponse recommandée |
|---|---|---|
| Configuration invalide | Compilation du conteneur. | Fais échouer le déploiement avant que le trafic n’atteigne l’application. |
| Service builder manquant | Tests du handler Messenger et tags de service. | Fais échouer le message et alerte l’équipe propriétaire. |
| Chemin de sortie non sûr | Constructeur du message et politique de stockage. | Rejette-le avant l’envoi ; garde la validation du handler comme défense en profondeur. |
| Extension optionnelle indisponible | Compiler pass et comportement de la fabrique. | Désactive la fonctionnalité optionnelle ou rends l’installation explicite. |
| Échec de conversion du service ou de rendu | Frontière du builder. | Échoue en mode fermé, sauf si le cas d’usage dispose d’un repli documenté. |
Valeurs par défaut sûres
Section intitulée « Valeurs par défaut sûres »| Préoccupation | Valeur par défaut | Quand la remplacer |
|---|---|---|
| Durée de vie de la fabrique | Service du conteneur. | Garde-la ; la fabrique est sûre parce qu’elle crée des documents. |
| Durée de vie du document | Une unité de travail. | Ne le partage jamais entre des requêtes ou des messages. |
| Validation du chemin de sortie | Constructeur du message et handler. | Ajoute des contraintes de tenant ou de racine de stockage dans le code applicatif. |
| Nom de fichier de la réponse | document.pdf. | Remplace-la par des identifiants métier nettoyés. |
| Transport Messenger | async. | Utilise un transport dédié quand le travail PDF est lourd. |
Liste de contrôle des tests
Section intitulée « Liste de contrôle des tests »- Les tests du conteneur compilent le bundle avec une configuration minimale et une configuration de production.
- Les tests de réponse vérifient les en-têtes de sécurité et la gestion du nom de fichier.
- Les tests Messenger vérifient que les chemins invalides et les noms de classe de builder invalides échouent avant l’envoi.
- Les tests du handler utilisent un vrai service de builder et un répertoire de sortie temporaire.
- Les tests des builders rendent un document représentatif et l’enregistrent sous des permissions de système de fichiers proches de la production.
- Les tests d’extension optionnelle couvrent les cas où Artisan est indisponible, où Premium est indisponible et le comportement du profil PDF/A configuré.