Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.20% covered (success)
97.20%
104 / 107
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Document
97.20% covered (success)
97.20%
104 / 107
66.67% covered (warning)
66.67%
4 / 6
36
0.00% covered (danger)
0.00%
0 / 1
 write
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 writeInfo
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
5
 writeFormatting
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
 writeTitlepg
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
5.07
 writeSections
95.56% covered (success)
95.56%
43 / 45
0.00% covered (danger)
0.00%
0 / 1
19
 getDateValue
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
2
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\RTF\Part;
19
20use PhpOffice\PhpWord\Element\Footer;
21use PhpOffice\PhpWord\Settings;
22use PhpOffice\PhpWord\Writer\RTF\Element\Container;
23use PhpOffice\PhpWord\Writer\RTF\Style\Section as SectionStyleWriter;
24
25/**
26 * RTF document part writer.
27 *
28 * @since 0.11.0
29 * @see  http://www.biblioscape.com/rtf15_spec.htm#Heading24
30 */
31class Document extends AbstractPart
32{
33    /**
34     * Write part.
35     *
36     * @return string
37     */
38    public function write()
39    {
40        $content = '';
41
42        $content .= $this->writeInfo();
43        $content .= $this->writeFormatting();
44        $content .= $this->writeSections();
45
46        return $content;
47    }
48
49    /**
50     * Write document information.
51     *
52     * @return string
53     */
54    private function writeInfo()
55    {
56        $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo();
57        $properties = ['title', 'subject', 'category', 'keywords', 'comment',
58            'author', 'operator', 'creatim', 'revtim', 'company', 'manager', ];
59        $mapping = [
60            'comment' => 'description',
61            'author' => 'creator',
62            'operator' => 'lastModifiedBy',
63            'creatim' => 'created',
64            'revtim' => 'modified', ];
65        $dateFields = ['creatim', 'revtim'];
66
67        $content = '';
68
69        $content .= '{';
70        $content .= '\info';
71        foreach ($properties as $property) {
72            $method = 'get' . ($mapping[$property] ?? $property);
73            if (!in_array($property, $dateFields) && Settings::isOutputEscapingEnabled()) {
74                $value = $this->escaper->escape($docProps->$method());
75            } else {
76                $value = $docProps->$method();
77            }
78            $value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value;
79            $content .= "{\\{$property} {$value}}";
80        }
81        $content .= '}';
82        $content .= PHP_EOL;
83
84        return $content;
85    }
86
87    /**
88     * Write document formatting properties.
89     *
90     * @return string
91     */
92    private function writeFormatting()
93    {
94        $docSettings = $this->getParentWriter()->getPhpWord()->getSettings();
95        // Applies a language to a text run (defaults to 1036 : French (France))
96        $langId = $docSettings->getThemeFontLang() != null && $docSettings->getThemeFontLang()->getLangId() != null ? $docSettings->getThemeFontLang()->getLangId() : 1036;
97
98        $content = '';
99
100        $content .= '\deftab720'; // Set the default tab size (720 twips)
101        $content .= '\viewkind1'; // Set the view mode of the document
102
103        $content .= '\uc1'; // Set the numberof bytes that follows a unicode character
104        $content .= '\pard'; // Resets to default paragraph properties.
105        $content .= '\nowidctlpar'; // No widow/orphan control
106        $content .= '\lang' . $langId;
107        $content .= '\kerning1'; // Point size (in half-points) above which to kern character pairs
108        $content .= '\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points
109        if ($docSettings->hasEvenAndOddHeaders()) {
110            $content .= '\\facingp';
111        }
112        $content .= PHP_EOL;
113
114        return $content;
115    }
116
117    /**
118     * Write titlepg directive if any "f" headers or footers.
119     *
120     * @param \PhpOffice\PhpWord\Element\Section $section
121     *
122     * @return string
123     */
124    private static function writeTitlepg($section)
125    {
126        foreach ($section->getHeaders() as $header) {
127            if ($header->getType() === Footer::FIRST) {
128                return '\\titlepg' . PHP_EOL;
129            }
130        }
131        foreach ($section->getFooters() as $header) {
132            if ($header->getType() === Footer::FIRST) {
133                return '\\titlepg' . PHP_EOL;
134            }
135        }
136
137        return '';
138    }
139
140    /**
141     * Write sections.
142     *
143     * @return string
144     */
145    private function writeSections()
146    {
147        $content = '';
148
149        $sections = $this->getParentWriter()->getPhpWord()->getSections();
150        $evenOdd = $this->getParentWriter()->getPhpWord()->getSettings()->hasEvenAndOddHeaders();
151        $sectOwed = false;
152        foreach ($sections as $section) {
153            if ($sectOwed) {
154                $content .= '\sect' . PHP_EOL;
155            } else {
156                $sectOwed = true;
157            }
158            $styleWriter = new SectionStyleWriter($section->getStyle());
159            $styleWriter->setParentWriter($this->getParentWriter());
160            $content .= $styleWriter->write();
161            $content .= self::writeTitlepg($section);
162
163            foreach ($section->getHeaders() as $header) {
164                $type = $header->getType();
165                if ($evenOdd || $type !== FOOTER::EVEN) {
166                    $content .= '{\\header';
167                    if ($type === Footer::FIRST) {
168                        $content .= 'f';
169                    } elseif ($evenOdd) {
170                        $content .= ($type === FOOTER::EVEN) ? 'l' : 'r';
171                    }
172                    foreach ($header->getElements() as $element) {
173                        $cl = get_class($element);
174                        $cl2 = str_replace('Element', 'Writer\\RTF\\Element', $cl);
175                        if (class_exists($cl2)) {
176                            $elementWriter = new $cl2($this->getParentWriter(), $element);
177                            $content .= $elementWriter->write();
178                        }
179                    }
180                    $content .= '}' . PHP_EOL;
181                }
182            }
183            foreach ($section->getFooters() as $footer) {
184                $type = $footer->getType();
185                if ($evenOdd || $type !== FOOTER::EVEN) {
186                    $content .= '{\\footer';
187                    if ($type === Footer::FIRST) {
188                        $content .= 'f';
189                    } elseif ($evenOdd) {
190                        $content .= ($type === FOOTER::EVEN) ? 'l' : 'r';
191                    }
192                    foreach ($footer->getElements() as $element) {
193                        $cl = get_class($element);
194                        $cl2 = str_replace('Element', 'Writer\\RTF\\Element', $cl);
195                        if (class_exists($cl2)) {
196                            $elementWriter = new $cl2($this->getParentWriter(), $element);
197                            $content .= $elementWriter->write();
198                        }
199                    }
200                    $content .= '}' . PHP_EOL;
201                }
202            }
203
204            $elementWriter = new Container($this->getParentWriter(), $section);
205            $content .= $elementWriter->write();
206        }
207
208        return $content;
209    }
210
211    /**
212     * Get date value.
213     *
214     * The format of date value is `\yr?\mo?\dy?\hr?\min?\sec?`
215     *
216     * @param int $value
217     *
218     * @return string
219     */
220    private function getDateValue($value)
221    {
222        $dateParts = [
223            'Y' => 'yr',
224            'm' => 'mo',
225            'd' => 'dy',
226            'H' => 'hr',
227            'i' => 'min',
228            's' => 'sec',
229        ];
230        $result = '';
231        foreach ($dateParts as $dateFormat => $controlWord) {
232            $result .= '\\' . $controlWord . date($dateFormat, $value);
233        }
234
235        return $result;
236    }
237}