Skip to content

Commit 9a94aea

Browse files
authored
Merge pull request #3924 from oleibman/issue3918
Default Style Alignment
2 parents 9c5bf34 + 280c18e commit 9a94aea

File tree

5 files changed

+133
-3
lines changed

5 files changed

+133
-3
lines changed

CHANGELOG.md

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

1010
### Added
1111

12-
- Nothing
12+
- Default Style Alignment Property (workaround for bug in non-Excel spreadsheet apps) [Issue #3918](https://github.com/PHPOffice/PhpSpreadsheet/issues/3918) [PR #3924](https://github.com/PHPOffice/PhpSpreadsheet/pull/3924)
1313

1414
### Changed
1515

@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
3232
- Fix issue with prepending zero in percentage [Issue #3920](https://github.com/PHPOffice/PhpSpreadsheet/issues/3920) [PR #3921](https://github.com/PHPOffice/PhpSpreadsheet/pull/3921)
3333
- Incorrect SUMPRODUCT Calculation [Issue #3909](https://github.com/PHPOffice/PhpSpreadsheet/issues/3909) [PR #3916](https://github.com/PHPOffice/PhpSpreadsheet/pull/3916)
3434
- Formula Misidentifying Text as Cell After Insertion/Deletion [Issue #3907](https://github.com/PHPOffice/PhpSpreadsheet/issues/3907) [PR #3915](https://github.com/PHPOffice/PhpSpreadsheet/pull/3915)
35+
- Unexpected Absolute Address in Xlsx Rels [Issue #3730](https://github.com/PHPOffice/PhpSpreadsheet/issues/3730) [PR #3923](https://github.com/PHPOffice/PhpSpreadsheet/pull/3923)
3536

3637
## 2.0.0 - 2024-01-04
3738

docs/topics/accessing-cells.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ $spreadsheet->getActiveSheet()
4242
If you make a call to `getCell()`, and the cell doesn't already exist, then
4343
PhpSpreadsheet will create that cell for you.
4444

45-
### BEWARE: Cells assigned to variables as a Detached Reference
45+
### BEWARE: Cells and Styles assigned to variables as a Detached Reference
4646

4747
As an "in-memory" model, PHPSpreadsheet can be very demanding of memory,
4848
particularly when working with large spreadsheets. One technique used to
@@ -54,6 +54,7 @@ While this is not normally an issue, it can become significant
5454
if you assign the result of a call to `getCell()` to a variable. Any
5555
subsequent calls to retrieve other cells will change that pointer, although
5656
the cell object will still retain its data values.
57+
This is also true when assigning a variable to the result of `getStyle()`.
5758

5859
What does this mean? Consider the following code:
5960

src/PhpSpreadsheet/Writer/Xlsx.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ class Xlsx extends BaseWriter
134134

135135
private Worksheet $writerPartWorksheet;
136136

137+
private bool $explicitStyle0 = false;
138+
137139
/**
138140
* Create a new Xlsx Writer.
139141
*/
@@ -692,4 +694,21 @@ private function processDrawing(WorksheetDrawing $drawing): string|null|false
692694

693695
return $data;
694696
}
697+
698+
public function getExplicitStyle0(): bool
699+
{
700+
return $this->explicitStyle0;
701+
}
702+
703+
/**
704+
* This may be useful if non-default Alignment is part of default style
705+
* and you think you might want to open the spreadsheet
706+
* with LibreOffice or Gnumeric.
707+
*/
708+
public function setExplicitStyle0(bool $explicitStyle0): self
709+
{
710+
$this->explicitStyle0 = $explicitStyle0;
711+
712+
return $this;
713+
}
695714
}

src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class Worksheet extends WriterPart
2828

2929
private string $evalError = '';
3030

31+
private bool $explicitStyle0;
32+
3133
/**
3234
* Write worksheet to XML format.
3335
*
@@ -38,6 +40,7 @@ class Worksheet extends WriterPart
3840
*/
3941
public function writeWorksheet(PhpspreadsheetWorksheet $worksheet, array $stringTable = [], bool $includeCharts = false): string
4042
{
43+
$this->explicitStyle0 = $this->getParentWriter()->getExplicitStyle0();
4144
$this->numberStoredAsText = '';
4245
$this->formula = '';
4346
$this->twoDigitTextYear = '';
@@ -1441,7 +1444,11 @@ private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksh
14411444
$objWriter->writeAttribute('r', $cellAddress);
14421445

14431446
// Sheet styles
1444-
self::writeAttributeIf($objWriter, (bool) $xfi, 's', "$xfi");
1447+
if ($xfi) {
1448+
$objWriter->writeAttribute('s', "$xfi");
1449+
} elseif ($this->explicitStyle0) {
1450+
$objWriter->writeAttribute('s', '0');
1451+
}
14451452

14461453
// If cell value is supplied, write cell value
14471454
if ($writeValue) {
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
8+
use PhpOffice\PhpSpreadsheet\Shared\File;
9+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
10+
use PhpOffice\PhpSpreadsheet\Style\Alignment;
11+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
12+
use PHPUnit\Framework\TestCase;
13+
14+
class ExplicitStyle0Test extends TestCase
15+
{
16+
private string $outputFile = '';
17+
18+
protected function tearDown(): void
19+
{
20+
if ($this->outputFile !== '') {
21+
unlink($this->outputFile);
22+
$this->outputFile = '';
23+
}
24+
}
25+
26+
public function testWithoutExplicitStyle0(): void
27+
{
28+
$spreadsheet = new Spreadsheet();
29+
$defaultStyle = $spreadsheet->getDefaultStyle();
30+
$defaultStyle->getFont()->setBold(true);
31+
$defaultStyle->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
32+
$sheet = $spreadsheet->getActiveSheet();
33+
$sheet->getCell('A1')->setValue('bold');
34+
$sheet->getCell('A2')->setValue('italic');
35+
$sheet->getStyle('A2')->getFont()->setItalic(true);
36+
$writer = new XlsxWriter($spreadsheet);
37+
$this->outputFile = File::temporaryFilename();
38+
$writer->save($this->outputFile);
39+
$spreadsheet->disconnectWorksheets();
40+
41+
$reader = new XlsxReader();
42+
$spreadsheet2 = $reader->load($this->outputFile);
43+
$sheet2 = $spreadsheet2->getActiveSheet();
44+
self::assertTrue($sheet2->getStyle('A1')->getFont()->getBold());
45+
self::assertFalse($sheet2->getStyle('A1')->getFont()->getItalic());
46+
self::assertSame(Alignment::HORIZONTAL_CENTER, $sheet2->getStyle('A1')->getAlignment()->getHorizontal());
47+
self::assertTrue($sheet2->getStyle('A2')->getFont()->getBold());
48+
self::assertTrue($sheet2->getStyle('A2')->getFont()->getItalic());
49+
self::assertSame(Alignment::HORIZONTAL_CENTER, $sheet2->getStyle('A2')->getAlignment()->getHorizontal());
50+
$spreadsheet2->disconnectWorksheets();
51+
52+
$file = 'zip://';
53+
$file .= $this->outputFile;
54+
$file .= '#xl/worksheets/sheet1.xml';
55+
$data = file_get_contents($file);
56+
if ($data === false) {
57+
self::fail('Unable to read file');
58+
} else {
59+
self::assertStringContainsString('<c r="A1" t="s"><v>0</v></c>', $data, 'no s attribute in c tag');
60+
self::assertStringContainsString('<c r="A2" s="1" t="s"><v>1</v></c>', $data);
61+
}
62+
}
63+
64+
public function testWithExplicitStyle0(): void
65+
{
66+
$spreadsheet = new Spreadsheet();
67+
$defaultStyle = $spreadsheet->getDefaultStyle();
68+
$defaultStyle->getFont()->setBold(true);
69+
$defaultStyle->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
70+
$sheet = $spreadsheet->getActiveSheet();
71+
$sheet->getCell('A1')->setValue('bold');
72+
$sheet->getCell('A2')->setValue('italic');
73+
$sheet->getStyle('A2')->getFont()->setItalic(true);
74+
$writer = new XlsxWriter($spreadsheet);
75+
$writer->setExplicitStyle0(true);
76+
$this->outputFile = File::temporaryFilename();
77+
$writer->save($this->outputFile);
78+
$spreadsheet->disconnectWorksheets();
79+
80+
$reader = new XlsxReader();
81+
$spreadsheet2 = $reader->load($this->outputFile);
82+
$sheet2 = $spreadsheet2->getActiveSheet();
83+
self::assertTrue($sheet2->getStyle('A1')->getFont()->getBold());
84+
self::assertFalse($sheet2->getStyle('A1')->getFont()->getItalic());
85+
self::assertSame(Alignment::HORIZONTAL_CENTER, $sheet2->getStyle('A1')->getAlignment()->getHorizontal());
86+
self::assertTrue($sheet2->getStyle('A2')->getFont()->getBold());
87+
self::assertTrue($sheet2->getStyle('A2')->getFont()->getItalic());
88+
self::assertSame(Alignment::HORIZONTAL_CENTER, $sheet2->getStyle('A2')->getAlignment()->getHorizontal());
89+
$spreadsheet2->disconnectWorksheets();
90+
91+
$file = 'zip://';
92+
$file .= $this->outputFile;
93+
$file .= '#xl/worksheets/sheet1.xml';
94+
$data = file_get_contents($file);
95+
if ($data === false) {
96+
self::fail('Unable to read file');
97+
} else {
98+
self::assertStringContainsString('<c r="A1" s="0" t="s"><v>0</v></c>', $data, 'has s attribute in c tag');
99+
self::assertStringContainsString('<c r="A2" s="1" t="s"><v>1</v></c>', $data);
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)