Retitling Cloned Worksheets

Fix #641 (marked stale in 2018, but now reopened). When a sheet's title is changed, PhpSpreadsheet updates references to the old sheet name found in formulas. Which is a good idea when the sheet is attached to the spreadsheet, but a bad idea when it isn't (often because it has been cloned without re-attaching to the spreadsheet). This PR continues to change formulas in the former case, but will no longer do so for the latter.
This commit is contained in:
oleibman
2025-01-05 22:40:29 -08:00
parent fb757cfc5b
commit dcc25637f2
3 changed files with 95 additions and 3 deletions
+10
View File
@@ -514,6 +514,16 @@ class Spreadsheet implements JsonSerializable
public function createSheet(?int $sheetIndex = null): Worksheet
{
$newSheet = new Worksheet($this);
$title = $newSheet->getTitle();
if ($this->sheetNameExists($title)) {
$i = 1;
$newTitle = "$title $i";
while ($this->sheetNameExists($newTitle)) {
++$i;
$newTitle = "$title $i";
}
$newSheet->setTitle($newTitle);
}
$this->addSheet($newSheet, $sheetIndex);
return $newSheet;
+3 -3
View File
@@ -321,6 +321,7 @@ class Worksheet
{
// Set parent and title
$this->parent = $parent;
$this->hash = spl_object_id($this);
$this->setTitle($title, false);
// setTitle can change $pTitle
$this->setCodeName($this->getTitle());
@@ -349,7 +350,6 @@ class Worksheet
$this->autoFilter = new AutoFilter('', $this);
// Table collection
$this->tableCollection = new ArrayObject();
$this->hash = spl_object_id($this);
}
/**
@@ -869,7 +869,7 @@ class Worksheet
// 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
@@ -899,7 +899,7 @@ class Worksheet
// 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()
@@ -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();
}
}