Add functionality to adjust CellRange by "modifying" the from/to CellAddress Value objects

This commit is contained in:
MarkBaker 2022-04-01 12:23:32 +02:00
parent 1849737abc
commit 6b4ffda5ae
8 changed files with 131 additions and 14 deletions

View File

@ -21,7 +21,7 @@ $config
'braces' => true,
'cast_spaces' => true,
'class_attributes_separation' => ['elements' => ['method' => 'one', 'property' => 'one']], // const are often grouped with other related const
'class_definition' => true,
'class_definition' => false,
'class_keyword_remove' => false, // ::class keyword gives us better support in IDE
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,

View File

@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Added
- Implementation of the FILTER(), SORT(), SORTBY() and UNIQUE() Lookup/Reference (array) functions
- Introduced CellAddress, CellRange, RowRange and ColumnRange value objects that can be used as an alternative to a string value (e.g. `'C5'`, `'B2:D4'`, `'2:2'` or `'B:C'`) in appropriate contexts.
- Implementation of the FILTER(), SORT(), SORTBY() and UNIQUE() Lookup/Reference (array) functions.
- Implementation of the ISREF() Information function.
- Added support for reading "formatted" numeric values from Csv files; although default behaviour of reading these values as strings is preserved.

View File

@ -0,0 +1,22 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Cell;
interface AddressRange
{
public const MAX_ROW = 1048576;
public const MAX_COLUMN = 'XFD';
/**
* @return mixed
*/
public function from();
/**
* @return mixed
*/
public function to();
public function __toString(): string;
}

View File

@ -32,7 +32,7 @@ class CellAddress
*/
protected $rowId;
protected function __construct(string $cellAddress, ?Worksheet $worksheet)
public function __construct(string $cellAddress, ?Worksheet $worksheet)
{
$this->cellAddress = str_replace('$', '', $cellAddress);
[$this->columnName, $rowId] = Coordinate::coordinateFromString($cellAddress);

View File

@ -5,7 +5,7 @@ namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class CellRange
class CellRange implements AddressRange
{
/**
* @var CellAddress
@ -34,8 +34,8 @@ class CellRange
$toWorksheet = $to->worksheet();
$this->validateWorksheets($fromWorksheet, $toWorksheet);
$this->from = CellAddress::fromColumnAndRow($firstColumn, $firstRow, $fromWorksheet);
$this->to = CellAddress::fromColumnAndRow($lastColumn, $lastRow, $toWorksheet);
$this->from = $this->cellAddressWrapper($firstColumn, $firstRow, $fromWorksheet);
$this->to = $this->cellAddressWrapper($lastColumn, $lastRow, $toWorksheet);
}
private function validateWorksheets(?Worksheet $fromWorksheet, ?Worksheet $toWorksheet): void
@ -54,18 +54,76 @@ class CellRange
}
}
private function cellAddressWrapper(int $column, int $row, ?Worksheet $worksheet = null): CellAddress
{
$cellAddress = Coordinate::stringFromColumnIndex($column) . (string) $row;
return new class ($cellAddress, $worksheet) extends CellAddress {
public function nextRow(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::nextRow($offset);
$this->rowId = $result->rowId;
$this->cellAddress = $result->cellAddress;
return $this;
}
public function previousRow(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::previousRow($offset);
$this->rowId = $result->rowId;
$this->cellAddress = $result->cellAddress;
return $this;
}
public function nextColumn(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::nextColumn($offset);
$this->columnId = $result->columnId;
$this->columnName = $result->columnName;
$this->cellAddress = $result->cellAddress;
return $this;
}
public function previousColumn(int $offset = 1): CellAddress
{
/** @var CellAddress $result */
$result = parent::previousColumn($offset);
$this->columnId = $result->columnId;
$this->columnName = $result->columnName;
$this->cellAddress = $result->cellAddress;
return $this;
}
};
}
public function from(): CellAddress
{
// Re-order from/to in case the cell addresses have been modified
$this->validateFromTo($this->from, $this->to);
return $this->from;
}
public function to(): CellAddress
{
// Re-order from/to in case the cell addresses have been modified
$this->validateFromTo($this->from, $this->to);
return $this->to;
}
public function __toString(): string
{
// Re-order from/to in case the cell addresses have been modified
$this->validateFromTo($this->from, $this->to);
if ($this->from->cellAddress() === $this->to->cellAddress()) {
return "{$this->from->fullCellAddress()}";
}

View File

@ -4,10 +4,8 @@ namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class ColumnRange
class ColumnRange implements AddressRange
{
private const MAX_ROW = 1048576;
/**
* @var ?Worksheet
*/
@ -107,7 +105,7 @@ class ColumnRange
{
return new CellRange(
CellAddress::fromColumnAndRow($this->from, 1, $this->worksheet),
CellAddress::fromColumnAndRow($this->to, self::MAX_ROW)
CellAddress::fromColumnAndRow($this->to, AddressRange::MAX_ROW)
);
}

View File

@ -4,10 +4,8 @@ namespace PhpOffice\PhpSpreadsheet\Cell;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class RowRange
class RowRange implements AddressRange
{
private const MAX_COLUMN = 'XFD';
/**
* @var ?Worksheet
*/
@ -78,7 +76,7 @@ class RowRange
{
return new CellRange(
CellAddress::fromColumnAndRow(Coordinate::columnIndexFromString('A'), $this->from, $this->worksheet),
CellAddress::fromColumnAndRow(Coordinate::columnIndexFromString(self::MAX_COLUMN), $this->to)
CellAddress::fromColumnAndRow(Coordinate::columnIndexFromString(AddressRange::MAX_COLUMN), $this->to)
);
}

View File

@ -110,4 +110,44 @@ class CellRangeTest extends TestCase
$to = CellAddress::fromCellAddress('E2', $worksheet2);
new CellRange($from, $to);
}
public function testShiftRangeTo(): void
{
$from = CellAddress::fromCellAddress('B5');
$to = CellAddress::fromCellAddress('E2');
$cellRange = new CellRange($from, $to);
self::assertSame('B2:E5', (string) $cellRange);
$cellRange->to()
->nextColumn(2)
->nextRow(2);
self::assertSame('B2', (string) $cellRange->from());
self::assertSame('G7', (string) $cellRange->to());
self::assertSame('B2:G7', (string) $cellRange);
$cellRange->to()
->previousColumn()
->previousRow();
self::assertSame('B2', (string) $cellRange->from());
self::assertSame('F6', (string) $cellRange->to());
self::assertSame('B2:F6', (string) $cellRange);
}
public function testShiftRangeFrom(): void
{
$from = CellAddress::fromCellAddress('B5');
$to = CellAddress::fromCellAddress('E2');
$cellRange = new CellRange($from, $to);
self::assertSame('B2:E5', (string) $cellRange);
$cellRange->from()
->nextColumn(5)
->nextRow(5);
self::assertSame('E5', (string) $cellRange->from());
self::assertSame('G7', (string) $cellRange->to());
self::assertSame('E5:G7', (string) $cellRange);
}
}