From be0a311a7e0b04422c1b1e3b58ae9f8cd20c7167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Rie=C3=9F?= Date: Wed, 20 May 2026 10:06:28 +0200 Subject: [PATCH 1/3] Move `first` method from pdfexport module into the hook It made little sense that we ask a concrete hook implementation for the first implementation of a hook. It essentially limited us to exactly one possible pdfexport extension (our own), which is not how hooks are supposed to work. Strict types have been left out intentionally to stay compatible with the existing imeplementation. --- .../Icinga/Application/Hook/PdfexportHook.php | 31 ++++++++++++++++--- library/Icinga/Common/PdfExport.php | 6 ++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/library/Icinga/Application/Hook/PdfexportHook.php b/library/Icinga/Application/Hook/PdfexportHook.php index 0ae0c530df..5fb7133232 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -5,16 +5,39 @@ namespace Icinga\Application\Hook; +use Icinga\Application\Hook; +use Icinga\Application\Logger; +use Icinga\Exception\IcingaException; +use RuntimeException; +use Throwable; + /** * Base class for the PDF Export Hook */ abstract class PdfexportHook { - use HookEssentials; - - final protected static function getHookName(): string + /** + * Get the first hook that supports PDF export + * + * @return static + */ + public static function first() { - return 'Pdfexport'; + foreach (Hook::all('Pdfexport') as $exporter) { + try { + if ($exporter->isSupported()) { + return $exporter; + } + } catch (Throwable $e) { + Logger::error( + "PDF exporter reported an error during support check: %s\n%s", + $e, + IcingaException::getConfidentialTraceAsString($e), + ); + } + } + + throw new RuntimeException('No supported PDF exporter available'); } /** diff --git a/library/Icinga/Common/PdfExport.php b/library/Icinga/Common/PdfExport.php index ed49fafb1e..4093a7ab63 100644 --- a/library/Icinga/Common/PdfExport.php +++ b/library/Icinga/Common/PdfExport.php @@ -5,6 +5,7 @@ namespace Icinga\Common; +use Icinga\Application\Hook\PdfexportHook; use Icinga\Application\Icinga; use Icinga\Date\DateFormatter; use Icinga\Exception\ConfigurationError; @@ -26,7 +27,8 @@ trait PdfExport * Export the requested action to PDF and send it * * @return never - * @throws ConfigurationError If the pdfexport module is not available + * + * @throws ConfigurationError If no pdfexport module is available */ protected function sendAsPdf() { @@ -71,7 +73,7 @@ protected function sendAsPdf() $doc->getAttributes()->add('class', 'icinga-module module-' . $moduleName); } - \Icinga\Module\Pdfexport\ProvidedHook\Pdfexport::first()->streamPdfFromHtml($doc, sprintf( + PdfexportHook::first()->streamPdfFromHtml($doc, sprintf( '%s-%s', $this->view->title ?: $this->getRequest()->getActionName(), $time From 504baf6d04d5867cd44aec0bb651b0ea1b2b3275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Rie=C3=9F?= Date: Wed, 20 May 2026 10:24:29 +0200 Subject: [PATCH 2/3] Define `htmlToPdf` in the Hook This method was always required because it was called by the reporting module assuming that our own implementation of the pdfexport module was the one chosen. Because this behavior exists and our pdfexport module is the only implementation of this hook this is not a breaking change. Strict types have been left out on purpose to be compatible with the already existing implementation. --- library/Icinga/Application/Hook/PdfexportHook.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/Icinga/Application/Hook/PdfexportHook.php b/library/Icinga/Application/Hook/PdfexportHook.php index 5fb7133232..e9e21f8cd9 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -54,4 +54,13 @@ abstract public function isSupported(); * @param string $filename The filename for the generated PDF */ abstract public function streamPdfFromHtml($html, $filename); + + /** + * Render the specified HTML to PDF and return the PDF document as a string + * + * @param ValidHtml $html The HTML to render to PDF + * + * @return string + */ + abstract public function htmlToPdf($html); } From bd3e787577ccd3771523ac7df214cf1c481eb9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Rie=C3=9F?= Date: Wed, 20 May 2026 10:34:15 +0200 Subject: [PATCH 3/3] Adjust phpdocs to clarify that `streamPdfFromHtml` never returns This commit also includes phpdoc formating changes. Strict types have been left out on purpose to be compatible with the already existing implementation. --- library/Icinga/Application/Hook/PdfexportHook.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Application/Hook/PdfexportHook.php b/library/Icinga/Application/Hook/PdfexportHook.php index e9e21f8cd9..3716ce88ac 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -8,6 +8,7 @@ use Icinga\Application\Hook; use Icinga\Application\Logger; use Icinga\Exception\IcingaException; +use ipl\Html\ValidHtml; use RuntimeException; use Throwable; @@ -43,15 +44,17 @@ public static function first() /** * Get whether PDF export is supported * - * @return bool + * @return bool */ abstract public function isSupported(); /** * Render the specified HTML to PDF and stream it to the client * - * @param string $html The HTML to render to PDF - * @param string $filename The filename for the generated PDF + * @param ValidHtml $html The HTML to render to PDF + * @param string $filename The filename for the generated PDF + * + * @return never */ abstract public function streamPdfFromHtml($html, $filename);