Skip to content

Commit f9319a8

Browse files
committed
Retitling Cloned Worksheets
Backport of PR #4302
1 parent b5ef72c commit f9319a8

File tree

4 files changed

+100
-4
lines changed

4 files changed

+100
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ 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)
1718

1819
# 2024-12-26 - 1.29.7
1920

src/PhpSpreadsheet/Spreadsheet.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ public function getActiveSheet()
599599
public function createSheet($sheetIndex = null)
600600
{
601601
$newSheet = new Worksheet($this);
602-
$this->addSheet($newSheet, $sheetIndex);
602+
$this->addSheet($newSheet, $sheetIndex, true);
603603

604604
return $newSheet;
605605
}
@@ -621,11 +621,24 @@ public function sheetNameExists($worksheetName)
621621
*
622622
* @param Worksheet $worksheet The worksheet to add
623623
* @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
624+
* @param bool $retitleIfNeeded add suffix if title exists in spreadsheet
624625
*
625626
* @return Worksheet
626627
*/
627-
public function addSheet(Worksheet $worksheet, $sheetIndex = null)
628+
public function addSheet(Worksheet $worksheet, $sheetIndex = null, $retitleIfNeeded = false)
628629
{
630+
if ($retitleIfNeeded) {
631+
$title = $worksheet->getTitle();
632+
if ($this->sheetNameExists($title)) {
633+
$i = 1;
634+
$newTitle = "$title $i";
635+
while ($this->sheetNameExists($newTitle)) {
636+
++$i;
637+
$newTitle = "$title $i";
638+
}
639+
$worksheet->setTitle($newTitle);
640+
}
641+
}
629642
if ($this->sheetNameExists($worksheet->getTitle())) {
630643
throw new Exception(
631644
"Workbook already contains a worksheet named '{$worksheet->getTitle()}'. Rename this worksheet first."

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ public function setTitle($title, $updateFormulaCellReferences = true, $validate
913913
// Syntax check
914914
self::checkSheetTitle($title);
915915

916-
if ($this->parent) {
916+
if ($this->parent && $this->parent->getIndex($this, true) >= 0) {
917917
// Is there already such sheet name?
918918
if ($this->parent->sheetNameExists($title)) {
919919
// Use name, but append with lowest possible integer
@@ -943,7 +943,7 @@ public function setTitle($title, $updateFormulaCellReferences = true, $validate
943943
// Set title
944944
$this->title = $title;
945945

946-
if ($this->parent && $this->parent->getCalculationEngine()) {
946+
if ($this->parent && $this->parent->getIndex($this, true) >= 0 && $this->parent->getCalculationEngine()) {
947947
// New title
948948
$newTitle = $this->getTitle();
949949
$this->parent->getCalculationEngine()
Lines changed: 82 additions & 0 deletions
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)