Merge branch 'master' into custom-column-widths
This commit is contained in:
commit
ad78049da1
@ -13,12 +13,20 @@ class StringHelper
|
|||||||
/** @var bool Whether the mbstring extension is loaded */
|
/** @var bool Whether the mbstring extension is loaded */
|
||||||
protected $hasMbstringSupport;
|
protected $hasMbstringSupport;
|
||||||
|
|
||||||
|
/** @var bool Whether the code is running with PHP7 or older versions */
|
||||||
|
private $isRunningPhp7OrOlder;
|
||||||
|
|
||||||
|
/** @var array Locale info, used for number formatting */
|
||||||
|
private $localeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->hasMbstringSupport = \extension_loaded('mbstring');
|
$this->hasMbstringSupport = \extension_loaded('mbstring');
|
||||||
|
$this->isRunningPhp7OrOlder = \version_compare(PHP_VERSION, '8.0.0') < 0;
|
||||||
|
$this->localeInfo = \localeconv();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,4 +76,30 @@ class StringHelper
|
|||||||
|
|
||||||
return ($position !== false) ? $position : -1;
|
return ($position !== false) ? $position : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a numeric value (int or float) in a way that's compatible with the expected spreadsheet format.
|
||||||
|
*
|
||||||
|
* Formatting of float values is locale dependent in PHP < 8.
|
||||||
|
* Thousands separators and decimal points vary from locale to locale (en_US: 12.34 vs pl_PL: 12,34).
|
||||||
|
* However, float values must be formatted with no thousands separator and a "." as decimal point
|
||||||
|
* to work properly. This method can be used to convert the value to the correct format before storing it.
|
||||||
|
*
|
||||||
|
* @see https://wiki.php.net/rfc/locale_independent_float_to_string for the changed behavior in PHP8.
|
||||||
|
*
|
||||||
|
* @param int|float $numericValue
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function formatNumericValue($numericValue)
|
||||||
|
{
|
||||||
|
if ($this->isRunningPhp7OrOlder && is_float($numericValue)) {
|
||||||
|
return str_replace(
|
||||||
|
[$this->localeInfo['thousands_sep'], $this->localeInfo['decimal_point']],
|
||||||
|
['', '.'],
|
||||||
|
$numericValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $numericValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,8 +231,9 @@ class WorksheetManager implements WorksheetManagerInterface
|
|||||||
$data .= '<text:p>' . $cell->getValue() . '</text:p>';
|
$data .= '<text:p>' . $cell->getValue() . '</text:p>';
|
||||||
$data .= '</table:table-cell>';
|
$data .= '</table:table-cell>';
|
||||||
} elseif ($cell->isNumeric()) {
|
} elseif ($cell->isNumeric()) {
|
||||||
$data .= ' office:value-type="float" calcext:value-type="float" office:value="' . $cell->getValue() . '">';
|
$cellValue = $this->stringHelper->formatNumericValue($cell->getValue());
|
||||||
$data .= '<text:p>' . $cell->getValue() . '</text:p>';
|
$data .= ' office:value-type="float" calcext:value-type="float" office:value="' . $cellValue . '">';
|
||||||
|
$data .= '<text:p>' . $cellValue . '</text:p>';
|
||||||
$data .= '</table:table-cell>';
|
$data .= '</table:table-cell>';
|
||||||
} elseif ($cell->isError() && is_string($cell->getValueEvenIfError())) {
|
} elseif ($cell->isError() && is_string($cell->getValueEvenIfError())) {
|
||||||
// only writes the error value if it's a string
|
// only writes the error value if it's a string
|
||||||
|
@ -265,7 +265,7 @@ EOD;
|
|||||||
} elseif ($cell->isBoolean()) {
|
} elseif ($cell->isBoolean()) {
|
||||||
$cellXML .= ' t="b"><v>' . (int) ($cell->getValue()) . '</v></c>';
|
$cellXML .= ' t="b"><v>' . (int) ($cell->getValue()) . '</v></c>';
|
||||||
} elseif ($cell->isNumeric()) {
|
} elseif ($cell->isNumeric()) {
|
||||||
$cellXML .= '><v>' . $cell->getValue() . '</v></c>';
|
$cellXML .= '><v>' . $this->stringHelper->formatNumericValue($cell->getValue()) . '</v></c>';
|
||||||
} elseif ($cell->isError() && is_string($cell->getValueEvenIfError())) {
|
} elseif ($cell->isError() && is_string($cell->getValueEvenIfError())) {
|
||||||
// only writes the error value if it's a string
|
// only writes the error value if it's a string
|
||||||
$cellXML .= ' t="e"><v>' . $cell->getValueEvenIfError() . '</v></c>';
|
$cellXML .= ' t="e"><v>' . $cell->getValueEvenIfError() . '</v></c>';
|
||||||
|
@ -279,6 +279,52 @@ class WriterTest extends TestCase
|
|||||||
$this->assertValueWasWrittenToSheet($fileName, 1, 10.2);
|
$this->assertValueWasWrittenToSheet($fileName, 1, 10.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testAddRowShouldSupportFloatValuesInDifferentLocale()
|
||||||
|
{
|
||||||
|
$previousLocale = \setlocale(LC_ALL, 0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Pick a supported locale whose decimal point is a comma.
|
||||||
|
// Installed locales differ from one system to another, so we can't pick
|
||||||
|
// a given locale.
|
||||||
|
$supportedLocales = explode("\n", shell_exec('locale -a'));
|
||||||
|
foreach ($supportedLocales as $supportedLocale) {
|
||||||
|
\setlocale(LC_ALL, $supportedLocale);
|
||||||
|
if (\localeconv()['decimal_point'] === ',') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->assertEquals(',', \localeconv()['decimal_point']);
|
||||||
|
|
||||||
|
$cellValue = 1234.5;
|
||||||
|
var_dump("Cell value before: " . $cellValue);
|
||||||
|
$cellValue = str_replace(
|
||||||
|
[\localeconv()['thousands_sep'], \localeconv()['decimal_point']],
|
||||||
|
['', '.'],
|
||||||
|
$cellValue
|
||||||
|
);
|
||||||
|
var_dump("Cell value after: " . $cellValue);
|
||||||
|
var_dump("Thousands sep: " . \localeconv()['thousands_sep']);
|
||||||
|
var_dump("Decimal point: " . \localeconv()['decimal_point']);
|
||||||
|
|
||||||
|
$fileName = 'test_add_row_should_support_float_values_in_different_locale.xlsx';
|
||||||
|
$dataRows = $this->createRowsFromValues([
|
||||||
|
[1234.5],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->writeToODSFile($dataRows, $fileName);
|
||||||
|
|
||||||
|
$this->assertValueWasNotWrittenToSheet($fileName, 1, "1234,5");
|
||||||
|
$this->assertValueWasWrittenToSheet($fileName, 1, "1234.5");
|
||||||
|
} finally {
|
||||||
|
// reset locale
|
||||||
|
\setlocale(LC_ALL, $previousLocale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
|
@ -393,6 +393,52 @@ class WriterTest extends TestCase
|
|||||||
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 't="e"><v>#DIV/0</v>');
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 't="e"><v>#DIV/0</v>');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testAddRowShouldSupportFloatValuesInDifferentLocale()
|
||||||
|
{
|
||||||
|
$previousLocale = \setlocale(LC_ALL, 0);
|
||||||
|
$valueToWrite = 1234.5; // needs to be defined before changing the locale as PHP8 would expect 1234,5
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Pick a supported locale whose decimal point is a comma.
|
||||||
|
// Installed locales differ from one system to another, so we can't pick
|
||||||
|
// a given locale.
|
||||||
|
$supportedLocales = explode("\n", shell_exec('locale -a'));
|
||||||
|
foreach ($supportedLocales as $supportedLocale) {
|
||||||
|
\setlocale(LC_ALL, $supportedLocale);
|
||||||
|
if (\localeconv()['decimal_point'] === ',') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->assertEquals(',', \localeconv()['decimal_point']);
|
||||||
|
|
||||||
|
var_dump("Cell value before: " . $valueToWrite);
|
||||||
|
$cellValue = str_replace(
|
||||||
|
[\localeconv()['thousands_sep'], \localeconv()['decimal_point']],
|
||||||
|
['', '.'],
|
||||||
|
$valueToWrite
|
||||||
|
);
|
||||||
|
var_dump("Cell value after: " . $cellValue);
|
||||||
|
var_dump("Thousands sep: " . \localeconv()['thousands_sep']);
|
||||||
|
var_dump("Decimal point: " . \localeconv()['decimal_point']);
|
||||||
|
|
||||||
|
$fileName = 'test_add_row_should_support_float_values_in_different_locale.xlsx';
|
||||||
|
$dataRows = $this->createRowsFromValues([
|
||||||
|
[$valueToWrite],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->writeToXLSXFile($dataRows, $fileName, $shouldUseInlineStrings = false);
|
||||||
|
|
||||||
|
$this->assertInlineDataWasNotWrittenToSheet($fileName, 1, "1234,5");
|
||||||
|
$this->assertInlineDataWasWrittenToSheet($fileName, 1, "1234.5");
|
||||||
|
} finally {
|
||||||
|
// reset locale
|
||||||
|
\setlocale(LC_ALL, $previousLocale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user