Skip to content

Commit 44c3bd5

Browse files
authored
Merge pull request #4487 from oleibman/issue1154
Various Writers RichText TextElement Should Inherit Cell Style
2 parents 5c643a8 + 5938717 commit 44c3bd5

File tree

11 files changed

+344
-36
lines changed

11 files changed

+344
-36
lines changed

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
99

1010
### Added
1111

12-
- Nothing yet.
12+
- VSTACK and HSTACK. [Issue #4485](https://github.com/PHPOffice/PhpSpreadsheet/issues/4485) [PR #4492](https://github.com/PHPOffice/PhpSpreadsheet/pull/4492)
13+
- TOCOL and TOROW. [PR #4493](https://github.com/PHPOffice/PhpSpreadsheet/pull/4493)
1314

1415
### Removed
1516

@@ -29,7 +30,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
2930

3031
### Fixed
3132

32-
- Nothing yet.
33+
- Various Writers RichText TextElement Should Inherit Cell Style. [Issue #1154](https://github.com/PHPOffice/PhpSpreadsheet/issues/1154) [PR #4487](https://github.com/PHPOffice/PhpSpreadsheet/pull/4487)
34+
- Minor Changes to FILTER function. [PR #4491](https://github.com/PHPOffice/PhpSpreadsheet/pull/4491)
3335

3436
## 2025-05-26 - 4.3.1
3537

samples/Basic4/42b_RichText.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
use PhpOffice\PhpSpreadsheet\RichText\RichText;
4+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
5+
6+
require __DIR__ . '/../Header.php';
7+
8+
/** @var PhpOffice\PhpSpreadsheet\Helper\Sample $helper */
9+
$helper->log('Create new Spreadsheet object');
10+
$spreadsheet = new Spreadsheet();
11+
$sheet = $spreadsheet->getActiveSheet();
12+
13+
$rtf = new RichText();
14+
$rtf->createText('~Cell Style~');
15+
$rtf->createTextRun('~RTF Style~')->getFont()?->setItalic(true);
16+
$rtf->createText('~No Style~');
17+
18+
$sheet->getCell('A1')->setValue($rtf);
19+
$sheet->getStyle('A1')->getFont()->setBold(true);
20+
21+
// Save
22+
$helper->write($spreadsheet, __FILE__, ['Xlsx', 'Xls', 'Html']);

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,24 +1096,30 @@ private function createCSSStyleAlignment(Alignment $alignment): array
10961096
*
10971097
* @return string[]
10981098
*/
1099-
private function createCSSStyleFont(Font $font): array
1099+
private function createCSSStyleFont(Font $font, bool $useDefaults = false): array
11001100
{
11011101
// Construct CSS
11021102
$css = [];
11031103

11041104
// Create CSS
11051105
if ($font->getBold()) {
11061106
$css['font-weight'] = 'bold';
1107+
} elseif ($useDefaults) {
1108+
$css['font-weight'] = 'normal';
11071109
}
11081110
if ($font->getUnderline() != Font::UNDERLINE_NONE && $font->getStrikethrough()) {
11091111
$css['text-decoration'] = 'underline line-through';
11101112
} elseif ($font->getUnderline() != Font::UNDERLINE_NONE) {
11111113
$css['text-decoration'] = 'underline';
11121114
} elseif ($font->getStrikethrough()) {
11131115
$css['text-decoration'] = 'line-through';
1116+
} elseif ($useDefaults) {
1117+
$css['text-decoration'] = 'normal';
11141118
}
11151119
if ($font->getItalic()) {
11161120
$css['font-style'] = 'italic';
1121+
} elseif ($useDefaults) {
1122+
$css['font-style'] = 'normal';
11171123
}
11181124

11191125
$css['color'] = '#' . $font->getColor()->getRGB();
@@ -1344,22 +1350,23 @@ private function generateRowCellCss(Worksheet $worksheet, string $cellAddress, i
13441350
return [$cell, $cssClass, $coordinate];
13451351
}
13461352

1347-
private function generateRowCellDataValueRich(RichText $richText): string
1353+
private function generateRowCellDataValueRich(RichText $richText, ?Font $defaultFont = null): string
13481354
{
13491355
$cellData = '';
13501356
// Loop through rich text elements
13511357
$elements = $richText->getRichTextElements();
13521358
foreach ($elements as $element) {
13531359
// Rich text start?
1354-
if ($element instanceof Run) {
1360+
$font = ($element instanceof Run) ? $element->getFont() : $defaultFont;
1361+
if ($element instanceof Run || $font !== null) {
13551362
$cellEnd = '';
1356-
if ($element->getFont() !== null) {
1357-
$cellData .= '<span style="' . $this->assembleCSS($this->createCSSStyleFont($element->getFont())) . '">';
1363+
if ($font !== null) {
1364+
$cellData .= '<span style="' . $this->assembleCSS($this->createCSSStyleFont($font, true)) . '">';
13581365

1359-
if ($element->getFont()->getSuperscript()) {
1366+
if ($font->getSuperscript()) {
13601367
$cellData .= '<sup>';
13611368
$cellEnd = '</sup>';
1362-
} elseif ($element->getFont()->getSubscript()) {
1369+
} elseif ($font->getSubscript()) {
13631370
$cellData .= '<sub>';
13641371
$cellEnd = '</sub>';
13651372
}
@@ -1387,7 +1394,7 @@ private function generateRowCellDataValueRich(RichText $richText): string
13871394
private function generateRowCellDataValue(Worksheet $worksheet, Cell $cell, string &$cellData): void
13881395
{
13891396
if ($cell->getValue() instanceof RichText) {
1390-
$cellData .= $this->generateRowCellDataValueRich($cell->getValue());
1397+
$cellData .= $this->generateRowCellDataValueRich($cell->getValue(), $cell->getStyle()->getFont());
13911398
} else {
13921399
if ($this->preCalculateFormulas) {
13931400
try {

src/PhpSpreadsheet/Writer/Xls.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,26 @@ public function save($filename, int $flags = 0): void
151151
$cell = $this->writerWorksheets[$i]->phpSheet->getCellCollection()->get($coordinate);
152152
$cVal = $cell->getValue();
153153
if ($cVal instanceof RichText) {
154+
$active = $this->spreadsheet->getActiveSheetIndex();
155+
$sheet = $cell->getWorksheet();
156+
$selected = $sheet->getSelectedCells();
157+
$font = $cell->getStyle()->getFont();
158+
$this->writerWorksheets[$i]
159+
->fontHashIndex[$font->getHashCode()] = $this->writerWorkbook->addFont($font);
160+
$sheet->setSelectedCells($selected);
161+
if ($active > -1) {
162+
$this->spreadsheet
163+
->setActiveSheetIndex($active);
164+
}
154165
$elements = $cVal->getRichTextElements();
155166
foreach ($elements as $element) {
156167
if ($element instanceof Run) {
157168
$font = $element->getFont();
158169
if ($font !== null) {
159-
$this->writerWorksheets[$i]->fontHashIndex[$font->getHashCode()] = $this->writerWorkbook->addFont($font);
170+
$this->writerWorksheets[$i]
171+
->fontHashIndex[
172+
$font->getHashCode()
173+
] = $this->writerWorkbook->addFont($font);
160174
}
161175
}
162176
}

src/PhpSpreadsheet/Writer/Xls/Worksheet.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,19 @@ public function close(): void
381381
if ($getFont !== null) {
382382
$str_fontidx = $this->fontHashIndex[$getFont->getHashCode()];
383383
}
384+
} else {
385+
$styleArray = $this->phpSheet
386+
->getParent()
387+
?->getCellXfCollection();
388+
if ($styleArray !== null) {
389+
$font = $styleArray[$xfIndex - 15] ?? null;
390+
if ($font !== null) {
391+
$font = $font->getFont();
392+
}
393+
if ($font !== null) {
394+
$str_fontidx = $this->fontHashIndex[$font->getHashCode()];
395+
}
396+
}
384397
}
385398
$arrcRun[] = ['strlen' => $str_pos, 'fontidx' => $str_fontidx];
386399
// Position FROM

src/PhpSpreadsheet/Writer/Xlsx/StringTable.php

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpOffice\PhpSpreadsheet\RichText\Run;
1111
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
1212
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
13+
use PhpOffice\PhpSpreadsheet\Style\Font;
1314
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as ActualWorksheet;
1415

1516
class StringTable extends WriterPart
@@ -111,7 +112,7 @@ public function writeStringTable(array $stringTable): string
111112
*
112113
* @param ?string $prefix Optional Namespace prefix
113114
*/
114-
public function writeRichText(XMLWriter $objWriter, RichText $richText, ?string $prefix = null): void
115+
public function writeRichText(XMLWriter $objWriter, RichText $richText, ?string $prefix = null, ?Font $defaultFont = null): void
115116
{
116117
if ($prefix !== null) {
117118
$prefix .= ':';
@@ -122,63 +123,64 @@ public function writeRichText(XMLWriter $objWriter, RichText $richText, ?string
122123
foreach ($elements as $element) {
123124
// r
124125
$objWriter->startElement($prefix . 'r');
126+
$font = ($element instanceof Run) ? $element->getFont() : $defaultFont;
125127

126128
// rPr
127-
if ($element instanceof Run && $element->getFont() !== null) {
129+
if ($font !== null) {
128130
// rPr
129131
$objWriter->startElement($prefix . 'rPr');
130132

131133
// rFont
132-
if ($element->getFont()->getName() !== null) {
134+
if ($font->getName() !== null) {
133135
$objWriter->startElement($prefix . 'rFont');
134-
$objWriter->writeAttribute('val', $element->getFont()->getName());
136+
$objWriter->writeAttribute('val', $font->getName());
135137
$objWriter->endElement();
136138
}
137139

138140
// Bold
139141
$objWriter->startElement($prefix . 'b');
140-
$objWriter->writeAttribute('val', ($element->getFont()->getBold() ? 'true' : 'false'));
142+
$objWriter->writeAttribute('val', ($font->getBold() ? 'true' : 'false'));
141143
$objWriter->endElement();
142144

143145
// Italic
144146
$objWriter->startElement($prefix . 'i');
145-
$objWriter->writeAttribute('val', ($element->getFont()->getItalic() ? 'true' : 'false'));
147+
$objWriter->writeAttribute('val', ($font->getItalic() ? 'true' : 'false'));
146148
$objWriter->endElement();
147149

148150
// Superscript / subscript
149-
if ($element->getFont()->getSuperscript() || $element->getFont()->getSubscript()) {
151+
if ($font->getSuperscript() || $font->getSubscript()) {
150152
$objWriter->startElement($prefix . 'vertAlign');
151-
if ($element->getFont()->getSuperscript()) {
153+
if ($font->getSuperscript()) {
152154
$objWriter->writeAttribute('val', 'superscript');
153-
} elseif ($element->getFont()->getSubscript()) {
155+
} elseif ($font->getSubscript()) {
154156
$objWriter->writeAttribute('val', 'subscript');
155157
}
156158
$objWriter->endElement();
157159
}
158160

159161
// Strikethrough
160162
$objWriter->startElement($prefix . 'strike');
161-
$objWriter->writeAttribute('val', ($element->getFont()->getStrikethrough() ? 'true' : 'false'));
163+
$objWriter->writeAttribute('val', ($font->getStrikethrough() ? 'true' : 'false'));
162164
$objWriter->endElement();
163165

164166
// Color
165-
if ($element->getFont()->getColor()->getARGB() !== null) {
167+
if ($font->getColor()->getARGB() !== null) {
166168
$objWriter->startElement($prefix . 'color');
167-
$objWriter->writeAttribute('rgb', $element->getFont()->getColor()->getARGB());
169+
$objWriter->writeAttribute('rgb', $font->getColor()->getARGB());
168170
$objWriter->endElement();
169171
}
170172

171173
// Size
172-
if ($element->getFont()->getSize() !== null) {
174+
if ($font->getSize() !== null) {
173175
$objWriter->startElement($prefix . 'sz');
174-
$objWriter->writeAttribute('val', (string) $element->getFont()->getSize());
176+
$objWriter->writeAttribute('val', (string) $font->getSize());
175177
$objWriter->endElement();
176178
}
177179

178180
// Underline
179-
if ($element->getFont()->getUnderline() !== null) {
181+
if ($font->getUnderline() !== null) {
180182
$objWriter->startElement($prefix . 'u');
181-
$objWriter->writeAttribute('val', $element->getFont()->getUnderline());
183+
$objWriter->writeAttribute('val', $font->getUnderline());
182184
$objWriter->endElement();
183185
}
184186

src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalColorScale;
1818
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
1919
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension;
20+
use PhpOffice\PhpSpreadsheet\Style\Font;
2021
use PhpOffice\PhpSpreadsheet\Worksheet\RowDimension;
2122
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
2223
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet;
@@ -1431,19 +1432,26 @@ private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $w
14311432
$objWriter->endElement();
14321433
}
14331434

1434-
private function writeCellInlineStr(XMLWriter $objWriter, string $mappedType, RichText|string $cellValue): void
1435+
private function writeCellInlineStr(XMLWriter $objWriter, string $mappedType, RichText|string $cellValue, ?Font $font): void
14351436
{
14361437
$objWriter->writeAttribute('t', $mappedType);
14371438
if (!$cellValue instanceof RichText) {
14381439
$objWriter->startElement('is');
14391440
$objWriter->writeElement(
14401441
't',
1441-
StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue, Settings::htmlEntityFlags()))
1442+
StringHelper::controlCharacterPHP2OOXML(
1443+
htmlspecialchars(
1444+
$cellValue,
1445+
Settings::htmlEntityFlags()
1446+
)
1447+
)
14421448
);
14431449
$objWriter->endElement();
14441450
} else {
14451451
$objWriter->startElement('is');
1446-
$this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $cellValue);
1452+
$this->getParentWriter()
1453+
->getWriterPartstringtable()
1454+
->writeRichText($objWriter, $cellValue, null, $font);
14471455
$objWriter->endElement();
14481456
}
14491457
}
@@ -1608,6 +1616,13 @@ private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksh
16081616
if (empty($xfi) && !$writeValue) {
16091617
return;
16101618
}
1619+
$styleArray = $this->getParentWriter()
1620+
->getSpreadsheet()
1621+
->getCellXfCollection();
1622+
$font = $styleArray[$xfi] ?? null;
1623+
if ($font !== null) {
1624+
$font = $font->getFont();
1625+
}
16111626
$objWriter->startElement('c');
16121627
$objWriter->writeAttribute('r', $cellAddress);
16131628
$mappedType = $pCell->getDataType();
@@ -1638,7 +1653,7 @@ private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksh
16381653
case 'inlinestr': // Inline string
16391654
/** @var RichText|string */
16401655
$richText = $cellValue;
1641-
$this->writeCellInlineStr($objWriter, $mappedType, $richText);
1656+
$this->writeCellInlineStr($objWriter, $mappedType, $richText, $font);
16421657

16431658
break;
16441659
case 's': // String

tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpOffice\PhpSpreadsheet\Spreadsheet;
99
use PhpOffice\PhpSpreadsheet\Writer\Html;
1010
use PhpOffice\PhpSpreadsheetTests\Functional;
11+
use PHPUnit\Framework\Attributes\DataProvider;
1112

1213
class HtmlCommentsTest extends Functional\AbstractFunctional
1314
{
@@ -60,15 +61,15 @@ public static function providerCommentRichText(): array
6061
. 'comment.</div>' . PHP_EOL
6162
. 'Comment</td>'],
6263
'single line simple rich text' => [$richSingle, '<td class="column0 style0 s"><a class="comment-indicator"></a><div class="comment">'
63-
. "<span style=\"font-weight:bold; color:#000000; font-family:'Calibri'; font-size:11pt\">I am comment.</span></div>" . PHP_EOL
64+
. "<span style=\"font-weight:bold; text-decoration:normal; font-style:normal; color:#000000; font-family:'Calibri'; font-size:11pt\">I am comment.</span></div>" . PHP_EOL
6465
. 'Comment</td>'],
6566
'multi-line simple rich text' => [$richMultiSimple, '<td class="column0 style0 s"><a class="comment-indicator"></a><div class="comment">'
66-
. "<span style=\"font-weight:bold; color:#000000; font-family:'Calibri'; font-size:11pt\">I am <br />" . PHP_EOL
67+
. "<span style=\"font-weight:bold; text-decoration:normal; font-style:normal; color:#000000; font-family:'Calibri'; font-size:11pt\">I am <br />" . PHP_EOL
6768
. 'multi-line<br />' . PHP_EOL
6869
. 'comment.</span></div>' . PHP_EOL
6970
. 'Comment</td>'],
7071
'multi-line mixed rich text' => [$richMultiMixed, '<td class="column0 style0 s"><a class="comment-indicator"></a><div class="comment">I am<br />' . PHP_EOL
71-
. "<span style=\"font-weight:bold; color:#000000; font-family:'Calibri'; font-size:11pt\">multi-line</span><br />" . PHP_EOL
72+
. "<span style=\"font-weight:bold; text-decoration:normal; font-style:normal; color:#000000; font-family:'Calibri'; font-size:11pt\">multi-line</span><br />" . PHP_EOL
7273
. 'comment!</div>' . PHP_EOL
7374
. 'Comment</td>'],
7475
'script single' => [$scriptSingle, '<td class="column0 style0 s"><a class="comment-indicator"></a><div class="comment">'
@@ -77,12 +78,14 @@ public static function providerCommentRichText(): array
7778
];
7879
}
7980

80-
#[\PHPUnit\Framework\Attributes\DataProvider('providerCommentRichText')]
81+
#[DataProvider('providerCommentRichText')]
8182
public function testComments(RichText $richText, string $expected): void
8283
{
8384
$spreadsheet = new Spreadsheet();
8485

85-
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Comment');
86+
$spreadsheet->getActiveSheet()
87+
->getCell('A1')
88+
->setValue('Comment');
8689

8790
$spreadsheet->getActiveSheet()
8891
->getComment('A1')

0 commit comments

Comments
 (0)