Skip to content

Commit 83aaf32

Browse files
author
MarkBaker
committed
Handle selected cells
1 parent 3ae5a3f commit 83aaf32

File tree

1 file changed

+60
-69
lines changed

1 file changed

+60
-69
lines changed

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 60 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,12 +1113,9 @@ public function getHighestRowAndColumn()
11131113
* @param null|array<int>|CellAddress|string $cellAddress Coordinate of the cell as a string, eg: 'C5';
11141114
* or as an array of [$columnIndex, $row] (e.g. [3, 5]), or a CellAddress object.
11151115
*/
1116-
protected function validateCellAddress($cellAddress, bool $allowNull = false): ?string
1116+
protected function validateCellAddress($cellAddress): string
11171117
{
1118-
if (is_string($cellAddress) || ($cellAddress === null && $allowNull === true)) {
1119-
if ($cellAddress === null) {
1120-
return null;
1121-
}
1118+
if (is_string($cellAddress)) {
11221119
[$worksheet, $address] = self::extractSheetTitle($cellAddress, true);
11231120
// if (!empty($worksheet) && $worksheet !== $this->getTitle()) {
11241121
// throw new Exception('Reference is not for this worksheet');
@@ -1134,16 +1131,38 @@ protected function validateCellAddress($cellAddress, bool $allowNull = false): ?
11341131
return (string) $cellAddress;
11351132
}
11361133

1134+
private function tryDefinedName(string $coordinate): string
1135+
{
1136+
// Uppercase coordinate
1137+
$coordinate = strtoupper($coordinate);
1138+
// Eliminate leading equal sign
1139+
$coordinate = self::pregReplace('/^=/', '', $coordinate);
1140+
$defined = $this->parent->getDefinedName($coordinate, $this);
1141+
if ($defined !== null) {
1142+
if ($defined->getWorksheet() === $this && !$defined->isFormula()) {
1143+
$coordinate = self::pregReplace('/^=/', '', $defined->getValue());
1144+
}
1145+
}
1146+
1147+
return $coordinate;
1148+
}
1149+
11371150
/**
1138-
* Validate a cell range.
1151+
* Validate a cell address or cell range.
11391152
*
1140-
* @param AddressRange|array<int>|CellAddress|string $cellRange Coordinate of the cells as a string, eg: 'C5:F12';
1153+
* @param AddressRange|array<int>|CellAddress|int|string $cellRange Coordinate of the cells as a string, eg: 'C5:F12';
11411154
* or as an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 12]),
11421155
* or as a CellAddress or AddressRange object.
11431156
*/
11441157
protected function validateCellOrCellRange($cellRange): string
11451158
{
1146-
if (is_object($cellRange) && $cellRange instanceof CellAddress) {
1159+
if (is_string($cellRange) || is_numeric($cellRange)) {
1160+
$cellRange = (string) $cellRange;
1161+
// Convert a single column reference like 'A' to 'A:A'
1162+
$cellRange = self::pregReplace('/^([A-Z]+)$/', '${1}:${1}', $cellRange);
1163+
// Convert a single row reference like '1' to '1:1'
1164+
$cellRange = self::pregReplace('/^(\d+)$/', '${1}:${1}', $cellRange);
1165+
} elseif (is_object($cellRange) && $cellRange instanceof CellAddress) {
11471166
$cellRange = new CellRange($cellRange, $cellRange);
11481167
}
11491168

@@ -1162,9 +1181,9 @@ protected function validateCellRange($cellRange): string
11621181
if (is_string($cellRange)) {
11631182
[$worksheet, $addressRange] = self::extractSheetTitle($cellRange, true);
11641183

1165-
// Convert 'A:C' to 'A1:C1048576'
1184+
// Convert Column ranges like 'A:C' to 'A1:C1048576'
11661185
$addressRange = self::pregReplace('/^([A-Z]+):([A-Z]+)$/', '${1}1:${2}1048576', $addressRange);
1167-
// Convert '1:3' to 'A1:XFD3'
1186+
// Convert Row ranges like '1:3' to 'A1:XFD3'
11681187
$addressRange = self::pregReplace('/^(\\d+):(\\d+)$/', 'A${1}:XFD${2}', $addressRange);
11691188

11701189
return empty($worksheet) ? strtoupper($addressRange) : $worksheet . '!' . strtoupper($addressRange);
@@ -1189,8 +1208,7 @@ protected function validateCellRange($cellRange): string
11891208
*/
11901209
public function setCellValue($coordinate, $value)
11911210
{
1192-
/** @var string $cellAddress */
1193-
$cellAddress = $this->validateCellAddress($coordinate);
1211+
$cellAddress = Functions::trimSheetFromCellReference($this->validateCellAddress($coordinate));
11941212
$this->getCell($cellAddress)->setValue($value);
11951213

11961214
return $this;
@@ -1211,7 +1229,7 @@ public function setCellValue($coordinate, $value)
12111229
*/
12121230
public function setCellValueByColumnAndRow($columnIndex, $row, $value)
12131231
{
1214-
$this->getCell([$columnIndex, $row])->setValue($value);
1232+
$this->getCell(Coordinate::stringFromColumnIndex($columnIndex) . $row)->setValue($value);
12151233

12161234
return $this;
12171235
}
@@ -1228,8 +1246,7 @@ public function setCellValueByColumnAndRow($columnIndex, $row, $value)
12281246
*/
12291247
public function setCellValueExplicit($coordinate, $value, $dataType)
12301248
{
1231-
/** @var string $cellAddress */
1232-
$cellAddress = $this->validateCellAddress($coordinate);
1249+
$cellAddress = Functions::trimSheetFromCellReference($this->validateCellAddress($coordinate));
12331250
$this->getCell($cellAddress)->setValueExplicit($value, $dataType);
12341251

12351252
return $this;
@@ -1251,7 +1268,7 @@ public function setCellValueExplicit($coordinate, $value, $dataType)
12511268
*/
12521269
public function setCellValueExplicitByColumnAndRow($columnIndex, $row, $value, $dataType)
12531270
{
1254-
$this->getCell([$columnIndex, $row])->setValueExplicit($value, $dataType);
1271+
$this->getCell(Coordinate::stringFromColumnIndex($columnIndex) . $row)->setValueExplicit($value, $dataType);
12551272

12561273
return $this;
12571274
}
@@ -1266,8 +1283,7 @@ public function setCellValueExplicitByColumnAndRow($columnIndex, $row, $value, $
12661283
*/
12671284
public function getCell($coordinate): Cell
12681285
{
1269-
/** @var string $cellAddress */
1270-
$cellAddress = $this->validateCellAddress($coordinate);
1286+
$cellAddress = Functions::trimSheetFromCellReference($this->validateCellAddress($coordinate));
12711287

12721288
// Shortcut for increased performance for the vast majority of simple cases
12731289
if ($this->cellCollection->has($cellAddress)) {
@@ -1368,7 +1384,7 @@ private function getCellOrNull($coordinate): ?Cell
13681384
*/
13691385
public function getCellByColumnAndRow($columnIndex, $row): Cell
13701386
{
1371-
return $this->getCell([$columnIndex, $row]);
1387+
return $this->getCell(Coordinate::stringFromColumnIndex($columnIndex) . $row);
13721388
}
13731389

13741390
/**
@@ -1418,7 +1434,6 @@ public function createNewCell($coordinate)
14181434
*/
14191435
public function cellExists($coordinate): bool
14201436
{
1421-
/** @var string $cellAddress */
14221437
$cellAddress = $this->validateCellAddress($coordinate);
14231438
/** @var Worksheet $sheet */
14241439
[$sheet, $finalCoordinate] = $this->getWorksheetAndCoordinate($cellAddress);
@@ -1438,7 +1453,7 @@ public function cellExists($coordinate): bool
14381453
*/
14391454
public function cellExistsByColumnAndRow($columnIndex, $row): bool
14401455
{
1441-
return $this->cellExists([$columnIndex, $row]);
1456+
return $this->cellExists(Coordinate::stringFromColumnIndex($columnIndex) . $row);
14421457
}
14431458

14441459
/**
@@ -1504,14 +1519,14 @@ public function getStyles()
15041519
/**
15051520
* Get style for cell.
15061521
*
1507-
* @param AddressRange|array<int>|CellAddress|string $cellCoordinate
1522+
* @param AddressRange|array<int>|CellAddress|int|string $cellCoordinate
15081523
* A simple string containing a cell address like 'A1' or a cell range like 'A1:E10'
15091524
* or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]),
15101525
* or a CellAddress or AddressRange object.
15111526
*/
15121527
public function getStyle($cellCoordinate): Style
15131528
{
1514-
$cellCoordinate = $this->validateCellRange($cellCoordinate);
1529+
$cellCoordinate = $this->validateCellOrCellRange($cellCoordinate);
15151530

15161531
// set this sheet as active
15171532
$this->parent->setActiveSheetIndex($this->parent->getIndex($this));
@@ -1749,7 +1764,7 @@ public function duplicateConditionalStyle(array $styles, $range = '')
17491764
*/
17501765
public function setBreak($coordinate, $break)
17511766
{
1752-
$cellAddress = Functions::trimSheetFromCellReference($this->validateCellAddress($coordinate) ?? '');
1767+
$cellAddress = Functions::trimSheetFromCellReference($this->validateCellAddress($coordinate));
17531768

17541769
if ($break === self::BREAK_NONE) {
17551770
if (isset($this->breaks[$cellAddress])) {
@@ -1777,7 +1792,7 @@ public function setBreak($coordinate, $break)
17771792
*/
17781793
public function setBreakByColumnAndRow($columnIndex, $row, $break)
17791794
{
1780-
return $this->setBreak([$columnIndex, $row], $break);
1795+
return $this->setBreak(Coordinate::stringFromColumnIndex($columnIndex) . $row, $break);
17811796
}
17821797

17831798
/**
@@ -1978,7 +1993,7 @@ public function setMergeCells(array $mergeCells)
19781993
/**
19791994
* Set protection on a cell or cell range.
19801995
*
1981-
* @param AddressRange|array<int>|CellAddress|string $range A simple string containing a Cell range like 'A1:E10'
1996+
* @param AddressRange|array<int>|CellAddress|int|string $range A simple string containing a Cell range like 'A1:E10'
19821997
* or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]),
19831998
* or a CellAddress or AddressRange object.
19841999
* @param string $password Password to unlock the protection
@@ -1988,7 +2003,7 @@ public function setMergeCells(array $mergeCells)
19882003
*/
19892004
public function protectCells($range, $password, $alreadyHashed = false)
19902005
{
1991-
$range = Functions::trimSheetFromCellReference($this->validateCellRange($range));
2006+
$range = Functions::trimSheetFromCellReference($this->validateCellOrCellRange($range));
19922007

19932008
if (!$alreadyHashed) {
19942009
$password = Shared\PasswordHasher::hashPassword($password);
@@ -2028,15 +2043,15 @@ public function protectCellsByColumnAndRow($columnIndex1, $row1, $columnIndex2,
20282043
/**
20292044
* Remove protection on a cell or cell range.
20302045
*
2031-
* @param AddressRange|array<int>|CellAddress|string $range A simple string containing a Cell range like 'A1:E10'
2046+
* @param AddressRange|array<int>|CellAddress|int|string $range A simple string containing a Cell range like 'A1:E10'
20322047
* or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]),
20332048
* or a CellAddress or AddressRange object.
20342049
*
20352050
* @return $this
20362051
*/
20372052
public function unprotectCells($range)
20382053
{
2039-
$range = Functions::trimSheetFromCellReference($this->validateCellRange($range));
2054+
$range = Functions::trimSheetFromCellReference($this->validateCellOrCellRange($range));
20402055

20412056
if (isset($this->protectedCells[$range])) {
20422057
unset($this->protectedCells[$range]);
@@ -2180,11 +2195,15 @@ public function getFreezePane()
21802195
*/
21812196
public function freezePane($coordinate, $topLeftCell = null)
21822197
{
2183-
$cellAddress = $this->validateCellAddress($coordinate, true);
2184-
if (is_string($cellAddress) && Coordinate::coordinateIsRange($cellAddress)) {
2198+
$cellAddress = ($coordinate !== null)
2199+
? Functions::trimSheetFromCellReference($this->validateCellAddress($coordinate))
2200+
: null;
2201+
if ($cellAddress !== null && Coordinate::coordinateIsRange($cellAddress)) {
21852202
throw new Exception('Freeze pane can not be set on a range of cells.');
21862203
}
2187-
$topLeftCell = $this->validateCellAddress($topLeftCell, true);
2204+
$topLeftCell = ($topLeftCell !== null)
2205+
? Functions::trimSheetFromCellReference($this->validateCellAddress($topLeftCell))
2206+
: null;
21882207

21892208
if ($cellAddress !== null && $topLeftCell === null) {
21902209
$coordinate = Coordinate::coordinateFromString($cellAddress);
@@ -2218,7 +2237,7 @@ public function setTopLeftCell(string $topLeftCell): self
22182237
*/
22192238
public function freezePaneByColumnAndRow($columnIndex, $row)
22202239
{
2221-
return $this->freezePane([$columnIndex, $row]);
2240+
return $this->freezePane(Coordinate::stringFromColumnIndex($columnIndex) . $row);
22222241
}
22232242

22242243
/**
@@ -2587,8 +2606,7 @@ public function setComments(array $comments)
25872606
*/
25882607
public function getComment($cellCoordinate)
25892608
{
2590-
/** @var string $cellAddress */
2591-
$cellAddress = $this->validateCellAddress($cellCoordinate);
2609+
$cellAddress = Functions::trimSheetFromCellReference($this->validateCellAddress($cellCoordinate));
25922610

25932611
if (Coordinate::coordinateIsRange($cellAddress)) {
25942612
throw new Exception('Cell coordinate string can not be a range of cells.');
@@ -2624,7 +2642,7 @@ public function getComment($cellCoordinate)
26242642
*/
26252643
public function getCommentByColumnAndRow($columnIndex, $row)
26262644
{
2627-
return $this->getComment([$columnIndex, $row]);
2645+
return $this->getComment(Coordinate::stringFromColumnIndex($columnIndex) . $row);
26282646
}
26292647

26302648
/**
@@ -2675,48 +2693,21 @@ public static function pregReplace(string $pattern, string $replacement, string
26752693
return self::ensureString(preg_replace($pattern, $replacement, $subject));
26762694
}
26772695

2678-
private function tryDefinedName(string $coordinate): string
2679-
{
2680-
// Uppercase coordinate
2681-
$coordinate = strtoupper($coordinate);
2682-
// Eliminate leading equal sign
2683-
$coordinate = self::pregReplace('/^=/', '', $coordinate);
2684-
$defined = $this->parent->getDefinedName($coordinate, $this);
2685-
if ($defined !== null) {
2686-
if ($defined->getWorksheet() === $this && !$defined->isFormula()) {
2687-
$coordinate = self::pregReplace('/^=/', '', $defined->getValue());
2688-
}
2689-
}
2690-
2691-
return $coordinate;
2692-
}
2693-
26942696
/**
26952697
* Select a range of cells.
26962698
*
2697-
* @param string $coordinate Cell range, examples: 'A1', 'B2:G5', 'A:C', '3:6'
2699+
* @param AddressRange|array<int>|CellAddress|int|string $coordinate A simple string containing a Cell range like 'A1:E10'
2700+
* or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]),
2701+
* or a CellAddress or AddressRange object.
26982702
*
26992703
* @return $this
27002704
*/
27012705
public function setSelectedCells($coordinate)
27022706
{
2703-
$originalCoordinate = $coordinate;
2704-
$coordinate = $this->tryDefinedName($coordinate);
2705-
2706-
// Convert 'A' to 'A:A'
2707-
$coordinate = self::pregReplace('/^([A-Z]+)$/', '${1}:${1}', $coordinate);
2708-
2709-
// Convert '1' to '1:1'
2710-
$coordinate = self::pregReplace('/^(\d+)$/', '${1}:${1}', $coordinate);
2711-
2712-
// Convert 'A:C' to 'A1:C1048576'
2713-
$coordinate = self::pregReplace('/^([A-Z]+):([A-Z]+)$/', '${1}1:${2}1048576', $coordinate);
2714-
2715-
// Convert '1:3' to 'A1:XFD3'
2716-
$coordinate = self::pregReplace('/^(\d+):(\d+)$/', 'A${1}:XFD${2}', $coordinate);
2717-
if (preg_match('/^\\$?[A-Z]{1,3}\\$?\d{1,7}(:\\$?[A-Z]{1,3}\\$?\d{1,7})?$/', $coordinate) !== 1) {
2718-
throw new Exception("Invalid setSelectedCells $originalCoordinate $coordinate");
2707+
if (is_string($coordinate)) {
2708+
$coordinate = $this->tryDefinedName($coordinate);
27192709
}
2710+
$coordinate = $this->validateCellOrCellRange($coordinate);
27202711

27212712
if (Coordinate::coordinateIsRange($coordinate)) {
27222713
[$first] = Coordinate::splitRange($coordinate);

0 commit comments

Comments
 (0)