diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index d3b2039e4..122a7c16e 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -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; + } } diff --git a/tests/PhpSpreadsheetTests/Reader/Gnumeric/ArrayFormulaTest.php b/tests/PhpSpreadsheetTests/Reader/Gnumeric/ArrayFormulaTest.php new file mode 100644 index 000000000..99d12a613 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Gnumeric/ArrayFormulaTest.php @@ -0,0 +1,81 @@ +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]], + ], + ]; + } +} diff --git a/tests/data/Reader/Gnumeric/ArrayFormulaTest.gnumeric b/tests/data/Reader/Gnumeric/ArrayFormulaTest.gnumeric new file mode 100644 index 000000000..d2bc20d3b Binary files /dev/null and b/tests/data/Reader/Gnumeric/ArrayFormulaTest.gnumeric differ