Skip to content

Commit 251605f

Browse files
author
Mark Baker
authored
Merge pull request #2682 from PHPOffice/Refactoring-Work-on-ReferenceHelper
Some work on refactoring the ReferenceHelper to extract the logic for updating cell references. This is a preliminary step toward allowing updates to absolute cell references, required to update Conditional Formatting rules. And a bugfix when deleting cells that contain hyperlinks (the hperlinks weren't being deleted, so were being "inherited" by whatever cell moved to that address). Plus some additional unit tests for the ReferenceHelper.
2 parents 09cf6ab + bbe6b80 commit 251605f

File tree

6 files changed

+364
-203
lines changed

6 files changed

+364
-203
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
3939

4040
### Fixed
4141

42+
- Fix bug when deleting cells with hyperlinks, where the hyperlink was then being "inherited" by whatever cell moved to that cell address.
4243
- Fix bug in Conditional Formatting in the Xls Writer that resulted in a broken file when there were multiple conditional ranges in a worksheet.
4344
- Fix Conditional Formatting in the Xls Writer to work with rules that contain string literals, cell references and formulae.
4445
- Fix for setting Active Sheet to the first loaded worksheet when bookViews element isn't defined [Issue #2666](https://github.com/PHPOffice/PhpSpreadsheet/issues/2666) [PR #2669](https://github.com/PHPOffice/PhpSpreadsheet/pull/2669)

phpstan-baseline.neon

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3165,31 +3165,11 @@ parameters:
31653165
count: 1
31663166
path: src/PhpSpreadsheet/ReferenceHelper.php
31673167

3168-
-
3169-
message: "#^Parameter \\#1 \\$index of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\:\\:setRowIndex\\(\\) expects int, string given\\.$#"
3170-
count: 1
3171-
path: src/PhpSpreadsheet/ReferenceHelper.php
3172-
3173-
-
3174-
message: "#^Parameter \\#2 \\$callback of function uksort expects callable\\(\\(int\\|string\\), \\(int\\|string\\)\\)\\: int, array\\{'self', 'cellReverseSort'\\} given\\.$#"
3175-
count: 4
3176-
path: src/PhpSpreadsheet/ReferenceHelper.php
3177-
3178-
-
3179-
message: "#^Parameter \\#2 \\$callback of function uksort expects callable\\(\\(int\\|string\\), \\(int\\|string\\)\\)\\: int, array\\{'self', 'cellSort'\\} given\\.$#"
3180-
count: 4
3181-
path: src/PhpSpreadsheet/ReferenceHelper.php
3182-
31833168
-
31843169
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
31853170
count: 1
31863171
path: src/PhpSpreadsheet/ReferenceHelper.php
31873172

3188-
-
3189-
message: "#^Static property PhpOffice\\\\PhpSpreadsheet\\\\ReferenceHelper\\:\\:\\$instance \\(PhpOffice\\\\PhpSpreadsheet\\\\ReferenceHelper\\) in isset\\(\\) is not nullable\\.$#"
3190-
count: 1
3191-
path: src/PhpSpreadsheet/ReferenceHelper.php
3192-
31933173
-
31943174
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\Run\\:\\:\\$font \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
31953175
count: 1
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet;
4+
5+
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
6+
7+
class CellReferenceHelper
8+
{
9+
/**
10+
* @var string
11+
*/
12+
protected $beforeCellAddress;
13+
14+
/**
15+
* @var int
16+
*/
17+
protected $beforeColumn;
18+
19+
/**
20+
* @var int
21+
*/
22+
protected $beforeRow;
23+
24+
/**
25+
* @var int
26+
*/
27+
protected $numberOfColumns;
28+
29+
/**
30+
* @var int
31+
*/
32+
protected $numberOfRows;
33+
34+
public function __construct(string $beforeCellAddress = 'A1', int $numberOfColumns = 0, int $numberOfRows = 0)
35+
{
36+
$this->beforeCellAddress = str_replace('$', '', $beforeCellAddress);
37+
$this->numberOfColumns = $numberOfColumns;
38+
$this->numberOfRows = $numberOfRows;
39+
40+
// Get coordinate of $beforeCellAddress
41+
[$beforeColumn, $beforeRow] = Coordinate::coordinateFromString($beforeCellAddress);
42+
$this->beforeColumn = (int) Coordinate::columnIndexFromString($beforeColumn);
43+
$this->beforeRow = (int) $beforeRow;
44+
}
45+
46+
public function refreshRequired(string $beforeCellAddress, int $numberOfColumns, int $numberOfRows): bool
47+
{
48+
return $this->beforeCellAddress !== $beforeCellAddress ||
49+
$this->numberOfColumns !== $numberOfColumns ||
50+
$this->numberOfRows !== $numberOfRows;
51+
}
52+
53+
public function updateCellReference(string $cellReference = 'A1'): string
54+
{
55+
if (Coordinate::coordinateIsRange($cellReference)) {
56+
throw new Exception('Only single cell references may be passed to this method.');
57+
}
58+
59+
// Get coordinate of $cellReference
60+
[$newColumn, $newRow] = Coordinate::coordinateFromString($cellReference);
61+
$newColumnIndex = (int) Coordinate::columnIndexFromString(str_replace('$', '', $newColumn));
62+
$newRowIndex = (int) str_replace('$', '', $newRow);
63+
64+
// Verify which parts should be updated
65+
$updateColumn = (($newColumn[0] !== '$') && $newColumnIndex >= $this->beforeColumn);
66+
$updateRow = (($newRow[0] !== '$') && $newRow >= $this->beforeRow);
67+
68+
// Create new column reference
69+
if ($updateColumn) {
70+
$newColumn = Coordinate::stringFromColumnIndex($newColumnIndex + $this->numberOfColumns);
71+
}
72+
73+
// Create new row reference
74+
if ($updateRow) {
75+
$newRow = $newRowIndex + $this->numberOfRows;
76+
}
77+
78+
// Return new reference
79+
return "{$newColumn}{$newRow}";
80+
}
81+
82+
public function cellAddressInDeleteRange(string $cellAddress): bool
83+
{
84+
[$cellColumn, $cellRow] = Coordinate::coordinateFromString($cellAddress);
85+
$cellColumnIndex = Coordinate::columnIndexFromString($cellColumn);
86+
// Is cell within the range of rows/columns if we're deleting
87+
if (
88+
$this->numberOfRows < 0 &&
89+
($cellRow >= ($this->beforeRow + $this->numberOfRows)) &&
90+
($cellRow < $this->beforeRow)
91+
) {
92+
return true;
93+
} elseif (
94+
$this->numberOfColumns < 0 &&
95+
($cellColumnIndex >= ($this->beforeColumn + $this->numberOfColumns)) &&
96+
($cellColumnIndex < $this->beforeColumn)
97+
) {
98+
return true;
99+
}
100+
101+
return false;
102+
}
103+
}

0 commit comments

Comments
 (0)