Skip to content

Commit f0fa91f

Browse files
committed
Merge branch 'support_for_xe_and_index_field' into develop
2 parents ee2dcdd + 8aabf81 commit f0fa91f

File tree

7 files changed

+177
-56
lines changed

7 files changed

+177
-56
lines changed

docs/elements.rst

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,35 @@ To be completed
377377
Fields
378378
------
379379

380-
To be completed
380+
Currently the following fields are supported:
381+
382+
- PAGE
383+
- NUMPAGES
384+
- DATE
385+
- XE
386+
- INDEX
387+
388+
.. code-block:: php
389+
390+
$section->addField($fieldType, [$properties], [$options], [$fieldText])
391+
392+
See ``\PhpOffice\PhpWord\Element\Field`` for list of properties and options available for each field type.
393+
Options which are not specifically defined can be added. Those must start with a ``\``.
394+
395+
For instance for the INDEX field, you can do the following (See `Index Field for list of available options <https://support.office.com/en-us/article/Field-codes-Index-field-adafcf4a-cb30-43f6-85c7-743da1635d9e?ui=en-US&rs=en-US&ad=US>`_ ):
396+
397+
.. code-block:: php
398+
399+
//the $fieldText can be either a simple string
400+
$fieldText = 'The index value';
401+
402+
//or a 'TextRun', to be able to format the text you want in the index
403+
$fieldText = new TextRun();
404+
$fieldText->addText('My ');
405+
$fieldText->addText('bold index', ['bold' => true]);
406+
$fieldText->addText(' entry');
407+
408+
$section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), $fieldText);
381409
382410
Line
383411
------

samples/Sample_27_Field.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<?php
2+
use PhpOffice\PhpWord\Element\TextRun;
3+
24
include_once 'Sample_Header.php';
35

46
// New Word document
@@ -21,11 +23,21 @@
2123

2224
$textrun = $section->addTextRun();
2325
$textrun->addText('An index field is ');
24-
$textrun->addField('XE', array(), array('Bold'), 'FieldValue');
26+
$textrun->addField('XE', array(), array('Italic'), 'My first index');
27+
$textrun->addText('here:');
28+
29+
$indexEntryText = new TextRun();
30+
$indexEntryText->addText('My ');
31+
$indexEntryText->addText('bold index', ['bold' => true]);
32+
$indexEntryText->addText(' entry');
33+
34+
$textrun = $section->addTextRun();
35+
$textrun->addText('A complex index field is ');
36+
$textrun->addField('XE', array(), array('Bold'), $indexEntryText);
2537
$textrun->addText('here:');
2638

2739
$section->addText('The actual index:');
28-
$section->addField('INDEX', array(), array('PreserveFormat'));
40+
$section->addField('INDEX', array(), array('\\e " "'), 'right click to update the index');
2941

3042
$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER));
3143
$textrun->addText('This is the date of lunar calendar ');

src/PhpWord/Element/AbstractContainer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false)
4040
* @method Object addObject(string $source, mixed $style = null)
4141
* @method TextBox addTextBox(mixed $style = null)
42-
* @method Field addField(string $type = null, array $properties = array(), array $options = array())
42+
* @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null)
4343
* @method Line addLine(mixed $lineStyle = null)
4444
* @method Shape addShape(string $type, mixed $style = null)
4545
* @method Chart addChart(string $type, array $categories, array $values, array $style = null)

src/PhpWord/Element/Field.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class Field extends AbstractElement
7474
/**
7575
* Field text
7676
*
77-
* @var string
77+
* @var TextRun | string
7878
*/
7979
protected $text;
8080

@@ -98,6 +98,7 @@ class Field extends AbstractElement
9898
* @param string $type
9999
* @param array $properties
100100
* @param array $options
101+
* @param TextRun | string $text
101102
*/
102103
public function __construct($type = null, $properties = array(), $options = array(), $text = null)
103104
{
@@ -205,16 +206,16 @@ public function getOptions()
205206
/**
206207
* Set Field text
207208
*
208-
* @param string $text
209+
* @param string | TextRun $text
209210
*
210-
* @return string
211+
* @return string | TextRun
211212
*
212213
* @throws \InvalidArgumentException
213214
*/
214215
public function setText($text)
215216
{
216217
if (isset($text)) {
217-
if (is_string($text)) {
218+
if (is_string($text) || $text instanceof TextRun) {
218219
$this->text = $text;
219220
} else {
220221
throw new \InvalidArgumentException("Invalid text");
@@ -226,7 +227,7 @@ public function setText($text)
226227
/**
227228
* Get Field text
228229
*
229-
* @return string
230+
* @return string | TextRun
230231
*/
231232
public function getText()
232233
{

src/PhpWord/Writer/Word2007/Element/Field.php

Lines changed: 82 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
namespace PhpOffice\PhpWord\Writer\Word2007\Element;
1919

20+
use PhpOffice\PhpWord\Element\TextRun;
21+
2022
/**
2123
* Field element writer
2224
*
@@ -37,51 +39,6 @@ public function write()
3739
return;
3840
}
3941

40-
$instruction = ' ' . $element->getType() . ' ';
41-
if ($element->getText() != null) {
42-
$instruction .= '"' . $element->getText() . '" ';
43-
}
44-
$properties = $element->getProperties();
45-
foreach ($properties as $propkey => $propval) {
46-
switch ($propkey) {
47-
case 'format':
48-
$instruction .= '\* ' . $propval . ' ';
49-
break;
50-
case 'numformat':
51-
$instruction .= '\# ' . $propval . ' ';
52-
break;
53-
case 'dateformat':
54-
$instruction .= '\@ "' . $propval . '" ';
55-
break;
56-
}
57-
}
58-
59-
$options = $element->getOptions();
60-
foreach ($options as $option) {
61-
switch ($option) {
62-
case 'PreserveFormat':
63-
$instruction .= '\* MERGEFORMAT ';
64-
break;
65-
case 'LunarCalendar':
66-
$instruction .= '\h ';
67-
break;
68-
case 'SakaEraCalendar':
69-
$instruction .= '\s ';
70-
break;
71-
case 'LastUsedFormat':
72-
$instruction .= '\l ';
73-
break;
74-
case 'Bold':
75-
$instruction .= '\b ';
76-
break;
77-
case 'Italic':
78-
$instruction .= '\i ';
79-
break;
80-
default:
81-
$instruction .= $option .' ';
82-
}
83-
}
84-
8542
$this->startElementP();
8643

8744
$xmlWriter->startElement('w:r');
@@ -90,13 +47,45 @@ public function write()
9047
$xmlWriter->endElement(); // w:fldChar
9148
$xmlWriter->endElement(); // w:r
9249

50+
$instruction = ' ' . $element->getType() . ' ';
51+
if ($element->getText() != null) {
52+
if (is_string($element->getText())) {
53+
$instruction .= '"' . $element->getText() . '" ';
54+
$instruction .= $this->buildPropertiesAndOptions($element);
55+
} else {
56+
$instruction .= '"';
57+
}
58+
} else {
59+
$instruction .= $this->buildPropertiesAndOptions($element);
60+
}
9361
$xmlWriter->startElement('w:r');
9462
$xmlWriter->startElement('w:instrText');
9563
$xmlWriter->writeAttribute('xml:space', 'preserve');
9664
$xmlWriter->text($instruction);
9765
$xmlWriter->endElement(); // w:instrText
9866
$xmlWriter->endElement(); // w:r
9967

68+
if ($element->getText() != null) {
69+
if ($element->getText() instanceof TextRun) {
70+
71+
$containerWriter = new Container($xmlWriter, $element->getText(), true);
72+
$containerWriter->write();
73+
74+
$xmlWriter->startElement('w:r');
75+
$xmlWriter->startElement('w:instrText');
76+
$xmlWriter->text('"' . $this->buildPropertiesAndOptions($element));
77+
$xmlWriter->endElement(); // w:instrText
78+
$xmlWriter->endElement(); // w:r
79+
80+
$xmlWriter->startElement('w:r');
81+
$xmlWriter->startElement('w:instrText');
82+
$xmlWriter->writeAttribute('xml:space', 'preserve');
83+
$xmlWriter->text(' ');
84+
$xmlWriter->endElement(); // w:instrText
85+
$xmlWriter->endElement(); // w:r
86+
}
87+
}
88+
10089
$xmlWriter->startElement('w:r');
10190
$xmlWriter->startElement('w:fldChar');
10291
$xmlWriter->writeAttribute('w:fldCharType', 'separate');
@@ -108,9 +97,9 @@ public function write()
10897
$xmlWriter->startElement('w:noProof');
10998
$xmlWriter->endElement(); // w:noProof
11099
$xmlWriter->endElement(); // w:rPr
111-
$xmlWriter->writeElement('w:t', $element->getText() == null ? '1' : $element->getText());
100+
$xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1');
112101
$xmlWriter->endElement(); // w:r
113-
102+
114103
$xmlWriter->startElement('w:r');
115104
$xmlWriter->startElement('w:fldChar');
116105
$xmlWriter->writeAttribute('w:fldCharType', 'end');
@@ -119,4 +108,50 @@ public function write()
119108

120109
$this->endElementP(); // w:p
121110
}
111+
112+
private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element)
113+
{
114+
$propertiesAndOptions = '';
115+
$properties = $element->getProperties();
116+
foreach ($properties as $propkey => $propval) {
117+
switch ($propkey) {
118+
case 'format':
119+
$propertiesAndOptions.= '\* ' . $propval . ' ';
120+
break;
121+
case 'numformat':
122+
$propertiesAndOptions.= '\# ' . $propval . ' ';
123+
break;
124+
case 'dateformat':
125+
$propertiesAndOptions.= '\@ "' . $propval . '" ';
126+
break;
127+
}
128+
}
129+
130+
$options = $element->getOptions();
131+
foreach ($options as $option) {
132+
switch ($option) {
133+
case 'PreserveFormat':
134+
$propertiesAndOptions.= '\* MERGEFORMAT ';
135+
break;
136+
case 'LunarCalendar':
137+
$propertiesAndOptions.= '\h ';
138+
break;
139+
case 'SakaEraCalendar':
140+
$propertiesAndOptions.= '\s ';
141+
break;
142+
case 'LastUsedFormat':
143+
$propertiesAndOptions.= '\l ';
144+
break;
145+
case 'Bold':
146+
$propertiesAndOptions.= '\b ';
147+
break;
148+
case 'Italic':
149+
$propertiesAndOptions.= '\i ';
150+
break;
151+
default:
152+
$propertiesAndOptions.= $option .' ';
153+
}
154+
}
155+
return $propertiesAndOptions;
156+
}
122157
}

tests/PhpWord/Element/FieldTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,23 @@ public function testConstructWithTypePropertiesOptionsText()
8484
$this->assertEquals('FieldValue', $oField->getText());
8585
}
8686

87+
/**
88+
* New instance with type and properties and options and text as TextRun
89+
*/
90+
public function testConstructWithTypePropertiesOptionsTextAsTextRun()
91+
{
92+
$textRun = new TextRun();
93+
$textRun->addText('test string');
94+
95+
$oField = new Field('XE', array(), array('Bold', 'Italic'), $textRun);
96+
97+
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField);
98+
$this->assertEquals('XE', $oField->getType());
99+
$this->assertEquals(array(), $oField->getProperties());
100+
$this->assertEquals(array('Bold', 'Italic'), $oField->getOptions());
101+
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oField->getText());
102+
}
103+
87104
public function testConstructWithOptionValue()
88105
{
89106
$oField = new Field('INDEX', array(), array('\\c "3" \\h "A"'));

tests/PhpWord/Writer/Word2007/ElementTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PhpOffice\Common\XMLWriter;
2020
use PhpOffice\PhpWord\PhpWord;
2121
use PhpOffice\PhpWord\TestHelperDOCX;
22+
use PhpOffice\PhpWord\Element\TextRun;
2223

2324
/**
2425
* Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace
@@ -210,6 +211,33 @@ public function testFieldElement()
210211
$this->assertEquals(' INDEX \\c "3" ', $doc->getElement($element)->textContent);
211212
}
212213

214+
public function testFieldElementWithComplexText()
215+
{
216+
$phpWord = new PhpWord();
217+
$section = $phpWord->addSection();
218+
219+
$text = new TextRun();
220+
$text->addText('test string', array('bold' => true));
221+
222+
$section->addField('XE', [], ['Bold', 'Italic'], $text);
223+
$doc = TestHelperDOCX::getDocument($phpWord);
224+
225+
$element = '/w:document/w:body/w:p/w:r[2]/w:instrText';
226+
$this->assertTrue($doc->elementExists($element));
227+
$this->assertEquals(' XE "', $doc->getElement($element)->textContent);
228+
229+
$element = '/w:document/w:body/w:p/w:r[3]/w:rPr/w:b';
230+
$this->assertTrue($doc->elementExists($element));
231+
232+
$element = '/w:document/w:body/w:p/w:r[3]/w:t';
233+
$this->assertTrue($doc->elementExists($element));
234+
$this->assertEquals('test string', $doc->getElement($element)->textContent);
235+
236+
$element = '/w:document/w:body/w:p/w:r[4]/w:instrText';
237+
$this->assertTrue($doc->elementExists($element));
238+
$this->assertEquals('"\\b \\i ', $doc->getElement($element)->textContent);
239+
}
240+
213241
/**
214242
* Test form fields
215243
*/

0 commit comments

Comments
 (0)