Skip to content

Commit 4f714cd

Browse files
authored
Merge pull request #3007 from PHPOffice/Issue-3005_Extract-CellReferences-in-Range-with-Worksheet-Reference
Adjust `extractAllCellReferencesInRange()` method to allow a worksheet in the reference
2 parents 069efdb + b0f7e83 commit 4f714cd

File tree

5 files changed

+98
-12
lines changed

5 files changed

+98
-12
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,11 +1060,6 @@ parameters:
10601060
count: 1
10611061
path: src/PhpSpreadsheet/Calculation/TextData/Text.php
10621062

1063-
-
1064-
message: "#^Elseif branch is unreachable because previous condition is always true\\.$#"
1065-
count: 1
1066-
path: src/PhpSpreadsheet/Cell/Cell.php
1067-
10681063
-
10691064
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:getFormulaAttributes\\(\\) has no return type specified\\.$#"
10701065
count: 1

src/PhpSpreadsheet/Cell/Coordinate.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PhpOffice\PhpSpreadsheet\Cell;
44

5+
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
56
use PhpOffice\PhpSpreadsheet\Exception;
67
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
78

@@ -349,6 +350,19 @@ public static function stringFromColumnIndex($columnIndex)
349350
*/
350351
public static function extractAllCellReferencesInRange($cellRange): array
351352
{
353+
if (substr_count($cellRange, '!') > 1) {
354+
throw new Exception('3-D Range References are not supported');
355+
}
356+
357+
[$worksheet, $cellRange] = Worksheet::extractSheetTitle($cellRange, true);
358+
$quoted = '';
359+
if ($worksheet > '') {
360+
$quoted = Worksheet::nameRequiresQuotes($worksheet) ? "'" : '';
361+
if (substr($worksheet, 0, 1) === "'" && substr($worksheet, -1, 1) === "'") {
362+
$worksheet = substr($worksheet, 1, -1);
363+
}
364+
$worksheet = str_replace("'", "''", $worksheet);
365+
}
352366
[$ranges, $operators] = self::getCellBlocksFromRangeString($cellRange);
353367

354368
$cells = [];
@@ -364,7 +378,12 @@ public static function extractAllCellReferencesInRange($cellRange): array
364378

365379
$cellList = array_merge(...$cells);
366380

367-
return self::sortCellReferenceArray($cellList);
381+
return array_map(
382+
function ($cellAddress) use ($worksheet, $quoted) {
383+
return ($worksheet !== '') ? "{$quoted}{$worksheet}{$quoted}!{$cellAddress}" : $cellAddress;
384+
},
385+
self::sortCellReferenceArray($cellList)
386+
);
368387
}
369388

370389
private static function processRangeSetOperators(array $operators, array $cells): array

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@
3232
class Worksheet implements IComparable
3333
{
3434
// Break types
35-
const BREAK_NONE = 0;
36-
const BREAK_ROW = 1;
37-
const BREAK_COLUMN = 2;
35+
public const BREAK_NONE = 0;
36+
public const BREAK_ROW = 1;
37+
public const BREAK_COLUMN = 2;
3838

3939
// Sheet state
40-
const SHEETSTATE_VISIBLE = 'visible';
41-
const SHEETSTATE_HIDDEN = 'hidden';
42-
const SHEETSTATE_VERYHIDDEN = 'veryHidden';
40+
public const SHEETSTATE_VISIBLE = 'visible';
41+
public const SHEETSTATE_HIDDEN = 'hidden';
42+
public const SHEETSTATE_VERYHIDDEN = 'veryHidden';
43+
44+
protected const SHEET_NAME_REQUIRES_NO_QUOTES = '/^[_\p{L}][_\p{L}\p{N}]*$/mui';
4345

4446
/**
4547
* Maximum 31 characters allowed for sheet title.
@@ -3037,7 +3039,11 @@ public function getHashCode()
30373039
* Extract worksheet title from range.
30383040
*
30393041
* Example: extractSheetTitle("testSheet!A1") ==> 'A1'
3042+
* Example: extractSheetTitle("testSheet!A1:C3") ==> 'A1:C3'
30403043
* Example: extractSheetTitle("'testSheet 1'!A1", true) ==> ['testSheet 1', 'A1'];
3044+
* Example: extractSheetTitle("'testSheet 1'!A1:C3", true) ==> ['testSheet 1', 'A1:C3'];
3045+
* Example: extractSheetTitle("A1", true) ==> ['', 'A1'];
3046+
* Example: extractSheetTitle("A1:C3", true) ==> ['', 'A1:C3']
30413047
*
30423048
* @param string $range Range to extract title from
30433049
* @param bool $returnRange Return range? (see example)
@@ -3436,4 +3442,9 @@ public function hasCodeName()
34363442
{
34373443
return $this->codeName !== null;
34383444
}
3445+
3446+
public static function nameRequiresQuotes(string $sheetName): bool
3447+
{
3448+
return preg_match(self::SHEET_NAME_REQUIRES_NO_QUOTES, $sheetName) !== 1;
3449+
}
34393450
}

testing/cellReferenceTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
4+
5+
error_reporting(E_ALL);
6+
set_time_limit(0);
7+
8+
date_default_timezone_set('UTC');
9+
10+
// Adjust the path as required to reference the PHPSpreadsheet Bootstrap file
11+
require_once __DIR__ . '/../vendor/autoload.php';
12+
13+
$cellRange1 = Coordinate::extractAllCellReferencesInRange('D3');
14+
var_dump($cellRange1);
15+
$cellRange2 = Coordinate::extractAllCellReferencesInRange('D3:E4');
16+
var_dump($cellRange2);
17+
$cellRange3 = Coordinate::extractAllCellReferencesInRange('Sheet1!D3');
18+
var_dump($cellRange3);
19+
$cellRange4 = Coordinate::extractAllCellReferencesInRange('Sheet1!D3:E4');
20+
var_dump($cellRange4);
21+
22+
$cellRange11 = Coordinate::extractAllCellReferencesInRange('D3:E4 D4:F6');
23+
var_dump($cellRange11);
24+
$cellRange12 = Coordinate::extractAllCellReferencesInRange('D3:E4,D4:F6');
25+
var_dump($cellRange12);
26+
27+
$cellRange5 = Coordinate::extractAllCellReferencesInRange('Sheet1!D3:Sheet2!E4');
28+
var_dump($cellRange5);

tests/data/CellExtractAllCellReferencesInRange.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,37 @@
130130
],
131131
'Z2:AA3',
132132
],
133+
[
134+
[
135+
'Sheet1!D3',
136+
],
137+
'Sheet1!D3',
138+
],
139+
[
140+
[
141+
'Sheet1!D3',
142+
'Sheet1!E3',
143+
'Sheet1!D4',
144+
'Sheet1!E4',
145+
],
146+
'Sheet1!D3:E4',
147+
],
148+
[
149+
[
150+
"'Sheet 1'!D3",
151+
"'Sheet 1'!E3",
152+
"'Sheet 1'!D4",
153+
"'Sheet 1'!E4",
154+
],
155+
"'Sheet 1'!D3:E4",
156+
],
157+
[
158+
[
159+
"'Mark''s Sheet'!D3",
160+
"'Mark''s Sheet'!E3",
161+
"'Mark''s Sheet'!D4",
162+
"'Mark''s Sheet'!E4",
163+
],
164+
"'Mark's Sheet'!D3:E4",
165+
],
133166
];

0 commit comments

Comments
 (0)