Skip to content

Commit fba2a43

Browse files
authored
Merge branch 'master' into issue4673
2 parents 4c79da5 + b5ba4ff commit fba2a43

File tree

27 files changed

+645
-15
lines changed

27 files changed

+645
-15
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a
1010
### Added
1111

1212
- Option to display numbers with less precision. [Issue #4626](https://github.com/PHPOffice/PhpSpreadsheet/issues/4626) [PR #4640](https://github.com/PHPOffice/PhpSpreadsheet/pull/4640)
13+
- Offer Tcpdf Interface which throws exception rather than die. [PR #4666](https://github.com/PHPOffice/PhpSpreadsheet/pull/4666)
1314

1415
### Removed
1516

@@ -39,6 +40,9 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a
3940
- Use prefix _xlfn for BASE function. [Issue #4638](https://github.com/PHPOffice/PhpSpreadsheet/issues/4638) [PR #4641](https://github.com/PHPOffice/PhpSpreadsheet/pull/4641)
4041
- Warning messages with corrupt Xls file. [Issue #4647](https://github.com/PHPOffice/PhpSpreadsheet/issues/4647) [PR #4648](https://github.com/PHPOffice/PhpSpreadsheet/pull/4648)
4142
- Additional support for union and intersection. [PR #4596](https://github.com/PHPOffice/PhpSpreadsheet/pull/4596)
43+
- Missing array keys x,o,v for Xml Reader. [Issue #4668](https://github.com/PHPOffice/PhpSpreadsheet/issues/4668) [PR #4669](https://github.com/PHPOffice/PhpSpreadsheet/pull/4669)
44+
- Missing array key x for Xlsx Reader VML. [Issue #4505](https://github.com/PHPOffice/PhpSpreadsheet/issues/4505) [PR #4676](https://github.com/PHPOffice/PhpSpreadsheet/pull/4676)
45+
- Better support for Style Alignment Read Order. [Issue #850](https://github.com/PHPOffice/PhpSpreadsheet/issues/850) [PR #4655](https://github.com/PHPOffice/PhpSpreadsheet/pull/4655)
4246

4347
## 2025-09-03 - 5.1.0
4448

src/PhpSpreadsheet/Reader/Html.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
1919
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
2020
use PhpOffice\PhpSpreadsheet\Spreadsheet;
21+
use PhpOffice\PhpSpreadsheet\Style\Alignment;
2122
use PhpOffice\PhpSpreadsheet\Style\Border;
2223
use PhpOffice\PhpSpreadsheet\Style\Color;
2324
use PhpOffice\PhpSpreadsheet\Style\Fill;
@@ -1014,6 +1015,17 @@ private function applyInlineStyle(Worksheet &$sheet, int $row, string $column, a
10141015

10151016
break;
10161017

1018+
case 'direction':
1019+
if ($styleValue === 'rtl') {
1020+
$cellStyle->getAlignment()
1021+
->setReadOrder(Alignment::READORDER_RTL);
1022+
} elseif ($styleValue === 'ltr') {
1023+
$cellStyle->getAlignment()
1024+
->setReadOrder(Alignment::READORDER_LTR);
1025+
}
1026+
1027+
break;
1028+
10171029
case 'font-weight':
10181030
if ($styleValue === 'bold' || $styleValue >= 500) {
10191031
$cellStyle->getFont()->setBold(true);
@@ -1083,8 +1095,11 @@ private function applyInlineStyle(Worksheet &$sheet, int $row, string $column, a
10831095
break;
10841096

10851097
case 'text-indent':
1098+
$indentDimension = new CssDimension($styleValueString);
1099+
$indent = $indentDimension
1100+
->toUnit(CssDimension::UOM_PIXELS);
10861101
$cellStyle->getAlignment()->setIndent(
1087-
(int) str_replace(['px'], '', $styleValueString)
1102+
(int) ($indent / Alignment::INDENT_UNITS_TO_PIXELS)
10881103
);
10891104

10901105
break;

src/PhpSpreadsheet/Reader/Xls.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,8 @@ protected function readXf(): void
12541254

12551255
break;
12561256
}
1257+
$readOrder = (0xC0 & ord($recordData[8])) >> 6;
1258+
$objStyle->getAlignment()->setReadOrder($readOrder);
12571259

12581260
// offset: 9; size: 1; Flags used for attribute groups
12591261

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1205,7 +1205,10 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
12051205
$shapes = self::xpathNoFalse($vmlCommentsFile, '//v:shape');
12061206
foreach ($shapes as $shape) {
12071207
/** @var SimpleXMLElement $shape */
1208-
$shape->registerXPathNamespace('v', Namespaces::URN_VML);
1208+
$vmlNamespaces = $shape->getNamespaces();
1209+
$shape->registerXPathNamespace('v', $vmlNamespaces['v'] ?? Namespaces::URN_VML);
1210+
$shape->registerXPathNamespace('x', $vmlNamespaces['x'] ?? Namespaces::URN_EXCEL);
1211+
$shape->registerXPathNamespace('o', $vmlNamespaces['o'] ?? Namespaces::URN_MSOFFICE);
12091212

12101213
if (isset($shape['style'])) {
12111214
$style = (string) $shape['style'];
@@ -1230,6 +1233,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
12301233
$clientData = $clientData[0];
12311234

12321235
if (isset($clientData['ObjectType']) && (string) $clientData['ObjectType'] == 'Note') {
1236+
$clientData->registerXPathNamespace('x', $vmlNamespaces['x'] ?? Namespaces::URN_EXCEL);
12331237
$temp = $clientData->xpath('.//x:Row');
12341238
if (is_array($temp)) {
12351239
$row = $temp[0];

src/PhpSpreadsheet/Reader/Xml/Style.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function parseStyles(SimpleXMLElement $xml, array $namespaces): array
7676
break;
7777
case 'Protection':
7878
$locked = $hidden = null;
79-
$styleAttributesP = $styleData->attributes($namespaces['x']);
79+
$styleAttributesP = array_key_exists('x', $namespaces) ? $styleData->attributes($namespaces['x']) : [];
8080
if (isset($styleAttributes['Protected'])) {
8181
$locked = ((bool) (string) $styleAttributes['Protected']) ? Protection::PROTECTION_PROTECTED : Protection::PROTECTION_UNPROTECTED;
8282
}

src/PhpSpreadsheet/Reader/Xml/Style/Alignment.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ public function parseStyle(SimpleXMLElement $styleAttributes): array
5454
case 'Indent':
5555
$style['alignment']['indent'] = $styleAttributeValue;
5656

57+
break;
58+
case 'ReadingOrder':
59+
if ($styleAttributeValue === 'RightToLeft') {
60+
$style['alignment']['readOrder'] = AlignmentStyles::READORDER_RTL;
61+
} elseif ($styleAttributeValue === 'LeftToRight') {
62+
$style['alignment']['readOrder'] = AlignmentStyles::READORDER_LTR;
63+
}
64+
5765
break;
5866
}
5967
}

src/PhpSpreadsheet/Style/Alignment.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ class Alignment extends Supervisor
9292
const TEXTROTATION_STACK_EXCEL = 255;
9393
const TEXTROTATION_STACK_PHPSPREADSHEET = -165; // 90 - 255
9494

95+
public const INDENT_UNITS_TO_PIXELS = 9;
96+
9597
/**
9698
* Horizontal alignment.
9799
*/

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,12 @@ private function createCSSStyleAlignment(Alignment $alignment): array
11151115
if ($textAlign) {
11161116
$css['text-align'] = $textAlign;
11171117
if (in_array($textAlign, ['left', 'right'])) {
1118-
$css['padding-' . $textAlign] = (string) ((int) $alignment->getIndent() * 9) . 'px';
1118+
$css['padding-' . $textAlign] = (string) ($alignment->getIndent() * Alignment::INDENT_UNITS_TO_PIXELS) . 'px';
1119+
}
1120+
} else {
1121+
$indent = $alignment->getIndent();
1122+
if ($indent !== 0) {
1123+
$css['text-indent'] = (string) ($alignment->getIndent() * Alignment::INDENT_UNITS_TO_PIXELS) . 'px';
11191124
}
11201125
}
11211126
$rotation = $alignment->getTextRotation();
@@ -1126,6 +1131,12 @@ private function createCSSStyleAlignment(Alignment $alignment): array
11261131
$css['transform'] = "rotate({$rotation}deg)";
11271132
}
11281133
}
1134+
$direction = $alignment->getReadOrder();
1135+
if ($direction === Alignment::READORDER_LTR) {
1136+
$css['direction'] = 'ltr';
1137+
} elseif ($direction === Alignment::READORDER_RTL) {
1138+
$css['direction'] = 'rtl';
1139+
}
11291140

11301141
return $css;
11311142
}
@@ -1516,7 +1527,6 @@ private function generateRowCellDataValue(Worksheet $worksheet, Cell $cell, stri
15161527
/** @param string|string[] $cssClass */
15171528
private function generateRowCellData(Worksheet $worksheet, null|Cell|string $cell, array|string &$cssClass): string
15181529
{
1519-
$cellData = ' ';
15201530
if ($cell instanceof Cell) {
15211531
$cellData = '';
15221532
// Don't know what this does, and no test cases.
@@ -1565,13 +1575,21 @@ private function generateRowCellData(Worksheet $worksheet, null|Cell|string $cel
15651575
}
15661576
}
15671577
} else {
1578+
$cellData = "$cell";
15681579
// Use default borders for empty cell
15691580
if (is_string($cssClass)) {
15701581
$cssClass .= ' style0';
15711582
}
15721583
}
1584+
/*
1585+
* Browsers may remove an entirely empty row.
1586+
* An interesting option is to leave an empty cell empty using css.
1587+
* td:empty::after{content: "\00a0";}
1588+
* This works well in modern browsers.
1589+
* Alas, none of our Pdf writers can handle it.
1590+
*/
15731591

1574-
return $cellData;
1592+
return (trim($cellData) === '') ? ' ' : $cellData;
15751593
}
15761594

15771595
private function generateRowIncludeCharts(Worksheet $worksheet, string $coordinate): string

src/PhpSpreadsheet/Writer/Ods/Cell/Style.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ private function writeCellProperties(CellStyle $style): void
151151
$vAlign = $style->getAlignment()->getVertical();
152152
$wrap = $style->getAlignment()->getWrapText();
153153
$indent = $style->getAlignment()->getIndent();
154+
$readOrder = $style->getAlignment()->getReadOrder();
154155

155156
$this->writer->startElement('style:table-cell-properties');
156157
if (!empty($vAlign) || $wrap) {
@@ -172,7 +173,7 @@ private function writeCellProperties(CellStyle $style): void
172173

173174
$this->writer->endElement();
174175

175-
if ($hAlign !== '' || !empty($indent)) {
176+
if ($hAlign !== '' || !empty($indent) || $readOrder === Alignment::READORDER_RTL || $readOrder === Alignment::READORDER_LTR) {
176177
$this->writer
177178
->startElement('style:paragraph-properties');
178179
if ($hAlign !== '') {
@@ -182,6 +183,11 @@ private function writeCellProperties(CellStyle $style): void
182183
$indentString = sprintf('%.4f', $indent * self::INDENT_TO_INCHES) . 'in';
183184
$this->writer->writeAttribute('fo:margin-left', $indentString);
184185
}
186+
if ($readOrder === Alignment::READORDER_RTL) {
187+
$this->writer->writeAttribute('style:writing-mode', 'rl-tb');
188+
} elseif ($readOrder === Alignment::READORDER_LTR) {
189+
$this->writer->writeAttribute('style:writing-mode', 'lr-tb');
190+
}
185191
$this->writer->endElement();
186192
}
187193
}

src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@ public function __construct(Spreadsheet $spreadsheet)
3030
*/
3131
protected function createExternalWriterInstance(string $orientation, string $unit, $paperSize): \TCPDF
3232
{
33+
$this->defines();
34+
3335
return new \TCPDF($orientation, $unit, $paperSize);
3436
}
3537

38+
protected function defines(): void
39+
{
40+
}
41+
3642
/**
3743
* Save Spreadsheet to file.
3844
*

0 commit comments

Comments
 (0)