Skip to content

Commit a2be574

Browse files
Roman DevmanPowerKiKi
authored andcommitted
Restore imperfect array formula values in xlsx writer
oleibman said: The results of uncommenting the statements will often not be successful. In Excel, if I enter `=MINVERSE({2,0;0,1})` into cell A1, you will get a `dynamic array` (which we do not yet support) - A1 will contain 0.5, A2 and B1 will contain 0, and B2 will contain 1. There are also `spill` implications for such a formula. The XML for these cells will be: ``` xml <row r="1" spans="1:2" x14ac:dyDescent="0.3"> <c r="A1" cm="1"> <f t="array" ref="A1:B2">MINVERSE({2,0;0,1})</f> <v>0.5</v> </c> <c r="B1"> <v>0</v> </c> </row> <row r="2" spans="1:2" x14ac:dyDescent="0.3"> <c r="A2"> <v>0</v> </c> <c r="B2"> <v>1</v> </c> </row> ``` I believe that the PhpSpreadsheet equivalent of doing this (with the statements uncommented) is: ```php $spreadsheet = new Spreadsheet(); $calculation = Calculation::getInstance($spreadsheet); $calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_ARRAY); $sheet = $spreadsheet->getActiveSheet(); $sheet->getCell('A1')->setValue('=MINVERSE({2,0;0,1})'); $writer = new Xlsx($spreadsheet); $oufil = 'issue.2343.xlsx'; $writer->save($oufil); ``` But our output file only fills in A1: ```xml <row r="1" spans="1:1"> <c r="A1"> <f>MINVERSE({2,0;0,1})</f> <v>0.5</v> </c> </row> ``` And, even though A1 has its correct value, note that its `f` tag does not have a `t` attribute. This is because we never set any formula attributes, except in Xlsx Reader (see next paragraph), so we do not encounter the `'array'` condtion for a formula newly added to a spreadsheet. We do slightly better when we read the first file (as opposed to creating a new spreadsheet), but we succeed only by accident. Because B1, A2, and B2 are assigned values in the XML, all 4 cells will have the expected values. But they are now independent of each other, not part of a dynamic array. When we write this out, it is almost correct: ```xml <row r="1" spans="1:2"> <c r="A1"> <f>MINVERSE({2,0;0,1})</f> <v>0.5</v> </c> <c r="B1"> <v>0</v> </c> </row> <row r="2" spans="1:2"> <c r="A2"> <v>0</v> </c> <c r="B2"> <v>1</v> </c> </row> ``` Again, the `f` tag has no `t` attribute, and it doesn't seem to matter whether we set RETURN_TYPE_ARRAY or not. I think this particular aspect of the problem might be relatively easy to fix.
1 parent 0c93bba commit a2be574

File tree

1 file changed

+20
-21
lines changed

1 file changed

+20
-21
lines changed

src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,27 +1205,26 @@ private function writeCellFormula(XMLWriter $objWriter, string $cellValue, Cell
12051205
$objWriter->writeAttribute('t', 'b');
12061206
$calculatedValue = (int) $calculatedValue;
12071207
}
1208-
// array values are not yet supported
1209-
//$attributes = $pCell->getFormulaAttributes();
1210-
//if (($attributes['t'] ?? null) === 'array') {
1211-
// $objWriter->startElement('f');
1212-
// $objWriter->writeAttribute('t', 'array');
1213-
// $objWriter->writeAttribute('ref', $pCellAddress);
1214-
// $objWriter->writeAttribute('aca', '1');
1215-
// $objWriter->writeAttribute('ca', '1');
1216-
// $objWriter->text(substr($cellValue, 1));
1217-
// $objWriter->endElement();
1218-
//} else {
1219-
// $objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
1220-
//}
1221-
$objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
1222-
self::writeElementIf(
1223-
$objWriter,
1224-
$this->getParentWriter()->getOffice2003Compatibility() === false,
1225-
'v',
1226-
($this->getParentWriter()->getPreCalculateFormulas() && !is_array($calculatedValue) && substr($calculatedValue ?? '', 0, 1) !== '#')
1227-
? StringHelper::formatNumber($calculatedValue) : '0'
1228-
);
1208+
1209+
$attributes = $cell->getFormulaAttributes();
1210+
if (($attributes['t'] ?? null) === 'array') {
1211+
$objWriter->startElement('f');
1212+
$objWriter->writeAttribute('t', 'array');
1213+
$objWriter->writeAttribute('ref', $cell->getCoordinate());
1214+
$objWriter->writeAttribute('aca', '1');
1215+
$objWriter->writeAttribute('ca', '1');
1216+
$objWriter->text(substr($cellValue, 1));
1217+
$objWriter->endElement();
1218+
} else {
1219+
$objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
1220+
self::writeElementIf(
1221+
$objWriter,
1222+
$this->getParentWriter()->getOffice2003Compatibility() === false,
1223+
'v',
1224+
($this->getParentWriter()->getPreCalculateFormulas() && !is_array($calculatedValue) && substr($calculatedValue, 0, 1) !== '#')
1225+
? StringHelper::formatNumber($calculatedValue) : '0'
1226+
);
1227+
}
12291228
}
12301229

12311230
/**

0 commit comments

Comments
 (0)