Aller au contenu

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.

CouchePropriétaireResponsabilitéÀ ne pas mettre ici
ContrôleurApplicationAutorise la requête, collecte les entrées, renvoie un PdfResponse.Mise en page PDF partagée entre les cas d’usage.
Service applicatifApplicationCharge les données du domaine et choisit un builder.Logique du compilateur de conteneur Symfony.
Service builderApplicationImplé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 Symfonynextpdf/symfonyEnregistre 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 principalnextpdf/nextpdfCompose et sérialise le document.Comportement de la réponse Symfony ou de Messenger.
ÉtapeComportementAction du développeur
Démarrage du bundleNextPdfBundle::build() enregistre la détection des extensions optionnelles.Laisse Symfony découvrir le bundle ou enregistre-le dans bundles.php.
Chargement de la configurationNextPdfExtension::load() traite la configuration nextpdf: et charge les définitions de services.Garde la configuration explicite et adaptée à l’environnement.
Utilisation de la fabriquePdfFactory::create() renvoie un nouveau document configuré.Ne stocke aucun document dans des services.
Sortie du contrôleurPdfResponse transforme un document terminé en réponse.Utilise le helper plutôt que d’assembler manuellement les en-têtes.
Envoi via MessengerGeneratePdfMessage 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 messageGeneratePdfHandler résout le builder depuis un service locator et enregistre le document.Rends les builders déterministes et idempotents.
CheminRô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;
}
}
<?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.

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.

Point d’extensionÀ utiliser pourContrainte
Décoration du service PdfFactoryAppliquer 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.
PdfBuilderInterfaceDéfinir des builders de documents réutilisables ou destinés à la file d’attente.Doit renvoyer un Document.
OptionalExtensionPassActiver 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 SymfonyValeurs 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 GeneratePdfHandlerRestreindre les builders accessibles depuis les messages en file d’attente.Le service locator ne doit exposer que les services de builder approuvés.
  1. Ajoute un service builder avec une entrée déterministe.
  2. Utilise PdfFactory::create() dans un contrôleur ou un service.
  3. Ajoute un test de réponse pour le nom de fichier, le type de contenu et les en-têtes.
  4. Enregistre le builder pour Messenger lorsque le même document doit être généré de façon asynchrone.
  5. Ajoute des tests de message invalide pour le nom de classe, le chemin de sortie et la forme du contexte.
  6. Ajoute un test de compilation du conteneur avec une configuration minimale et une configuration de production.
  7. Mesure le temps de rendu et la mémoire avec les mêmes réglages PHP qu’en production.
ÉchecOù il doit être géréRéponse recommandée
Configuration invalideCompilation du conteneur.Fais échouer le déploiement avant que le trafic n’atteigne l’application.
Service builder manquantTests du handler Messenger et tags de service.Fais échouer le message et alerte l’équipe propriétaire.
Chemin de sortie non sûrConstructeur du message et politique de stockage.Rejette-le avant l’envoi ; garde la validation du handler comme défense en profondeur.
Extension optionnelle indisponibleCompiler pass et comportement de la fabrique.Désactive la fonctionnalité optionnelle ou rends l’installation explicite.
Échec de conversion du service ou de renduFrontière du builder.Échoue en mode fermé, sauf si le cas d’usage dispose d’un repli documenté.
PréoccupationValeur par défautQuand la remplacer
Durée de vie de la fabriqueService du conteneur.Garde-la ; la fabrique est sûre parce qu’elle crée des documents.
Durée de vie du documentUne unité de travail.Ne le partage jamais entre des requêtes ou des messages.
Validation du chemin de sortieConstructeur du message et handler.Ajoute des contraintes de tenant ou de racine de stockage dans le code applicatif.
Nom de fichier de la réponsedocument.pdf.Remplace-la par des identifiants métier nettoyés.
Transport Messengerasync.Utilise un transport dédié quand le travail PDF est lourd.
  • 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é.