Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
35 / 35
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
PdfHtmxController
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
4 / 4
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 modalPrintRecord
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
2
 modalBulkPdf
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 preview
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Modules\Pdf\Presentation\Htmx;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Modules\Pdf\Application\Service\PdfGeneratorServiceInterface;
12use App\Modules\Pdf\Domain\Repository\PdfTemplateRepositoryInterface;
13use Psr\Http\Message\ResponseFactoryInterface;
14use Psr\Http\Message\ResponseInterface;
15use Psr\Http\Message\ServerRequestInterface;
16use Twig\Environment as TwigEnvironment;
17
18/**
19 * HTMX Controller for Interactive PDF Modals and Live Previews.
20 *
21 * @package App\Modules\Pdf\Presentation\Htmx
22 */
23final readonly class PdfHtmxController
24{
25    private const string CONTENT_TYPE_HTML = 'text/html; charset=utf-8';
26
27    /**
28     * PdfHtmxController constructor.
29     *
30     * @param TwigEnvironment                $twig            Twig template engine.
31     * @param ResponseFactoryInterface       $responseFactory PSR-17 response factory.
32     * @param PdfTemplateRepositoryInterface $repository      Template repository.
33     * @param PdfGeneratorServiceInterface   $generator       PDF generator service.
34     */
35    public function __construct(
36        private TwigEnvironment $twig,
37        private ResponseFactoryInterface $responseFactory,
38        private PdfTemplateRepositoryInterface $repository,
39        private PdfGeneratorServiceInterface $generator
40    ) {
41    }
42
43    /**
44     * Renders modal dialog for single record PDF print/export.
45     *
46     * @param string $moduleName Business module name.
47     * @param int    $recordId   Target record ID.
48     * @return ResponseInterface HTML modal partial response.
49     */
50    public function modalPrintRecord(
51        string $moduleName,
52        int $recordId
53    ): ResponseInterface {
54        $templates = $this->repository->findAllActiveByModule($moduleName);
55        $selectedTemplate = $templates !== [] ? $templates[0] : null;
56
57        $html = $this->twig->render('modules/pdf_templates/partials/modal_print_record.twig', [
58            'module_name'        => $moduleName,
59            'record_id'          => $recordId,
60            'templates'          => $templates,
61            'selected_template'  => $selectedTemplate,
62        ]);
63
64        $response = $this->responseFactory->createResponse(200)
65            ->withHeader('Content-Type', self::CONTENT_TYPE_HTML);
66        $response->getBody()->write($html);
67
68        return $response;
69    }
70
71    /**
72     * Renders modal dialog for bulk DataGrid record PDF print/export.
73     *
74     * @param ServerRequestInterface $request    HTTP request.
75     * @param string                 $moduleName Business module name.
76     * @return ResponseInterface HTML modal partial response.
77     */
78    public function modalBulkPdf(
79        ServerRequestInterface $request,
80        string $moduleName
81    ): ResponseInterface {
82        $queryParams = $request->getQueryParams();
83        $recordIdsParam = (string)($queryParams['record_ids'] ?? '');
84        $recordIds = array_filter(array_map('intval', explode(',', $recordIdsParam)));
85
86        $templates = $this->repository->findAllActiveByModule($moduleName);
87
88        $html = $this->twig->render('modules/pdf_templates/partials/modal_bulk_pdf.twig', [
89            'module_name' => $moduleName,
90            'record_ids'  => implode(',', $recordIds),
91            'count'       => count($recordIds),
92            'templates'   => $templates,
93        ]);
94
95        $response = $this->responseFactory->createResponse(200)
96            ->withHeader('Content-Type', self::CONTENT_TYPE_HTML);
97        $response->getBody()->write($html);
98
99        return $response;
100    }
101
102    /**
103     * Streams inlined HTML preview into the modal iframe.
104     *
105     * @param ServerRequestInterface $request    HTTP request.
106     * @param int                    $templateId Template ID.
107     * @param int                    $recordId   Target record ID.
108     * @return ResponseInterface Self-contained HTML response.
109     */
110    public function preview(
111        ServerRequestInterface $request,
112        int $templateId,
113        int $recordId
114    ): ResponseInterface {
115        $queryParams = $request->getQueryParams();
116        $module = (string)($queryParams['module'] ?? 'tickets');
117
118        $previewHtml = $this->generator->renderHtmlPreview($templateId, $module, $recordId);
119
120        $response = $this->responseFactory->createResponse(200)
121            ->withHeader('Content-Type', self::CONTENT_TYPE_HTML);
122        $response->getBody()->write($previewHtml);
123
124        return $response;
125    }
126}