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