Skip to content

Commit

Permalink
Retitling Clone Worksheets
Browse files Browse the repository at this point in the history
Backport of PR PHPOffice#4302.
  • Loading branch information
oleibman committed Jan 7, 2025
1 parent 528dd5c commit 9e21d76
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Fixed

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


# 2024-12-26 - 2.3.5

Expand Down
16 changes: 14 additions & 2 deletions src/PhpSpreadsheet/Spreadsheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ public function getActiveSheet(): Worksheet
public function createSheet(?int $sheetIndex = null): Worksheet
{
$newSheet = new Worksheet($this);
$this->addSheet($newSheet, $sheetIndex);
$this->addSheet($newSheet, $sheetIndex, true);

return $newSheet;
}
Expand All @@ -532,8 +532,20 @@ public function sheetNameExists(string $worksheetName): bool
* @param Worksheet $worksheet The worksheet to add
* @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
*/
public function addSheet(Worksheet $worksheet, ?int $sheetIndex = null): Worksheet
public function addSheet(Worksheet $worksheet, ?int $sheetIndex = null, bool $retitleIfNeeded = false): Worksheet
{
if ($retitleIfNeeded) {
$title = $worksheet->getTitle();
if ($this->sheetNameExists($title)) {
$i = 1;
$newTitle = "$title $i";
while ($this->sheetNameExists($newTitle)) {
++$i;
$newTitle = "$title $i";
}
$worksheet->setTitle($newTitle);
}
}
if ($this->sheetNameExists($worksheet->getTitle())) {
throw new Exception(
"Workbook already contains a worksheet named '{$worksheet->getTitle()}'. Rename this worksheet first."
Expand Down
4 changes: 2 additions & 2 deletions src/PhpSpreadsheet/Worksheet/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ public function setTitle(string $title, bool $updateFormulaCellReferences = true
// Syntax check
self::checkSheetTitle($title);

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

if ($this->parent && $this->parent->getCalculationEngine()) {
if ($this->parent && $this->parent->getIndex($this, true) >= 0 && $this->parent->getCalculationEngine()) {
// New title
$newTitle = $this->getTitle();
$this->parent->getCalculationEngine()
Expand Down
82 changes: 82 additions & 0 deletions tests/PhpSpreadsheetTests/Worksheet/Issue641Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Worksheet;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;

class Issue641Test extends TestCase
{
/**
* Problem cloning sheet referred to in formulas.
*/
public function testIssue641(): void
{
$xlsx = new Spreadsheet();
$xlsx->removeSheetByIndex(0);
$availableWs = [];

$worksheet = $xlsx->createSheet();
$worksheet->setTitle('Condensed A');
$worksheet->getCell('A1')->setValue("=SUM('Detailed A'!A1:A10)");
$worksheet->getCell('A2')->setValue(mt_rand(1, 30));
$availableWs[] = 'Condensed A';

$worksheet = $xlsx->createSheet();
$worksheet->setTitle('Condensed B');
$worksheet->getCell('A1')->setValue("=SUM('Detailed B'!A1:A10)");
$worksheet->getCell('A2')->setValue(mt_rand(1, 30));
$availableWs[] = 'Condensed B';

// at this point the value in worksheet 'Condensed B' cell A1 is
// =SUM('Detailed B'!A1:A10)

// worksheet in question is cloned and totals are attached
$totalWs1 = clone $xlsx->getSheet($xlsx->getSheetCount() - 1);
$totalWs1->setTitle('Condensed Total');
$xlsx->addSheet($totalWs1);
$formula = '=';
foreach ($availableWs as $ws) {
$formula .= sprintf("+'%s'!A2", $ws);
}
$totalWs1->getCell('A1')->setValue("=SUM('Detailed Total'!A1:A10)");
$totalWs1->getCell('A2')->setValue($formula);

$availableWs = [];

$worksheet = $xlsx->createSheet();
$worksheet->setTitle('Detailed A');
for ($step = 1; $step <= 10; ++$step) {
$worksheet->getCell("A{$step}")->setValue(mt_rand(1, 30));
}
$availableWs[] = 'Detailed A';

$worksheet = $xlsx->createSheet();
$worksheet->setTitle('Detailed B');
for ($step = 1; $step <= 10; ++$step) {
$worksheet->getCell("A{$step}")->setValue(mt_rand(1, 30));
}
$availableWs[] = 'Detailed B';

$totalWs2 = clone $xlsx->getSheet($xlsx->getSheetCount() - 1);
$totalWs2->setTitle('Detailed Total');
$xlsx->addSheet($totalWs2);

for ($step = 1; $step <= 10; ++$step) {
$formula = '=';
foreach ($availableWs as $ws) {
$formula .= sprintf("+'%s'!A%s", $ws, $step);
}
$totalWs2->getCell("A{$step}")->setValue($formula);
}

self::assertSame("=SUM('Detailed A'!A1:A10)", $xlsx->getSheetByName('Condensed A')?->getCell('A1')?->getValue());
self::assertSame("=SUM('Detailed B'!A1:A10)", $xlsx->getSheetByName('Condensed B')?->getCell('A1')?->getValue());
self::assertSame("=SUM('Detailed Total'!A1:A10)", $xlsx->getSheetByName('Condensed Total')?->getCell('A1')?->getValue());
self::assertSame("=+'Detailed A'!A1+'Detailed B'!A1", $xlsx->getSheetByName('Detailed Total')?->getCell('A1')?->getValue());

$xlsx->disconnectWorksheets();
}
}

0 comments on commit 9e21d76

Please sign in to comment.