improve `cloneBlock` regex

it wrongly matched `<w:pPr` when looking for `<w:p`

in that case the cloned block would not be valid XML,
and so the generated docx document could not be opened by Word

adding the `\b` word boundary to the regex fixes this.

the accompanying unit test failed with this message when trying to load
the generated file:

```
ErrorException: DOMDocument::loadXML(): Opening and ending tag mismatch:
p line 2 and body in Entity, line: 2
```

This might solve issues such as #681 and #664.
This commit is contained in:
Nicolas Dermine 2018-02-02 16:19:21 +01:00
parent 9a91d54e10
commit 4105a9aad1
2 changed files with 53 additions and 1 deletions

View File

@ -322,7 +322,7 @@ class TemplateProcessor
{
$xmlBlock = null;
preg_match(
'/(<\?xml.*)(<w:p.*>\${' . $blockname . '}<\/w:.*?p>)(.*)(<w:p.*\${\/' . $blockname . '}<\/w:.*?p>)/is',
'/(<\?xml.*)(<w:p\b.*>\${' . $blockname . '}<\/w:.*?p>)(.*)(<w:p\b.*\${\/' . $blockname . '}<\/w:.*?p>)/is',
$this->tempDocumentMainPart,
$matches
);

View File

@ -223,4 +223,56 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase
unlink($docName);
$this->assertTrue($docFound);
}
/**
* @covers ::cloneBlock
* @test
*/
public function cloneBlockCanCloneABlockTwice()
{
// create template with placeholders and block
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$documentElements = array(
'Title: ${title}',
'${subreport}',
'${subreport.id}: ${subreport.text}. ',
'${/subreport}',
);
foreach ($documentElements as $documentElement) {
$section->addText($documentElement);
}
$objWriter = IOFactory::createWriter($phpWord);
$templatePath = 'test.docx';
$objWriter->save($templatePath);
// replace placeholders and save the file
$templateProcessor = new TemplateProcessor($templatePath);
$templateProcessor->setValue('title', 'Some title');
$templateProcessor->cloneBlock('subreport', 2);
$templateProcessor->setValue('subreport.id', '123', 1);
$templateProcessor->setValue('subreport.text', 'Some text', 1);
$templateProcessor->setValue('subreport.id', '456', 1);
$templateProcessor->setValue('subreport.text', 'Some other text', 1);
$templateProcessor->saveAs($templatePath);
// assert the block has been cloned twice
// and the placeholders have been replaced correctly
$phpWord = IOFactory::load($templatePath);
$sections = $phpWord->getSections();
$actualElements = $sections[0]->getElements();
unlink($templatePath);
$expectedElements = array(
'Title: Some title',
'123: Some text. ',
'456: Some other text. ',
);
$this->assertCount(count($expectedElements), $actualElements);
foreach ($expectedElements as $i => $expectedElement) {
$this->assertEquals(
$expectedElement,
$actualElements[$i]->getText()
);
}
}
}