Handle aray formulae in the Gnumeric Reader (with unit tests)

This commit is contained in:
MarkBaker
2022-03-04 22:09:14 +01:00
parent e4b7d73a9a
commit 3dbc7ddd25
3 changed files with 109 additions and 4 deletions
+28 -4
View File
@@ -516,15 +516,24 @@ class Gnumeric extends BaseReader
): void {
$ValueType = $cellAttributes->ValueType;
$ExprID = (string) $cellAttributes->ExprID;
$rows = (int) ($cellAttributes->Rows ?? 0);
$cols = (int) ($cellAttributes->Cols ?? 0);
$type = DataType::TYPE_FORMULA;
$isArrayFormula = ($rows > 0 || $cols > 0);
$arrayFormulaRange = $isArrayFormula ? $this->getArrayFormulaRange($column, $row, $cols, $rows) : null;
if ($ExprID > '') {
if (((string) $cell) > '') {
// Formula
$this->expressions[$ExprID] = [
'column' => $cellAttributes->Col,
'row' => $cellAttributes->Row,
'formula' => (string) $cell,
];
} else {
// "Shared" Formula
$expression = $this->expressions[$ExprID];
$cell = $this->referenceHelper->updateFormulaReferences(
@@ -535,22 +544,37 @@ class Gnumeric extends BaseReader
$worksheetName
);
}
$type = DataType::TYPE_FORMULA;
} else {
} elseif ($isArrayFormula === false) {
$vtype = (string) $ValueType;
if (array_key_exists($vtype, self::$mappings['dataType'])) {
$type = self::$mappings['dataType'][$vtype];
}
if ($vtype === '20') { // Boolean
if ($vtype === '20') { // Boolean
$cell = $cell == 'TRUE';
}
}
$this->spreadsheet->getActiveSheet()->getCell($column . $row)->setValueExplicit((string) $cell, $type);
$this->spreadsheet->getActiveSheet()
->getCell($column . $row)
->setValueExplicit((string) $cell, $type, $isArrayFormula, $arrayFormulaRange);
if (isset($cellAttributes->ValueFormat)) {
$this->spreadsheet->getActiveSheet()->getCell($column . $row)
->getStyle()->getNumberFormat()
->setFormatCode((string) $cellAttributes->ValueFormat);
}
}
private function getArrayFormulaRange(string $column, int $row, int $cols, int $rows): string
{
$arrayFormulaRange = $column . $row;
$arrayFormulaRange .= ':' .
Coordinate::stringFromColumnIndex(
Coordinate::columnIndexFromString($column)
+ $cols - 1
) .
(string) ($row + $rows - 1);
return $arrayFormulaRange;
}
}
@@ -0,0 +1,81 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Gnumeric;
use PhpOffice\PhpSpreadsheet\Reader\Gnumeric;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class ArrayFormulaTest extends TestCase
{
/**
* @var Spreadsheet
*/
private $spreadsheet;
protected function setUp(): void
{
$filename = 'tests/data/Reader/Gnumeric/ArrayFormulaTest.gnumeric';
$reader = new Gnumeric();
$this->spreadsheet = $reader->load($filename);
}
/**
* @dataProvider arrayFormulaReaderProvider
*/
public function testArrayFormulaReader(
string $cellAddress,
string $expectedRange,
string $expectedFormula,
array $expectedValue
): void {
$worksheet = $this->spreadsheet->getActiveSheet();
$cell = $worksheet->getCell($cellAddress);
self::assertTrue($cell->isArrayFormula());
self::assertSame($expectedRange, $cell->arrayFormulaRange());
self::assertSame($expectedFormula, $cell->getValue());
self::assertSame($expectedValue, $cell->getCalculatedValue(true, true));
// self::assertSame(8, $cell->getCalculatedValue());
// self::assertSame(8, $cell->getCalculatedValue());
// self::assertSame(12, $worksheet->getCell('C2')->getCalculatedValue());
// self::assertSame(10, $worksheet->getCell('B3')->getCalculatedValue());
// self::assertSame(15, $worksheet->getCell('C3')->getCalculatedValue());
}
public function arrayFormulaReaderProvider(): array
{
return [
[
'D1',
'D1:E2',
'=A1:B1*A1:A2',
[[4, 6], [8, 12]],
],
[
'D4',
'D4:E5',
'=A4:B4*A4:A5',
[[9, 12], [15, 20]],
],
[
'D7',
'D7:E8',
'=A7:B7*A7:A8',
[[16, 20], [24, 30]],
],
[
'D10',
'D10:E11',
'=A10:B10*A10:A11',
[[25, 30], [35, 42]],
],
[
'D13',
'D13:E14',
'=A13:B13*A13:A14',
[[36, 42], [48, 56]],
],
];
}
}
Binary file not shown.