AutorÃa | Ultima modificación | Ver Log |
<?phpnamespace PhpOffice\PhpSpreadsheet\Cell;use PhpOffice\PhpSpreadsheet\Exception;use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;use Stringable;/*** @implements AddressRange<CellAddress>*/class CellRange implements AddressRange, Stringable{protected CellAddress $from;protected CellAddress $to;public function __construct(CellAddress $from, CellAddress $to){$this->validateFromTo($from, $to);}private function validateFromTo(CellAddress $from, CellAddress $to): void{// Identify actual top-left and bottom-right values (in case we've been given top-right and bottom-left)$firstColumn = min($from->columnId(), $to->columnId());$firstRow = min($from->rowId(), $to->rowId());$lastColumn = max($from->columnId(), $to->columnId());$lastRow = max($from->rowId(), $to->rowId());$fromWorksheet = $from->worksheet();$toWorksheet = $to->worksheet();$this->validateWorksheets($fromWorksheet, $toWorksheet);$this->from = $this->cellAddressWrapper($firstColumn, $firstRow, $fromWorksheet);$this->to = $this->cellAddressWrapper($lastColumn, $lastRow, $toWorksheet);}private function validateWorksheets(?Worksheet $fromWorksheet, ?Worksheet $toWorksheet): void{if ($fromWorksheet !== null && $toWorksheet !== null) {// We could simply compare worksheets rather than worksheet titles; but at some point we may introduce// support for 3d ranges; and at that point we drop this check and let the validation fall through// to the check for same workbook; but unless we check on titles, this test will also detect if the// worksheets are in different spreadsheets, and the next check will never execute or throw its// own exception.if ($fromWorksheet->getTitle() !== $toWorksheet->getTitle()) {throw new Exception('3d Cell Ranges are not supported');} elseif ($fromWorksheet->getParent() !== $toWorksheet->getParent()) {throw new Exception('Worksheets must be in the same spreadsheet');}}}private function cellAddressWrapper(int $column, int $row, ?Worksheet $worksheet = null): CellAddress{$cellAddress = Coordinate::stringFromColumnIndex($column) . (string) $row;return new class ($cellAddress, $worksheet) extends CellAddress {public function nextRow(int $offset = 1): CellAddress{/** @var CellAddress $result */$result = parent::nextRow($offset);$this->rowId = $result->rowId;$this->cellAddress = $result->cellAddress;return $this;}public function previousRow(int $offset = 1): CellAddress{/** @var CellAddress $result */$result = parent::previousRow($offset);$this->rowId = $result->rowId;$this->cellAddress = $result->cellAddress;return $this;}public function nextColumn(int $offset = 1): CellAddress{/** @var CellAddress $result */$result = parent::nextColumn($offset);$this->columnId = $result->columnId;$this->columnName = $result->columnName;$this->cellAddress = $result->cellAddress;return $this;}public function previousColumn(int $offset = 1): CellAddress{/** @var CellAddress $result */$result = parent::previousColumn($offset);$this->columnId = $result->columnId;$this->columnName = $result->columnName;$this->cellAddress = $result->cellAddress;return $this;}};}public function from(): CellAddress{// Re-order from/to in case the cell addresses have been modified$this->validateFromTo($this->from, $this->to);return $this->from;}public function to(): CellAddress{// Re-order from/to in case the cell addresses have been modified$this->validateFromTo($this->from, $this->to);return $this->to;}public function __toString(): string{// Re-order from/to in case the cell addresses have been modified$this->validateFromTo($this->from, $this->to);if ($this->from->cellAddress() === $this->to->cellAddress()) {return "{$this->from->fullCellAddress()}";}$fromAddress = $this->from->fullCellAddress();$toAddress = $this->to->cellAddress();return "{$fromAddress}:{$toAddress}";}}