xref: /plugin/dw2pdf/action.php (revision 4c5691130dbf9035b960f10f5b3cb4b319a026d8)
1<?php
2
3use dokuwiki\ErrorHandler;
4use dokuwiki\Extension\ActionPlugin;
5use dokuwiki\Extension\Event;
6use dokuwiki\Extension\EventHandler;
7use dokuwiki\plugin\dw2pdf\MenuItem;
8use dokuwiki\plugin\dw2pdf\src\Cache;
9use dokuwiki\plugin\dw2pdf\src\CollectorFactory;
10use dokuwiki\plugin\dw2pdf\src\Config;
11use dokuwiki\plugin\dw2pdf\src\ExportException;
12use dokuwiki\plugin\dw2pdf\src\PdfExportService;
13use Mpdf\MpdfException;
14
15/**
16 * dw2Pdf Plugin: Conversion from dokuwiki content to pdf.
17 *
18 * Export html content to pdf, for different url parameter configurations
19 * DokuPDF which extends mPDF is used for generating the pdf from html.
20 *
21 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
22 * @author     Luigi Micco <l.micco@tiscali.it>
23 * @author     Andreas Gohr <andi@splitbrain.org>
24 */
25class action_plugin_dw2pdf extends ActionPlugin
26{
27    /**
28     * Register the events
29     *
30     * @param EventHandler $controller
31     */
32    public function register(EventHandler $controller)
33    {
34        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'convert');
35        $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'addsvgbutton');
36    }
37
38    /**
39     * Do the HTML to PDF conversion work
40     *
41     * @param Event $event
42     * @throws MpdfException
43     */
44    public function convert(Event $event)
45    {
46        global $REV, $DATE_AT, $INPUT;
47
48        // our event?
49        $allowedEvents = ['export_pdfbook', 'export_pdf', 'export_pdfns'];
50        if (!in_array($event->data, $allowedEvents)) {
51            return;
52        }
53
54        $this->loadConfig();
55
56        try {
57            $config = new Config($this->conf);
58            $collector = CollectorFactory::create(
59                $event->data,
60                $config,
61                ((int) $REV) ?: null,
62                ((int) $DATE_AT) ?: null
63            );
64            $cache = new Cache($config, $collector);
65
66            $pdfService = new PdfExportService(
67                $config,
68                $collector,
69                $cache,
70                $this->getLang('tocheader'),
71                $INPUT->server->str('REMOTE_USER', '', true)
72            );
73
74            $cacheFile = $pdfService->getPdf(); // dumps HTML when in debug mode and exits
75        } catch (ExportException $e) {
76            // expected failure carrying a message meant for the user; escape dynamic parts as
77            // the message may end up in an HTML sink (see exportError())
78            $args = array_map('hsc', $e->getArgs());
79            $this->exportError($event, vsprintf($this->getLang($e->getMessage()), $args));
80            return;
81        } catch (\Exception $e) {
82            // unexpected failure, keep the details out of the user's way but log them
83            ErrorHandler::logException($e);
84            $this->exportError($event, $this->getLang('exportfailed'));
85            return;
86        }
87
88        // take over the request and deliver the file
89        $event->preventDefault();
90        $event->stopPropagation();
91
92        $pdfService->sendPdf($cacheFile); // exits after sending
93    }
94
95    /**
96     * Surface an export failure to the user
97     *
98     * BookCreator triggers export_pdfbook as a background download via the jQuery.fileDownload
99     * plugin, which cannot be redirected. It reads the response body and injects it into an error
100     * dialog through jQuery.html(), so failures for that action are answered with an HTTP error and
101     * the message in the body. Any dynamic parts of the message must therefore be HTML escaped by
102     * the caller. All other actions are regular navigations and get a flash message plus a redirect
103     * back to the current page.
104     *
105     * @param Event $event The export event being handled
106     * @param string $message The localized message to show the user, safe for HTML output
107     * @return void
108     */
109    protected function exportError(Event $event, string $message): void
110    {
111        if ($event->data === 'export_pdfbook') {
112            http_status(400);
113            header('Content-Type: text/html; charset=utf-8');
114            echo $message;
115            exit();
116        }
117
118        msg($message, -1);
119        $event->data = 'redirect';
120    }
121
122
123    /**
124     * Add 'export pdf' button to page tools, new SVG based mechanism
125     *
126     * @param Event $event
127     */
128    public function addsvgbutton(Event $event)
129    {
130        global $INFO;
131        if ($event->data['view'] != 'page' || !$this->getConf('showexportbutton')) {
132            return;
133        }
134
135        if (!$INFO['exists']) {
136            return;
137        }
138
139        array_splice($event->data['items'], -1, 0, [new MenuItem()]);
140    }
141}
142