Skip to content

Commit 6b4ffda

Browse files
author
MarkBaker
committed
Add functionality to adjust CellRange by "modifying" the from/to CellAddress Value objects
1 parent 1849737 commit 6b4ffda

File tree

8 files changed

+131
-14
lines changed

8 files changed

+131
-14
lines changed

.php-cs-fixer.dist.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
'braces' => true,
2222
'cast_spaces' => true,
2323
'class_attributes_separation' => ['elements' => ['method' => 'one', 'property' => 'one']], // const are often grouped with other related const
24-
'class_definition' => true,
24+
'class_definition' => false,
2525
'class_keyword_remove' => false, // ::class keyword gives us better support in IDE
2626
'combine_consecutive_issets' => true,
2727
'combine_consecutive_unsets' => true,

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
99

1010
### Added
1111

12-
- Implementation of the FILTER(), SORT(), SORTBY() and UNIQUE() Lookup/Reference (array) functions
12+
- 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.
13+
- Implementation of the FILTER(), SORT(), SORTBY() and UNIQUE() Lookup/Reference (array) functions.
1314
- Implementation of the ISREF() Information function.
1415
- Added support for reading "formatted" numeric values from Csv files; although default behaviour of reading these values as strings is preserved.
1516

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Cell;
4+
5+
interface AddressRange
6+
{
7+
public const MAX_ROW = 1048576;
8+
9+
public const MAX_COLUMN = 'XFD';
10+
11+
/**
12+
* @return mixed
13+
*/
14+
public function from();
15+
16+
/**
17+
* @return mixed
18+
*/
19+
public function to();
20+
21+
public function __toString(): string;
22+
}

src/PhpSpreadsheet/Cell/CellAddress.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class CellAddress
3232
*/
3333
protected $rowId;
3434

35-
protected function __construct(string $cellAddress, ?Worksheet $worksheet)
35+
public function __construct(string $cellAddress, ?Worksheet $worksheet)
3636
{
3737
$this->cellAddress = str_replace('$', '', $cellAddress);
3838
[$this->columnName, $rowId] = Coordinate::coordinateFromString($cellAddress);

src/PhpSpreadsheet/Cell/CellRange.php

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use PhpOffice\PhpSpreadsheet\Exception;
66
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
77

8-
class CellRange
8+
class CellRange implements AddressRange
99
{
1010
/**
1111
* @var CellAddress
@@ -34,8 +34,8 @@ private function validateFromTo(CellAddress $from, CellAddress $to): void
3434
$toWorksheet = $to->worksheet();
3535
$this->validateWorksheets($fromWorksheet, $toWorksheet);
3636

37-
$this->from = CellAddress::fromColumnAndRow($firstColumn, $firstRow, $fromWorksheet);
38-
$this->to = CellAddress::fromColumnAndRow($lastColumn, $lastRow, $toWorksheet);
37+
$this->from = $this->cellAddressWrapper($firstColumn, $firstRow, $fromWorksheet);
38+
$this->to = $this->cellAddressWrapper($lastColumn, $lastRow, $toWorksheet);
3939
}
4040

4141
private function validateWorksheets(?Worksheet $fromWorksheet, ?Worksheet $toWorksheet): void
@@ -54,18 +54,76 @@ private function validateWorksheets(?Worksheet $fromWorksheet, ?Worksheet $toWor
5454
}
5555
}
5656

57+
private function cellAddressWrapper(int $column, int $row, ?Worksheet $worksheet = null): CellAddress
58+
{
59+
$cellAddress = Coordinate::stringFromColumnIndex($column) . (string) $row;
60+
61+
return new class ($cellAddress, $worksheet) extends CellAddress {
62+
public function nextRow(int $offset = 1): CellAddress
63+
{
64+
/** @var CellAddress $result */
65+
$result = parent::nextRow($offset);
66+
$this->rowId = $result->rowId;
67+
$this->cellAddress = $result->cellAddress;
68+
69+
return $this;
70+
}
71+
72+
public function previousRow(int $offset = 1): CellAddress
73+
{
74+
/** @var CellAddress $result */
75+
$result = parent::previousRow($offset);
76+
$this->rowId = $result->rowId;
77+
$this->cellAddress = $result->cellAddress;
78+
79+
return $this;
80+
}
81+
82+
public function nextColumn(int $offset = 1): CellAddress
83+
{
84+
/** @var CellAddress $result */
85+
$result = parent::nextColumn($offset);
86+
$this->columnId = $result->columnId;
87+
$this->columnName = $result->columnName;
88+
$this->cellAddress = $result->cellAddress;
89+
90+
return $this;
91+
}
92+
93+
public function previousColumn(int $offset = 1): CellAddress
94+
{
95+
/** @var CellAddress $result */
96+
$result = parent::previousColumn($offset);
97+
$this->columnId = $result->columnId;
98+
$this->columnName = $result->columnName;
99+
$this->cellAddress = $result->cellAddress;
100+
101+
return $this;
102+
}
103+
};
104+
}
105+
57106
public function from(): CellAddress
58107
{
108+
// Re-order from/to in case the cell addresses have been modified
109+
$this->validateFromTo($this->from, $this->to);
110+
59111
return $this->from;
60112
}
61113

62114
public function to(): CellAddress
63115
{
116+
// Re-order from/to in case the cell addresses have been modified
117+
$this->validateFromTo($this->from, $this->to);
118+
64119
return $this->to;
65120
}
66121

67122
public function __toString(): string
68123
{
124+
// Re-order from/to in case the cell addresses have been modified
125+
$this->validateFromTo($this->from, $this->to);
126+
69127
if ($this->from->cellAddress() === $this->to->cellAddress()) {
70128
return "{$this->from->fullCellAddress()}";
71129
}

src/PhpSpreadsheet/Cell/ColumnRange.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
66

7-
class ColumnRange
7+
class ColumnRange implements AddressRange
88
{
9-
private const MAX_ROW = 1048576;
10-
119
/**
1210
* @var ?Worksheet
1311
*/
@@ -107,7 +105,7 @@ public function toCellRange(): CellRange
107105
{
108106
return new CellRange(
109107
CellAddress::fromColumnAndRow($this->from, 1, $this->worksheet),
110-
CellAddress::fromColumnAndRow($this->to, self::MAX_ROW)
108+
CellAddress::fromColumnAndRow($this->to, AddressRange::MAX_ROW)
111109
);
112110
}
113111

src/PhpSpreadsheet/Cell/RowRange.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
66

7-
class RowRange
7+
class RowRange implements AddressRange
88
{
9-
private const MAX_COLUMN = 'XFD';
10-
119
/**
1210
* @var ?Worksheet
1311
*/
@@ -78,7 +76,7 @@ public function toCellRange(): CellRange
7876
{
7977
return new CellRange(
8078
CellAddress::fromColumnAndRow(Coordinate::columnIndexFromString('A'), $this->from, $this->worksheet),
81-
CellAddress::fromColumnAndRow(Coordinate::columnIndexFromString(self::MAX_COLUMN), $this->to)
79+
CellAddress::fromColumnAndRow(Coordinate::columnIndexFromString(AddressRange::MAX_COLUMN), $this->to)
8280
);
8381
}
8482

tests/PhpSpreadsheetTests/Cell/CellRangeTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,44 @@ public function testCreateCellRangeWithMismatchedSpreadsheets(): void
110110
$to = CellAddress::fromCellAddress('E2', $worksheet2);
111111
new CellRange($from, $to);
112112
}
113+
114+
public function testShiftRangeTo(): void
115+
{
116+
$from = CellAddress::fromCellAddress('B5');
117+
$to = CellAddress::fromCellAddress('E2');
118+
$cellRange = new CellRange($from, $to);
119+
self::assertSame('B2:E5', (string) $cellRange);
120+
121+
$cellRange->to()
122+
->nextColumn(2)
123+
->nextRow(2);
124+
125+
self::assertSame('B2', (string) $cellRange->from());
126+
self::assertSame('G7', (string) $cellRange->to());
127+
self::assertSame('B2:G7', (string) $cellRange);
128+
129+
$cellRange->to()
130+
->previousColumn()
131+
->previousRow();
132+
133+
self::assertSame('B2', (string) $cellRange->from());
134+
self::assertSame('F6', (string) $cellRange->to());
135+
self::assertSame('B2:F6', (string) $cellRange);
136+
}
137+
138+
public function testShiftRangeFrom(): void
139+
{
140+
$from = CellAddress::fromCellAddress('B5');
141+
$to = CellAddress::fromCellAddress('E2');
142+
$cellRange = new CellRange($from, $to);
143+
self::assertSame('B2:E5', (string) $cellRange);
144+
145+
$cellRange->from()
146+
->nextColumn(5)
147+
->nextRow(5);
148+
149+
self::assertSame('E5', (string) $cellRange->from());
150+
self::assertSame('G7', (string) $cellRange->to());
151+
self::assertSame('E5:G7', (string) $cellRange);
152+
}
113153
}

0 commit comments

Comments
 (0)