Skip to content

Commit

Permalink
Merge pull request #4302 from oleibman/issue641
Browse files Browse the repository at this point in the history
Retitling Cloned Worksheets
  • Loading branch information
oleibman authored Jan 8, 2025
2 parents 17706a9 + decc0a4 commit f5c285e
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Fixed

- 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)
- Retitling cloned Worksheets. [Issue #641](https://github.com/PHPOffice/PhpSpreadsheet/issues/641) [PR #4302](https://github.com/PHPOffice/PhpSpreadsheet/pull/4302)

## 2024-12-26 - 3.7.0

Expand Down
16 changes: 14 additions & 2 deletions src/PhpSpreadsheet/Spreadsheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,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 @@ -535,8 +535,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
6 changes: 3 additions & 3 deletions src/PhpSpreadsheet/Worksheet/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ public function __construct(?Spreadsheet $parent = null, string $title = 'Worksh
{
// 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());
Expand Down Expand Up @@ -349,7 +350,6 @@ public function __construct(?Spreadsheet $parent = null, string $title = 'Worksh
$this->autoFilter = new AutoFilter('', $this);
// Table collection
$this->tableCollection = new ArrayObject();
$this->hash = spl_object_id($this);
}

/**
Expand Down Expand Up @@ -869,7 +869,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 @@ -899,7 +899,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 f5c285e

Please sign in to comment.