Description
This is:
- [x] a bug report
- [ ] a feature request
- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)
What is the expected behavior?
Xlsx files written using this library should have its formulas recalculated when opening the file from Excel.
What is the current behavior?
The formulas do not get recalculated.
What are the steps to reproduce?
- Create a very simple spreadsheet from Excel with:
- a formula on A1 => '=A2*2'.
- a value on A2 => 0
- Save the file from Excel
- Now open this file with the library and set value = 3 on A2
- Save a new xlsx file from the library
- Open the new xslx with Excel
- The formula on A1 is not updated
I have seen that the library will set these attributes on the generated xl/workbook.xml
inside the xslx compressed file:
<x:calcPr calcId="999999" calcMode="auto" fullCalcOnLoad="1" calcCompleted="0"/>
BUT if I tamper the file with C# library OpenXML and follow the steps from the accepted answer from the post, which suggests doing this:
spreadSheet.WorkbookPart.Workbook.CalculationProperties.ForceFullCalculation = true;
spreadSheet.WorkbookPart.Workbook.CalculationProperties.FullCalculationOnLoad = true;
Then the generated xl/workbook.xml
file has following flags instead:
<x:calcPr calcId="999999" calcMode="auto" fullCalcOnLoad="1" calcCompleted="0" forceFullCalc="1" />
Notice the additional forceFullCalc="1"
attribute.
If I modify the file src/PhpSpreadsheet/Writer/Xlsx/Workbook.php and change this...
private function writeCalcPr(XMLWriter $objWriter, $recalcRequired = true)
{
$objWriter->startElement('calcPr');
// Set the calcid to a higher value than Excel itself will use, otherwise Excel will always recalc
// If MS Excel does do a recalc, then users opening a file in MS Excel will be prompted to save on exit
// because the file has changed
$objWriter->writeAttribute('calcId', '999999');
$objWriter->writeAttribute('calcMode', 'auto');
// fullCalcOnLoad isn't needed if we've recalculating for the save
$objWriter->writeAttribute('calcCompleted', ($recalcRequired) ? 1 : 0);
$objWriter->writeAttribute('fullCalcOnLoad', ($recalcRequired) ? 0 : 1);
$objWriter->endElement();
}
... to this (changes in bold)...
private function writeCalcPr(XMLWriter $objWriter, $recalcRequired = true)
{
$objWriter->startElement('calcPr');
// Set the calcid to a higher value than Excel itself will use, otherwise Excel will always recalc
// If MS Excel does do a recalc, then users opening a file in MS Excel will be prompted to save on exit
// because the file has changed
$objWriter->writeAttribute('calcId', '999999');
$objWriter->writeAttribute('calcMode', 'auto');
// fullCalcOnLoad isn't needed if we've recalculating for the save
$objWriter->writeAttribute('calcCompleted', ($recalcRequired) ? 1 : 0);
$objWriter->writeAttribute('fullCalcOnLoad', ($recalcRequired) ? 0 : 1);
**$objWriter->writeAttribute('forceFullCalc', ($recalcRequired) ? 0 : 1);**
$objWriter->endElement();
}
Everything works as expected.
Which versions of PhpSpreadsheet and PHP are affected?
The latset version of PhpSpreadsheet