Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
99.10% covered (success)
99.10%
110 / 111
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Head
99.10% covered (success)
99.10%
110 / 111
66.67% covered (warning)
66.67%
2 / 3
22
0.00% covered (danger)
0.00%
0 / 1
 write
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
5
 writeStyles
100.00% covered (success)
100.00%
76 / 76
100.00% covered (success)
100.00%
1 / 1
14
 getFontFamily
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
1<?php
2/**
3 * This file is part of PHPWord - A pure PHP library for reading and writing
4 * word processing documents.
5 *
6 * PHPWord is free software distributed under the terms of the GNU Lesser
7 * General Public License version 3 as published by the Free Software Foundation.
8 *
9 * For the full copyright and license information, please read the LICENSE
10 * file that was distributed with this source code. For the full list of
11 * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
12 *
13 * @see         https://github.com/PHPOffice/PHPWord
14 *
15 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16 */
17
18namespace PhpOffice\PhpWord\Writer\HTML\Part;
19
20use PhpOffice\PhpWord\Settings;
21use PhpOffice\PhpWord\Shared\Converter;
22use PhpOffice\PhpWord\Style;
23use PhpOffice\PhpWord\Style\Font;
24use PhpOffice\PhpWord\Style\Paragraph;
25use PhpOffice\PhpWord\Style\Table;
26use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter;
27use PhpOffice\PhpWord\Writer\HTML\Style\Generic as GenericStyleWriter;
28use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter;
29use PhpOffice\PhpWord\Writer\HTML\Style\Table as TableStyleWriter;
30
31/**
32 * RTF head part writer.
33 *
34 * @since 0.11.0
35 */
36class Head extends AbstractPart
37{
38    /**
39     * Write part.
40     *
41     * @return string
42     */
43    public function write()
44    {
45        $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo();
46        $propertiesMapping = [
47            'creator' => 'author',
48            'title' => '',
49            'description' => '',
50            'subject' => '',
51            'keywords' => '',
52            'category' => '',
53            'company' => '',
54            'manager' => '',
55        ];
56        $title = $docProps->getTitle();
57        $title = ($title != '') ? $title : 'PHPWord';
58
59        $content = '';
60
61        $content .= '<head>' . PHP_EOL;
62        $content .= '<meta charset="UTF-8" />' . PHP_EOL;
63        $content .= '<title>' . $title . '</title>' . PHP_EOL;
64        foreach ($propertiesMapping as $key => $value) {
65            $value = ($value == '') ? $key : $value;
66            $method = 'get' . $key;
67            if ($docProps->$method() != '') {
68                $content .= '<meta name="' . $value . '"'
69                    . ' content="'
70                    . $this->getParentWriter()->escapeHTML($docProps->$method())
71                    . '"'
72                    . ' />' . PHP_EOL;
73            }
74        }
75        $content .= $this->writeStyles();
76        $content .= '</head>' . PHP_EOL;
77
78        return $content;
79    }
80
81    /**
82     * Get styles.
83     */
84    private function writeStyles(): string
85    {
86        $css = '<style>' . PHP_EOL;
87
88        // Default styles
89        $astarray = [
90            'font-family' => $this->getFontFamily(Settings::getDefaultFontName(), $this->getParentWriter()->getDefaultGenericFont()),
91            'font-size' => Settings::getDefaultFontSize() . 'pt',
92        ];
93        // Mpdf sometimes needs separate tag for body; doesn't harm others.
94        $bodyarray = $astarray;
95
96        $defaultWhiteSpace = $this->getParentWriter()->getDefaultWhiteSpace();
97        if ($defaultWhiteSpace) {
98            $astarray['white-space'] = $defaultWhiteSpace;
99        }
100
101        foreach ([
102            'body' => $bodyarray,
103            '*' => $astarray,
104            'a.NoteRef' => [
105                'text-decoration' => 'none',
106            ],
107            'hr' => [
108                'height' => '1px',
109                'padding' => '0',
110                'margin' => '1em 0',
111                'border' => '0',
112                'border-top' => '1px solid #CCC',
113            ],
114            'table' => [
115                'border' => '1px solid black',
116                'border-spacing' => '0px',
117                'width ' => '100%',
118            ],
119            'td' => [
120                'border' => '1px solid black',
121            ],
122        ] as $selector => $style) {
123            $styleWriter = new GenericStyleWriter($style);
124            $css .= $selector . ' {' . $styleWriter->write() . '}' . PHP_EOL;
125        }
126
127        // Custom styles
128        $customStyles = Style::getStyles();
129        if (is_array($customStyles)) {
130            foreach ($customStyles as $name => $style) {
131                $styleParagraph = null;
132                if ($style instanceof Font) {
133                    $styleWriter = new FontStyleWriter($style);
134                    if ($style->getStyleType() == 'title') {
135                        $name = str_replace('Heading_', 'h', $name);
136                        $styleParagraph = $style->getParagraph();
137                        $style = $styleParagraph;
138                    } else {
139                        $name = '.' . $name;
140                    }
141                    $css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
142                }
143                if ($style instanceof Paragraph) {
144                    $styleWriter = new ParagraphStyleWriter($style);
145                    $styleWriter->setParentWriter($this->getParentWriter());
146                    if (!$styleParagraph) {
147                        $name = '.' . $name;
148                    }
149                    if ($name === '.Normal') {
150                        $name = "p, $name";
151                    }
152                    $css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
153                }
154                if ($style instanceof Table) {
155                    $styleWriter = new TableStyleWriter($style);
156                    $css .= ".{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
157                }
158            }
159        }
160
161        $css .= 'body > div + div {page-break-before: always;}' . PHP_EOL;
162        $css .= 'div > *:first-child {page-break-before: auto;}' . PHP_EOL;
163
164        $sectionNum = 0;
165        foreach ($this->getParentWriter()->getPhpWord()->getSections() as $section) {
166            ++$sectionNum;
167
168            $css .= "@page page$sectionNum {";
169
170            $paperSize = $section->getStyle()->getPaperSize();
171            $orientation = $section->getStyle()->getOrientation();
172            if ($this->getParentWriter()->isPdf()) {
173                if ($orientation === 'landscape') {
174                    $paperSize .= '-L';
175                }
176                $css .= "sheet-size: $paperSize";
177            } else {
178                $css .= "size: $paperSize $orientation";
179            }
180
181            $css .= 'margin-right: ' . (string) ($section->getStyle()->getMarginRight() / Converter::INCH_TO_TWIP) . 'in; ';
182            $css .= 'margin-left: ' . (string) ($section->getStyle()->getMarginLeft() / Converter::INCH_TO_TWIP) . 'in; ';
183            $css .= 'margin-top: ' . (string) ($section->getStyle()->getMarginTop() / Converter::INCH_TO_TWIP) . 'in; ';
184            $css .= 'margin-bottom: ' . (string) ($section->getStyle()->getMarginBottom() / Converter::INCH_TO_TWIP) . 'in; ';
185            $css .= '}' . PHP_EOL;
186        }
187
188        $css .= '</style>' . PHP_EOL;
189
190        return $css;
191    }
192
193    /**
194     * Set font and alternates for css font-family.
195     */
196    private function getFontFamily(string $font, string $genericFont): string
197    {
198        if (empty($font)) {
199            return '';
200        }
201        $fontfamily = "'" . htmlspecialchars($font, ENT_QUOTES, 'UTF-8') . "'";
202        if (!empty($genericFont)) {
203            $fontfamily .= "$genericFont";
204        }
205
206        return $fontfamily;
207    }
208}