diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php
index 7d4209953b..35e101338a 100644
--- a/src/PhpWord/Reader/Word2007/AbstractPart.php
+++ b/src/PhpWord/Reader/Word2007/AbstractPart.php
@@ -21,6 +21,7 @@
use DOMElement;
use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType;
use PhpOffice\PhpWord\Element\AbstractContainer;
+use PhpOffice\PhpWord\Element\FormField;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Element\TrackChange;
use PhpOffice\PhpWord\PhpWord;
@@ -112,8 +113,47 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
$headingDepth = $this->getHeadingDepth($paragraphStyle);
}
- // PreserveText
- if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) {
+ if ($xmlReader->elementExists('w:r/w:fldChar/w:ffData', $domNode)) {
+ // FormField
+ $partOfFormField = false;
+ $formNodes = [];
+ $formType = null;
+// $field = new FormField("type", "forntsyle", "paragraphstyle"):
+ $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag', $domNode);
+ if (0 === $textRunContainers) {
+ $parent->addTextBreak(null, $paragraphStyle);
+ } else {
+ $nodes = $xmlReader->getElements('*', $domNode);
+ $paragraph = $parent->addTextRun($paragraphStyle);
+ foreach ($nodes as $node) {
+ if ($xmlReader->elementExists('w:fldChar/w:ffData', $node)) {
+ $partOfFormField = true;
+ $formNodes[] = $node;
+ if ($xmlReader->elementExists('w:fldChar/w:ffData/w:ddList', $node)) {
+ $formType = 'dropdown';
+ } elseif ($xmlReader->elementExists('w:fldChar/w:ffData/w:textInput', $node)) {
+ $formType = 'textinput';
+ } elseif ($xmlReader->elementExists('w:fldChar/w:ffData/w:checkBox', $node)) {
+ $formType = 'checkbox';
+ }
+ } elseif ($partOfFormField &&
+ $xmlReader->elementExists('w:fldChar', $node) &&
+ 'end' == $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar')
+ ) {
+ $formNodes[] = $node;
+ $partOfFormField = false;
+ // Process the form fields
+ $this->readFormField($xmlReader, $formNodes, $paragraph, $paragraphStyle, $formType);
+ } elseif ($partOfFormField) {
+ $formNodes[] = $node;
+ } else {
+ // normal runs
+ $this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle);
+ }
+ }
+ }
+ } elseif ($xmlReader->elementExists('w:r/w:instrText', $domNode)) {
+ // PreserveText
$ignoreText = false;
$textContent = '';
$fontStyle = $this->readFontStyle($xmlReader, $domNode);
@@ -176,6 +216,109 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
}
}
+ /**
+ * @param DOMElement[] $domNodes
+ * @param AbstractContainer $parent
+ * @param mixed $paragraphStyle
+ * @param string $formType
+ */
+ private function readFormField(XMLReader $xmlReader, array $domNodes, $parent, $paragraphStyle, $formType): void
+ {
+ if (!in_array($formType, ['textinput', 'checkbox', 'dropdown'])) {
+ return;
+ }
+
+ $formField = $parent->addFormField($formType, null, $paragraphStyle);
+ $ffData = $xmlReader->getElement('w:fldChar/w:ffData', $domNodes[0]);
+
+ foreach ($xmlReader->getElements('*', $ffData) as $node) {
+ /** @var DOMElement $node */
+ switch ($node->localName) {
+ case 'name':
+ $formField->setName($node->getAttribute('w:val'));
+
+ break;
+ case 'ddList':
+ $listEntries = [];
+ foreach ($xmlReader->getElements('*', $node) as $ddListNode) {
+ switch ($ddListNode->localName) {
+ case 'result':
+ $formField->setValue($xmlReader->getAttribute('w:val', $ddListNode));
+
+ break;
+ case 'default':
+ $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode));
+
+ break;
+ case 'listEntry':
+ $listEntries[] = $xmlReader->getAttribute('w:val', $ddListNode);
+
+ break;
+ }
+ }
+ $formField->setEntries($listEntries);
+ if (null !== $formField->getValue()) {
+ $formField->setText($listEntries[$formField->getValue()]);
+ }
+
+ break;
+ case 'textInput':
+ foreach ($xmlReader->getElements('*', $node) as $ddListNode) {
+ switch ($ddListNode->localName) {
+ case 'default':
+ $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode));
+
+ break;
+ case 'format':
+ case 'maxLength':
+ break;
+ }
+ }
+
+ break;
+ case 'checkBox':
+ foreach ($xmlReader->getElements('*', $node) as $ddListNode) {
+ switch ($ddListNode->localName) {
+ case 'default':
+ $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode));
+
+ break;
+ case 'checked':
+ $formField->setValue($xmlReader->getAttribute('w:val', $ddListNode));
+
+ break;
+ case 'size':
+ case 'sizeAuto':
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ if ('textinput' == $formType) {
+ $ignoreText = true;
+ $textContent = '';
+ foreach ($domNodes as $node) {
+ if ($xmlReader->elementExists('w:fldChar', $node)) {
+ $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar');
+ if ('separate' == $fldCharType) {
+ $ignoreText = false;
+ } elseif ('end' == $fldCharType) {
+ $ignoreText = true;
+ }
+ }
+
+ if (false === $ignoreText) {
+ $textContent .= $xmlReader->getValue('w:t', $node);
+ }
+ }
+ $formField->setValue(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'));
+ $formField->setText(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'));
+ }
+ }
+
/**
* Returns the depth of the Heading, returns 0 for a Title.
*
diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php
index 8403f44f7b..cd34cf2af5 100644
--- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php
+++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php
@@ -312,4 +312,192 @@ public function testReadDrawing(): void
$elements = $phpWord->getSection(0)->getElements();
self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
}
+
+ /**
+ * Test reading FormField - DROPDOWN.
+ */
+ public function testReadFormFieldDropdown(): void
+ {
+ $documentXml = '
+
+ Reference
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FORMDROPDOWN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+
+ $subElements = $elements[0]->getElements();
+
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $subElements[0]);
+ self::assertEquals('Reference', $subElements[0]->getText());
+
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\FormField', $subElements[1]);
+ self::assertEquals('dropdown', $subElements[1]->getType());
+ self::assertEquals('DropDownList1', $subElements[1]->getName());
+ self::assertEquals('2', $subElements[1]->getValue());
+ self::assertEquals('Option Two', $subElements[1]->getText());
+ self::assertEquals(['TBD', 'Option One', 'Option Two', 'Option Three', 'Other'], $subElements[1]->getEntries());
+ }
+
+ /**
+ * Test reading FormField - textinput.
+ */
+ public function testReadFormFieldTextinput(): void
+ {
+ $documentXml = '
+
+ Fieldname
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FORMTEXT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is some sample text
+
+
+
+
+
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+
+ $subElements = $elements[0]->getElements();
+
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $subElements[0]);
+ self::assertEquals('Fieldname', $subElements[0]->getText());
+
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\FormField', $subElements[1]);
+ self::assertEquals('textinput', $subElements[1]->getType());
+ self::assertEquals('TextInput2', $subElements[1]->getName());
+ self::assertEquals('This is some sample text', $subElements[1]->getValue());
+ self::assertEquals('This is some sample text', $subElements[1]->getText());
+ }
+
+ /**
+ * Test reading FormField - checkbox.
+ */
+ public function testReadFormFieldCheckbox(): void
+ {
+ $documentXml = '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FORMCHECKBOX
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+
+ $subElements = $elements[0]->getElements();
+
+// $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $subElements[0]);
+// $this->assertEquals('Fieldname', $subElements[0]->getText());
+
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\FormField', $subElements[0]);
+ self::assertEquals('checkbox', $subElements[0]->getType());
+ self::assertEquals('SomeCheckbox', $subElements[0]->getName());
+ }
}