diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d30c80349..a86794c05b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Fixed
+- Html Writer Conditional Formatting Inline Css. [Issue #4539](https://github.com/PHPOffice/PhpSpreadsheet/issues/4539) [PR #4541](https://github.com/PHPOffice/PhpSpreadsheet/pull/4541)
- Do not use htmlspecialchars when formatting XML. [Issue #4537](https://github.com/PHPOffice/PhpSpreadsheet/issues/4537) [PR #4540](https://github.com/PHPOffice/PhpSpreadsheet/pull/4540)
- Writer Html/Pdf support RTL alignment of tables. [Issue #1104](https://github.com/PHPOffice/PhpSpreadsheet/issues/1104) [PR #4535](https://github.com/PHPOffice/PhpSpreadsheet/pull/4535)
- Xlsx Reader use dynamic arrays if spreadsheet did so. [PR #4533](https://github.com/PHPOffice/PhpSpreadsheet/pull/4533)
diff --git a/src/PhpSpreadsheet/Style/Conditional.php b/src/PhpSpreadsheet/Style/Conditional.php
index 736b72be5e..2ef7cacd79 100644
--- a/src/PhpSpreadsheet/Style/Conditional.php
+++ b/src/PhpSpreadsheet/Style/Conditional.php
@@ -272,7 +272,7 @@ public function addCondition($condition): static
public function getStyle(mixed $cellData = null): Style
{
if ($this->conditionType === self::CONDITION_COLORSCALE && $cellData !== null && $this->colorScale !== null && is_numeric($cellData)) {
- $style = new Style();
+ $style = new Style(isConditional: true);
$style->getFill()->setFillType(Fill::FILL_SOLID);
$style->getFill()->getStartColor()->setARGB($this->colorScale->getColorForValue((float) $cellData));
diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/StyleMerger.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/StyleMerger.php
index 10f3ba65dd..645f2387f5 100644
--- a/src/PhpSpreadsheet/Style/ConditionalFormatting/StyleMerger.php
+++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/StyleMerger.php
@@ -14,7 +14,10 @@ class StyleMerger
public function __construct(Style $baseStyle)
{
- $this->baseStyle = $baseStyle;
+ // Setting to $baseStyle sometimes causes problems later on.
+ $array = $baseStyle->exportArray();
+ $this->baseStyle = new Style();
+ $this->baseStyle->applyFromArray($array);
}
public function getStyle(): Style
@@ -75,7 +78,11 @@ protected function mergeBordersStyle(Borders $baseBordersStyle, Borders $borders
protected function mergeBorderStyle(Border $baseBorderStyle, Border $borderStyle): void
{
- $baseBorderStyle->setBorderStyle($borderStyle->getBorderStyle());
+ if ($borderStyle->getBorderStyle() !== Border::BORDER_OMIT) {
+ $baseBorderStyle->setBorderStyle(
+ $borderStyle->getBorderStyle()
+ );
+ }
if ($borderStyle->getColor()->getARGB() !== null) {
$baseBorderStyle->setColor($borderStyle->getColor());
}
diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php
index c79b5737a9..d783ec9450 100644
--- a/src/PhpSpreadsheet/Writer/Html.php
+++ b/src/PhpSpreadsheet/Writer/Html.php
@@ -1074,13 +1074,13 @@ public function buildCSS(bool $generateSurroundingHTML = true): array
*
* @return string[]
*/
- private function createCSSStyle(Style $style): array
+ private function createCSSStyle(Style $style, bool $conditional = false): array
{
// Create CSS
return array_merge(
- $this->createCSSStyleAlignment($style->getAlignment()),
+ $conditional ? [] : $this->createCSSStyleAlignment($style->getAlignment()),
$this->createCSSStyleBorders($style->getBorders()),
- $this->createCSSStyleFont($style->getFont()),
+ $this->createCSSStyleFont($style->getFont(), conditional: $conditional),
$this->createCSSStyleFill($style->getFill())
);
}
@@ -1124,7 +1124,7 @@ private function createCSSStyleAlignment(Alignment $alignment): array
*
* @return string[]
*/
- private function createCSSStyleFont(Font $font, bool $useDefaults = false): array
+ private function createCSSStyleFont(Font $font, bool $useDefaults = false, bool $conditional = false): array
{
// Construct CSS
$css = [];
@@ -1151,12 +1151,29 @@ private function createCSSStyleFont(Font $font, bool $useDefaults = false): arra
}
$css['color'] = '#' . $font->getColor()->getRGB();
- $css['font-family'] = '\'' . htmlspecialchars((string) $font->getName(), ENT_QUOTES) . '\'';
- $css['font-size'] = $font->getSize() . 'pt';
+ if (!$conditional) {
+ $css['font-family'] = '\'' . htmlspecialchars((string) $font->getName(), ENT_QUOTES) . '\'';
+ $css['font-size'] = $font->getSize() . 'pt';
+ }
return $css;
}
+ /**
+ * @param string[] $css
+ */
+ private function styleBorder(array &$css, string $index, Border $border): void
+ {
+ $borderStyle = $border->getBorderStyle();
+ // Mpdf doesn't process !important, so omit unimportant border none
+ if ($borderStyle === Border::BORDER_NONE && $this instanceof Pdf\Mpdf) {
+ return;
+ }
+ if ($borderStyle !== Border::BORDER_OMIT) {
+ $css[$index] = $this->createCSSStyleBorder($border);
+ }
+ }
+
/**
* Create CSS style.
*
@@ -1170,26 +1187,10 @@ private function createCSSStyleBorders(Borders $borders): array
$css = [];
// Create CSS
- if (!($this instanceof Pdf\Mpdf)) {
- $css['border-bottom'] = $this->createCSSStyleBorder($borders->getBottom());
- $css['border-top'] = $this->createCSSStyleBorder($borders->getTop());
- $css['border-left'] = $this->createCSSStyleBorder($borders->getLeft());
- $css['border-right'] = $this->createCSSStyleBorder($borders->getRight());
- } else {
- // Mpdf doesn't process !important, so omit unimportant border none
- if ($borders->getBottom()->getBorderStyle() !== Border::BORDER_NONE) {
- $css['border-bottom'] = $this->createCSSStyleBorder($borders->getBottom());
- }
- if ($borders->getTop()->getBorderStyle() !== Border::BORDER_NONE) {
- $css['border-top'] = $this->createCSSStyleBorder($borders->getTop());
- }
- if ($borders->getLeft()->getBorderStyle() !== Border::BORDER_NONE) {
- $css['border-left'] = $this->createCSSStyleBorder($borders->getLeft());
- }
- if ($borders->getRight()->getBorderStyle() !== Border::BORDER_NONE) {
- $css['border-right'] = $this->createCSSStyleBorder($borders->getRight());
- }
- }
+ $this->styleBorder($css, 'border-bottom', $borders->getBottom());
+ $this->styleBorder($css, 'border-top', $borders->getTop());
+ $this->styleBorder($css, 'border-left', $borders->getLeft());
+ $this->styleBorder($css, 'border-right', $borders->getRight());
return $css;
}
@@ -1393,7 +1394,11 @@ private function generateRowStart(Worksheet $worksheet, int $sheetIndex, int $ro
$style = isset($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $row])
? $this->assembleCSS($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $row]) : '';
- $html .= '
' . PHP_EOL;
+ if ($style === '') {
+ $html .= '
' . PHP_EOL;
+ } else {
+ $html .= '
' . PHP_EOL;
+ }
}
return $html;
@@ -1605,6 +1610,7 @@ private function generateRowWriteCell(
$html .= ' data-type="' . DataType::TYPE_STRING . '"';
}
}
+ $holdCss = '';
if (!$this->useInlineCss && !$this->isPdf && is_string($cssClass)) {
$html .= ' class="' . $cssClass . '"';
if ($htmlx) {
@@ -1650,9 +1656,17 @@ private function generateRowWriteCell(
$xcssClass['position'] = 'relative';
}
/** @var string[] $xcssClass */
- $html .= ' style="' . $this->assembleCSS($xcssClass) . '"';
+ $holdCss = $this->assembleCSS($xcssClass);
if ($this->useInlineCss) {
- $html .= ' class="gridlines gridlinesp"';
+ $prntgrid = $worksheet->getPrintGridlines();
+ $viewgrid = $this->isPdf ? $prntgrid : $worksheet->getShowGridlines();
+ if ($viewgrid && $prntgrid) {
+ $html .= ' class="gridlines gridlinesp"';
+ } elseif ($viewgrid) {
+ $html .= ' class="gridlines"';
+ } elseif ($prntgrid) {
+ $html .= ' class="gridlinesp"';
+ }
}
}
@@ -1700,14 +1714,23 @@ private function generateRowWriteCell(
}
}
if ($matched) {
- $styles = $this->createCSSStyle($styleMerger->getStyle());
+ $styles = $this->createCSSStyle($styleMerger->getStyle(), true);
$html .= ' style="';
+ if ($holdCss !== '') {
+ $html .= "$holdCss; ";
+ $holdCss = '';
+ }
foreach ($styles as $key => $value) {
- $html .= $key . ':' . $value . ';';
+ if (!str_starts_with($key, 'border-') || $value !== 'none #000000') {
+ $html .= $key . ':' . $value . ';';
+ }
}
$html .= '"';
}
}
+ if ($holdCss !== '') {
+ $html .= ' style="' . $holdCss . '"';
+ }
$html .= '>';
$html .= $htmlx;
diff --git a/tests/PhpSpreadsheetTests/Writer/Dompdf/HideMergeTest.php b/tests/PhpSpreadsheetTests/Writer/Dompdf/HideMergeTest.php
index 7bbe5c6cc3..a8b365baad 100644
--- a/tests/PhpSpreadsheetTests/Writer/Dompdf/HideMergeTest.php
+++ b/tests/PhpSpreadsheetTests/Writer/Dompdf/HideMergeTest.php
@@ -99,7 +99,7 @@ public function testHideWithMerge(): void
self::assertStringContainsString(
'
'
. '| | '
- . 'Hello World Headline | '
+ . 'Hello World Headline | '
. '
',
$html
);
@@ -112,8 +112,8 @@ public function testHideWithMerge(): void
self::assertStringContainsString(
''
. '| | '
- . 'Label 1 | '
- . 'Text 1 | '
+ . 'Label 1 | '
+ . 'Text 1 | '
. '
',
$html
);
@@ -126,8 +126,8 @@ public function testHideWithMerge(): void
self::assertStringContainsString(
''
. '| | '
- . 'Label 2 | '
- . 'Text 2 | '
+ . 'Label 2 | '
+ . 'Text 2 | '
. '
',
$html
);
diff --git a/tests/PhpSpreadsheetTests/Writer/Html/BetterBooleanTest.php b/tests/PhpSpreadsheetTests/Writer/Html/BetterBooleanTest.php
index 71d81122a9..e033c8ab4b 100644
--- a/tests/PhpSpreadsheetTests/Writer/Html/BetterBooleanTest.php
+++ b/tests/PhpSpreadsheetTests/Writer/Html/BetterBooleanTest.php
@@ -139,6 +139,7 @@ public function testInline(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
+ $sheet->setPrintGridlines(true);
$sheet->getCell('A1')->setValue(1);
$sheet->getCell('B1')->setValue('Hello');
$sheet->getCell('C1')->setValue(true);
@@ -153,15 +154,15 @@ public function testInline(): void
$writer->setUseInlineCss(true);
$html = $writer->generateHtmlAll();
$html = str_replace('vertical-align:bottom; color:#000000; font-family:\'Calibri\'; font-size:11pt; ', '', $html);
- $html = str_replace(' width:42pt" class="gridlines gridlinesp"', '"', $html);
+ $html = str_replace(' width:42pt"', '"', $html);
self::assertStringNotContainsString('TRUE', $html);
- self::assertStringContainsString('1 | ', $html);
- self::assertStringContainsString('Hello | ', $html);
- self::assertStringContainsString('VRAI | ', $html);
- self::assertStringContainsString('FAUX | ', $html);
- self::assertStringContainsString('1 | ', $html);
- self::assertStringContainsString('AB | ', $html);
- self::assertStringContainsString('3 | ', $html);
+ self::assertStringContainsString('1 | ', $html);
+ self::assertStringContainsString('Hello | ', $html);
+ self::assertStringContainsString('VRAI | ', $html);
+ self::assertStringContainsString('FAUX | ', $html);
+ self::assertStringContainsString('1 | ', $html);
+ self::assertStringContainsString('AB | ', $html);
+ self::assertStringContainsString('3 | ', $html);
$reloaded = $this->writeAndReload($spreadsheet, 'Html', null, $this->setBetter(...));
$spreadsheet->disconnectWorksheets();
diff --git a/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php b/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php
index e4f292c2da..6177434639 100644
--- a/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php
+++ b/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php
@@ -15,6 +15,8 @@ public function testInlineAndNot(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
+ $sheet->setShowGridlines(false);
+ $sheet->setPrintGridlines(true);
$sheet->getCell('A1')->setValue(1);
$styleArray = [
'fill' => [
@@ -34,7 +36,10 @@ public function testInlineAndNot(): void
self::assertStringContainsString('.n { text-align:right }', $html);
$writer->setUseInlineCss(true);
$html = $writer->generateHtmlAll();
- self::assertStringContainsString('1 | ', $html);
+ self::assertStringContainsString('1 | ', $html);
+ $sheet->setPrintGridlines(false);
+ $html = $writer->generateHtmlAll();
+ self::assertStringContainsString('1 | ', $html);
$spreadsheet->disconnectWorksheets();
}
}
diff --git a/tests/PhpSpreadsheetTests/Writer/Html/Issue4539Test.php b/tests/PhpSpreadsheetTests/Writer/Html/Issue4539Test.php
new file mode 100644
index 0000000000..ee9924c7af
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Writer/Html/Issue4539Test.php
@@ -0,0 +1,48 @@
+load($infile);
+ $writer = new Html($spreadsheet);
+ $writer->setConditionalFormatting(true);
+ $writer->setUseInlineCss(true);
+ $html = $writer->generateHtmlAll();
+ $expected = '5 | ';
+ self::assertStringContainsString($expected, $html, 'inline conditional style');
+ $expected = 'Column Heading | ';
+ self::assertStringContainsString($expected, $html, 'inline no conditional style');
+ $expected = '1 | ';
+ self::assertStringContainsString($expected, $html, 'inline border-top');
+ $expected = '2 | ';
+ self::assertStringContainsString($expected, $html, 'inline border-top and bold');
+ $expected = '3 | ';
+ self::assertStringContainsString($expected, $html, 'inline nomatch');
+
+ $writer->setUseInlineCss(false);
+ $html = $writer->generateHtmlAll();
+ $expected = '5 | ';
+ self::assertStringContainsString($expected, $html, 'notinline conditional style');
+ $expected = 'Column Heading | ';
+ self::assertStringContainsString($expected, $html, 'notinline no conditional style');
+ $expected = '1 | ';
+ self::assertStringContainsString($expected, $html, 'notinline border-top');
+ $expected = '2 | ';
+ self::assertStringContainsString($expected, $html, 'notinline border-top bold');
+ $expected = '3 | ';
+ self::assertStringContainsString($expected, $html, 'notinline nomatch');
+
+ $spreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php
index 7faf8a6ad3..4a6a5f4c2d 100644
--- a/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php
+++ b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php
@@ -23,7 +23,7 @@ public function testNoTitle(): void
$writer->setUseInlineCss(true);
$html = $writer->generateHTMLAll();
self::assertStringContainsString('Sheet1', $html);
- self::assertStringContainsString('C1 | ', $html);
+ self::assertStringContainsString('C1 | ', $html);
$writer->setUseInlineCss(false);
$html = $writer->generateHTMLAll();
self::assertStringContainsString('C1 | ', $html);
@@ -55,8 +55,8 @@ public function testHideSomeGridlines(): void
$writer = new Html($spreadsheet);
$writer->setUseInlineCss(true);
$html = $writer->generateHTMLAll();
- self::assertStringContainsString('7 | ', $html);
- self::assertStringContainsString('19 | ', $html);
+ self::assertStringContainsString('7 | ', $html);
+ self::assertStringContainsString('19 | ', $html);
$spreadsheet->disconnectWorksheets();
}
}
diff --git a/tests/PhpSpreadsheetTests/Writer/Mpdf/HideMergeTest.php b/tests/PhpSpreadsheetTests/Writer/Mpdf/HideMergeTest.php
index d6f9b02702..9753bed441 100644
--- a/tests/PhpSpreadsheetTests/Writer/Mpdf/HideMergeTest.php
+++ b/tests/PhpSpreadsheetTests/Writer/Mpdf/HideMergeTest.php
@@ -93,7 +93,7 @@ public function testHideWithMerge(): void
);
self::assertStringContainsString(
''
- . '| Hello World Headline | '
+ . 'Hello World Headline | '
. '
',
$html
);
@@ -104,8 +104,8 @@ public function testHideWithMerge(): void
);
self::assertStringContainsString(
''
- . '| Label 1 | '
- . 'Text 1 | '
+ . 'Label 1 | '
+ . 'Text 1 | '
. '
',
$html
);
@@ -116,8 +116,8 @@ public function testHideWithMerge(): void
);
self::assertStringContainsString(
''
- . '| Label 2 | '
- . 'Text 2 | '
+ . 'Label 2 | '
+ . 'Text 2 | '
. '
',
$html
);
diff --git a/tests/PhpSpreadsheetTests/Writer/Tcpdf/HideMergeTest.php b/tests/PhpSpreadsheetTests/Writer/Tcpdf/HideMergeTest.php
index 04284c0814..8eea9a1b42 100644
--- a/tests/PhpSpreadsheetTests/Writer/Tcpdf/HideMergeTest.php
+++ b/tests/PhpSpreadsheetTests/Writer/Tcpdf/HideMergeTest.php
@@ -17,6 +17,7 @@ public function testHideWithMerge(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
+ $worksheet->setPrintGridlines(true);
// just some labels for better visualisation of the problem
$worksheet->setCellValue('A1', 'A');
$worksheet->setCellValue('B1', 'B');
@@ -87,15 +88,15 @@ public function testHideWithMerge(): void
self::assertStringContainsString(
''
. ' | '
- . 'B | '
- . 'C | '
+ . 'B | '
+ . 'C | '
. '
',
$html
);
self::assertStringContainsString(
''
. ' | '
- . 'Hello World Headline | '
+ . 'Hello World Headline | '
. '
',
$html
);
@@ -109,16 +110,16 @@ public function testHideWithMerge(): void
self::assertStringContainsString(
''
. ' | '
- . 'Label 1 | '
- . 'Text 1 | '
+ . 'Label 1 | '
+ . 'Text 1 | '
. '
',
$html
);
self::assertStringContainsString(
''
. ' | '
- . 'Label 2 | '
- . 'Text 2 | '
+ . 'Label 2 | '
+ . 'Text 2 | '
. '
',
$html
);
diff --git a/tests/PhpSpreadsheetTests/Writer/Tcpdf/MergedBorderTest.php b/tests/PhpSpreadsheetTests/Writer/Tcpdf/MergedBorderTest.php
index 5b61c649aa..9c3df41f8c 100644
--- a/tests/PhpSpreadsheetTests/Writer/Tcpdf/MergedBorderTest.php
+++ b/tests/PhpSpreadsheetTests/Writer/Tcpdf/MergedBorderTest.php
@@ -32,7 +32,7 @@ public static function testMergedBorder(): void
$sheet->setShowGridlines(false);
$writer = new Tcpdf($spreadsheet);
$html = $writer->generateHtmlAll();
- self::assertSame(1, preg_match('/border-bottom:1px solid #FF0000 !important; border-top:1px solid #FF0000 !important; border-left:1px solid #FF0000 !important; border-right:1px solid #FF0000 !important; color:#000000;[^>]+ colspan="2" rowspan="4"/', $html));
+ self::assertSame(1, preg_match('/ colspan="2" rowspan="4" style="vertical-align:bottom; border-bottom:1px solid #FF0000 !important; border-top:1px solid #FF0000 !important; border-left:1px solid #FF0000 !important; border-right:1px solid #FF0000 !important; color:#000000;[^>]+/', $html));
$spreadsheet->disconnectWorksheets();
}
}
diff --git a/tests/data/Reader/XLSX/issue.4539.xlsx b/tests/data/Reader/XLSX/issue.4539.xlsx
new file mode 100644
index 0000000000..e44a88d5ba
Binary files /dev/null and b/tests/data/Reader/XLSX/issue.4539.xlsx differ