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