Allow more control over what non-string datatypes are converted to strings in the StringValueBinder
This commit is contained in:
parent
642fc7dee7
commit
8e41445fbd
|
|
@ -2,10 +2,58 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Cell;
|
namespace PhpOffice\PhpSpreadsheet\Cell;
|
||||||
|
|
||||||
|
use DateTimeInterface;
|
||||||
|
use PhpOffice\PhpSpreadsheet\RichText\RichText;
|
||||||
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
|
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
|
||||||
|
|
||||||
class StringValueBinder implements IValueBinder
|
class StringValueBinder implements IValueBinder
|
||||||
{
|
{
|
||||||
|
protected $convertNull = true;
|
||||||
|
|
||||||
|
protected $convertBoolean = true;
|
||||||
|
|
||||||
|
protected $convertNumeric = true;
|
||||||
|
|
||||||
|
protected $convertFormula = true;
|
||||||
|
|
||||||
|
public function setNullConversion(bool $suppressConversion = false): self
|
||||||
|
{
|
||||||
|
$this->convertNull = $suppressConversion;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBooleanConversion(bool $suppressConversion = false): self
|
||||||
|
{
|
||||||
|
$this->convertBoolean = $suppressConversion;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNumericConversion(bool $suppressConversion = false): self
|
||||||
|
{
|
||||||
|
$this->convertNumeric = $suppressConversion;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFormulaConversion(bool $suppressConversion = false): self
|
||||||
|
{
|
||||||
|
$this->convertFormula = $suppressConversion;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConversionForAllValueTypes(bool $suppressConversion = false): self
|
||||||
|
{
|
||||||
|
$this->convertNull = $suppressConversion;
|
||||||
|
$this->convertBoolean = $suppressConversion;
|
||||||
|
$this->convertNumeric = $suppressConversion;
|
||||||
|
$this->convertFormula = $suppressConversion;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind value to a cell.
|
* Bind value to a cell.
|
||||||
*
|
*
|
||||||
|
|
@ -21,9 +69,35 @@ class StringValueBinder implements IValueBinder
|
||||||
$value = StringHelper::sanitizeUTF8($value);
|
$value = StringHelper::sanitizeUTF8($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cell->setValueExplicit((string) $value, DataType::TYPE_STRING);
|
if (is_object($value)) {
|
||||||
|
// Handle any objects that might be injected
|
||||||
|
if ($value instanceof DateTimeInterface) {
|
||||||
|
$value = $value->format('Y-m-d H:i:s');
|
||||||
|
} elseif ($value instanceof RichText) {
|
||||||
|
$cell->setValueExplicit((string) $value, DataType::TYPE_INLINE);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Attempt to cast any unexpected objects to string
|
||||||
|
$value = (string) $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value === null && $this->convertNull === false) {
|
||||||
|
$cell->setValueExplicit($value, DataType::TYPE_NULL);
|
||||||
|
} elseif (is_bool($value) && $this->convertBoolean === false) {
|
||||||
|
$cell->setValueExplicit($value, DataType::TYPE_BOOL);
|
||||||
|
} elseif ((is_int($value) || is_float($value)) && $this->convertNumeric === false) {
|
||||||
|
$cell->setValueExplicit($value, DataType::TYPE_NUMERIC);
|
||||||
|
} elseif (is_string($value) && strlen($value) > 1 && $value[0] === '=' && $this->convertFormula === false) {
|
||||||
|
$cell->setValueExplicit($value, DataType::TYPE_FORMULA);
|
||||||
|
} else {
|
||||||
|
if (is_string($value) && strlen($value) > 1 && $value[0] === '=') {
|
||||||
|
$cell->getStyle()->setQuotePrefix(true);
|
||||||
|
}
|
||||||
|
$cell->setValueExplicit((string) $value, DataType::TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
// Done!
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,225 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Cell;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Cell\StringValueBinder;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Style\Style;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class StringValueBinderTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function createCellStub($expectedValue, string $expectedDataType, bool $quotePrefix = false): Cell
|
||||||
|
{
|
||||||
|
/** @var Style&MockObject $styleStub */
|
||||||
|
$styleStub = $this->getMockBuilder(Style::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
/** @var Cell&MockObject $cellStub */
|
||||||
|
$cellStub = $this->getMockBuilder(Cell::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
// Configure the stub.
|
||||||
|
$cellStub->expects(self::once())
|
||||||
|
->method('setValueExplicit')
|
||||||
|
->with($expectedValue, $expectedDataType)
|
||||||
|
->willReturn(true);
|
||||||
|
$cellStub->expects($quotePrefix ? self::once() : self::never())
|
||||||
|
->method('getStyle')
|
||||||
|
->willReturn($styleStub);
|
||||||
|
|
||||||
|
return $cellStub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDataValuesDefault
|
||||||
|
*/
|
||||||
|
public function testStringValueBinderDefaultBehaviour(
|
||||||
|
$value,
|
||||||
|
$expectedValue,
|
||||||
|
string $expectedDataType,
|
||||||
|
bool $quotePrefix = false
|
||||||
|
): void {
|
||||||
|
$cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix);
|
||||||
|
|
||||||
|
$binder = new StringValueBinder();
|
||||||
|
$binder->bindValue($cellStub, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDataValuesDefault(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[null, '', DataType::TYPE_STRING],
|
||||||
|
[true, '1', DataType::TYPE_STRING],
|
||||||
|
[false, '', DataType::TYPE_STRING],
|
||||||
|
['', '', DataType::TYPE_STRING],
|
||||||
|
['123', '123', DataType::TYPE_STRING],
|
||||||
|
['123.456', '123.456', DataType::TYPE_STRING],
|
||||||
|
['0.123', '0.123', DataType::TYPE_STRING],
|
||||||
|
['.123', '.123', DataType::TYPE_STRING],
|
||||||
|
['-0.123', '-0.123', DataType::TYPE_STRING],
|
||||||
|
['-.123', '-.123', DataType::TYPE_STRING],
|
||||||
|
['1.23e-4', '1.23e-4', DataType::TYPE_STRING],
|
||||||
|
['ABC', 'ABC', DataType::TYPE_STRING],
|
||||||
|
['=SUM(A1:C3)', '=SUM(A1:C3)', DataType::TYPE_STRING, true],
|
||||||
|
[123, '123', DataType::TYPE_STRING],
|
||||||
|
[123.456, '123.456', DataType::TYPE_STRING],
|
||||||
|
[0.123, '0.123', DataType::TYPE_STRING],
|
||||||
|
[.123, '0.123', DataType::TYPE_STRING],
|
||||||
|
[-0.123, '-0.123', DataType::TYPE_STRING],
|
||||||
|
[-.123, '-0.123', DataType::TYPE_STRING],
|
||||||
|
[1.23e-4, '0.000123', DataType::TYPE_STRING],
|
||||||
|
[1.23e-24, '1.23E-24', DataType::TYPE_STRING],
|
||||||
|
[new DateTime('2021-06-01 00:00:00', new DateTimeZone('UTC')), '2021-06-01 00:00:00', DataType::TYPE_STRING],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDataValuesSuppressNullConversion
|
||||||
|
*/
|
||||||
|
public function testStringValueBinderSuppressNullConversion(
|
||||||
|
$value,
|
||||||
|
$expectedValue,
|
||||||
|
string $expectedDataType,
|
||||||
|
bool $quotePrefix = false
|
||||||
|
): void {
|
||||||
|
$cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix);
|
||||||
|
|
||||||
|
$binder = new StringValueBinder();
|
||||||
|
$binder->setNullConversion(false);
|
||||||
|
$binder->bindValue($cellStub, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDataValuesSuppressNullConversion(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[null, null, DataType::TYPE_NULL],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDataValuesSuppressBooleanConversion
|
||||||
|
*/
|
||||||
|
public function testStringValueBinderSuppressBooleanConversion(
|
||||||
|
$value,
|
||||||
|
$expectedValue,
|
||||||
|
string $expectedDataType,
|
||||||
|
bool $quotePrefix = false
|
||||||
|
): void {
|
||||||
|
$cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix);
|
||||||
|
|
||||||
|
$binder = new StringValueBinder();
|
||||||
|
$binder->setBooleanConversion(false);
|
||||||
|
$binder->bindValue($cellStub, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDataValuesSuppressBooleanConversion(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[true, true, DataType::TYPE_BOOL],
|
||||||
|
[false, false, DataType::TYPE_BOOL],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDataValuesSuppressNumericConversion
|
||||||
|
*/
|
||||||
|
public function testStringValueBinderSuppressNumericConversion(
|
||||||
|
$value,
|
||||||
|
$expectedValue,
|
||||||
|
string $expectedDataType,
|
||||||
|
bool $quotePrefix = false
|
||||||
|
): void {
|
||||||
|
$cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix);
|
||||||
|
|
||||||
|
$binder = new StringValueBinder();
|
||||||
|
$binder->setNumericConversion(false);
|
||||||
|
$binder->bindValue($cellStub, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDataValuesSuppressNumericConversion(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[123, 123, DataType::TYPE_NUMERIC],
|
||||||
|
[123.456, 123.456, DataType::TYPE_NUMERIC],
|
||||||
|
[0.123, 0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[.123, 0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[-0.123, -0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[-.123, -0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[1.23e-4, 0.000123, DataType::TYPE_NUMERIC],
|
||||||
|
[1.23e-24, 1.23E-24, DataType::TYPE_NUMERIC],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDataValuesSuppressFormulaConversion
|
||||||
|
*/
|
||||||
|
public function testStringValueBinderSuppressFormulaConversion(
|
||||||
|
$value,
|
||||||
|
$expectedValue,
|
||||||
|
string $expectedDataType,
|
||||||
|
bool $quotePrefix = false
|
||||||
|
): void {
|
||||||
|
$cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix);
|
||||||
|
|
||||||
|
$binder = new StringValueBinder();
|
||||||
|
$binder->setFormulaConversion(false);
|
||||||
|
$binder->bindValue($cellStub, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDataValuesSuppressFormulaConversion(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['=SUM(A1:C3)', '=SUM(A1:C3)', DataType::TYPE_FORMULA, false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDataValuesSuppressAllConversion
|
||||||
|
*/
|
||||||
|
public function testStringValueBinderSuppressAllConversion(
|
||||||
|
$value,
|
||||||
|
$expectedValue,
|
||||||
|
string $expectedDataType,
|
||||||
|
bool $quotePrefix = false
|
||||||
|
): void {
|
||||||
|
$cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix);
|
||||||
|
|
||||||
|
$binder = new StringValueBinder();
|
||||||
|
$binder->setConversionForAllValueTypes(false);
|
||||||
|
$binder->bindValue($cellStub, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDataValuesSuppressAllConversion(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[null, null, DataType::TYPE_NULL],
|
||||||
|
[true, true, DataType::TYPE_BOOL],
|
||||||
|
[false, false, DataType::TYPE_BOOL],
|
||||||
|
['', '', DataType::TYPE_STRING],
|
||||||
|
['123', '123', DataType::TYPE_STRING],
|
||||||
|
['123.456', '123.456', DataType::TYPE_STRING],
|
||||||
|
['0.123', '0.123', DataType::TYPE_STRING],
|
||||||
|
['.123', '.123', DataType::TYPE_STRING],
|
||||||
|
['-0.123', '-0.123', DataType::TYPE_STRING],
|
||||||
|
['-.123', '-.123', DataType::TYPE_STRING],
|
||||||
|
['1.23e-4', '1.23e-4', DataType::TYPE_STRING],
|
||||||
|
['ABC', 'ABC', DataType::TYPE_STRING],
|
||||||
|
['=SUM(A1:C3)', '=SUM(A1:C3)', DataType::TYPE_FORMULA, false],
|
||||||
|
[123, 123, DataType::TYPE_NUMERIC],
|
||||||
|
[123.456, 123.456, DataType::TYPE_NUMERIC],
|
||||||
|
[0.123, 0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[.123, 0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[-0.123, -0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[-.123, -0.123, DataType::TYPE_NUMERIC],
|
||||||
|
[1.23e-4, 0.000123, DataType::TYPE_NUMERIC],
|
||||||
|
[1.23e-24, 1.23E-24, DataType::TYPE_NUMERIC],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue