Skip to content

Commit ae4df82

Browse files
committed
Xlsx Reader Use Dynamic Arrays if Spreadsheet Did So
By default, when an Xlsx spreadsheet is read, its calculation engine is set to `RETURN_ARRAY_AS_VALUE` for array formulas. The user does have the option to change this. However, the presence of certain metadata in the file indicates that it was saved as if `RETURN_ARRAY_AS_ARRAY` was in use. This PR tests for the metadata, and, if present, sets `...ARRAY` rather than `...VALUE`. This eliminates the need for any extra action on the user's part.
1 parent 747ccd1 commit ae4df82

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PhpOffice\PhpSpreadsheet\Reader;
44

5+
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
56
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
67
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
78
use PhpOffice\PhpSpreadsheet\Cell\DataType;
@@ -449,6 +450,15 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
449450
$relTarget = substr($relTarget, 4);
450451
}
451452
switch ($rel['Type']) {
453+
case "$xmlNamespaceBase/sheetMetadata":
454+
if ($this->fileExistsInArchive($zip, "xl/{$relTarget}")) {
455+
$excel->getCalculationEngine()
456+
?->setInstanceArrayReturnType(
457+
Calculation::RETURN_ARRAY_AS_ARRAY
458+
);
459+
}
460+
461+
break;
452462
case "$xmlNamespaceBase/theme":
453463
if (!$this->fileExistsInArchive($zip, "xl/{$relTarget}")) {
454464
break; // issue3770
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
8+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
10+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
11+
12+
class ReadDynamTest extends AbstractFunctional
13+
{
14+
public function writeCse(XlsxWriter $writer): void
15+
{
16+
$writer->setUseCSEArrays(true);
17+
}
18+
19+
public function testCse(): void
20+
{
21+
$spreadsheetOld = new Spreadsheet();
22+
$sheetOld = $spreadsheetOld->getActiveSheet();
23+
$calcOld = Calculation::getInstance($spreadsheetOld);
24+
$calcOld->setInstanceArrayReturnType(
25+
Calculation::RETURN_ARRAY_AS_ARRAY
26+
);
27+
$sheetOld->fromArray(
28+
[1, 2, 2, 4, 3, 2, 1, 3, 3, 3, 5],
29+
null,
30+
'A14',
31+
true
32+
);
33+
$sheetOld->setCellValue('A15', '=UNIQUE(A14:K14, TRUE)');
34+
/** @var callable */
35+
$callableWriter = [$this, 'writeCse'];
36+
$spreadsheet = $this->writeAndReload($spreadsheetOld, 'Xlsx', null, $callableWriter);
37+
$spreadsheetOld->disconnectWorksheets();
38+
$calc = Calculation::getInstance($spreadsheet);
39+
self::assertSame(
40+
Calculation::RETURN_ARRAY_AS_VALUE,
41+
$calc->getInstanceArrayReturnType()
42+
);
43+
$spreadsheet->disconnectWorksheets();
44+
}
45+
46+
public function testDynam(): void
47+
{
48+
$spreadsheetOld = new Spreadsheet();
49+
$sheetOld = $spreadsheetOld->getActiveSheet();
50+
$calcOld = Calculation::getInstance($spreadsheetOld);
51+
$calcOld->setInstanceArrayReturnType(
52+
Calculation::RETURN_ARRAY_AS_ARRAY
53+
);
54+
$sheetOld->fromArray(
55+
[1, 2, 2, 4, 3, 2, 1, 3, 3, 3, 5],
56+
null,
57+
'A14',
58+
true
59+
);
60+
$sheetOld->setCellValue('A15', '=UNIQUE(A14:K14, TRUE)');
61+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheetOld, 'Xlsx');
62+
$spreadsheet = $this->writeAndReload($spreadsheetOld, 'Xlsx');
63+
$spreadsheetOld->disconnectWorksheets();
64+
$calc = Calculation::getInstance($spreadsheet);
65+
self::assertSame(
66+
Calculation::RETURN_ARRAY_AS_ARRAY,
67+
$calc->getInstanceArrayReturnType()
68+
);
69+
$spreadsheet->disconnectWorksheets();
70+
}
71+
}

0 commit comments

Comments
 (0)