1<?php 2 3namespace dokuwiki\plugin\dw2pdf\src; 4 5use Mpdf\HTMLParserMode; 6use Mpdf\MpdfException; 7 8/** 9 * @todo handle actual writing in a separate method to allow for centralized error handling and debug writing to HTML 10 */ 11class Writer 12{ 13 14 protected DokuPdf $mpdf; 15 protected Template $template; 16 protected bool $breakBeforeNext = false; 17 18 /** 19 * @param DokuPdf $mpdf 20 * @param Template $template 21 */ 22 public function __construct(DokuPdf $mpdf, Template $template) 23 { 24 $this->mpdf = $mpdf; 25 $this->template = $template; 26 } 27 28 /** 29 * Initialize the document 30 * 31 * @param string $title 32 * @return void 33 * @throws MpdfException 34 */ 35 public function startDocument(string $title): void 36 { 37 $this->mpdf->SetTitle($title); 38 39 // Set the styles FIXME to be moved into Styles class 40 $styles = '@page landscape-page { size:landscape }'; 41 $styles .= 'div.dw2pdf-landscape { page:landscape-page }'; 42 $styles .= '@page portrait-page { size:portrait }'; 43 $styles .= 'div.dw2pdf-portrait { page:portrait-page }'; 44 // FIXME$styles .= $this->loadCSS(); 45 $this->mpdf->WriteHTML($styles, HTMLParserMode::HEADER_CSS); 46 47 //start body html 48 $this->mpdf->WriteHTML('<div class="dokuwiki">', HTMLParserMode::HTML_BODY, true, false); 49 } 50 51 /** 52 * Insert a page break 53 * 54 * @return void 55 * @throws MpdfException 56 */ 57 public function pageBreak(): void 58 { 59 $this->mpdf->WriteHTML('<pagebreak />', 2, false, false); 60 } 61 62 /** 63 * Write a wiki page into the PDF 64 * 65 * @param string $html The rendered HTML of the wiki page 66 * @return void 67 * @throws MpdfException 68 */ 69 public function wikiPage(string $html): void 70 { 71 $this->conditionalPageBreak(); 72 73 $this->applyHeaderFooters(); 74 75 $this->mpdf->WriteHTML($html, HTMLParserMode::HTML_BODY, false, false); 76 77 // add citation box if any 78 $cite = $this->template->getHTML('citation'); 79 if ($cite) { 80 $this->mpdf->WriteHTML($cite, HTMLParserMode::HTML_BODY, false, false); 81 } 82 83 $this->breakAfterMe(); 84 } 85 86 public function toc(): void 87 { 88 $this->conditionalPageBreak(); 89 // FIXME 90 $this->breakAfterMe(); 91 } 92 93 /** 94 * Insert a cover page 95 * 96 * Should be called once at the beginning of the PDF generation. Will do nothing if 97 * no cover page is configured. 98 * 99 * @return void 100 * @throws MpdfException 101 */ 102 public function cover(): void 103 { 104 $this->conditionalPageBreak(); 105 106 $html = $this->template->getHTML('cover'); 107 if (!$html) return; 108 109 $this->mpdf->WriteHTML($html, HTMLParserMode::HTML_BODY, false, false); 110 111 $this->breakAfterMe(); 112 } 113 114 /** 115 * Insert a back page 116 * 117 * Should be called once at the end of the PDF generation. Will do nothing if 118 * no back page is configured. 119 * 120 * @return void 121 * @throws MpdfException 122 */ 123 public function back(): void 124 { 125 $this->conditionalPageBreak(); 126 127 $html = $this->template->getHTML('back'); 128 if (!$html) return; 129 130 $this->mpdf->WriteHTML($html, HTMLParserMode::HTML_BODY, false, false); 131 } 132 133 /** 134 * Finalize the document 135 * 136 * @return void 137 * @throws MpdfException 138 */ 139 public function endDocument(): void 140 { 141 // adds the closing div and finalizes the document 142 $this->mpdf->WriteHTML('</div>', HTMLParserMode::HTML_BODY, false, true); 143 } 144 145 /** 146 * Set new headers and footers 147 * 148 * This will call the appropriate mpdf methods to set headers and footers. It should be called 149 * before each wiki page is added to the PDF. 150 * 151 * On first call on this instance it will set the headers/footers for the first page, afterwards 152 * it will use the standard headers/footers. 153 * 154 * We always set even and odd headers/footers, though they may be identical. 155 * @return void 156 */ 157 protected function applyHeaderFooters(): void 158 { 159 if ($this->isFirstPage) { 160 $header = $this->template->getHTML('header', 'first'); 161 $footer = $this->template->getHTML('footer', 'first'); 162 163 if ($header) { 164 $this->mpdf->SetHTMLHeader($header, 'O'); 165 $this->mpdf->SetHTMLHeader($header, 'E'); 166 } 167 if ($footer) { 168 $this->mpdf->SetHTMLFooter($footer, 'O'); 169 $this->mpdf->SetHTMLFooter($footer, 'E'); 170 } 171 $this->isFirstPage = false; 172 } else { 173 $headerOdd = $this->template->getHTML('header', 'odd'); 174 $headerEven = $this->template->getHTML('header', 'even'); 175 $footerOdd = $this->template->getHTML('footer', 'odd'); 176 $footerEven = $this->template->getHTML('footer', 'even'); 177 178 if ($headerOdd) { 179 $this->mpdf->SetHTMLHeader($headerOdd, 'O'); 180 } 181 if ($headerEven) { 182 $this->mpdf->SetHTMLHeader($headerEven, 'E'); 183 } 184 if ($footerOdd) { 185 $this->mpdf->SetHTMLFooter($footerOdd, 'O'); 186 } 187 if ($footerEven) { 188 $this->mpdf->SetHTMLFooter($footerEven, 'E'); 189 } 190 } 191 } 192 193 /** 194 * Insert a page break if there was previous content 195 * 196 * @return void 197 */ 198 protected function conditionalPageBreak(): void 199 { 200 if ($this->breakBeforeNext) { 201 $this->pageBreak(); 202 $this->breakBeforeNext = false; 203 } 204 } 205 206 /** 207 * Signal that a page break should be inserted before the next content 208 * 209 * @return void 210 */ 211 protected function breakAfterMe(): void 212 { 213 $this->breakBeforeNext = true; 214 } 215} 216