Skip to content

Commit

Permalink
Add functionality to adjust CellRange by "modifying" the from/to Cell…
Browse files Browse the repository at this point in the history
…Address Value objects
  • Loading branch information
MarkBaker committed Apr 1, 2022
1 parent 1849737 commit 6b4ffda
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .php-cs-fixer.dist.php
Expand Up @@ -21,7 +21,7 @@
'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,
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -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.

Expand Down
22 changes: 22 additions & 0 deletions src/PhpSpreadsheet/Cell/AddressRange.php
@@ -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;
}
2 changes: 1 addition & 1 deletion src/PhpSpreadsheet/Cell/CellAddress.php
Expand Up @@ -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);
Expand Down
64 changes: 61 additions & 3 deletions src/PhpSpreadsheet/Cell/CellRange.php
Expand Up @@ -5,7 +5,7 @@
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class CellRange
class CellRange implements AddressRange
{
/**
* @var CellAddress
Expand Down Expand Up @@ -34,8 +34,8 @@ private function validateFromTo(CellAddress $from, CellAddress $to): void
$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
Expand All @@ -54,18 +54,76 @@ private function validateWorksheets(?Worksheet $fromWorksheet, ?Worksheet $toWor
}
}

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()}";
}
Expand Down
6 changes: 2 additions & 4 deletions src/PhpSpreadsheet/Cell/ColumnRange.php
Expand Up @@ -4,10 +4,8 @@

use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class ColumnRange
class ColumnRange implements AddressRange
{
private const MAX_ROW = 1048576;

/**
* @var ?Worksheet
*/
Expand Down Expand Up @@ -107,7 +105,7 @@ public function toCellRange(): CellRange
{
return new CellRange(
CellAddress::fromColumnAndRow($this->from, 1, $this->worksheet),
CellAddress::fromColumnAndRow($this->to, self::MAX_ROW)
CellAddress::fromColumnAndRow($this->to, AddressRange::MAX_ROW)
);
}

Expand Down
6 changes: 2 additions & 4 deletions src/PhpSpreadsheet/Cell/RowRange.php
Expand Up @@ -4,10 +4,8 @@

use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class RowRange
class RowRange implements AddressRange
{
private const MAX_COLUMN = 'XFD';

/**
* @var ?Worksheet
*/
Expand Down Expand Up @@ -78,7 +76,7 @@ public function toCellRange(): CellRange
{
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)
);
}

Expand Down
40 changes: 40 additions & 0 deletions tests/PhpSpreadsheetTests/Cell/CellRangeTest.php
Expand Up @@ -110,4 +110,44 @@ public function testCreateCellRangeWithMismatchedSpreadsheets(): void
$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);
}
}

0 comments on commit 6b4ffda

Please sign in to comment.