Skip to content

Commit 3ef77d3

Browse files
committed
Retitling Clone Worksheets
Backport of PR PHPOffice#4302.
1 parent 5c3d84a commit 3ef77d3

File tree

4 files changed

+100
-4
lines changed

4 files changed

+100
-4
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
1414
### Fixed
1515

1616
- Change hash code for worksheet. Backport of [PR #4207](https://github.com/PHPOffice/PhpSpreadsheet/pull/4207)
17+
- Retitling cloned worksheets. Backport of [PR #4302](https://github.com/PHPOffice/PhpSpreadsheet/pull/4302)
18+
1719

1820
# 2024-12-26 - 2.1.6
1921

src/PhpSpreadsheet/Spreadsheet.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ public function getActiveSheet(): Worksheet
508508
public function createSheet(?int $sheetIndex = null): Worksheet
509509
{
510510
$newSheet = new Worksheet($this);
511-
$this->addSheet($newSheet, $sheetIndex);
511+
$this->addSheet($newSheet, $sheetIndex, true);
512512

513513
return $newSheet;
514514
}
@@ -529,8 +529,20 @@ public function sheetNameExists(string $worksheetName): bool
529529
* @param Worksheet $worksheet The worksheet to add
530530
* @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
531531
*/
532-
public function addSheet(Worksheet $worksheet, ?int $sheetIndex = null): Worksheet
532+
public function addSheet(Worksheet $worksheet, ?int $sheetIndex = null, bool $retitleIfNeeded = false): Worksheet
533533
{
534+
if ($retitleIfNeeded) {
535+
$title = $worksheet->getTitle();
536+
if ($this->sheetNameExists($title)) {
537+
$i = 1;
538+
$newTitle = "$title $i";
539+
while ($this->sheetNameExists($newTitle)) {
540+
++$i;
541+
$newTitle = "$title $i";
542+
}
543+
$worksheet->setTitle($newTitle);
544+
}
545+
}
534546
if ($this->sheetNameExists($worksheet->getTitle())) {
535547
throw new Exception(
536548
"Workbook already contains a worksheet named '{$worksheet->getTitle()}'. Rename this worksheet first."

src/PhpSpreadsheet/Worksheet/Worksheet.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ public function setTitle(string $title, bool $updateFormulaCellReferences = true
863863
// Syntax check
864864
self::checkSheetTitle($title);
865865

866-
if ($this->parent) {
866+
if ($this->parent && $this->parent->getIndex($this, true) >= 0) {
867867
// Is there already such sheet name?
868868
if ($this->parent->sheetNameExists($title)) {
869869
// Use name, but append with lowest possible integer
@@ -893,7 +893,7 @@ public function setTitle(string $title, bool $updateFormulaCellReferences = true
893893
// Set title
894894
$this->title = $title;
895895

896-
if ($this->parent && $this->parent->getCalculationEngine()) {
896+
if ($this->parent && $this->parent->getIndex($this, true) >= 0 && $this->parent->getCalculationEngine()) {
897897
// New title
898898
$newTitle = $this->getTitle();
899899
$this->parent->getCalculationEngine()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PHPUnit\Framework\TestCase;
9+
10+
class Issue641Test extends TestCase
11+
{
12+
/**
13+
* Problem cloning sheet referred to in formulas.
14+
*/
15+
public function testIssue641(): void
16+
{
17+
$xlsx = new Spreadsheet();
18+
$xlsx->removeSheetByIndex(0);
19+
$availableWs = [];
20+
21+
$worksheet = $xlsx->createSheet();
22+
$worksheet->setTitle('Condensed A');
23+
$worksheet->getCell('A1')->setValue("=SUM('Detailed A'!A1:A10)");
24+
$worksheet->getCell('A2')->setValue(mt_rand(1, 30));
25+
$availableWs[] = 'Condensed A';
26+
27+
$worksheet = $xlsx->createSheet();
28+
$worksheet->setTitle('Condensed B');
29+
$worksheet->getCell('A1')->setValue("=SUM('Detailed B'!A1:A10)");
30+
$worksheet->getCell('A2')->setValue(mt_rand(1, 30));
31+
$availableWs[] = 'Condensed B';
32+
33+
// at this point the value in worksheet 'Condensed B' cell A1 is
34+
// =SUM('Detailed B'!A1:A10)
35+
36+
// worksheet in question is cloned and totals are attached
37+
$totalWs1 = clone $xlsx->getSheet($xlsx->getSheetCount() - 1);
38+
$totalWs1->setTitle('Condensed Total');
39+
$xlsx->addSheet($totalWs1);
40+
$formula = '=';
41+
foreach ($availableWs as $ws) {
42+
$formula .= sprintf("+'%s'!A2", $ws);
43+
}
44+
$totalWs1->getCell('A1')->setValue("=SUM('Detailed Total'!A1:A10)");
45+
$totalWs1->getCell('A2')->setValue($formula);
46+
47+
$availableWs = [];
48+
49+
$worksheet = $xlsx->createSheet();
50+
$worksheet->setTitle('Detailed A');
51+
for ($step = 1; $step <= 10; ++$step) {
52+
$worksheet->getCell("A{$step}")->setValue(mt_rand(1, 30));
53+
}
54+
$availableWs[] = 'Detailed A';
55+
56+
$worksheet = $xlsx->createSheet();
57+
$worksheet->setTitle('Detailed B');
58+
for ($step = 1; $step <= 10; ++$step) {
59+
$worksheet->getCell("A{$step}")->setValue(mt_rand(1, 30));
60+
}
61+
$availableWs[] = 'Detailed B';
62+
63+
$totalWs2 = clone $xlsx->getSheet($xlsx->getSheetCount() - 1);
64+
$totalWs2->setTitle('Detailed Total');
65+
$xlsx->addSheet($totalWs2);
66+
67+
for ($step = 1; $step <= 10; ++$step) {
68+
$formula = '=';
69+
foreach ($availableWs as $ws) {
70+
$formula .= sprintf("+'%s'!A%s", $ws, $step);
71+
}
72+
$totalWs2->getCell("A{$step}")->setValue($formula);
73+
}
74+
75+
self::assertSame("=SUM('Detailed A'!A1:A10)", $xlsx->getSheetByName('Condensed A')?->getCell('A1')?->getValue());
76+
self::assertSame("=SUM('Detailed B'!A1:A10)", $xlsx->getSheetByName('Condensed B')?->getCell('A1')?->getValue());
77+
self::assertSame("=SUM('Detailed Total'!A1:A10)", $xlsx->getSheetByName('Condensed Total')?->getCell('A1')?->getValue());
78+
self::assertSame("=+'Detailed A'!A1+'Detailed B'!A1", $xlsx->getSheetByName('Detailed Total')?->getCell('A1')?->getValue());
79+
80+
$xlsx->disconnectWorksheets();
81+
}
82+
}

0 commit comments

Comments
 (0)