From 22eb55ddfe383318538b36d291c63a37d8b4d167 Mon Sep 17 00:00:00 2001 From: aVadim Date: Fri, 12 Apr 2024 21:53:16 +0300 Subject: [PATCH] upd: save formulas with values --- docs/03-writing.md | 18 ++++++++++++++++++ src/FastExcelWriter/Sheet.php | 6 ++++-- src/FastExcelWriter/Writer/Writer.php | 16 ++++++++++++---- tests/FastExcelWriterTest.php | 5 +++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/docs/03-writing.md b/docs/03-writing.md index 7442adc..54d9709 100644 --- a/docs/03-writing.md +++ b/docs/03-writing.md @@ -335,6 +335,24 @@ $sheet1->writeRow([120, 560]); $sheet1->writeRow([130, 117]); ``` +**Important!** The library cannot pre-calculate values of formulas. It save formulas as is, without pre-calculation. +But when the saved file is opened in Excel, Excel recalculates all cells with formulas and show results. +There's only one way to save pre-calculations: you do those calculations in your code and save them along with the formula +```php +$a1 = 10; +$b1 = 30; +$a2 = 50; +$b2 = 70; +$sheet->writeRow([$a1, $b1]); +$sheet->writeRow([$a2, $b2]); + +// formula and pre-calculated result +$a3 = ['=A1+A2', $a1 + $a2]; +$b3 = ['=B1+B2', $b1 + $b2]; +$sheet->writeRow([$a3, $b3]); +``` + + ### Hyperlinks You can insert URLs as active hyperlinks diff --git a/src/FastExcelWriter/Sheet.php b/src/FastExcelWriter/Sheet.php index fc67673..c12b7b3 100644 --- a/src/FastExcelWriter/Sheet.php +++ b/src/FastExcelWriter/Sheet.php @@ -2311,7 +2311,10 @@ protected function _setCellData($cellAddress, $value, $styles = null, ?bool $mer } if ($value !== null) { - if (!is_scalar($value)) { + if (is_array($value) && !empty($value[0]) && is_string($value[0]) && ($value[0][0] === '=') && count($value) === 2) { + // it's a formula & value ['=A1+B2', 123] + } + elseif (!is_scalar($value)) { $addr = Excel::cellAddress($colIdx + 1, $rowIdx + 1); Exception::throwNew('Value for cell %s must be scalar', $addr); } @@ -2377,7 +2380,6 @@ public function setFormula($cellAddress, $value, array $styles = null): Sheet $value = '=' . $value; } - ///-- $styles = $styles ? Style::normalize($styles) : null; $this->_setCellData($cellAddress, $value, $styles, true); return $this; diff --git a/src/FastExcelWriter/Writer/Writer.php b/src/FastExcelWriter/Writer/Writer.php index c52a6e3..4689296 100644 --- a/src/FastExcelWriter/Writer/Writer.php +++ b/src/FastExcelWriter/Writer/Writer.php @@ -1200,14 +1200,22 @@ public function _writeCell(FileWriter $file, int $rowNumber, int $colNumber, $va if (is_array($value) && isset($value['shared_index'])) { $file->write('' . $value['shared_index'] . ''); } - elseif (!is_scalar($value) || $value === '') { //objects, array, empty; null is not scalar - $file->write(''); - } - elseif (is_string($value) && $value[0] === '=') { + elseif ($value && is_string($value) && $value[0] === '=') { // formula $value = $this->_convertFormula($value, [$rowNumber, $colNumber]); $file->write('' . self::xmlSpecialChars($value) . ''); } + elseif (is_array($value) && !empty($value[0]) && $value[0][0] === '=' && isset($value[1])) { + // formula & value + $formula = $this->_convertFormula($value[0], [$rowNumber, $colNumber]); + $file->write(''); + $file->write('' . self::xmlSpecialChars($formula) . ''); + $file->write('' . self::xmlSpecialChars($value[1]) . ''); + $file->write(''); + } + elseif (!is_scalar($value) || $value === '') { //objects, array, empty; null is not scalar + $file->write(''); + } elseif ($numFormatType === 'n_shared_string') { $file->write('' . $value . ''); } diff --git a/tests/FastExcelWriterTest.php b/tests/FastExcelWriterTest.php index 9210429..e335337 100644 --- a/tests/FastExcelWriterTest.php +++ b/tests/FastExcelWriterTest.php @@ -536,6 +536,7 @@ public function testExcelWriter4() $data = [ [2, 2, '=RC[-1]+RC[-2]', 2], [3, 3, '=RC[-1]+RC[-2]', 3], + [4, 4, ['=RC[-1]+RC[-2]', 8], 4], // formula & value ]; $area = $sheet->beginArea('b2'); $area->moveTo('c3'); @@ -549,6 +550,10 @@ public function testExcelWriter4() $this->assertEquals([1, 1, '=D3+C3', '1'], $this->getValues(['c3', 'd3', 'e3', 'f3'])); + // formula & value + $this->assertEquals(8, $this->cells[6]['E']['v']); + $this->assertEquals('=D6+C6', $this->cells[6]['E']['f']); + $style = $this->getStyle('c3', true); $this->assertEquals('21', $style['font-size']); $this->assertEquals('Century', $style['font-name']);