Skip to content

Commit

Permalink
Allow override of the Value Binder when setting a Cell value
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkBaker committed Feb 14, 2023
1 parent c95a8b7 commit 83d8838
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
17 changes: 17 additions & 0 deletions docs/topics/accessing-cells.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions src/PhpSpreadsheet/Cell/Cell.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
}

Expand Down
11 changes: 7 additions & 4 deletions src/PhpSpreadsheet/Worksheet/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1157,13 +1158,14 @@ public function getHighestRowAndColumn()
* @param array<int>|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;
}
Expand All @@ -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;
}
Expand Down
44 changes: 44 additions & 0 deletions tests/PhpSpreadsheetTests/Cell/CellTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
*
Expand Down

0 comments on commit 83d8838

Please sign in to comment.