Skip to content

Commit 12861f4

Browse files
authored
Merge pull request PHPOffice#4787 from oleibman/issue1810
Option To Use OldCalculatedValue in ToArray and its Relatives
2 parents 7758d91 + c735e2f commit 12861f4

File tree

3 files changed

+76
-11
lines changed

3 files changed

+76
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a
99

1010
### Added
1111

12+
- Option to use OldCalculatedValue in ToArray and Relatives. [Issue #1810](https://github.com/PHPOffice/PhpSpreadsheet/issues/1810) [PR #4787](https://github.com/PHPOffice/PhpSpreadsheet/pull/4787)
1213
- Add checkbox style (Xlsx and Html). [PR #4781](https://github.com/PHPOffice/PhpSpreadsheet/pull/4781)
1314
- Writer/Html add ability to set line ending. [PR #4779](https://github.com/PHPOffice/PhpSpreadsheet/pull/4779)
1415
- Writer/Html optionally save formulas as data attributes. [PR #4783](https://github.com/PHPOffice/PhpSpreadsheet/pull/4783)

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2985,19 +2985,24 @@ public function fromArray(array $source, mixed $nullValue = null, string $startC
29852985
* @param null|bool|float|int|RichText|string $nullValue value to use when null
29862986
* @param bool $formatData Whether to format data according to cell's style.
29872987
* @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value
2988+
* @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead.
29882989
*
29892990
* @throws Exception
29902991
* @throws \PhpOffice\PhpSpreadsheet\Calculation\Exception
29912992
*/
2992-
protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $formatData, mixed $nullValue, bool $lessFloatPrecision = false): mixed
2993+
protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $formatData, mixed $nullValue, bool $lessFloatPrecision = false, $oldCalculatedValue = false): mixed
29932994
{
29942995
$returnValue = $nullValue;
29952996

29962997
if ($cell->getValue() !== null) {
29972998
if ($cell->getValue() instanceof RichText) {
29982999
$returnValue = $cell->getValue()->getPlainText();
3000+
} elseif ($calculateFormulas) {
3001+
$returnValue = $cell->getCalculatedValue();
3002+
} elseif ($oldCalculatedValue && ($cell->getDataType() === DataType::TYPE_FORMULA)) {
3003+
$returnValue = $cell->getOldCalculatedValue() ?? $cell->getValue();
29993004
} else {
3000-
$returnValue = ($calculateFormulas) ? $cell->getCalculatedValue() : $cell->getValue();
3005+
$returnValue = $cell->getValue();
30013006
}
30023007

30033008
if ($formatData) {
@@ -3027,6 +3032,7 @@ protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $format
30273032
* True - Don't return values for rows/columns that are defined as hidden.
30283033
* @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value.
30293034
* @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value
3035+
* @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead.
30303036
*
30313037
* @return mixed[][]
30323038
*/
@@ -3038,12 +3044,13 @@ public function rangeToArray(
30383044
bool $returnCellRef = false,
30393045
bool $ignoreHidden = false,
30403046
bool $reduceArrays = false,
3041-
bool $lessFloatPrecision = false
3047+
bool $lessFloatPrecision = false,
3048+
bool $oldCalculatedValue = false,
30423049
): array {
30433050
$returnValue = [];
30443051

30453052
// Loop through rows
3046-
foreach ($this->rangeToArrayYieldRows($range, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision) as $rowRef => $rowArray) {
3053+
foreach ($this->rangeToArrayYieldRows($range, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue) as $rowRef => $rowArray) {
30473054
/** @var int $rowRef */
30483055
$returnValue[$rowRef] = $rowArray;
30493056
}
@@ -3064,6 +3071,7 @@ public function rangeToArray(
30643071
* True - Don't return values for rows/columns that are defined as hidden.
30653072
* @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value.
30663073
* @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value
3074+
* @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead.
30673075
*
30683076
* @return mixed[][]
30693077
*/
@@ -3076,13 +3084,14 @@ public function rangesToArray(
30763084
bool $ignoreHidden = false,
30773085
bool $reduceArrays = false,
30783086
bool $lessFloatPrecision = false,
3087+
bool $oldCalculatedValue = false,
30793088
): array {
30803089
$returnValue = [];
30813090

30823091
$parts = explode(',', $ranges);
30833092
foreach ($parts as $part) {
30843093
// Loop through rows
3085-
foreach ($this->rangeToArrayYieldRows($part, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision) as $rowRef => $rowArray) {
3094+
foreach ($this->rangeToArrayYieldRows($part, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue) as $rowRef => $rowArray) {
30863095
/** @var int $rowRef */
30873096
$returnValue[$rowRef] = $rowArray;
30883097
}
@@ -3104,6 +3113,7 @@ public function rangesToArray(
31043113
* True - Don't return values for rows/columns that are defined as hidden.
31053114
* @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value.
31063115
* @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value
3116+
* @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead.
31073117
*
31083118
* @return Generator<array<mixed>>
31093119
*/
@@ -3115,7 +3125,8 @@ public function rangeToArrayYieldRows(
31153125
bool $returnCellRef = false,
31163126
bool $ignoreHidden = false,
31173127
bool $reduceArrays = false,
3118-
bool $lessFloatPrecision = false
3128+
bool $lessFloatPrecision = false,
3129+
bool $oldCalculatedValue = false,
31193130
) {
31203131
$range = Validations::validateCellOrCellRange($range);
31213132

@@ -3181,7 +3192,7 @@ public function rangeToArrayYieldRows(
31813192
$columnRef = $returnCellRef ? $col : ($thisCol - $minColInt);
31823193
$cell = $this->cellCollection->get("{$col}{$thisRow}");
31833194
if ($cell !== null) {
3184-
$value = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue, lessFloatPrecision: $lessFloatPrecision);
3195+
$value = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue, lessFloatPrecision: $lessFloatPrecision, oldCalculatedValue: $oldCalculatedValue);
31853196
if ($reduceArrays) {
31863197
while (is_array($value)) {
31873198
$value = array_shift($value);
@@ -3284,6 +3295,7 @@ private function validateNamedRange(string $definedName, bool $returnNullIfInval
32843295
* True - Don't return values for rows/columns that are defined as hidden.
32853296
* @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value.
32863297
* @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value
3298+
* @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead.
32873299
*
32883300
* @return mixed[][]
32893301
*/
@@ -3295,7 +3307,8 @@ public function namedRangeToArray(
32953307
bool $returnCellRef = false,
32963308
bool $ignoreHidden = false,
32973309
bool $reduceArrays = false,
3298-
bool $lessFloatPrecision = false
3310+
bool $lessFloatPrecision = false,
3311+
bool $oldCalculatedValue = false,
32993312
): array {
33003313
$retVal = [];
33013314
$namedRange = $this->validateNamedRange($definedName);
@@ -3304,7 +3317,7 @@ public function namedRangeToArray(
33043317
$cellRange = str_replace('$', '', $cellRange);
33053318
$workSheet = $namedRange->getWorksheet();
33063319
if ($workSheet !== null) {
3307-
$retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision);
3320+
$retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue);
33083321
}
33093322
}
33103323

@@ -3323,6 +3336,7 @@ public function namedRangeToArray(
33233336
* True - Don't return values for rows/columns that are defined as hidden.
33243337
* @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value.
33253338
* @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value
3339+
* @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead.
33263340
*
33273341
* @return mixed[][]
33283342
*/
@@ -3333,7 +3347,8 @@ public function toArray(
33333347
bool $returnCellRef = false,
33343348
bool $ignoreHidden = false,
33353349
bool $reduceArrays = false,
3336-
bool $lessFloatPrecision = false
3350+
bool $lessFloatPrecision = false,
3351+
bool $oldCalculatedValue = false,
33373352
): array {
33383353
// Garbage collect...
33393354
$this->garbageCollect();
@@ -3344,7 +3359,7 @@ public function toArray(
33443359
$maxRow = $this->getHighestRow();
33453360

33463361
// Return
3347-
return $this->rangeToArray("A1:{$maxCol}{$maxRow}", $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision);
3362+
return $this->rangeToArray("A1:{$maxCol}{$maxRow}", $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue);
33483363
}
33493364

33503365
/**
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
9+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
10+
11+
class ToArrayOldCalculatedValueTest extends AbstractFunctional
12+
{
13+
public function testOldCalculatedValue(): void
14+
{
15+
$spreadsheet = new Spreadsheet();
16+
$sheet = $spreadsheet->getActiveSheet();
17+
$sheet->fromArray([['A', 'B', 'C', '=1+2']]);
18+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
19+
$spreadsheet->disconnectWorksheets();
20+
$rsheet = $reloadedSpreadsheet->getActiveSheet();
21+
$rsheet->setCellValue('D1', '=1+3');
22+
$array1 = $rsheet->toArray(formatData: false, calculateFormulas: false, oldCalculatedValue: true);
23+
self::assertSame([['A', 'B', 'C', 3]], $array1, 'uses value as read from spreadsheet');
24+
$array2 = $rsheet->toArray(formatData: false);
25+
self::assertSame([['A', 'B', 'C', 4]], $array2, 'uses newly calculated value');
26+
27+
$reloadedSpreadsheet->disconnectWorksheets();
28+
}
29+
30+
private function noPreCalculation(XlsxWriter $writer): void
31+
{
32+
$writer->setPreCalculateFormulas(false);
33+
}
34+
35+
public function testNoPreCalculate(): void
36+
{
37+
$spreadsheet = new Spreadsheet();
38+
$sheet = $spreadsheet->getActiveSheet();
39+
$sheet->fromArray([['A', 'B', 'C', '=1+2']]);
40+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', null, $this->noPreCalculation(...));
41+
$spreadsheet->disconnectWorksheets();
42+
$rsheet = $reloadedSpreadsheet->getActiveSheet();
43+
$rsheet->setCellValue('D1', '=1+3');
44+
$array1 = $rsheet->toArray(formatData: false, calculateFormulas: false, oldCalculatedValue: true);
45+
self::assertSame([['A', 'B', 'C', '=1+3']], $array1, 'uses value of cell if formula was not calculated');
46+
47+
$reloadedSpreadsheet->disconnectWorksheets();
48+
}
49+
}

0 commit comments

Comments
 (0)