From 7bbc9a9bc170b759a81ddcba7402ee179ed0e4eb Mon Sep 17 00:00:00 2001 From: Jui-Nan Lin Date: Mon, 5 Aug 2024 14:11:55 +0800 Subject: [PATCH 1/5] feat: add support of rowspan while importing to html --- src/PhpWord/Shared/Html.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 2022f7da09..9c02659206 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -472,11 +472,39 @@ protected static function parseCell($node, $element, &$styles) $cellStyles['gridSpan'] = $colspan - 0; } + $rowspan = $node->getAttribute('rowspan'); + if (!empty($rowspan)) { + $cellStyles['vMerge'] = 'restart'; + } + $beforespan = $node->getAttribute('beforespan'); + if (!empty($beforespan)) { + $cellRowContinue = array('vMerge' => 'continue'); + $beforecolspan = $node->getAttribute('beforecolspan'); + if (!empty($beforecolspan)) { + $cellRowContinue['gridSpan'] = $beforecolspan; + } + for ($s = 1; $s <= $beforespan; $s++){ + $element->addCell(null, $cellRowContinue); + } + } + // set cell width to control column widths $width = $cellStyles['width'] ?? null; unset($cellStyles['width']); // would not apply $cell = $element->addCell($width, $cellStyles); + $afterspan = $node->getAttribute('afterspan'); + if (!empty($afterspan)) { + $cellRowContinue = array('vMerge' => 'continue'); + $aftercolspan = $node->getAttribute('aftercolspan'); + if( ! empty($aftercolspan) ) { + $cellRowContinue['gridSpan'] = $aftercolspan; + } + for($s = 1; $s <= $afterspan; $s++) { + $element->addCell(null,$cellRowContinue); + } + } + if (self::shouldAddTextRun($node)) { return $cell->addTextRun(self::filterOutNonInheritedStyles(self::parseInlineStyle($node, $styles['paragraph']))); } From 1dc34b7ed714a8a209ee554ff648fa197cc8e899 Mon Sep 17 00:00:00 2001 From: aya Date: Wed, 7 Aug 2024 15:07:52 +0800 Subject: [PATCH 2/5] support array type of before/after-colspan --- src/PhpWord/Shared/Html.php | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 9c02659206..3eb79dca4b 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -480,10 +480,17 @@ protected static function parseCell($node, $element, &$styles) if (!empty($beforespan)) { $cellRowContinue = array('vMerge' => 'continue'); $beforecolspan = $node->getAttribute('beforecolspan'); - if (!empty($beforecolspan)) { - $cellRowContinue['gridSpan'] = $beforecolspan; - } + for ($s = 1; $s <= $beforespan; $s++){ + if (!empty($beforecolspan)) { + if (is_numeric($beforecolspan)) { + $beforecolspan = (int) $beforecolspan; + } else { + $beforecolspans = json_decode($beforecolspan, true); + $beforecolspan = $beforecolspans[$s - 1]; + } + $cellRowContinue['gridSpan'] = $beforecolspan; + } $element->addCell(null, $cellRowContinue); } } @@ -497,10 +504,17 @@ protected static function parseCell($node, $element, &$styles) if (!empty($afterspan)) { $cellRowContinue = array('vMerge' => 'continue'); $aftercolspan = $node->getAttribute('aftercolspan'); - if( ! empty($aftercolspan) ) { - $cellRowContinue['gridSpan'] = $aftercolspan; - } + for($s = 1; $s <= $afterspan; $s++) { + if (!empty($aftercolspan)) { + if (is_numeric($aftercolspan)) { + $aftercolspan = (int) $aftercolspan; + } else { + $aftercolspans = json_decode($aftercolspan, true); + $aftercolspan = $aftercolspans[$s - 1]; + } + $cellRowContinue['gridSpan'] = $aftercolspan; + } $element->addCell(null,$cellRowContinue); } } From 7f99efbc7d8a53a196bc3e56acc78524d528a799 Mon Sep 17 00:00:00 2001 From: Jui-Nan Lin Date: Wed, 7 Aug 2024 16:05:24 +0800 Subject: [PATCH 3/5] doc: add changelog --- docs/changes/2.x/2.0.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 18f9267f39..ba1bff73da 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -6,6 +6,7 @@ - IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) - PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) +- HTML Parser : Added support for rowspan in add HTML [#1643](https://github.com/PHPOffice/PHPWord/issues/1643) ### Bug fixes From f4fac68b66450d58721ef0b9bf05cdb90d5f9c4e Mon Sep 17 00:00:00 2001 From: Jui-Nan Lin Date: Wed, 7 Aug 2024 16:29:14 +0800 Subject: [PATCH 4/5] fix: style & phpstan --- phpstan-baseline.neon | 2 +- src/PhpWord/Shared/Html.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 2e44745b3d..d7220fe562 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -397,7 +397,7 @@ parameters: - message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" - count: 1 + count: 6 path: src/PhpWord/Shared/Html.php - diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 3eb79dca4b..95ed5eb842 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -478,10 +478,10 @@ protected static function parseCell($node, $element, &$styles) } $beforespan = $node->getAttribute('beforespan'); if (!empty($beforespan)) { - $cellRowContinue = array('vMerge' => 'continue'); + $cellRowContinue = ['vMerge' => 'continue']; $beforecolspan = $node->getAttribute('beforecolspan'); - for ($s = 1; $s <= $beforespan; $s++){ + for ($s = 1; $s <= $beforespan; ++$s) { if (!empty($beforecolspan)) { if (is_numeric($beforecolspan)) { $beforecolspan = (int) $beforecolspan; @@ -502,10 +502,10 @@ protected static function parseCell($node, $element, &$styles) $afterspan = $node->getAttribute('afterspan'); if (!empty($afterspan)) { - $cellRowContinue = array('vMerge' => 'continue'); + $cellRowContinue = ['vMerge' => 'continue']; $aftercolspan = $node->getAttribute('aftercolspan'); - for($s = 1; $s <= $afterspan; $s++) { + for ($s = 1; $s <= $afterspan; ++$s) { if (!empty($aftercolspan)) { if (is_numeric($aftercolspan)) { $aftercolspan = (int) $aftercolspan; @@ -515,7 +515,7 @@ protected static function parseCell($node, $element, &$styles) } $cellRowContinue['gridSpan'] = $aftercolspan; } - $element->addCell(null,$cellRowContinue); + $element->addCell(null, $cellRowContinue); } } From da62475f90767f63501d98b9f9aa9ef6b5c45f2a Mon Sep 17 00:00:00 2001 From: Jui-Nan Lin Date: Wed, 7 Aug 2024 16:45:17 +0800 Subject: [PATCH 5/5] test: add unit test for rowspan --- tests/PhpWordTests/Shared/HtmlTest.php | 34 +++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index c8640509de..1b80b1b980 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -127,7 +127,7 @@ public function testParseStyle(): void background-color:red; } - +

Calculator

'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); @@ -418,6 +418,38 @@ public function testParseTable(): void self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p/w:pPr/w:pBdr')); } + public function testParseTableWithRowSpan(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $html = ' + + + + + + + + + + + + + + + + + + + + +
ABCD
A1 BC1 D1
AB23 C2 D2
C3 D3
A456 B4 CD45
B5
C6 D6
A7 B7 C7 D7
A8 BC8 D8
ABC9 D9
A9 B9 C9
'; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl')); + } + /** * Parse widths in tables and cells, which also allows for controlling column width. */