From 1d6365cd3e39cefd0f934b9a93dbbbdabcaef249 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:23:49 -0800 Subject: [PATCH 1/3] TemplateProcessor SetComplexBlock/Value and Sections Fix #2561. Allow the TemplateProcessor methods `setComplexBlock` and `setComplexValue` to work with Sections. --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/TemplateProcessor.php | 6 ++ .../TemplateProcessorSectionTest.php | 89 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/PhpWordTests/TemplateProcessorSectionTest.php diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 575510b222..35308cb7c8 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -9,6 +9,7 @@ ### Bug fixes - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) +- TemplateProcessor setComplexBlock/Value and Section by [@oleibman](https://github.com/oleibman) fixing [#2561](https://github.com/PHPOffice/PHPWord/issues/2561) in [#2562](https://github.com/PHPOffice/PHPWord/pull/2562) - TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 8aee40c546..c8f7956d56 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -278,6 +278,9 @@ protected static function ensureUtf8Encoded($subject) public function setComplexValue($search, Element\AbstractElement $complexType): void { $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1); + if ($elementName === 'Section') { + $elementName = 'Container'; + } $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; $xmlWriter = new XMLWriter(); @@ -305,6 +308,9 @@ public function setComplexValue($search, Element\AbstractElement $complexType): public function setComplexBlock($search, Element\AbstractElement $complexType): void { $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1); + if ($elementName === 'Section') { + $elementName = 'Container'; + } $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; $xmlWriter = new XMLWriter(); diff --git a/tests/PhpWordTests/TemplateProcessorSectionTest.php b/tests/PhpWordTests/TemplateProcessorSectionTest.php new file mode 100644 index 0000000000..e905fcc119 --- /dev/null +++ b/tests/PhpWordTests/TemplateProcessorSectionTest.php @@ -0,0 +1,89 @@ +templateProcessor = new TemplateProcessor($filename); + + return $this->templateProcessor; + } + + protected function tearDown(): void + { + if ($this->templateProcessor !== null) { + $filename = $this->templateProcessor->getTempDocumentFilename(); + $this->templateProcessor = null; + if (file_exists($filename)) { + @unlink($filename); + } + } + } + + public function testSetComplexSection(): void + { + $templateProcessor = $this->getTemplateProcessor('C:/git/sectiontemplate/tests/PhpWordTests/_files/templates/document22-xml.docx'); + $html = ' +

 Bug Report:

+

BugTracker X is ${facing1} an issue.

+

BugTracker X is ${facing2} an issue.

+ '; + $section = new Section(0); + Html::addHtml($section, $html, false, false); + $templateProcessor->setComplexBlock('test', $section); + $facing1 = new TextRun(); + $facing1->addText('facing', ['bold' => true]); + $facing2 = new TextRun(); + $facing2->addText('facing', ['italic' => true]); + + $templateProcessor->setComplexBlock('test', $section); + $templateProcessor->setComplexValue('facing1', $facing1); + $templateProcessor->setComplexValue('facing2', $facing2); + + $docName = $templateProcessor->save(); + $docFound = file_exists($docName); + self::assertTrue($docFound); + $contents = file_get_contents("zip://$docName#word/document2.xml"); + unlink($docName); + self::assertNotFalse($contents); + $contents = preg_replace('/>\s+<', $contents) ?? ''; + self::assertStringContainsString('Test', $contents); + self::assertStringContainsString('facing', $contents, 'bold string found'); + self::assertStringContainsString('facing', $contents, 'italic string found'); + self::assertStringNotContainsString('$', $contents, 'no leftover macros'); + self::assertStringNotContainsString('facing1', $contents, 'no leftover replaced string1'); + self::assertStringNotContainsString('facing2', $contents, 'no leftover replaced string2'); + } +} From 1104358854346a68dd70e2e17e18655f511cf8f5 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:42:02 -0800 Subject: [PATCH 2/3] Typo In Filename --- tests/PhpWordTests/TemplateProcessorSectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWordTests/TemplateProcessorSectionTest.php b/tests/PhpWordTests/TemplateProcessorSectionTest.php index e905fcc119..67f9afff60 100644 --- a/tests/PhpWordTests/TemplateProcessorSectionTest.php +++ b/tests/PhpWordTests/TemplateProcessorSectionTest.php @@ -54,7 +54,7 @@ protected function tearDown(): void public function testSetComplexSection(): void { - $templateProcessor = $this->getTemplateProcessor('C:/git/sectiontemplate/tests/PhpWordTests/_files/templates/document22-xml.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); $html = '

 Bug Report:

BugTracker X is ${facing1} an issue.

From 4d2f85245ba902f33c362f921aed2cec06ffa6fc Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 31 Jan 2024 02:09:58 -0800 Subject: [PATCH 3/3] Permit Multiple Substitutions in setComplexValue It currently makes only one substitution, with no way to determine if there are more. Add an additional optional parameter to allow multiple substitutions; default is false to match current implementation (so no break). --- src/PhpWord/TemplateProcessor.php | 7 ++++++- tests/PhpWordTests/TemplateProcessorSectionTest.php | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index c8f7956d56..56bba43e46 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -275,8 +275,10 @@ protected static function ensureUtf8Encoded($subject) /** * @param string $search */ - public function setComplexValue($search, Element\AbstractElement $complexType): void + public function setComplexValue($search, Element\AbstractElement $complexType, bool $multiple = false): void { + $originalSearch = $search; + $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1); if ($elementName === 'Section') { $elementName = 'Container'; @@ -300,6 +302,9 @@ public function setComplexValue($search, Element\AbstractElement $complexType): $search = static::ensureMacroCompleted($search); $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:r'); + if ($multiple === true) { + $this->setComplexValue($originalSearch, $complexType, true); + } } /** diff --git a/tests/PhpWordTests/TemplateProcessorSectionTest.php b/tests/PhpWordTests/TemplateProcessorSectionTest.php index 67f9afff60..0402d4fc66 100644 --- a/tests/PhpWordTests/TemplateProcessorSectionTest.php +++ b/tests/PhpWordTests/TemplateProcessorSectionTest.php @@ -59,6 +59,7 @@ public function testSetComplexSection(): void

 Bug Report:

BugTracker X is ${facing1} an issue.

BugTracker X is ${facing2} an issue.

+

BugTracker X is ${facing1} an issue.

'; $section = new Section(0); Html::addHtml($section, $html, false, false); @@ -69,7 +70,7 @@ public function testSetComplexSection(): void $facing2->addText('facing', ['italic' => true]); $templateProcessor->setComplexBlock('test', $section); - $templateProcessor->setComplexValue('facing1', $facing1); + $templateProcessor->setComplexValue('facing1', $facing1, true); $templateProcessor->setComplexValue('facing2', $facing2); $docName = $templateProcessor->save(); @@ -80,8 +81,10 @@ public function testSetComplexSection(): void self::assertNotFalse($contents); $contents = preg_replace('/>\s+<', $contents) ?? ''; self::assertStringContainsString('Test', $contents); - self::assertStringContainsString('facing', $contents, 'bold string found'); - self::assertStringContainsString('facing', $contents, 'italic string found'); + $count = substr_count($contents, 'facing'); + self::assertSame(2, $count, 'should be 2 bold strings'); + $count = substr_count($contents, 'facing'); + self::assertSame(1, $count, 'should be 1 italic string'); self::assertStringNotContainsString('$', $contents, 'no leftover macros'); self::assertStringNotContainsString('facing1', $contents, 'no leftover replaced string1'); self::assertStringNotContainsString('facing2', $contents, 'no leftover replaced string2');