Skip to content

Commit 455f112

Browse files
committed
RTL Text Alignment in Xlsx Comment
Fix #4004. RTL text can be included in a comment, and will display correctly, but the comment as a whole will be left-aligned. There already exists an `alignment` property for Comment, but it is unused. This PR will allow that property to be set, and to be read from and written to an Xlsx spreadsheet when possible. The Xml tags that govern this property are found, unusually, in a drawing Vml file. The important property is `x:TextHAlign`, which can be set to Left, Right, Center, Justified, or Distributed. There are other tags which seemed like they were relevant to this problem, but I don't think they actually matter: ```xml <v:textbox style='mso-direction-alt:auto'> <div style='text-align:right;direction:rtl'></div> </v:textbox> ```
1 parent 35030fa commit 455f112

File tree

5 files changed

+67
-2
lines changed

5 files changed

+67
-2
lines changed

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
11321132
$fillColor = strtoupper(substr((string) $shape['fillcolor'], 1));
11331133
$column = null;
11341134
$row = null;
1135+
$textHAlign = null;
11351136
$fillImageRelId = null;
11361137
$fillImageTitle = '';
11371138

@@ -1149,8 +1150,17 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
11491150
if (is_array($temp)) {
11501151
$column = $temp[0];
11511152
}
1153+
$temp = $clientData->xpath('.//x:TextHAlign');
1154+
if (!empty($temp)) {
1155+
$textHAlign = $temp[0];
1156+
}
11521157
}
11531158
}
1159+
$rowx = (string) $row;
1160+
$colx = (string) $column;
1161+
if (is_numeric($rowx) && is_numeric($colx) && $textHAlign !== null) {
1162+
$docSheet->getComment([1 + (int) $colx, 1 + (int) $rowx], false)->setAlignment((string) $textHAlign);
1163+
}
11541164

11551165
$fillImageRelNode = $shape->xpath('.//v:fill/@o:relid');
11561166
if (is_array($fillImageRelNode) && !empty($fillImageRelNode)) {

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2626,7 +2626,7 @@ public function removeComment(CellAddress|string|array $cellCoordinate): self
26262626
* @param array{0: int, 1: int}|CellAddress|string $cellCoordinate Coordinate of the cell as a string, eg: 'C5';
26272627
* or as an array of [$columnIndex, $row] (e.g. [3, 5]), or a CellAddress object.
26282628
*/
2629-
public function getComment(CellAddress|string|array $cellCoordinate): Comment
2629+
public function getComment(CellAddress|string|array $cellCoordinate, bool $attachNew = true): Comment
26302630
{
26312631
$cellAddress = Functions::trimSheetFromCellReference(Validations::validateCellAddress($cellCoordinate));
26322632

@@ -2645,7 +2645,9 @@ public function getComment(CellAddress|string|array $cellCoordinate): Comment
26452645

26462646
// If not, create a new comment.
26472647
$newComment = new Comment();
2648-
$this->comments[$cellAddress] = $newComment;
2648+
if ($attachNew) {
2649+
$this->comments[$cellAddress] = $newComment;
2650+
}
26492651

26502652
return $newComment;
26512653
}

src/PhpSpreadsheet/Writer/Xlsx/Comments.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@
66
use PhpOffice\PhpSpreadsheet\Comment;
77
use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces;
88
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
9+
use PhpOffice\PhpSpreadsheet\Style\Alignment;
910

1011
class Comments extends WriterPart
1112
{
13+
private const VALID_HORIZONTAL_ALIGNMENT = [
14+
Alignment::HORIZONTAL_CENTER,
15+
Alignment::HORIZONTAL_DISTRIBUTED,
16+
Alignment::HORIZONTAL_JUSTIFY,
17+
Alignment::HORIZONTAL_LEFT,
18+
Alignment::HORIZONTAL_RIGHT,
19+
];
20+
1221
/**
1322
* Write comments to XML format.
1423
*
@@ -223,6 +232,12 @@ private function writeVMLComment(XMLWriter $objWriter, string $cellReference, Co
223232
// x:AutoFill
224233
$objWriter->writeElement('x:AutoFill', 'False');
225234

235+
// x:TextHAlign horizontal alignment of text
236+
$alignment = strtolower($comment->getAlignment());
237+
if (in_array($alignment, self::VALID_HORIZONTAL_ALIGNMENT, true)) {
238+
$objWriter->writeElement('x:TextHAlign', ucfirst($alignment));
239+
}
240+
226241
// x:Row
227242
$objWriter->writeElement('x:Row', (string) ($row - 1));
228243

tests/PhpSpreadsheetTests/CommentTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,6 @@ public function testRemoveComment(): void
9696
self::assertArrayHasKey('A2', $comments1);
9797
$sheet->removeComment('A2');
9898
self::assertEmpty($sheet->getComments());
99+
$spreadsheet->disconnectWorksheets();
99100
}
100101
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PhpOffice\PhpSpreadsheet\Style\Alignment;
9+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
10+
11+
class CommentAlignmentTest extends AbstractFunctional
12+
{
13+
public function testIssue4004(): void
14+
{
15+
$type = 'Xlsx';
16+
$spreadsheet = new Spreadsheet();
17+
$sheet = $spreadsheet->getActiveSheet();
18+
$sheet->getComment('A3')->getText()->createText('Comment');
19+
$sheet->getComment('A4')->getText()->createText('שלום');
20+
$sheet->getComment('A4')->setAlignment(Alignment::HORIZONTAL_RIGHT);
21+
22+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $type);
23+
$spreadsheet->disconnectWorksheets();
24+
25+
self::assertCount(1, $reloadedSpreadsheet->getAllSheets());
26+
27+
$rsheet = $reloadedSpreadsheet->getActiveSheet();
28+
$comment1 = $rsheet->getComment('A3');
29+
self::assertSame('Comment', $comment1->getText()->getPlainText());
30+
self::assertSame('general', $comment1->getAlignment());
31+
$comment2 = $rsheet->getComment('A4');
32+
self::assertSame('שלום', $comment2->getText()->getPlainText());
33+
self::assertSame('Right', $comment2->getAlignment());
34+
35+
$reloadedSpreadsheet->disconnectWorksheets();
36+
}
37+
}

0 commit comments

Comments
 (0)