From 8aabf812f8bd27ba49e251d904f4953b6b91cca5 Mon Sep 17 00:00:00 2001 From: antoine Date: Sun, 11 Jun 2017 12:56:59 +0200 Subject: [PATCH] update XE field to support formatted text + add documentation --- docs/elements.rst | 30 +++- samples/Sample_27_Field.php | 16 ++- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/Field.php | 11 +- src/PhpWord/Writer/Word2007/Element/Field.php | 129 +++++++++++------- tests/PhpWord/Element/FieldTest.php | 17 +++ tests/PhpWord/Writer/Word2007/ElementTest.php | 28 ++++ 7 files changed, 177 insertions(+), 56 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index d68ee035..b753ddf7 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -358,7 +358,35 @@ To be completed Fields ------ -To be completed +Currently the following fields are supported: + +- PAGE +- NUMPAGES +- DATE +- XE +- INDEX + +.. code-block:: php + + $section->addField($fieldType, [$properties], [$options], [$fieldText]) + +See ``\PhpOffice\PhpWord\Element\Field`` for list of properties and options available for each field type. +Options which are not specifically defined can be added. Those must start with a ``\``. + +For instance for the INDEX field, you can do the following (See `Index Field for list of available options `_ ): + +.. code-block:: php + + //the $fieldText can be either a simple string + $fieldText = 'The index value'; + + //or a 'TextRun', to be able to format the text you want in the index + $fieldText = new TextRun(); + $fieldText->addText('My '); + $fieldText->addText('bold index', ['bold' => true]); + $fieldText->addText(' entry'); + + $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), $fieldText); Line ------ diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 7e2b968e..b5be12ca 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -1,4 +1,6 @@ addField('NUMPAGES', array('numformat' => '0,00', 'format' => 'Arabic' $textrun = $section->addTextRun(); $textrun->addText('An index field is '); -$textrun->addField('XE', array(), array('Bold'), 'FieldValue'); +$textrun->addField('XE', array(), array('Italic'), 'My first index'); +$textrun->addText('here:'); + +$indexEntryText = new TextRun(); +$indexEntryText->addText('My '); +$indexEntryText->addText('bold index', ['bold' => true]); +$indexEntryText->addText(' entry'); + +$textrun = $section->addTextRun(); +$textrun->addText('A complex index field is '); +$textrun->addField('XE', array(), array('Bold'), $indexEntryText); $textrun->addText('here:'); $section->addText('The actual index:'); -$section->addField('INDEX', array(), array('PreserveFormat')); +$section->addField('INDEX', array(), array('\\e " "'), 'right click to update the index'); $textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $textrun->addText('This is the date of lunar calendar '); diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index a3872e0b..0107006f 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -39,7 +39,7 @@ namespace PhpOffice\PhpWord\Element; * @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false) * @method Object addObject(string $source, mixed $style = null) * @method TextBox addTextBox(mixed $style = null) - * @method Field addField(string $type = null, array $properties = array(), array $options = array()) + * @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null) * @method Line addLine(mixed $lineStyle = null) * @method Shape addShape(string $type, mixed $style = null) * @method Chart addChart(string $type, array $categories, array $values, array $style = null) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index bdfdcb40..380d7a92 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -74,7 +74,7 @@ class Field extends AbstractElement /** * Field text * - * @var string + * @var TextRun | string */ protected $text; @@ -98,6 +98,7 @@ class Field extends AbstractElement * @param string $type * @param array $properties * @param array $options + * @param TextRun | string $text */ public function __construct($type = null, $properties = array(), $options = array(), $text = null) { @@ -205,16 +206,16 @@ class Field extends AbstractElement /** * Set Field text * - * @param string $text + * @param string | TextRun $text * - * @return string + * @return string | TextRun * * @throws \InvalidArgumentException */ public function setText($text) { if (isset($text)) { - if (is_string($text)) { + if (is_string($text) || $text instanceof TextRun) { $this->text = $text; } else { throw new \InvalidArgumentException("Invalid text"); @@ -226,7 +227,7 @@ class Field extends AbstractElement /** * Get Field text * - * @return string + * @return string | TextRun */ public function getText() { diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 802803db..a79683e2 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\TextRun; + /** * Field element writer * @@ -37,51 +39,6 @@ class Field extends Text return; } - $instruction = ' ' . $element->getType() . ' '; - if ($element->getText() != null) { - $instruction .= '"' . $element->getText() . '" '; - } - $properties = $element->getProperties(); - foreach ($properties as $propkey => $propval) { - switch ($propkey) { - case 'format': - $instruction .= '\* ' . $propval . ' '; - break; - case 'numformat': - $instruction .= '\# ' . $propval . ' '; - break; - case 'dateformat': - $instruction .= '\@ "' . $propval . '" '; - break; - } - } - - $options = $element->getOptions(); - foreach ($options as $option) { - switch ($option) { - case 'PreserveFormat': - $instruction .= '\* MERGEFORMAT '; - break; - case 'LunarCalendar': - $instruction .= '\h '; - break; - case 'SakaEraCalendar': - $instruction .= '\s '; - break; - case 'LastUsedFormat': - $instruction .= '\l '; - break; - case 'Bold': - $instruction .= '\b '; - break; - case 'Italic': - $instruction .= '\i '; - break; - default: - $instruction .= $option .' '; - } - } - $this->startElementP(); $xmlWriter->startElement('w:r'); @@ -90,6 +47,17 @@ class Field extends Text $xmlWriter->endElement(); // w:fldChar $xmlWriter->endElement(); // w:r + $instruction = ' ' . $element->getType() . ' '; + if ($element->getText() != null) { + if (is_string($element->getText())) { + $instruction .= '"' . $element->getText() . '" '; + $instruction .= $this->buildPropertiesAndOptions($element); + } else { + $instruction .= '"'; + } + } else { + $instruction .= $this->buildPropertiesAndOptions($element); + } $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); @@ -97,6 +65,27 @@ class Field extends Text $xmlWriter->endElement(); // w:instrText $xmlWriter->endElement(); // w:r + if ($element->getText() != null) { + if ($element->getText() instanceof TextRun) { + + $containerWriter = new Container($xmlWriter, $element->getText(), true); + $containerWriter->write(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->text('"' . $this->buildPropertiesAndOptions($element)); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text(' '); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + } + } + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); $xmlWriter->writeAttribute('w:fldCharType', 'separate'); @@ -108,9 +97,9 @@ class Field extends Text $xmlWriter->startElement('w:noProof'); $xmlWriter->endElement(); // w:noProof $xmlWriter->endElement(); // w:rPr - $xmlWriter->writeElement('w:t', $element->getText() == null ? '1' : $element->getText()); + $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1'); $xmlWriter->endElement(); // w:r - + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); $xmlWriter->writeAttribute('w:fldCharType', 'end'); @@ -119,4 +108,50 @@ class Field extends Text $this->endElementP(); // w:p } + + private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element) + { + $propertiesAndOptions = ''; + $properties = $element->getProperties(); + foreach ($properties as $propkey => $propval) { + switch ($propkey) { + case 'format': + $propertiesAndOptions.= '\* ' . $propval . ' '; + break; + case 'numformat': + $propertiesAndOptions.= '\# ' . $propval . ' '; + break; + case 'dateformat': + $propertiesAndOptions.= '\@ "' . $propval . '" '; + break; + } + } + + $options = $element->getOptions(); + foreach ($options as $option) { + switch ($option) { + case 'PreserveFormat': + $propertiesAndOptions.= '\* MERGEFORMAT '; + break; + case 'LunarCalendar': + $propertiesAndOptions.= '\h '; + break; + case 'SakaEraCalendar': + $propertiesAndOptions.= '\s '; + break; + case 'LastUsedFormat': + $propertiesAndOptions.= '\l '; + break; + case 'Bold': + $propertiesAndOptions.= '\b '; + break; + case 'Italic': + $propertiesAndOptions.= '\i '; + break; + default: + $propertiesAndOptions.= $option .' '; + } + } + return $propertiesAndOptions; + } } diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index 415aaa0b..6f5ebbbf 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -84,6 +84,23 @@ class FieldTest extends \PHPUnit_Framework_TestCase $this->assertEquals('FieldValue', $oField->getText()); } + /** + * New instance with type and properties and options and text as TextRun + */ + public function testConstructWithTypePropertiesOptionsTextAsTextRun() + { + $textRun = new TextRun(); + $textRun->addText('test string'); + + $oField = new Field('XE', array(), array('Bold', 'Italic'), $textRun); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals('XE', $oField->getType()); + $this->assertEquals(array(), $oField->getProperties()); + $this->assertEquals(array('Bold', 'Italic'), $oField->getOptions()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oField->getText()); + } + public function testConstructWithOptionValue() { $oField = new Field('INDEX', array(), array('\\c "3" \\h "A"')); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 7208449d..5a04c25b 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Element\TextRun; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace @@ -210,6 +211,33 @@ class ElementTest extends \PHPUnit_Framework_TestCase $this->assertEquals(' INDEX \\c "3" ', $doc->getElement($element)->textContent); } + public function testFieldElementWithComplexText() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $text = new TextRun(); + $text->addText('test string', array('bold' => true)); + + $section->addField('XE', [], ['Bold', 'Italic'], $text); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' XE "', $doc->getElement($element)->textContent); + + $element = '/w:document/w:body/w:p/w:r[3]/w:rPr/w:b'; + $this->assertTrue($doc->elementExists($element)); + + $element = '/w:document/w:body/w:p/w:r[3]/w:t'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('test string', $doc->getElement($element)->textContent); + + $element = '/w:document/w:body/w:p/w:r[4]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('"\\b \\i ', $doc->getElement($element)->textContent); + } + /** * Test form fields */