From 91504dfddc7d5695549576df09f495b8f198a88f Mon Sep 17 00:00:00 2001 From: simivar Date: Wed, 23 Jun 2021 12:07:45 +0200 Subject: [PATCH 1/5] Introduce deleteRow() method for TemplateProcessor --- src/PhpWord/TemplateProcessor.php | 108 ++++++++++++++++++ tests/PhpWordTests/TemplateProcessorTest.php | 27 +++++ .../_files/templates/delete-row.docx | Bin 0 -> 13171 bytes 3 files changed, 135 insertions(+) create mode 100644 tests/PhpWordTests/_files/templates/delete-row.docx diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 1cf32429..c7c5d4ff 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -759,6 +759,77 @@ class TemplateProcessor $this->tempDocumentMainPart = $result; } + /** + * Delete a table row in a template document. + * + * @param string $search + * + * @return void + * + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function deleteRow($search) + { + 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, '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('##', $xmlRow)) { + // $extraRowStart = $rowEnd; + $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('##', $tmpXmlRow) && + !preg_match('##', $tmpXmlRow) + ) { + break; + } + + $tableStart = $this->findTableStart($extraRowEnd + 1); + $tableEnd = $this->findTableEnd($extraRowEnd + 1); + $xmlTable = $this->getSlice($tableStart, $tableEnd); + if (substr_count($xmlTable, '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 +1150,43 @@ class TemplateProcessor return '[Content_Types].xml'; } + /** + * Find the start position of the nearest table before $offset. + * + * @param integer $offset + * + * @return integer + * + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + protected function findTableStart($offset) + { + $rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1)); + + if (!$rowStart) { + $rowStart = strrpos($this->tempDocumentMainPart, '', + ((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. + * + * @param integer $offset + * + * @return integer + */ + protected function findTableEnd($offset) + { + return strpos($this->tempDocumentMainPart, '', $offset) + 7; + } + /** * Find the start position of the nearest table row before $offset. * diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index fc975fab..1efe6601 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -182,6 +182,33 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase @$templateProcessor->applyXslStyleSheet($xslDomDocument); } + /** + * @covers ::getVariables + * @covers ::deleteRow + * @covers ::saveAs + * @test + */ + public function testDeleteRow() + { + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx'); + + $this->assertEquals( + array('deleteMe', 'deleteMeToo'), + $templateProcessor->getVariables() + ); + + $docName = 'delete-row-test-result.docx'; + $templateProcessor->deleteRow('deleteMe'); + $this->assertEquals( + array(), + $templateProcessor->getVariables() + ); + $templateProcessor->saveAs($docName); + $docFound = file_exists($docName); + unlink($docName); + $this->assertTrue($docFound); + } + /** * @covers ::cloneRow * @covers ::saveAs diff --git a/tests/PhpWordTests/_files/templates/delete-row.docx b/tests/PhpWordTests/_files/templates/delete-row.docx new file mode 100644 index 0000000000000000000000000000000000000000..dd8d8a3188d7b6b103783a8264b58d442a756b71 GIT binary patch literal 13171 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 literal 0 HcmV?d00001 From 9a6eb6970d7b22b55381cd9065db7ab576e1a67c Mon Sep 17 00:00:00 2001 From: Krystian Marcisz Date: Sun, 6 Nov 2022 19:01:51 +0100 Subject: [PATCH 2/5] Update src/PhpWord/TemplateProcessor.php Co-authored-by: Progi1984 --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index c7c5d4ff..d46e28a2 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -768,7 +768,7 @@ class TemplateProcessor * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function deleteRow($search) + public function deleteRow(string $search): void { if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { $search = '${' . $search . '}'; From 4b7e7e46121904ccccddcdca40a99e1ab72144eb Mon Sep 17 00:00:00 2001 From: Krystian Marcisz Date: Sun, 6 Nov 2022 19:01:58 +0100 Subject: [PATCH 3/5] Update src/PhpWord/TemplateProcessor.php Co-authored-by: Progi1984 --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index d46e28a2..176d9cc4 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1159,7 +1159,7 @@ class TemplateProcessor * * @throws \PhpOffice\PhpWord\Exception\Exception */ - protected function findTableStart($offset) + protected function findTableStart(int $offset): int { $rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1)); From 46e61d4c1845d0f222d353fbf04b950c797beeab Mon Sep 17 00:00:00 2001 From: Krystian Marcisz Date: Sun, 6 Nov 2022 19:02:32 +0100 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Progi1984 --- src/PhpWord/TemplateProcessor.php | 3 +-- tests/PhpWordTests/TemplateProcessorTest.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 176d9cc4..f2438338 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -797,7 +797,6 @@ class TemplateProcessor // Check if there's a cell spanning multiple rows. if (preg_match('##', $xmlRow)) { - // $extraRowStart = $rowEnd; $extraRowStart = $rowStart; while (true) { $extraRowStart = $this->findRowStart($extraRowStart + 1); @@ -1182,7 +1181,7 @@ class TemplateProcessor * * @return integer */ - protected function findTableEnd($offset) + protected function findTableEnd(int $offset): int { return strpos($this->tempDocumentMainPart, '', $offset) + 7; } diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 1efe6601..61f76528 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -188,7 +188,7 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase * @covers ::saveAs * @test */ - public function testDeleteRow() + public function testDeleteRow(): void { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx'); From f482f2600bfa8c0e7b82c2b3f541544f99ee223f Mon Sep 17 00:00:00 2001 From: simivar Date: Mon, 7 Nov 2022 22:38:19 +0100 Subject: [PATCH 5/5] CS Fixer --- src/PhpWord/TemplateProcessor.php | 36 +++++++------------- tests/PhpWordTests/TemplateProcessorTest.php | 13 ++++--- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f2438338..6f1ba922 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -761,12 +761,6 @@ class TemplateProcessor /** * Delete a table row in a template document. - * - * @param string $search - * - * @return void - * - * @throws \PhpOffice\PhpWord\Exception\Exception */ public function deleteRow(string $search): void { @@ -776,7 +770,7 @@ class TemplateProcessor $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)); + throw new Exception(sprintf('Can not delete row %s, template variable not found or variable contains markup.', $search)); } $tableStart = $this->findTableStart($tagPos); @@ -1151,21 +1145,21 @@ class TemplateProcessor /** * Find the start position of the nearest table before $offset. - * - * @param integer $offset - * - * @return integer - * - * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function findTableStart(int $offset): int { - $rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1)); + $rowStart = strrpos( + $this->tempDocumentMainPart, + 'tempDocumentMainPart) - $offset) * -1) + ); if (!$rowStart) { - $rowStart = strrpos($this->tempDocumentMainPart, '', - ((strlen($this->tempDocumentMainPart) - $offset) * -1)); + $rowStart = strrpos( + $this->tempDocumentMainPart, + '', + ((strlen($this->tempDocumentMainPart) - $offset) * -1) + ); } if (!$rowStart) { throw new Exception('Can not find the start position of the table.'); @@ -1175,12 +1169,8 @@ class TemplateProcessor } /** - * Find the end position of the nearest table row after $offset. - * - * @param integer $offset - * - * @return integer - */ + * Find the end position of the nearest table row after $offset. + */ protected function findTableEnd(int $offset): int { return strpos($this->tempDocumentMainPart, '', $offset) + 7; diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 61f76528..e57e5bf1 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -183,30 +183,29 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase } /** - * @covers ::getVariables * @covers ::deleteRow + * @covers ::getVariables * @covers ::saveAs - * @test */ public function testDeleteRow(): void { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx'); - $this->assertEquals( - array('deleteMe', 'deleteMeToo'), + self::assertEquals( + ['deleteMe', 'deleteMeToo'], $templateProcessor->getVariables() ); $docName = 'delete-row-test-result.docx'; $templateProcessor->deleteRow('deleteMe'); - $this->assertEquals( - array(), + self::assertEquals( + [], $templateProcessor->getVariables() ); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); - $this->assertTrue($docFound); + self::assertTrue($docFound); } /**