Skip to content

Commit f5c285e

Browse files
authored
Merge pull request #4302 from oleibman/issue641
Retitling Cloned Worksheets
2 parents 17706a9 + decc0a4 commit f5c285e

File tree

4 files changed

+100
-5
lines changed

4 files changed

+100
-5
lines changed

CHANGELOG.md

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

2828
- Xlsx Reader Shared Formula with Boolean Result. Partial solution for [Issue #4280](https://github.com/PHPOffice/PhpSpreadsheet/issues/4280) [PR #4281](https://github.com/PHPOffice/PhpSpreadsheet/pull/4281)
29+
- Retitling cloned Worksheets. [Issue #641](https://github.com/PHPOffice/PhpSpreadsheet/issues/641) [PR #4302](https://github.com/PHPOffice/PhpSpreadsheet/pull/4302)
2930

3031
## 2024-12-26 - 3.7.0
3132

src/PhpSpreadsheet/Spreadsheet.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ public function getActiveSheet(): Worksheet
514514
public function createSheet(?int $sheetIndex = null): Worksheet
515515
{
516516
$newSheet = new Worksheet($this);
517-
$this->addSheet($newSheet, $sheetIndex);
517+
$this->addSheet($newSheet, $sheetIndex, true);
518518

519519
return $newSheet;
520520
}
@@ -535,8 +535,20 @@ public function sheetNameExists(string $worksheetName): bool
535535
* @param Worksheet $worksheet The worksheet to add
536536
* @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
537537
*/
538-
public function addSheet(Worksheet $worksheet, ?int $sheetIndex = null): Worksheet
538+
public function addSheet(Worksheet $worksheet, ?int $sheetIndex = null, bool $retitleIfNeeded = false): Worksheet
539539
{
540+
if ($retitleIfNeeded) {
541+
$title = $worksheet->getTitle();
542+
if ($this->sheetNameExists($title)) {
543+
$i = 1;
544+
$newTitle = "$title $i";
545+
while ($this->sheetNameExists($newTitle)) {
546+
++$i;
547+
$newTitle = "$title $i";
548+
}
549+
$worksheet->setTitle($newTitle);
550+
}
551+
}
540552
if ($this->sheetNameExists($worksheet->getTitle())) {
541553
throw new Exception(
542554
"Workbook already contains a worksheet named '{$worksheet->getTitle()}'. Rename this worksheet first."

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ public function __construct(?Spreadsheet $parent = null, string $title = 'Worksh
321321
{
322322
// Set parent and title
323323
$this->parent = $parent;
324+
$this->hash = spl_object_id($this);
324325
$this->setTitle($title, false);
325326
// setTitle can change $pTitle
326327
$this->setCodeName($this->getTitle());
@@ -349,7 +350,6 @@ public function __construct(?Spreadsheet $parent = null, string $title = 'Worksh
349350
$this->autoFilter = new AutoFilter('', $this);
350351
// Table collection
351352
$this->tableCollection = new ArrayObject();
352-
$this->hash = spl_object_id($this);
353353
}
354354

355355
/**
@@ -869,7 +869,7 @@ public function setTitle(string $title, bool $updateFormulaCellReferences = true
869869
// Syntax check
870870
self::checkSheetTitle($title);
871871

872-
if ($this->parent) {
872+
if ($this->parent && $this->parent->getIndex($this, true) >= 0) {
873873
// Is there already such sheet name?
874874
if ($this->parent->sheetNameExists($title)) {
875875
// Use name, but append with lowest possible integer
@@ -899,7 +899,7 @@ public function setTitle(string $title, bool $updateFormulaCellReferences = true
899899
// Set title
900900
$this->title = $title;
901901

902-
if ($this->parent && $this->parent->getCalculationEngine()) {
902+
if ($this->parent && $this->parent->getIndex($this, true) >= 0 && $this->parent->getCalculationEngine()) {
903903
// New title
904904
$newTitle = $this->getTitle();
905905
$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)