Merge pull request #2104 from simivar/feature/delete-row

Introduce deleteRow() method for TemplateProcessor
This commit is contained in:
Adrien Crivelli 2022-11-16 21:58:25 +01:00 committed by GitHub
commit 14c6e6f370
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 0 deletions

View File

@ -759,6 +759,70 @@ class TemplateProcessor
$this->tempDocumentMainPart = $result;
}
/**
* Delete a table row in a template document.
*/
public function deleteRow(string $search): void
{
if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) {
$search = '${' . $search . '}';
}
$tagPos = strpos($this->tempDocumentMainPart, $search);
if (!$tagPos) {
throw new Exception(sprintf('Can not delete row %s, template variable not found or variable contains markup.', $search));
}
$tableStart = $this->findTableStart($tagPos);
$tableEnd = $this->findTableEnd($tagPos);
$xmlTable = $this->getSlice($tableStart, $tableEnd);
if (substr_count($xmlTable, '<w:tr') === 1) {
$this->tempDocumentMainPart = $this->getSlice(0, $tableStart) . $this->getSlice($tableEnd);
return;
}
$rowStart = $this->findRowStart($tagPos);
$rowEnd = $this->findRowEnd($tagPos);
$xmlRow = $this->getSlice($rowStart, $rowEnd);
$this->tempDocumentMainPart = $this->getSlice(0, $rowStart) . $this->getSlice($rowEnd);
// Check if there's a cell spanning multiple rows.
if (preg_match('#<w:vMerge w:val="restart"/>#', $xmlRow)) {
$extraRowStart = $rowStart;
while (true) {
$extraRowStart = $this->findRowStart($extraRowStart + 1);
$extraRowEnd = $this->findRowEnd($extraRowStart + 1);
// If extraRowEnd is lower then 7, there was no next row found.
if ($extraRowEnd < 7) {
break;
}
// If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.
$tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd);
if (!preg_match('#<w:vMerge/>#', $tmpXmlRow) &&
!preg_match('#<w:vMerge w:val="continue" />#', $tmpXmlRow)
) {
break;
}
$tableStart = $this->findTableStart($extraRowEnd + 1);
$tableEnd = $this->findTableEnd($extraRowEnd + 1);
$xmlTable = $this->getSlice($tableStart, $tableEnd);
if (substr_count($xmlTable, '<w:tr') === 1) {
$this->tempDocumentMainPart = $this->getSlice(0, $tableStart) . $this->getSlice($tableEnd);
return;
}
$this->tempDocumentMainPart = $this->getSlice(0, $extraRowStart) . $this->getSlice($extraRowEnd);
}
}
}
/**
* Clones a table row and populates it's values from a two-dimensional array in a template document.
*
@ -1079,6 +1143,39 @@ class TemplateProcessor
return '[Content_Types].xml';
}
/**
* Find the start position of the nearest table before $offset.
*/
protected function findTableStart(int $offset): int
{
$rowStart = strrpos(
$this->tempDocumentMainPart,
'<w:tbl ',
((strlen($this->tempDocumentMainPart) - $offset) * -1)
);
if (!$rowStart) {
$rowStart = strrpos(
$this->tempDocumentMainPart,
'<w:tbl>',
((strlen($this->tempDocumentMainPart) - $offset) * -1)
);
}
if (!$rowStart) {
throw new Exception('Can not find the start position of the table.');
}
return $rowStart;
}
/**
* Find the end position of the nearest table row after $offset.
*/
protected function findTableEnd(int $offset): int
{
return strpos($this->tempDocumentMainPart, '</w:tbl>', $offset) + 7;
}
/**
* Find the start position of the nearest table row before $offset.
*

View File

@ -182,6 +182,32 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase
@$templateProcessor->applyXslStyleSheet($xslDomDocument);
}
/**
* @covers ::deleteRow
* @covers ::getVariables
* @covers ::saveAs
*/
public function testDeleteRow(): void
{
$templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx');
self::assertEquals(
['deleteMe', 'deleteMeToo'],
$templateProcessor->getVariables()
);
$docName = 'delete-row-test-result.docx';
$templateProcessor->deleteRow('deleteMe');
self::assertEquals(
[],
$templateProcessor->getVariables()
);
$templateProcessor->saveAs($docName);
$docFound = file_exists($docName);
unlink($docName);
self::assertTrue($docFound);
}
/**
* @covers ::cloneRow
* @covers ::saveAs

Binary file not shown.