diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index a299d15b41..06a7ba3675 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -7,6 +7,7 @@ - IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) - PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) - Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651) +- Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652) ### Bug fixes diff --git a/docs/usage/elements/field.md b/docs/usage/elements/field.md index fe8e9756fc..1cafd18ef8 100644 --- a/docs/usage/elements/field.md +++ b/docs/usage/elements/field.md @@ -8,6 +8,7 @@ Currently the following fields are supported: - XE - INDEX - FILENAME +- REF ``` php addText('My '); $fieldText->addText('bold index', ['bold' => true]); $fieldText->addText(' entry'); $section->addField('XE', array(), array(), $fieldText); -//this actually adds the index +// this actually adds the index $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index'); + +// Adding reference to a bookmark +$fieldText->addField('REF', [ + 'name' => 'bookmark' +], [ + 'InsertParagraphNumberRelativeContext', + 'CreateHyperLink', +]); ``` diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index b371bb80d7..a828aaa02e 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -91,6 +91,10 @@ class Field extends AbstractElement ], 'options' => ['Path', 'PreserveFormat'], ], + 'REF' => [ + 'properties' => ['name' => ''], + 'options' => ['f', 'h', 'n', 'p', 'r', 't', 'w'], + ], ]; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 4d7c2a0b46..2977c01626 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\Field as ElementField; +use PhpOffice\PhpWord\Element\TextRun; + /** * Field element writer. * @@ -30,7 +33,7 @@ class Field extends Text public function write(): void { $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + if (!$element instanceof ElementField) { return; } @@ -42,7 +45,7 @@ public function write(): void } } - private function writeDefault(\PhpOffice\PhpWord\Element\Field $element): void + private function writeDefault(ElementField $element): void { $xmlWriter = $this->getXmlWriter(); $this->startElementP(); @@ -73,7 +76,7 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element): void $xmlWriter->endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + if ($element->getText() instanceof TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); @@ -120,7 +123,7 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element): void * * //TODO A lot of code duplication with general method, should maybe be refactored */ - protected function writeMacrobutton(\PhpOffice\PhpWord\Element\Field $element): void + protected function writeMacrobutton(ElementField $element): void { $xmlWriter = $this->getXmlWriter(); $this->startElementP(); @@ -159,7 +162,7 @@ protected function writeMacrobutton(\PhpOffice\PhpWord\Element\Field $element): $this->endElementP(); // w:p } - private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element) + private function buildPropertiesAndOptions(ElementField $element) { $propertiesAndOptions = ''; $properties = $element->getProperties(); @@ -226,4 +229,104 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele return $propertiesAndOptions; } + + /** + * Writes a REF field. + */ + protected function writeRef(ElementField $element): void + { + $xmlWriter = $this->getXmlWriter(); + $this->startElementP(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $instruction = ' ' . $element->getType() . ' '; + + foreach ($element->getProperties() as $property) { + $instruction .= $property . ' '; + } + foreach ($element->getOptions() as $optionKey => $optionValue) { + $instruction .= $this->convertRefOption($optionKey, $optionValue) . ' '; + } + + $xmlWriter->startElement('w:r'); + $this->writeFontStyle(); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text($instruction); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + if ($element->getText() != null) { + if ($element->getText() instanceof \PhpOffice\PhpWord\Element\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'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:noProof'); + $xmlWriter->endElement(); // w:noProof + $xmlWriter->endElement(); // w:rPr + $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'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $this->endElementP(); // w:p + } + + private function convertRefOption(string $optionKey, string $optionValue): string + { + if ($optionKey === 'NumberSeperatorSequence') { + return '\\d ' . $optionValue; + } + + switch ($optionValue) { + case 'IncrementAndInsertText': + return '\\f'; + case 'CreateHyperLink': + return '\\h'; + case 'NoTrailingPeriod': + return '\\n'; + case 'IncludeAboveOrBelow': + return '\\p'; + case 'InsertParagraphNumberRelativeContext': + return '\\r'; + case 'SuppressNonDelimiterNonNumericalText': + return '\\t'; + case 'InsertParagraphNumberFullContext': + return '\\w'; + default: + return ''; + } + } } diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php new file mode 100644 index 0000000000..30f875c08c --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php @@ -0,0 +1,73 @@ +addSection(); + $section->addField( + 'REF', + [ + 'name' => 'my-bookmark', + ], + [ + 'InsertParagraphNumberRelativeContext', + 'CreateHyperLink', + ] + ); + + $section->addListItem('line one item'); + $section->addListItem('line two item'); + $section->addBookmark('my-bookmark'); + $section->addListItem('line three item'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $refFieldPath = '/w:document/w:body/w:p[1]/w:r[2]/w:instrText'; + self::assertTrue($doc->elementExists($refFieldPath)); + + $bookMarkElement = $doc->getElement($refFieldPath); + self::assertNotNull($bookMarkElement); + self::assertEquals(' REF my-bookmark \r \h ', $bookMarkElement->textContent); + + $bookmarkPath = '/w:document/w:body/w:bookmarkStart'; + self::assertTrue($doc->elementExists($bookmarkPath)); + self::assertEquals('my-bookmark', $doc->getElementAttribute("$bookmarkPath", 'w:name')); + } +}