From 2f50975b2ce0b80fc7a6b265fbf911bf63e84c7a 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/7] 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. --- .../Icinga/Application/Hook/PdfexportHook.php | 31 +++++++++++++++++++ library/Icinga/Common/PdfExport.php | 7 +++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Application/Hook/PdfexportHook.php b/library/Icinga/Application/Hook/PdfexportHook.php index 2c1d6b3d4e..24e433e0b9 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -5,11 +5,42 @@ namespace Icinga\Application\Hook; +use Icinga\Application\Hook; +use Icinga\Application\Logger; +use RuntimeException; +use Throwable; + /** * Base class for the PDF Export Hook */ abstract class PdfexportHook { + /** + * Get the first hook + * + * @return static + */ + public static function first() + { + if (! Hook::has('Pdfexport')) { + throw new RuntimeException('No PDF exporter available'); + } + + foreach (Hook::all('Pdfexport') as $exporter) { + try { + if (! $exporter->isSupported()) { + continue; + } + + return $exporter; + } catch (Throwable $e) { + Logger::error('PDF exporter reported an error during support check: %s', $e); + } + } + + throw new RuntimeException('Not supported PDF exporter available'); + } + /** * Get whether PDF export is supported * diff --git a/library/Icinga/Common/PdfExport.php b/library/Icinga/Common/PdfExport.php index ed49fafb1e..b0ff609e99 100644 --- a/library/Icinga/Common/PdfExport.php +++ b/library/Icinga/Common/PdfExport.php @@ -5,6 +5,8 @@ namespace Icinga\Common; +use Icinga\Application\Hook; +use Icinga\Application\Hook\PdfexportHook; use Icinga\Application\Icinga; use Icinga\Date\DateFormatter; use Icinga\Exception\ConfigurationError; @@ -26,7 +28,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 +74,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 0688c2ab8ad78afb1e6cc29a6877602fd9bead49 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/7] 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. --- 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 24e433e0b9..fe3ca8fc66 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -55,4 +55,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 cfe57fc04343ce94793d0a378d64ff36d6077b24 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/7] Clarify that `streamPdfFromHtml` never returns This commit also includes phpdoc formating changes --- 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 fe3ca8fc66..f02b5c25b5 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -7,6 +7,7 @@ use Icinga\Application\Hook; use Icinga\Application\Logger; +use ipl\Html\ValidHtml; use RuntimeException; use Throwable; @@ -44,15 +45,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); From 4455bf0f6e7afc1a09d0cd863a6a2eef59904b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Rie=C3=9F?= Date: Thu, 21 May 2026 13:09:15 +0200 Subject: [PATCH 4/7] fixup! simplify condition --- library/Icinga/Application/Hook/PdfexportHook.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/Icinga/Application/Hook/PdfexportHook.php b/library/Icinga/Application/Hook/PdfexportHook.php index f02b5c25b5..108cdcafe1 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -29,11 +29,9 @@ public static function first() foreach (Hook::all('Pdfexport') as $exporter) { try { - if (! $exporter->isSupported()) { - continue; + if ($exporter->isSupported()) { + return $exporter; } - - return $exporter; } catch (Throwable $e) { Logger::error('PDF exporter reported an error during support check: %s', $e); } From d80698dd9f318767c759bb13ddd0a6312e659be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Rie=C3=9F?= Date: Thu, 21 May 2026 13:09:23 +0200 Subject: [PATCH 5/7] fixup! Remove unused import --- library/Icinga/Common/PdfExport.php | 1 - 1 file changed, 1 deletion(-) diff --git a/library/Icinga/Common/PdfExport.php b/library/Icinga/Common/PdfExport.php index b0ff609e99..4093a7ab63 100644 --- a/library/Icinga/Common/PdfExport.php +++ b/library/Icinga/Common/PdfExport.php @@ -5,7 +5,6 @@ namespace Icinga\Common; -use Icinga\Application\Hook; use Icinga\Application\Hook\PdfexportHook; use Icinga\Application\Icinga; use Icinga\Date\DateFormatter; From 32338b1ce83be41f0253f6015a55dcf9fbcf0ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Rie=C3=9F?= Date: Thu, 21 May 2026 13:49:43 +0200 Subject: [PATCH 6/7] fixup! Properly log error and remove Hook::has guard --- library/Icinga/Application/Hook/PdfexportHook.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/Icinga/Application/Hook/PdfexportHook.php b/library/Icinga/Application/Hook/PdfexportHook.php index 108cdcafe1..481cdfb4e8 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -7,6 +7,7 @@ use Icinga\Application\Hook; use Icinga\Application\Logger; +use Icinga\Exception\IcingaException; use ipl\Html\ValidHtml; use RuntimeException; use Throwable; @@ -23,21 +24,18 @@ abstract class PdfexportHook */ public static function first() { - if (! Hook::has('Pdfexport')) { - throw new RuntimeException('No PDF exporter available'); - } - 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', $e); + Logger::error('PDF exporter reported an error during support check: %s', $e->getMessage()); + Logger::error("%s\n%s", $e, IcingaException::getConfidentialTraceAsString($e)); } } - throw new RuntimeException('Not supported PDF exporter available'); + throw new RuntimeException('No supported PDF exporter available'); } /** From 16bbb12ced9b2bdf11c00c799485e1ef63fe17d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Rie=C3=9F?= Date: Thu, 21 May 2026 15:29:38 +0200 Subject: [PATCH 7/7] fixup! Remove extra log message --- library/Icinga/Application/Hook/PdfexportHook.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Application/Hook/PdfexportHook.php b/library/Icinga/Application/Hook/PdfexportHook.php index 481cdfb4e8..9603705fdd 100644 --- a/library/Icinga/Application/Hook/PdfexportHook.php +++ b/library/Icinga/Application/Hook/PdfexportHook.php @@ -30,8 +30,11 @@ public static function first() return $exporter; } } catch (Throwable $e) { - Logger::error('PDF exporter reported an error during support check: %s', $e->getMessage()); - Logger::error("%s\n%s", $e, IcingaException::getConfidentialTraceAsString($e)); + Logger::error( + "PDF exporter reported an error during support check: %s\n%s", + $e, + IcingaException::getConfidentialTraceAsString($e), + ); } }