<?php
declare(strict_types=1);
/**
* @author Mehrez Labidi
*/
namespace App\Services;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\{
Request,
RedirectResponse,
Response
};
use Dompdf\Dompdf;
use Dompdf\Options;
use Twig\Environment;
class PDFGenerator {
/**
* @var string
*/
public static $directory_storage_pdf;
/**
* @var Environment
*/
private Environment $templating;
/**
* @param Environment $twig
* @param string $directory_storage_pdf
*/
public function __construct(Environment $twig, string $directory_storage_pdf) {
$this->templating = $twig;
static::$directory_storage_pdf = $directory_storage_pdf;
}
/**
*
* @param type $view
* @param type $var
* @param type $fileName
* @param type $title
* @param type $footerText
*/
public function generatePDFviewBrowser($view, $var, $fileName, $title, $footerText = "") {
$pdfOptions = new Options();
$pdfOptions->set('isRemoteEnabled', true);
$pdfOptions->set('isPhpEnabled', true);
$pdfOptions->set('defaultFont', 'helvetica');
// Instantiate Dompdf with our options
$dompdf = new Dompdf($pdfOptions);
// Retrieve the HTML generated in our twig file
$vars = ['title' => $title];
foreach ($var as $keyItem => $valueItem) {
$vars[$keyItem] = $valueItem;
}
$html = $this->templating->render($view, $vars);
// Load HTML to Dompdf
$dompdf->loadHtml($html);
// (Optional) Setup the paper size and orientation 'portrait' or 'portrait'
$dompdf->setPaper('A4', 'portrait');
// Render the HTML as PDF
$dompdf->render();
if ($footerText) {
// Solution Canvas qui fonctionne sur TOUTES les pages
$canvas = $dompdf->getCanvas();
$fontMetrics = $dompdf->getFontMetrics();
// Méthode page_script pour Dompdf 3.0
$canvas->page_script(function ($pageNumber, $pageCount, $canvas, $fontMetrics) use ($footerText) {
// Police en italique
$font = $fontMetrics->get_font("helvetica", "italic");
$fontSize = 8;
// Texte du footer
$text = $footerText;
// Dimensions de la page
$pageWidth = $canvas->get_width();
$pageHeight = $canvas->get_height();
// Marges identiques au body
$leftMargin = 50;
$rightMargin = 50; // Ajout d'une marge droite pour équilibrer
// Largeur disponible pour le texte
$availableWidth = $pageWidth - $leftMargin - $rightMargin;
// Fonction pour découper le texte en lignes
$lines = [];
$words = preg_split('/\s+/', $text);
$currentLine = '';
foreach ($words as $word) {
$testLine = $currentLine . ($currentLine ? ' ' : '') . $word;
$testWidth = $fontMetrics->get_text_width($testLine, $font, $fontSize);
if ($testWidth > $availableWidth && $currentLine !== '') {
// La ligne est trop longue, on ajoute la ligne courante et on commence une nouvelle
$lines[] = $currentLine;
$currentLine = $word;
} else {
// Le mot tient sur la ligne courante
$currentLine = $testLine;
}
}
// Ajouter la dernière ligne si elle n'est pas vide
if ($currentLine !== '') {
$lines[] = $currentLine;
}
// Interligne
$lineHeight = 12; // Hauteur de ligne (ajustable)
// Calculer la position Y de départ pour centrer verticalement le bloc de texte
$totalTextHeight = count($lines) * $lineHeight;
$baseY = $pageHeight - 30 - ($totalTextHeight - $lineHeight);
// Position de la ligne de séparation (au-dessus du texte)
$separatorY = $baseY - 10;
// Dessiner chaque ligne de texte
$x = $leftMargin;
$y = $baseY;
foreach ($lines as $line) {
// Changement ici : [0, 0, 0] pour noir au lieu de [0.5, 0.5, 0.5] pour gris
$canvas->text($x, $y, $line, $font, $fontSize, [0, 0, 0]);
$y += $lineHeight;
}
});
}
// // Output the generated PDF to Browser (inline view)
// $dompdf->stream("$fileName.pdf", [
// 'Attachment' => false,
// ]);
// ⚠️ Très important : ne rien envoyer en direct, vider tout tampon éventuel
while (ob_get_level() > 0) {
@ob_end_clean();
}
$pdf = $dompdf->output();
return new Response($pdf, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="' . $fileName . '.pdf"',
'Content-Length' => (string) strlen($pdf),
// Optionnel: forcer no-cache si besoin
'Cache-Control' => 'private, must-revalidate, max-age=0',
'Pragma' => 'public',
]);
}
/**
* @param $view
* @param $var
* @param $fileName
* @param $title
*
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public function generatePDFStoreDisk($view, $var, $fileName, $title) {
$pdfOptions = new Options();
$pdfOptions->set('defaultFont', 'Arial');
$dompdf = new Dompdf($pdfOptions);
$vars = ['title' => $title];
foreach ($var as $keyItem => $valueItem) {
$vars[$keyItem] = $valueItem;
}
$html = $this->templating->render($view, $vars);
// Load HTML to Dompdf
$dompdf->loadHtml($html);
// (Optional) Setup the paper size and orientation 'portrait' or 'portrait'
$dompdf->setPaper('A4', 'portrait');
// Render the HTML as PDF
$dompdf->render();
// Store PDF Binary Data
$output = $dompdf->output();
// In this case, we want to write the file in the public directory
$publicDirectory = self::$directory_storage_pdf;
if (!is_dir($publicDirectory)) {
mkdir($publicDirectory, 0777, true);
}
// e.g /var/www/project/public/mypdf.pdf
$pdfFilepath = $publicDirectory . $fileName . '.pdf';
// Write file to the desired path
file_put_contents($pdfFilepath, $output);
}
/**
* @param string $url
* @return void
*/
public function displayPDFByURL(string $url): StreamedResponse {
return new StreamedResponse(function () use ($url) {
readfile($url);
}, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="' . basename($url) . '"',
]);
}
}