Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.38% covered (warning)
88.38%
175 / 198
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Field
88.38% covered (warning)
88.38%
175 / 198
66.67% covered (warning)
66.67%
4 / 6
50.46
0.00% covered (danger)
0.00%
0 / 1
 write
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 writeDefault
100.00% covered (success)
100.00%
54 / 54
100.00% covered (success)
100.00%
1 / 1
7
 writeMacrobutton
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
4
 buildPropertiesAndOptions
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
1 / 1
16
 writeRef
73.08% covered (warning)
73.08%
38 / 52
0.00% covered (danger)
0.00%
0 / 1
7.96
 convertRefOption
47.06% covered (danger)
47.06%
8 / 17
0.00% covered (danger)
0.00%
0 / 1
24.84
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\Word2007\Element;
20
21use PhpOffice\PhpWord\Element\Field as ElementField;
22use PhpOffice\PhpWord\Element\TextRun;
23
24/**
25 * Field element writer.
26 *
27 * @since 0.11.0
28 */
29class Field extends Text
30{
31    /**
32     * Write field element.
33     */
34    public function write(): void
35    {
36        $element = $this->getElement();
37        if (!$element instanceof ElementField) {
38            return;
39        }
40
41        $methodName = 'write' . ucfirst(strtolower($element->getType()));
42        if (method_exists($this, $methodName)) {
43            $this->$methodName($element);
44        } else {
45            $this->writeDefault($element);
46        }
47    }
48
49    private function writeDefault(ElementField $element): void
50    {
51        $xmlWriter = $this->getXmlWriter();
52        $this->startElementP();
53
54        $xmlWriter->startElement('w:r');
55        $xmlWriter->startElement('w:fldChar');
56        $xmlWriter->writeAttribute('w:fldCharType', 'begin');
57        $xmlWriter->endElement(); // w:fldChar
58        $xmlWriter->endElement(); // w:r
59
60        $instruction = ' ' . $element->getType() . ' ';
61        if ($element->getText() != null) {
62            if (is_string($element->getText())) {
63                $instruction .= '"' . $element->getText() . '" ';
64                $instruction .= $this->buildPropertiesAndOptions($element);
65            } else {
66                $instruction .= '"';
67            }
68        } else {
69            $instruction .= $this->buildPropertiesAndOptions($element);
70        }
71        $xmlWriter->startElement('w:r');
72        $this->writeFontStyle();
73        $xmlWriter->startElement('w:instrText');
74        $xmlWriter->writeAttribute('xml:space', 'preserve');
75        $xmlWriter->text($instruction);
76        $xmlWriter->endElement(); // w:instrText
77        $xmlWriter->endElement(); // w:r
78
79        if ($element->getText() != null) {
80            if ($element->getText() instanceof TextRun) {
81                $containerWriter = new Container($xmlWriter, $element->getText(), true);
82                $containerWriter->write();
83
84                $xmlWriter->startElement('w:r');
85                $xmlWriter->startElement('w:instrText');
86                $xmlWriter->text('"' . $this->buildPropertiesAndOptions($element));
87                $xmlWriter->endElement(); // w:instrText
88                $xmlWriter->endElement(); // w:r
89
90                $xmlWriter->startElement('w:r');
91                $xmlWriter->startElement('w:instrText');
92                $xmlWriter->writeAttribute('xml:space', 'preserve');
93                $xmlWriter->text(' ');
94                $xmlWriter->endElement(); // w:instrText
95                $xmlWriter->endElement(); // w:r
96            }
97        }
98
99        $xmlWriter->startElement('w:r');
100        $xmlWriter->startElement('w:fldChar');
101        $xmlWriter->writeAttribute('w:fldCharType', 'separate');
102        $xmlWriter->endElement(); // w:fldChar
103        $xmlWriter->endElement(); // w:r
104
105        $xmlWriter->startElement('w:r');
106        $xmlWriter->startElement('w:rPr');
107        $xmlWriter->startElement('w:noProof');
108        $xmlWriter->endElement(); // w:noProof
109        $xmlWriter->endElement(); // w:rPr
110        $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1');
111        $xmlWriter->endElement(); // w:r
112
113        $xmlWriter->startElement('w:r');
114        $xmlWriter->startElement('w:fldChar');
115        $xmlWriter->writeAttribute('w:fldCharType', 'end');
116        $xmlWriter->endElement(); // w:fldChar
117        $xmlWriter->endElement(); // w:r
118
119        $this->endElementP(); // w:p
120    }
121
122    /**
123     * Writes a macrobutton field.
124     *
125     * //TODO A lot of code duplication with general method, should maybe be refactored
126     */
127    protected function writeMacrobutton(ElementField $element): void
128    {
129        $xmlWriter = $this->getXmlWriter();
130        $this->startElementP();
131
132        $xmlWriter->startElement('w:r');
133        $xmlWriter->startElement('w:fldChar');
134        $xmlWriter->writeAttribute('w:fldCharType', 'begin');
135        $xmlWriter->endElement(); // w:fldChar
136        $xmlWriter->endElement(); // w:r
137
138        $instruction = ' ' . $element->getType() . ' ' . $this->buildPropertiesAndOptions($element);
139        if (is_string($element->getText())) {
140            $instruction .= $element->getText() . ' ';
141        }
142
143        $xmlWriter->startElement('w:r');
144        $xmlWriter->startElement('w:instrText');
145        $xmlWriter->writeAttribute('xml:space', 'preserve');
146        $xmlWriter->text($instruction);
147        $xmlWriter->endElement(); // w:instrText
148        $xmlWriter->endElement(); // w:r
149
150        if ($element->getText() != null) {
151            if ($element->getText() instanceof TextRun) {
152                $containerWriter = new Container($xmlWriter, $element->getText(), true);
153                $containerWriter->write();
154            }
155        }
156
157        $xmlWriter->startElement('w:r');
158        $xmlWriter->startElement('w:fldChar');
159        $xmlWriter->writeAttribute('w:fldCharType', 'end');
160        $xmlWriter->endElement(); // w:fldChar
161        $xmlWriter->endElement(); // w:r
162
163        $this->endElementP(); // w:p
164    }
165
166    private function buildPropertiesAndOptions(ElementField $element)
167    {
168        $propertiesAndOptions = '';
169        $properties = $element->getProperties();
170        foreach ($properties as $propkey => $propval) {
171            switch ($propkey) {
172                case 'format':
173                    $propertiesAndOptions .= '\\* ' . $propval . ' ';
174
175                    break;
176                case 'numformat':
177                    $propertiesAndOptions .= '\\# ' . $propval . ' ';
178
179                    break;
180                case 'dateformat':
181                    $propertiesAndOptions .= '\\@ "' . $propval . '" ';
182
183                    break;
184                case 'macroname':
185                    $propertiesAndOptions .= $propval . ' ';
186
187                    break;
188                default:
189                    $propertiesAndOptions .= '"' . $propval . '" ';
190
191                    break;
192            }
193        }
194
195        $options = $element->getOptions();
196        foreach ($options as $option) {
197            switch ($option) {
198                case 'PreserveFormat':
199                    $propertiesAndOptions .= '\\* MERGEFORMAT ';
200
201                    break;
202                case 'LunarCalendar':
203                    $propertiesAndOptions .= '\\h ';
204
205                    break;
206                case 'SakaEraCalendar':
207                    $propertiesAndOptions .= '\\s ';
208
209                    break;
210                case 'LastUsedFormat':
211                    $propertiesAndOptions .= '\\l ';
212
213                    break;
214                case 'Bold':
215                    $propertiesAndOptions .= '\\b ';
216
217                    break;
218                case 'Italic':
219                    $propertiesAndOptions .= '\\i ';
220
221                    break;
222                case 'Path':
223                    $propertiesAndOptions .= '\\p ';
224
225                    break;
226                default:
227                    $propertiesAndOptions .= $option . ' ';
228            }
229        }
230
231        return $propertiesAndOptions;
232    }
233
234    /**
235     * Writes a REF field.
236     */
237    protected function writeRef(ElementField $element): void
238    {
239        $xmlWriter = $this->getXmlWriter();
240        $this->startElementP();
241
242        $xmlWriter->startElement('w:r');
243        $xmlWriter->startElement('w:fldChar');
244        $xmlWriter->writeAttribute('w:fldCharType', 'begin');
245        $xmlWriter->endElement(); // w:fldChar
246        $xmlWriter->endElement(); // w:r
247
248        $instruction = ' ' . $element->getType() . ' ';
249
250        foreach ($element->getProperties() as $property) {
251            $instruction .= $property . ' ';
252        }
253        foreach ($element->getOptions() as $optionKey => $optionValue) {
254            $instruction .= $this->convertRefOption($optionKey, $optionValue) . ' ';
255        }
256
257        $xmlWriter->startElement('w:r');
258        $this->writeFontStyle();
259        $xmlWriter->startElement('w:instrText');
260        $xmlWriter->writeAttribute('xml:space', 'preserve');
261        $xmlWriter->text($instruction);
262        $xmlWriter->endElement(); // w:instrText
263        $xmlWriter->endElement(); // w:r
264
265        if ($element->getText() != null) {
266            if ($element->getText() instanceof TextRun) {
267                $containerWriter = new Container($xmlWriter, $element->getText(), true);
268                $containerWriter->write();
269
270                $xmlWriter->startElement('w:r');
271                $xmlWriter->startElement('w:instrText');
272                $xmlWriter->text('"' . $this->buildPropertiesAndOptions($element));
273                $xmlWriter->endElement(); // w:instrText
274                $xmlWriter->endElement(); // w:r
275
276                $xmlWriter->startElement('w:r');
277                $xmlWriter->startElement('w:instrText');
278                $xmlWriter->writeAttribute('xml:space', 'preserve');
279                $xmlWriter->text(' ');
280                $xmlWriter->endElement(); // w:instrText
281                $xmlWriter->endElement(); // w:r
282            }
283        }
284
285        $xmlWriter->startElement('w:r');
286        $xmlWriter->startElement('w:fldChar');
287        $xmlWriter->writeAttribute('w:fldCharType', 'separate');
288        $xmlWriter->endElement(); // w:fldChar
289        $xmlWriter->endElement(); // w:r
290
291        $xmlWriter->startElement('w:r');
292        $xmlWriter->startElement('w:rPr');
293        $xmlWriter->startElement('w:noProof');
294        $xmlWriter->endElement(); // w:noProof
295        $xmlWriter->endElement(); // w:rPr
296        $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1');
297        $xmlWriter->endElement(); // w:r
298
299        $xmlWriter->startElement('w:r');
300        $xmlWriter->startElement('w:fldChar');
301        $xmlWriter->writeAttribute('w:fldCharType', 'end');
302        $xmlWriter->endElement(); // w:fldChar
303        $xmlWriter->endElement(); // w:r
304
305        $this->endElementP(); // w:p
306    }
307
308    private function convertRefOption(string $optionKey, string $optionValue): string
309    {
310        if ($optionKey === 'NumberSeperatorSequence') {
311            return '\\d ' . $optionValue;
312        }
313
314        switch ($optionValue) {
315            case 'IncrementAndInsertText':
316                return '\\f';
317            case 'CreateHyperLink':
318                return '\\h';
319            case 'NoTrailingPeriod':
320                return '\\n';
321            case 'IncludeAboveOrBelow':
322                return '\\p';
323            case 'InsertParagraphNumberRelativeContext':
324                return '\\r';
325            case 'SuppressNonDelimiterNonNumericalText':
326                return '\\t';
327            case 'InsertParagraphNumberFullContext':
328                return '\\w';
329            default:
330                return '';
331        }
332    }
333}