From 83d88380ae7d2cdcf97b9113ec921d1683e6df73 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Tue, 14 Feb 2023 00:23:31 +0100 Subject: [PATCH] Allow override of the Value Binder when setting a Cell value --- CHANGELOG.md | 1 + docs/topics/accessing-cells.md | 17 ++++++++ src/PhpSpreadsheet/Cell/Cell.php | 8 +++- src/PhpSpreadsheet/Worksheet/Worksheet.php | 11 ++++-- tests/PhpSpreadsheetTests/Cell/CellTest.php | 44 +++++++++++++++++++++ 5 files changed, 75 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd0fbf5576..acc14c90ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Wizards for defining Number Format masks for Numbers, Percentages, Scientific, Currency and Accounting [PR #3334](https://github.com/PHPOffice/PhpSpreadsheet/pull/3334) - Support for fixed value divisor in fractional Number Format Masks [PR #3339](https://github.com/PHPOffice/PhpSpreadsheet/pull/3339) - Allow More Fonts/Fontnames for Exact Width Calculation [PR #3326](https://github.com/PHPOffice/PhpSpreadsheet/pull/3326) [Issue #3190](https://github.com/PHPOffice/PhpSpreadsheet/issues/3190) +- Allow override of the Value Binder when setting a Cell value [PR #3361](https://github.com/PHPOffice/PhpSpreadsheet/pull/3361) ### Changed diff --git a/docs/topics/accessing-cells.md b/docs/topics/accessing-cells.md index d3bcc70185..47b1d98256 100644 --- a/docs/topics/accessing-cells.md +++ b/docs/topics/accessing-cells.md @@ -584,6 +584,23 @@ $stringValueBinder->setNumericConversion(false) \PhpOffice\PhpSpreadsheet\Cell\Cell::setValueBinder( $stringValueBinder ); ``` +You can override the current binder when setting individual cell values by specifying a different Binder to use in the Cell's `setValue()` or the Worksheet's `setCellValue()` methods. +```php +$spreadsheet = new Spreadsheet(); +Cell::setValueBinder(new AdvancedValueBinder()); + +$value = '12.5%'; + +$cell = $spreadsheet->getActiveSheet()->getCell('A1'); +// Value will be set as a number 0.125 with a format mask '0.00%' +$cell->setValue($value); // Using the Advanced Value Binder + +$cell = $spreadsheet->getActiveSheet()->getCell('A2'); +// Value will be set as a string '12.5%' with a format mask 'General' +$cell->setValue($value, new StringValueBinder()); // Overriding the Advanced Value Binder +``` + + ### Creating your own value binder Creating your own value binder is relatively straightforward. When more specialised diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index a7e6602a75..a53294e53e 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -221,12 +221,16 @@ protected static function updateIfCellIsTableHeader(?Worksheet $workSheet, self * Sets the value for a cell, automatically determining the datatype using the value binder * * @param mixed $value Value + * @param null|IValueBinder $binder Value Binder to override the currently set Value Binder + * + * @throws Exception * * @return $this */ - public function setValue($value): self + public function setValue($value, ?IValueBinder $binder = null): self { - if (!self::getValueBinder()->bindValue($this, $value)) { + $binder ??= self::getValueBinder(); + if (!$binder->bindValue($this, $value)) { throw new Exception('Value could not be bound to cell.'); } diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 97e3163b9b..2759dc1cbf 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -13,6 +13,7 @@ use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DataValidation; use PhpOffice\PhpSpreadsheet\Cell\Hyperlink; +use PhpOffice\PhpSpreadsheet\Cell\IValueBinder; use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Collection\Cells; use PhpOffice\PhpSpreadsheet\Collection\CellsFactory; @@ -1157,13 +1158,14 @@ public function getHighestRowAndColumn() * @param array|CellAddress|string $coordinate Coordinate of the cell as a string, eg: 'C5'; * or as an array of [$columnIndex, $row] (e.g. [3, 5]), or a CellAddress object. * @param mixed $value Value for the cell + * @param null|IValueBinder $binder Value Binder to override the currently set Value Binder * * @return $this */ - public function setCellValue($coordinate, $value) + public function setCellValue($coordinate, $value, ?IValueBinder $binder = null) { $cellAddress = Functions::trimSheetFromCellReference(Validations::validateCellAddress($coordinate)); - $this->getCell($cellAddress)->setValue($value); + $this->getCell($cellAddress)->setValue($value, $binder); return $this; } @@ -1179,12 +1181,13 @@ public function setCellValue($coordinate, $value) * @param int $columnIndex Numeric column coordinate of the cell * @param int $row Numeric row coordinate of the cell * @param mixed $value Value of the cell + * @param null|IValueBinder $binder Value Binder to override the currently set Value Binder * * @return $this */ - public function setCellValueByColumnAndRow($columnIndex, $row, $value) + public function setCellValueByColumnAndRow($columnIndex, $row, $value, ?IValueBinder $binder = null) { - $this->getCell(Coordinate::stringFromColumnIndex($columnIndex) . $row)->setValue($value); + $this->getCell(Coordinate::stringFromColumnIndex($columnIndex) . $row)->setValue($value, $binder); return $this; } diff --git a/tests/PhpSpreadsheetTests/Cell/CellTest.php b/tests/PhpSpreadsheetTests/Cell/CellTest.php index 0ec8154fc1..84cc4c782d 100644 --- a/tests/PhpSpreadsheetTests/Cell/CellTest.php +++ b/tests/PhpSpreadsheetTests/Cell/CellTest.php @@ -2,7 +2,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Cell; +use PhpOffice\PhpSpreadsheet\Cell\Cell; +use PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder; use PhpOffice\PhpSpreadsheet\Cell\DataType; +use PhpOffice\PhpSpreadsheet\Cell\StringValueBinder; use PhpOffice\PhpSpreadsheet\Exception; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\Color; @@ -13,6 +16,47 @@ class CellTest extends TestCase { + public function testSetValueBinderOverride(): void + { + $value = '12.5%'; + $spreadsheet = new Spreadsheet(); + + $cell = $spreadsheet->getActiveSheet()->getCell('A1'); + $cell->setValue($value); // Using the Default Value Binder + + self::assertSame('12.5%', $cell->getValue()); + self::assertSame('General', $cell->getStyle()->getNumberFormat()->getFormatCode()); + + $cell = $spreadsheet->getActiveSheet()->getCell('A2'); + $cell->setValue($value, new AdvancedValueBinder()); // Overriding the Default Value Binder + + self::assertSame(0.125, $cell->getValue()); + self::assertSame('0.00%', $cell->getStyle()->getNumberFormat()->getFormatCode()); + + $spreadsheet->disconnectWorksheets(); + } + + public function testSetValueBinderOverride2(): void + { + $value = '12.5%'; + $spreadsheet = new Spreadsheet(); + Cell::setValueBinder(new AdvancedValueBinder()); + + $cell = $spreadsheet->getActiveSheet()->getCell('A1'); + $cell->setValue($value); // Using the Advanced Value Binder + + self::assertSame(0.125, $cell->getValue()); + self::assertSame('0.00%', $cell->getStyle()->getNumberFormat()->getFormatCode()); + + $cell = $spreadsheet->getActiveSheet()->getCell('A2'); + $cell->setValue($value, new StringValueBinder()); // Overriding the Advanced Value Binder + + self::assertSame('12.5%', $cell->getValue()); + self::assertSame('General', $cell->getStyle()->getNumberFormat()->getFormatCode()); + + $spreadsheet->disconnectWorksheets(); + } + /** * @dataProvider providerSetValueExplicit *