Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to calculate formula field in Excel file #3811

Open
StepanKutyrev opened this issue Dec 5, 2023 · 5 comments
Open

Failed to calculate formula field in Excel file #3811

StepanKutyrev opened this issue Dec 5, 2023 · 5 comments

Comments

@StepanKutyrev
Copy link

What is the expected behavior?

I am trying to take information from Excel file. It works well with all field types except formulas. For example, I am trying to receive a column with the formula (A2+10%)/2 (field A2 = 48,34%) but instead of the calculated formula I am getting "#VALUE!"

What are the steps to reproduce?

        Settings::setLocale('fr_FR');
        $baseName = 'test';
        $tempAbsolutePath =  $this->parameterBag->get('kernel.project_dir') . '/public/uploads/files/temp/';
        $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($tempAbsolutePath . $baseName);
        
        foreach ($spreadsheet->getActiveSheet()->getRowIterator() as $key => $row) {
            $rowData = [];
            foreach ($row->getCellIterator() as $cell) {
                if ($cell->getDataType() === \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_FORMULA) {
                    $rowData[] = $cell->getCalculatedValue();;
                } else {
                    $rowData[] = trim($cell->getFormattedValue());
                }
            }
        }

And you need excel file with at least two rows
First row |=(10%+A2)/2|
Second row |48,34%|

What features do you think are causing the issue

Formula Calculations

Does an issue affect all spreadsheet file formats? If not, which formats are affected?

Faced only with Excel file

Which versions of PhpSpreadsheet and PHP are affected?

"php": "^7.4",
"phpoffice/phpspreadsheet": "dev-master"

@oleibman
Copy link
Collaborator

oleibman commented Dec 5, 2023

I suspect this has to do with your use of comma as the decimal separator in cell A2. Because of your different locale, I would need to see your spreadsheet (it only needs to contain the two cells in question), but I'm guessing that value is stored as a string rather than a numeric value.

@StepanKutyrev
Copy link
Author

testxlsx.xlsx
COLUMN L @oleibman

@oleibman
Copy link
Collaborator

oleibman commented Dec 6, 2023

As suspected, cell L2 (and the rest of the cells with percentages) is stored as a string rather than a number. Out of curiosity, how were the cells entered into the spreadsheet in the first place? Regardless, when I open your spreadsheet using my normal en_US locale, Excel shows cell L1 as #VALUE, the same as PhpSpreadsheet. Granted, when I change my locale to fr_FR, Excel shows L1 as a calculated value. I notice that you have set a locale in your code. I am not sure how well that setting is, or can be, integrated into the Calculation engine.

@oleibman
Copy link
Collaborator

oleibman commented Dec 6, 2023

However, I don't think that's the best solution. Try this after your Settings::setLocale:

StringHelper::setThousandsSeparator('.');
StringHelper::setDecimalSeparator(',');

I am a bit surprised that doesn't happen automatically with Settings::setLocale. I will investigate further, but this seems like an easy enough workaround for now.

@StepanKutyrev
Copy link
Author

Thanks

oleibman added a commit to oleibman/PhpSpreadsheet that referenced this issue Dec 8, 2023
This was suggested by the investigation of issue PHPOffice#3811. No fix is necessary for the issue. However, two possible code solutions (Php setlocale, which comes with certain design flaws, and StringHelper set(Decimal/Thousands)Separator were suggested, and neither is adequately tested. This PR adds such tests.

Unusually, getting StringHelper Decimal Separator, Thousands Separator, and Currency Code can result in a change to those properties. So, the existing design in several tests where those properties are captured in Setup and restored in Teardown do not work quite as designed. Instead, the ability to set those properties to their default value (null) is added, and the tests re-done to restore the default in Teardown.

The two methods yield the same results when parsing input. However, they diverge when examining output fields through `getFormattedValue`. Such output is currently correct (usually) when using setlocale, but not when using StringHelper. The former works through the 'trick' of using `sprintf(%f)`, which generates a locale-aware string. However, using non-locale-aware `sprintf(%F)` followed by `str_replace` will produce the correct result for both setlocale and StringHelper. One place in the code uses a cast to string, which is incorrect for both methods. Following that up with the same str_replace makes it correct for both. These changes permit, but do not require, the user to avoid setlocale altogether.

It remains an open question whether Settings/Calculation::setLocale should set DecimalSeparator, CurrencySeparator, and CurrencyCode. That makes logical sense, but it would be a breaking change, and having to explicitly set those values when using setLocale does not seem especially burdensome. For now, such a change will not be made.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants