Files
PhpSpreadsheet/tests/PhpSpreadsheetTests/Functional/ArrayFunctionsSpillTest.php
T
oleibman d7700125fa Spills
Implement SPILL for dynamic arrays. Calculating a dynamic array function will result in a SPILL error if it attempts to overlay a non-null cell which was not part of its previous calculation. Furthermore, it will set to null all cells which were part of its previous calculation but which are not part of the current one (i.e. one or both of the dimensions of the calculation is smaller than it had been); this should also apply for spills (whose result is reduced to 1*1).

Excel will stop you from changing the value in any cell in a dynamic array except the formula cell itself. I have not built this particular aspect into PhpSpreadsheet.

As usual, MS has taken some unusual steps here. If the result of a dynamic array calculation is #SPILL!, it will nevertheless be written to the xml as #VALUE!. It recognizes this situation by adding a new `vm` attribute to the cell, and expanding metadata.xml to recognize this.

A new optional parameter `$reduceArrays` is added to `toArray` and related functions. This will reduce a dynamic array to its first cell, which seems more useful than outputing it as an array (default).
2024-06-17 14:22:52 -07:00

72 lines
3.2 KiB
PHP

<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Functional;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class ArrayFunctionsSpillTest extends TestCase
{
private string $arrayReturnType;
protected function setUp(): void
{
$this->arrayReturnType = Calculation::getArrayReturnType();
}
protected function tearDown(): void
{
Calculation::setArrayReturnType($this->arrayReturnType);
}
public function testArrayOutput(): void
{
Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_ARRAY);
$spreadsheet = new Spreadsheet();
$calculation = Calculation::getInstance($spreadsheet);
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('B5', 'OCCUPIED');
$columnArray = [[1], [2], [2], [2], [3], [3], [3], [3], [4], [4], [4], [5]];
$sheet->fromArray($columnArray, 'A1');
$sheet->setCellValue('B1', '=UNIQUE(A1:A12)');
$expected = [['#SPILL!'], [null], [null], [null], ['OCCUPIED']];
self::assertSame($expected, $sheet->rangeToArray('B1:B5', calculateFormulas: true, formatData: false, reduceArrays: true), 'spill with B5 unchanged');
$calculation->clearCalculationCache();
$columnArray = [[1], [2], [2], [2], [3], [3], [3], [3], [4], [4], [4], [4]];
$sheet->fromArray($columnArray, 'A1');
$sheet->setCellValue('B1', '=UNIQUE(A1:A12)');
$expected = [[1], [2], [3], [4], ['OCCUPIED']];
self::assertSame($expected, $sheet->rangeToArray('B1:B5', calculateFormulas: true, formatData: false, reduceArrays: true), 'fill B1:B4 with B5 unchanged');
$calculation->clearCalculationCache();
$columnArray = [[1], [3], [3], [3], [3], [3], [3], [3], [3], [3], [3], [3]];
$sheet->fromArray($columnArray, 'A1');
$sheet->setCellValue('B1', '=UNIQUE(A1:A12)');
$expected = [[1], [3], [null], [null], ['OCCUPIED']];
self::assertSame($expected, $sheet->rangeToArray('B1:B5', calculateFormulas: true, formatData: false, reduceArrays: true), 'fill B1:B2(changed from prior) set B3:B4 to null B5 unchanged');
$calculation->clearCalculationCache();
$columnArray = [[1], [2], [3], [3], [3], [3], [3], [3], [3], [3], [3], [3]];
$sheet->fromArray($columnArray, 'A1');
$sheet->setCellValue('B1', '=UNIQUE(A1:A12)');
$expected = [[1], [2], [3], [null], ['OCCUPIED']];
self::assertSame($expected, $sheet->rangeToArray('B1:B5', calculateFormulas: true, formatData: false, reduceArrays: true), 'fill B1:B3(B2 changed from prior) set B4 to null B5 unchanged');
$calculation->clearCalculationCache();
$columnArray = [[1], [2], [2], [2], [3], [3], [3], [3], [4], [4], [4], [5]];
$sheet->fromArray($columnArray, 'A1');
$sheet->setCellValue('B1', '=UNIQUE(A1:A12)');
$expected = [['#SPILL!'], [null], [null], [null], ['OCCUPIED']];
self::assertSame($expected, $sheet->rangeToArray('B1:B5', calculateFormulas: true, formatData: false, reduceArrays: true), 'spill clears B2:B4 with B5 unchanged');
$calculation->clearCalculationCache();
$spreadsheet->disconnectWorksheets();
}
}