BREAKING `Worksheet::getCell()` cannot return null anymore
`Worksheet::getCell()` used to optionnaly return null if passed a second argument. This second argument was removed entirely and the method always returns a Cell (possibly creating it if needed). This make the API more predictable and easier to do static analysis with tools such as PHPStan. If you relied on that second parameter, you should instead use the `Worksheet::cellExists()` before calling `getCell()`.
This commit is contained in:
parent
a34695e0f9
commit
d85eaacfa3
File diff suppressed because it is too large
Load Diff
|
|
@ -5334,9 +5334,7 @@ class Calculation
|
||||||
$recursiveCalculationCell = ($definedNameWorksheet !== null && $definedNameWorksheet !== $pCellWorksheet)
|
$recursiveCalculationCell = ($definedNameWorksheet !== null && $definedNameWorksheet !== $pCellWorksheet)
|
||||||
? $definedNameWorksheet->getCell('A1')
|
? $definedNameWorksheet->getCell('A1')
|
||||||
: $pCell;
|
: $pCell;
|
||||||
$recursiveCalculationCellAddress = $recursiveCalculationCell !== null
|
$recursiveCalculationCellAddress = $recursiveCalculationCell->getCoordinate();
|
||||||
? $recursiveCalculationCell->getCoordinate()
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Adjust relative references in ranges and formulae so that we execute the calculation for the correct rows and columns
|
// Adjust relative references in ranges and formulae so that we execute the calculation for the correct rows and columns
|
||||||
$definedNameValue = self::$referenceHelper->updateFormulaReferencesAnyWorksheet(
|
$definedNameValue = self::$referenceHelper->updateFormulaReferencesAnyWorksheet(
|
||||||
|
|
|
||||||
|
|
@ -730,7 +730,7 @@ class Worksheet implements IComparable
|
||||||
|
|
||||||
// loop through all cells in the worksheet
|
// loop through all cells in the worksheet
|
||||||
foreach ($this->getCoordinates(false) as $coordinate) {
|
foreach ($this->getCoordinates(false) as $coordinate) {
|
||||||
$cell = $this->getCell($coordinate, false);
|
$cell = $this->getCellOrNull($coordinate);
|
||||||
if ($cell !== null && isset($autoSizes[$this->cellCollection->getCurrentColumn()])) {
|
if ($cell !== null && isset($autoSizes[$this->cellCollection->getCurrentColumn()])) {
|
||||||
//Determine if cell is in merge range
|
//Determine if cell is in merge range
|
||||||
$isMerged = isset($isMergeCell[$this->cellCollection->getCurrentCoordinate()]);
|
$isMerged = isset($isMergeCell[$this->cellCollection->getCurrentCoordinate()]);
|
||||||
|
|
@ -1168,52 +1168,86 @@ class Worksheet implements IComparable
|
||||||
/**
|
/**
|
||||||
* Get cell at a specific coordinate.
|
* Get cell at a specific coordinate.
|
||||||
*
|
*
|
||||||
* @param string $pCoordinate Coordinate of the cell, eg: 'A1'
|
* @param string $coordinate Coordinate of the cell, eg: 'A1'
|
||||||
* @param bool $createIfNotExists Flag indicating whether a new cell should be created if it doesn't
|
|
||||||
* already exist, or a null should be returned instead
|
|
||||||
*
|
*
|
||||||
* @return null|Cell Cell that was found/created or null
|
* @return Cell Cell that was found or created
|
||||||
*/
|
*/
|
||||||
public function getCell($pCoordinate, $createIfNotExists = true)
|
public function getCell(string $coordinate): Cell
|
||||||
{
|
{
|
||||||
// Uppercase coordinate
|
/** @var Worksheet $sheet */
|
||||||
$pCoordinateUpper = strtoupper($pCoordinate);
|
[$sheet, $finalCoordinate] = $this->getWorksheetAndCoordinate($coordinate);
|
||||||
|
$cell = $sheet->cellCollection->get($finalCoordinate);
|
||||||
|
|
||||||
// Check cell collection
|
return $cell ?? $sheet->createNewCell($finalCoordinate);
|
||||||
if ($this->cellCollection->has($pCoordinateUpper)) {
|
}
|
||||||
return $this->cellCollection->get($pCoordinateUpper);
|
|
||||||
}
|
/**
|
||||||
|
* Get the correct Worksheet and coordinate from a coordinate that may
|
||||||
|
* contains reference to another sheet or a named range.
|
||||||
|
*
|
||||||
|
* @return array{0: Worksheet, 1: string}
|
||||||
|
*/
|
||||||
|
private function getWorksheetAndCoordinate(string $pCoordinate): array
|
||||||
|
{
|
||||||
|
$sheet = null;
|
||||||
|
$finalCoordinate = null;
|
||||||
|
|
||||||
// Worksheet reference?
|
// Worksheet reference?
|
||||||
if (strpos($pCoordinate, '!') !== false) {
|
if (strpos($pCoordinate, '!') !== false) {
|
||||||
$worksheetReference = self::extractSheetTitle($pCoordinate, true);
|
$worksheetReference = self::extractSheetTitle($pCoordinate, true);
|
||||||
|
|
||||||
return $this->parent->getSheetByName($worksheetReference[0])
|
$sheet = $this->parent->getSheetByName($worksheetReference[0]);
|
||||||
->getCell(strtoupper($worksheetReference[1]), $createIfNotExists);
|
$finalCoordinate = strtoupper($worksheetReference[1]);
|
||||||
}
|
|
||||||
|
|
||||||
// Named range?
|
if (!$sheet) {
|
||||||
if (
|
throw new Exception('Sheet not found for name: ' . $worksheetReference[0]);
|
||||||
(!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate, $matches)) &&
|
}
|
||||||
(preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate, $matches))
|
} elseif (
|
||||||
|
!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate) &&
|
||||||
|
preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate)
|
||||||
) {
|
) {
|
||||||
|
// Named range?
|
||||||
$namedRange = $this->validateNamedRange($pCoordinate, true);
|
$namedRange = $this->validateNamedRange($pCoordinate, true);
|
||||||
if ($namedRange !== null) {
|
if ($namedRange !== null) {
|
||||||
$cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!');
|
$sheet = $namedRange->getWorksheet();
|
||||||
$cellCoordinate = str_replace('$', '', $cellCoordinate);
|
if (!$sheet) {
|
||||||
|
throw new Exception('Sheet not found for named range: ' . $namedRange->getName());
|
||||||
|
}
|
||||||
|
|
||||||
return $namedRange->getWorksheet()->getCell($cellCoordinate, $createIfNotExists);
|
$cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!');
|
||||||
|
$finalCoordinate = str_replace('$', '', $cellCoordinate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Coordinate::coordinateIsRange($pCoordinate)) {
|
if (!$sheet || !$finalCoordinate) {
|
||||||
throw new Exception('Cell coordinate can not be a range of cells.');
|
$sheet = $this;
|
||||||
} elseif (strpos($pCoordinate, '$') !== false) {
|
$finalCoordinate = strtoupper($pCoordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Coordinate::coordinateIsRange($finalCoordinate)) {
|
||||||
|
throw new Exception('Cell coordinate string can not be a range of cells.');
|
||||||
|
} elseif (strpos($finalCoordinate, '$') !== false) {
|
||||||
throw new Exception('Cell coordinate must not be absolute.');
|
throw new Exception('Cell coordinate must not be absolute.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new cell object, if required
|
return [$sheet, $finalCoordinate];
|
||||||
return $createIfNotExists ? $this->createNewCell($pCoordinateUpper) : null;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an existing cell at a specific coordinate, or null.
|
||||||
|
*
|
||||||
|
* @param string $coordinate Coordinate of the cell, eg: 'A1'
|
||||||
|
*
|
||||||
|
* @return null|Cell Cell that was found or null
|
||||||
|
*/
|
||||||
|
private function getCellOrNull($coordinate): ?Cell
|
||||||
|
{
|
||||||
|
// Check cell collection
|
||||||
|
if ($this->cellCollection->has($coordinate)) {
|
||||||
|
return $this->cellCollection->get($coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1281,44 +1315,16 @@ class Worksheet implements IComparable
|
||||||
/**
|
/**
|
||||||
* Does the cell at a specific coordinate exist?
|
* Does the cell at a specific coordinate exist?
|
||||||
*
|
*
|
||||||
* @param string $pCoordinate Coordinate of the cell eg: 'A1'
|
* @param string $coordinate Coordinate of the cell eg: 'A1'
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function cellExists($pCoordinate)
|
public function cellExists($coordinate)
|
||||||
{
|
{
|
||||||
// Worksheet reference?
|
/** @var Worksheet $sheet */
|
||||||
if (strpos($pCoordinate, '!') !== false) {
|
[$sheet, $finalCoordinate] = $this->getWorksheetAndCoordinate($coordinate);
|
||||||
$worksheetReference = self::extractSheetTitle($pCoordinate, true);
|
|
||||||
|
|
||||||
return $this->parent->getSheetByName($worksheetReference[0])->cellExists(strtoupper($worksheetReference[1]));
|
return $sheet->cellCollection->has($finalCoordinate);
|
||||||
}
|
|
||||||
|
|
||||||
// Named range?
|
|
||||||
if (
|
|
||||||
(!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate, $matches)) &&
|
|
||||||
(preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate, $matches))
|
|
||||||
) {
|
|
||||||
$namedRange = $this->validateNamedRange($pCoordinate, true);
|
|
||||||
if ($namedRange !== null) {
|
|
||||||
$cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!');
|
|
||||||
$cellCoordinate = str_replace('$', '', $cellCoordinate);
|
|
||||||
|
|
||||||
return $namedRange->getWorksheet()->cellExists($cellCoordinate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uppercase coordinate
|
|
||||||
$pCoordinate = strtoupper($pCoordinate);
|
|
||||||
|
|
||||||
if (Coordinate::coordinateIsRange($pCoordinate)) {
|
|
||||||
throw new Exception('Cell coordinate can not be a range of cells.');
|
|
||||||
} elseif (strpos($pCoordinate, '$') !== false) {
|
|
||||||
throw new Exception('Cell coordinate must not be absolute.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cell exists?
|
|
||||||
return $this->cellCollection->has($pCoordinate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class WorksheetNamedRangesTest extends TestCase
|
||||||
$namedRange = 'Range1';
|
$namedRange = 'Range1';
|
||||||
|
|
||||||
$this->expectException(Exception::class);
|
$this->expectException(Exception::class);
|
||||||
$this->expectExceptionMessage('Cell coordinate can not be a range of cells');
|
$this->expectExceptionMessage('Cell coordinate string can not be a range of cells');
|
||||||
|
|
||||||
$worksheet = $this->spreadsheet->getActiveSheet();
|
$worksheet = $this->spreadsheet->getActiveSheet();
|
||||||
$worksheet->cellExists($namedRange);
|
$worksheet->cellExists($namedRange);
|
||||||
|
|
@ -118,7 +118,7 @@ class WorksheetNamedRangesTest extends TestCase
|
||||||
$namedCell = 'Range1';
|
$namedCell = 'Range1';
|
||||||
|
|
||||||
$this->expectException(Exception::class);
|
$this->expectException(Exception::class);
|
||||||
$this->expectExceptionMessage('Cell coordinate can not be a range of cells');
|
$this->expectExceptionMessage('Cell coordinate string can not be a range of cells');
|
||||||
|
|
||||||
$worksheet = $this->spreadsheet->getActiveSheet();
|
$worksheet = $this->spreadsheet->getActiveSheet();
|
||||||
$worksheet->getCell($namedCell);
|
$worksheet->getCell($namedCell);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue