Introduce deleteRow() method for TemplateProcessor
This commit is contained in:
parent
fab9966b8c
commit
91504dfddc
@ -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, '<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 = $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('#<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 +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, '<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.
|
||||
*
|
||||
* @param integer $offset
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
protected function findTableEnd($offset)
|
||||
{
|
||||
return strpos($this->tempDocumentMainPart, '</w:tbl>', $offset) + 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the start position of the nearest table row before $offset.
|
||||
*
|
||||
|
||||
@ -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
|
||||
|
||||
BIN
tests/PhpWordTests/_files/templates/delete-row.docx
Normal file
BIN
tests/PhpWordTests/_files/templates/delete-row.docx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user