HEX
Server: Apache
System: Linux webm004.cluster121.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64
User: grainesdfo (155059)
PHP: 5.4.45
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/grainesdfo/www/wp-content/plugins/tablepress/libraries/vendor/PhpSpreadsheet/Cell/Cell.php
<?php

namespace TablePress\PhpOffice\PhpSpreadsheet\Cell;

use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException;
use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Functions;
use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use TablePress\PhpOffice\PhpSpreadsheet\Collection\Cells;
use TablePress\PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
use TablePress\PhpOffice\PhpSpreadsheet\RichText\RichText;
use TablePress\PhpOffice\PhpSpreadsheet\Shared\Date as SharedDate;
use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use TablePress\PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\CellStyleAssessor;
use TablePress\PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use TablePress\PhpOffice\PhpSpreadsheet\Style\Protection;
use TablePress\PhpOffice\PhpSpreadsheet\Style\Style;
use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Table;
use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Stringable;

class Cell
{
	/**
	 * Value binder to use.
	 */
	private static ?IValueBinder $valueBinder = null;
	/**
	 * Value of the cell.
	 * @var mixed
	 */
	private $value;
	/**
	 *    Calculated value of the cell (used for caching)
	 *    This returns the value last calculated by MS Excel or whichever spreadsheet program was used to
	 *        create the original spreadsheet file.
	 *    Note that this value is not guaranteed to reflect the actual calculated value because it is
	 *        possible that auto-calculation was disabled in the original spreadsheet, and underlying data
	 *        values used by the formula have changed since it was last calculated.
	 *
	 * @var mixed
	 */
	private $calculatedValue;
	/**
	 * Type of the cell data.
	 */
	private string $dataType;
	/**
	 * The collection of cells that this cell belongs to (i.e. The Cell Collection for the parent Worksheet).
	 */
	private ?Cells $parent;
	/**
	 * Index to the cellXf reference for the styling of this cell.
	 */
	private int $xfIndex = 0;
	/**
	 * Attributes of the formula.
	 *
	 * @var null|array<string, string>
	 */
	private ?array $formulaAttributes = null;
	private IgnoredErrors $ignoredErrors;
	/**
	 * Update the cell into the cell collection.
	 *
	 * @throws SpreadsheetException
	 */
	public function updateInCollection(): self
	{
		$parent = $this->parent;
		if ($parent === null) {
			throw new SpreadsheetException('Cannot update when cell is not bound to a worksheet');
		}
		$parent->update($this);

		return $this;
	}
	public function detach(): void
	{
		$this->parent = null;
	}
	public function attach(Cells $parent): void
	{
		$this->parent = $parent;
	}
	/**
	 * Create a new Cell.
	 *
	 * @throws SpreadsheetException
	 * @param mixed $value
	 */
	public function __construct($value, ?string $dataType, Worksheet $worksheet)
	{
		// Initialise cell value
		$this->value = $value;

		// Set worksheet cache
		$this->parent = $worksheet->getCellCollection();

		// Set datatype?
		if ($dataType !== null) {
			if ($dataType == DataType::TYPE_STRING2) {
				$dataType = DataType::TYPE_STRING;
			}
			$this->dataType = $dataType;
		} else {
			$valueBinder = (($nullsafeVariable1 = $worksheet->getParent()) ? $nullsafeVariable1->getValueBinder() : null) ?? self::getValueBinder();
			if ($valueBinder->bindValue($this, $value) === false) {
				throw new SpreadsheetException('Value could not be bound to cell.');
			}
		}
		$this->ignoredErrors = new IgnoredErrors();
	}
	/**
	 * Get cell coordinate column.
	 *
	 * @throws SpreadsheetException
	 */
	public function getColumn(): string
	{
		$parent = $this->parent;
		if ($parent === null) {
			throw new SpreadsheetException('Cannot get column when cell is not bound to a worksheet');
		}

		return $parent->getCurrentColumn();
	}
	/**
	 * Get cell coordinate row.
	 *
	 * @throws SpreadsheetException
	 */
	public function getRow(): int
	{
		$parent = $this->parent;
		if ($parent === null) {
			throw new SpreadsheetException('Cannot get row when cell is not bound to a worksheet');
		}

		return $parent->getCurrentRow();
	}
	/**
	 * Get cell coordinate.
	 *
	 * @throws SpreadsheetException
	 */
	public function getCoordinate(): string
	{
		$parent = $this->parent;
		if ($parent !== null) {
			$coordinate = $parent->getCurrentCoordinate();
		} else {
			$coordinate = null;
		}
		if ($coordinate === null) {
			throw new SpreadsheetException('Coordinate no longer exists');
		}

		return $coordinate;
	}
	/**
	 * Get cell value.
	 * @return mixed
	 */
	public function getValue()
	{
		return $this->value;
	}
	public function getValueString(): string
	{
		return StringHelper::convertToString($this->value, false);
	}
	/**
	 * Get cell value with formatting.
	 */
	public function getFormattedValue(): string
	{
		$currentCalendar = SharedDate::getExcelCalendar();
		SharedDate::setExcelCalendar(($nullsafeVariable2 = $this->getWorksheet()->getParent()) ? $nullsafeVariable2->getExcelCalendar() : null);
		$formattedValue = (string) NumberFormat::toFormattedString(
			$this->getCalculatedValueString(),
			(string) $this->getStyle()->getNumberFormat()->getFormatCode(true)
		);
		SharedDate::setExcelCalendar($currentCalendar);

		return $formattedValue;
	}
	/**
	 * @param mixed $oldValue
	 * @param mixed $newValue
	 */
	protected static function updateIfCellIsTableHeader(?Worksheet $workSheet, self $cell, $oldValue, $newValue): void
	{
		$oldValue = StringHelper::convertToString($oldValue, false);
		$newValue = StringHelper::convertToString($newValue, false);
		if (StringHelper::strToLower($oldValue) === StringHelper::strToLower($newValue) || $workSheet === null) {
			return;
		}

		foreach ($workSheet->getTableCollection() as $table) {
			/** @var Table $table */
			if ($cell->isInRange($table->getRange())) {
				$rangeRowsColumns = Coordinate::getRangeBoundaries($table->getRange());
				if ($cell->getRow() === (int) $rangeRowsColumns[0][1]) {
					Table\Column::updateStructuredReferences($workSheet, $oldValue, $newValue);
				}

				return;
			}
		}
	}
	/**
	 * Set cell value.
	 *
	 *    Sets the value for a cell, automatically determining the datatype using the value binder
	 *
	 * @param mixed $value Value
	 * @param null|IValueBinder $binder Value Binder to override the currently set Value Binder
	 *
	 * @throws SpreadsheetException
	 */
	public function setValue($value, ?IValueBinder $binder = null): self
	{
		// Cells?->Worksheet?->Spreadsheet
		$binder ??= (($nullsafeVariable3 = ($nullsafeVariable4 = ($nullsafeVariable5 = $this->parent) ? $nullsafeVariable5->getParent() : null) ? $nullsafeVariable4->getParent() : null) ? $nullsafeVariable3->getValueBinder() : null) ?? self::getValueBinder();
		if (!$binder->bindValue($this, $value)) {
			throw new SpreadsheetException('Value could not be bound to cell.');
		}

		return $this;
	}
	/**
	 * Set the value for a cell, with the explicit data type passed to the method (bypassing any use of the value binder).
	 *
	 * @param mixed $value Value
	 * @param string $dataType Explicit data type, see DataType::TYPE_*
	 *        Note that PhpSpreadsheet does not validate that the value and datatype are consistent, in using this
	 *             method, then it is your responsibility as an end-user developer to validate that the value and
	 *             the datatype match.
	 *       If you do mismatch value and datatype, then the value you enter may be changed to match the datatype
	 *          that you specify.
	 *
	 * @throws SpreadsheetException
	 */
	public function setValueExplicit($value, string $dataType = DataType::TYPE_STRING): self
	{
		$oldValue = $this->value;
		$quotePrefix = false;

		// set the value according to data type
		switch ($dataType) {
			case DataType::TYPE_NULL:
				$this->value = null;

				break;
			case DataType::TYPE_STRING2:
				$dataType = DataType::TYPE_STRING;
				// no break
			case DataType::TYPE_STRING:
				// Synonym for string
				if (is_string($value) && strlen($value) > 1 && $value[0] === '=') {
					$quotePrefix = true;
				}
				// no break
			case DataType::TYPE_INLINE:
				// Rich text
				$value2 = StringHelper::convertToString($value, true);
				$this->value = DataType::checkString(($value instanceof RichText) ? $value : $value2);

				break;
			case DataType::TYPE_NUMERIC:
				if ($value !== null && !is_bool($value) && !is_numeric($value)) {
					throw new SpreadsheetException('Invalid numeric value for datatype Numeric');
				}
				$this->value = 0 + $value;

				break;
			case DataType::TYPE_FORMULA:
				$this->value = StringHelper::convertToString($value, true);

				break;
			case DataType::TYPE_BOOL:
				$this->value = (bool) $value;

				break;
			case DataType::TYPE_ISO_DATE:
				$this->value = SharedDate::convertIsoDate($value);
				$dataType = DataType::TYPE_NUMERIC;

				break;
			case DataType::TYPE_ERROR:
				$this->value = DataType::checkErrorCode($value);

				break;
			default:
				throw new SpreadsheetException('Invalid datatype: ' . $dataType);
		}

		// set the datatype
		$this->dataType = $dataType;

		$this->updateInCollection();
		$cellCoordinate = $this->getCoordinate();
		self::updateIfCellIsTableHeader(($nullsafeVariable6 = $this->getParent()) ? $nullsafeVariable6->getParent() : null, $this, $oldValue, $value);
		$worksheet = $this->getWorksheet();
		$spreadsheet = $worksheet->getParent();
		if (isset($spreadsheet) && $spreadsheet->getIndex($worksheet, true) >= 0) {
			$originalSelected = $worksheet->getSelectedCells();
			$activeSheetIndex = $spreadsheet->getActiveSheetIndex();
			$style = $this->getStyle();
			$oldQuotePrefix = $style->getQuotePrefix();
			if ($oldQuotePrefix !== $quotePrefix) {
				$style->setQuotePrefix($quotePrefix);
			}
			$worksheet->setSelectedCells($originalSelected);
			if ($activeSheetIndex >= 0) {
				$spreadsheet->setActiveSheetIndex($activeSheetIndex);
			}
		}

		return (($nullsafeVariable7 = $this->getParent()) ? $nullsafeVariable7->get($cellCoordinate) : null) ?? $this;
	}
	public const CALCULATE_DATE_TIME_ASIS = 0;
	public const CALCULATE_DATE_TIME_FLOAT = 1;
	public const CALCULATE_TIME_FLOAT = 2;
	private static int $calculateDateTimeType = self::CALCULATE_DATE_TIME_ASIS;
	public static function getCalculateDateTimeType(): int
	{
		return self::$calculateDateTimeType;
	}
	/** @throws CalculationException */
	public static function setCalculateDateTimeType(int $calculateDateTimeType): void
	{
		switch ($calculateDateTimeType) {
						case self::CALCULATE_DATE_TIME_ASIS:
						case self::CALCULATE_DATE_TIME_FLOAT:
						case self::CALCULATE_TIME_FLOAT:
							self::$calculateDateTimeType = $calculateDateTimeType;
							break;
						default:
							throw new CalculationException("Invalid value $calculateDateTimeType for calculated date time type");
					}
	}
	/**
	 * Convert date, time, or datetime from int to float if desired.
	 * @param mixed $result
	 * @return mixed
	 */
	private function convertDateTimeInt($result)
	{
		if (is_int($result)) {
			if (self::$calculateDateTimeType === self::CALCULATE_TIME_FLOAT) {
				if (SharedDate::isDateTime($this, $result, false)) {
					$result = (float) $result;
				}
			} elseif (self::$calculateDateTimeType === self::CALCULATE_DATE_TIME_FLOAT) {
				if (SharedDate::isDateTime($this, $result, true)) {
					$result = (float) $result;
				}
			}
		}

		return $result;
	}
	/**
	 * Get calculated cell value converted to string.
	 */
	public function getCalculatedValueString(): string
	{
		$value = $this->getCalculatedValue();
		while (is_array($value)) {
			$value = array_shift($value);
		}

		return StringHelper::convertToString($value, false);
	}
	/**
	 * Get calculated cell value.
	 *
	 * @param bool $resetLog Whether the calculation engine logger should be reset or not
	 *
	 * @throws CalculationException
	 * @return mixed
	 */
	public function getCalculatedValue(bool $resetLog = true)
	{
		$title = 'unknown';
		$oldAttributes = $this->formulaAttributes;
		$oldAttributesT = $oldAttributes['t'] ?? '';
		$coordinate = $this->getCoordinate();
		$oldAttributesRef = $oldAttributes['ref'] ?? $coordinate;
		$originalValue = $this->value;
		$originalDataType = $this->dataType;
		$this->formulaAttributes = [];
		$spill = false;

		if ($this->dataType === DataType::TYPE_FORMULA) {
			try {
				$currentCalendar = SharedDate::getExcelCalendar();
				SharedDate::setExcelCalendar(($nullsafeVariable8 = $this->getWorksheet()->getParent()) ? $nullsafeVariable8->getExcelCalendar() : null);
				$thisworksheet = $this->getWorksheet();
				$index = $thisworksheet->getParentOrThrow()->getActiveSheetIndex();
				$selected = $thisworksheet->getSelectedCells();
				$title = $thisworksheet->getTitle();
				$calculation = Calculation::getInstance($thisworksheet->getParent());
				$result = $calculation->calculateCellValue($this, $resetLog);
				$result = $this->convertDateTimeInt($result);
				$thisworksheet->setSelectedCells($selected);
				$thisworksheet->getParentOrThrow()->setActiveSheetIndex($index);
				if (is_array($result) && $calculation->getInstanceArrayReturnType() !== Calculation::RETURN_ARRAY_AS_ARRAY) {
					while (is_array($result)) {
						$result = array_shift($result);
					}
				}
				if (
					!is_array($result)
					&& $calculation->getInstanceArrayReturnType() === Calculation::RETURN_ARRAY_AS_ARRAY
					&& $oldAttributesT === 'array'
					&& ($oldAttributesRef === $coordinate || $oldAttributesRef === "$coordinate:$coordinate")
				) {
					$result = [$result];
				}
				// if return_as_array for formula like '=sheet!cell'
				if (is_array($result) && count($result) === 1) {
					$resultKey = array_keys($result)[0];
					$resultValue = $result[$resultKey];
					if (is_int($resultKey) && is_array($resultValue) && count($resultValue) === 1) {
						$resultKey2 = array_keys($resultValue)[0];
						$resultValue2 = $resultValue[$resultKey2];
						if (is_string($resultKey2) && !is_array($resultValue2) && preg_match('/[a-zA-Z]{1,3}/', $resultKey2) === 1) {
							$result = $resultValue2;
						}
					}
				}
				$newColumn = $this->getColumn();
				if (is_array($result)) {
					$this->formulaAttributes['t'] = 'array';
					$this->formulaAttributes['ref'] = $maxCoordinate = $coordinate;
					$newRow = $row = $this->getRow();
					$column = $this->getColumn();
					foreach ($result as $resultRow) {
						if (is_array($resultRow)) {
							$newColumn = $column;
							foreach ($resultRow as $resultValue) {
								if ($row !== $newRow || $column !== $newColumn) {
									$maxCoordinate = $newColumn . $newRow;
									if ($thisworksheet->getCell($newColumn . $newRow)->getValue() !== null) {
										if (!Coordinate::coordinateIsInsideRange($oldAttributesRef, $newColumn . $newRow)) {
											$spill = true;

											break;
										}
									}
								}
								++$newColumn;
							}
							++$newRow;
						} else {
							if ($row !== $newRow || $column !== $newColumn) {
								$maxCoordinate = $newColumn . $newRow;
								if ($thisworksheet->getCell($newColumn . $newRow)->getValue() !== null) {
									if (!Coordinate::coordinateIsInsideRange($oldAttributesRef, $newColumn . $newRow)) {
										$spill = true;
									}
								}
							}
							++$newColumn;
						}
						if ($spill) {
							break;
						}
					}
					if (!$spill) {
						$this->formulaAttributes['ref'] .= ":$maxCoordinate";
					}
					$thisworksheet->getCell($column . $row);
				}
				if (is_array($result)) {
					if ($oldAttributes !== null && $calculation->getInstanceArrayReturnType() === Calculation::RETURN_ARRAY_AS_ARRAY) {
						if (($oldAttributesT) === 'array') {
							$thisworksheet = $this->getWorksheet();
							$coordinate = $this->getCoordinate();
							$ref = $oldAttributesRef;
							if (preg_match('/^([A-Z]{1,3})([0-9]{1,7})(:([A-Z]{1,3})([0-9]{1,7}))?$/', $ref, $matches) === 1) {
								if (isset($matches[3])) {
									$minCol = $matches[1];
									$minRow = (int) $matches[2];
									// https://github.com/phpstan/phpstan/issues/11602
									$maxCol = $matches[4]; // @phpstan-ignore-line
									++$maxCol;
									$maxRow = (int) $matches[5]; // @phpstan-ignore-line
									for ($row = $minRow; $row <= $maxRow; ++$row) {
										for ($col = $minCol; $col !== $maxCol; ++$col) {
											if ("$col$row" !== $coordinate) {
												$thisworksheet->getCell("$col$row")->setValue(null);
											}
										}
									}
								}
							}
							$thisworksheet->getCell($coordinate);
						}
					}
				}
				if ($spill) {
					$result = ExcelError::SPILL();
				}
				if (is_array($result)) {
					$newRow = $row = $this->getRow();
					$newColumn = $column = $this->getColumn();
					foreach ($result as $resultRow) {
						if (is_array($resultRow)) {
							$newColumn = $column;
							foreach ($resultRow as $resultValue) {
								if ($row !== $newRow || $column !== $newColumn) {
									$thisworksheet->getCell($newColumn . $newRow)->setValue($resultValue);
								}
								++$newColumn;
							}
							++$newRow;
						} else {
							if ($row !== $newRow || $column !== $newColumn) {
								$thisworksheet->getCell($newColumn . $newRow)->setValue($resultRow);
							}
							++$newColumn;
						}
					}
					$thisworksheet->getCell($column . $row);
					$this->value = $originalValue;
					$this->dataType = $originalDataType;
				}
			} catch (SpreadsheetException $ex) {
				SharedDate::setExcelCalendar($currentCalendar);
				if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->calculatedValue !== null)) {
					return $this->calculatedValue; // Fallback for calculations referencing external files.
				} elseif (preg_match('/[Uu]ndefined (name|offset: 2|array key 2)/', $ex->getMessage()) === 1) {
					return ExcelError::NAME();
				}

				throw new CalculationException(
					$title . '!' . $this->getCoordinate() . ' -> ' . $ex->getMessage(),
					$ex->getCode(),
					$ex
				);
			}
			SharedDate::setExcelCalendar($currentCalendar);

			if ($result === Functions::NOT_YET_IMPLEMENTED) {
				$this->formulaAttributes = $oldAttributes;

				return $this->calculatedValue; // Fallback if calculation engine does not support the formula.
			}

			return $result;
		} elseif ($this->value instanceof RichText) {
			return $this->value->getPlainText();
		}

		return $this->convertDateTimeInt($this->value);
	}
	/**
	 * Set old calculated value (cached).
	 *
	 * @param mixed $originalValue Value
	 */
	public function setCalculatedValue($originalValue, bool $tryNumeric = true): self
	{
		if ($originalValue !== null) {
			$this->calculatedValue = ($tryNumeric && is_numeric($originalValue)) ? (0 + $originalValue) : $originalValue;
		}

		return $this->updateInCollection();
	}
	/**
	 *    Get old calculated value (cached)
	 *    This returns the value last calculated by MS Excel or whichever spreadsheet program was used to
	 *        create the original spreadsheet file.
	 *    Note that this value is not guaranteed to reflect the actual calculated value because it is
	 *        possible that auto-calculation was disabled in the original spreadsheet, and underlying data
	 *        values used by the formula have changed since it was last calculated.
	 * @return mixed
	 */
	public function getOldCalculatedValue()
	{
		return $this->calculatedValue;
	}
	/**
	 * Get cell data type.
	 */
	public function getDataType(): string
	{
		return $this->dataType;
	}
	/**
	 * Set cell data type.
	 *
	 * @param string $dataType see DataType::TYPE_*
	 */
	public function setDataType(string $dataType): self
	{
		$this->setValueExplicit($this->value, $dataType);

		return $this;
	}
	/**
	 * Identify if the cell contains a formula.
	 */
	public function isFormula(): bool
	{
		return $this->dataType === DataType::TYPE_FORMULA && $this->getStyle()->getQuotePrefix() === false;
	}
	/**
	 *    Does this cell contain Data validation rules?
	 *
	 * @throws SpreadsheetException
	 */
	public function hasDataValidation(): bool
	{
		if (!isset($this->parent)) {
			throw new SpreadsheetException('Cannot check for data validation when cell is not bound to a worksheet');
		}

		return $this->getWorksheet()->dataValidationExists($this->getCoordinate());
	}
	/**
	 * Get Data validation rules.
	 *
	 * @throws SpreadsheetException
	 */
	public function getDataValidation(): DataValidation
	{
		if (!isset($this->parent)) {
			throw new SpreadsheetException('Cannot get data validation for cell that is not bound to a worksheet');
		}

		return $this->getWorksheet()->getDataValidation($this->getCoordinate());
	}
	/**
	 * Set Data validation rules.
	 *
	 * @throws SpreadsheetException
	 */
	public function setDataValidation(?DataValidation $dataValidation = null): self
	{
		if (!isset($this->parent)) {
			throw new SpreadsheetException('Cannot set data validation for cell that is not bound to a worksheet');
		}

		$this->getWorksheet()->setDataValidation($this->getCoordinate(), $dataValidation);

		return $this->updateInCollection();
	}
	/**
	 * Does this cell contain valid value?
	 */
	public function hasValidValue(): bool
	{
		$validator = new DataValidator();

		return $validator->isValid($this);
	}
	/**
	 * Does this cell contain a Hyperlink?
	 *
	 * @throws SpreadsheetException
	 */
	public function hasHyperlink(): bool
	{
		if (!isset($this->parent)) {
			throw new SpreadsheetException('Cannot check for hyperlink when cell is not bound to a worksheet');
		}

		return $this->getWorksheet()->hyperlinkExists($this->getCoordinate());
	}
	/**
	 * Get Hyperlink.
	 *
	 * @throws SpreadsheetException
	 */
	public function getHyperlink(): Hyperlink
	{
		if (!isset($this->parent)) {
			throw new SpreadsheetException('Cannot get hyperlink for cell that is not bound to a worksheet');
		}

		return $this->getWorksheet()->getHyperlink($this->getCoordinate());
	}
	/**
	 * Set Hyperlink.
	 *
	 * @throws SpreadsheetException
	 */
	public function setHyperlink(?Hyperlink $hyperlink = null): self
	{
		if (!isset($this->parent)) {
			throw new SpreadsheetException('Cannot set hyperlink for cell that is not bound to a worksheet');
		}

		$this->getWorksheet()->setHyperlink($this->getCoordinate(), $hyperlink);

		return $this->updateInCollection();
	}
	/**
	 * Get cell collection.
	 */
	public function getParent(): ?Cells
	{
		return $this->parent;
	}
	/**
	 * Get parent worksheet.
	 *
	 * @throws SpreadsheetException
	 */
	public function getWorksheet(): Worksheet
	{
		$parent = $this->parent;
		if ($parent !== null) {
			$worksheet = $parent->getParent();
		} else {
			$worksheet = null;
		}

		if ($worksheet === null) {
			throw new SpreadsheetException('Worksheet no longer exists');
		}

		return $worksheet;
	}
	public function getWorksheetOrNull(): ?Worksheet
	{
		$parent = $this->parent;
		if ($parent !== null) {
			$worksheet = $parent->getParent();
		} else {
			$worksheet = null;
		}

		return $worksheet;
	}
	/**
	 * Is this cell in a merge range.
	 */
	public function isInMergeRange(): bool
	{
		return (bool) $this->getMergeRange();
	}
	/**
	 * Is this cell the master (top left cell) in a merge range (that holds the actual data value).
	 */
	public function isMergeRangeValueCell(): bool
	{
		if ($mergeRange = $this->getMergeRange()) {
			$mergeRange = Coordinate::splitRange($mergeRange);
			[$startCell] = $mergeRange[0];

			return $this->getCoordinate() === $startCell;
		}

		return false;
	}
	/**
	 * If this cell is in a merge range, then return the range.
	 *
	 * @return false|string
	 */
	public function getMergeRange()
	{
		foreach ($this->getWorksheet()->getMergeCells() as $mergeRange) {
			if ($this->isInRange($mergeRange)) {
				return $mergeRange;
			}
		}

		return false;
	}
	/**
	 * Get cell style.
	 */
	public function getStyle(): Style
	{
		return $this->getWorksheet()->getStyle($this->getCoordinate());
	}
	/**
	 * Get cell style.
	 */
	public function getAppliedStyle(): Style
	{
		if ($this->getWorksheet()->conditionalStylesExists($this->getCoordinate()) === false) {
			return $this->getStyle();
		}
		$range = $this->getWorksheet()->getConditionalRange($this->getCoordinate());
		if ($range === null) {
			return $this->getStyle();
		}

		$matcher = new CellStyleAssessor($this, $range);

		return $matcher->matchConditions($this->getWorksheet()->getConditionalStyles($this->getCoordinate()));
	}
	/**
	 * Re-bind parent.
	 */
	public function rebindParent(Worksheet $parent): self
	{
		$this->parent = $parent->getCellCollection();

		return $this->updateInCollection();
	}
	/**
	 *    Is cell in a specific range?
	 *
	 * @param string $range Cell range (e.g. A1:A1)
	 */
	public function isInRange(string $range): bool
	{
		[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($range);

		// Translate properties
		$myColumn = Coordinate::columnIndexFromString($this->getColumn());
		$myRow = $this->getRow();

		// Verify if cell is in range
		return ($rangeStart[0] <= $myColumn) && ($rangeEnd[0] >= $myColumn)
			&& ($rangeStart[1] <= $myRow) && ($rangeEnd[1] >= $myRow);
	}
	/**
	 * Compare 2 cells.
	 *
	 * @param Cell $a Cell a
	 * @param Cell $b Cell b
	 *
	 * @return int Result of comparison (always -1 or 1, never zero!)
	 */
	public static function compareCells(self $a, self $b): int
	{
		if ($a->getRow() < $b->getRow()) {
			return -1;
		} elseif ($a->getRow() > $b->getRow()) {
			return 1;
		} elseif (Coordinate::columnIndexFromString($a->getColumn()) < Coordinate::columnIndexFromString($b->getColumn())) {
			return -1;
		}

		return 1;
	}
	/**
	 * Get value binder to use.
	 */
	public static function getValueBinder(): IValueBinder
	{
		if (self::$valueBinder === null) {
			self::$valueBinder = new DefaultValueBinder();
		}

		return self::$valueBinder;
	}
	/**
	 * Set value binder to use.
	 */
	public static function setValueBinder(IValueBinder $binder): void
	{
		self::$valueBinder = $binder;
	}
	/**
	 * Implement PHP __clone to create a deep clone, not just a shallow copy.
	 */
	public function __clone()
	{
		$vars = get_object_vars($this);
		foreach ($vars as $propertyName => $propertyValue) {
			if ((is_object($propertyValue)) && ($propertyName !== 'parent')) {
				$this->$propertyName = clone $propertyValue;
			} else {
				$this->$propertyName = $propertyValue;
			}
		}
	}
	/**
	 * Get index to cellXf.
	 */
	public function getXfIndex(): int
	{
		return $this->xfIndex;
	}
	/**
	 * Set index to cellXf.
	 */
	public function setXfIndex(int $indexValue): self
	{
		$this->xfIndex = $indexValue;

		return $this->updateInCollection();
	}
	/**
	 * Set the formula attributes.
	 *
	 * @param $attributes null|array<string, string>
	 *
	 * @return $this
	 */
	public function setFormulaAttributes(?array $attributes): self
	{
		$this->formulaAttributes = $attributes;

		return $this;
	}
	/**
	 * Get the formula attributes.
	 *
	 * @return null|array<string, string>
	 */
	public function getFormulaAttributes(): ?array
	{
		return $this->formulaAttributes;
	}
	/**
	 * Convert to string.
	 */
	public function __toString(): string
	{
		$retVal = $this->value;

		return StringHelper::convertToString($retVal, false);
	}
	public function getIgnoredErrors(): IgnoredErrors
	{
		return $this->ignoredErrors;
	}
	public function isLocked(): bool
	{
		$protected = ($nullsafeVariable9 = ($nullsafeVariable10 = ($nullsafeVariable11 = $this->parent) ? $nullsafeVariable11->getParent() : null) ? $nullsafeVariable10->getProtection() : null) ? $nullsafeVariable9->getSheet() : null;
		if ($protected !== true) {
			return false;
		}
		$locked = $this->getStyle()->getProtection()->getLocked();

		return $locked !== Protection::PROTECTION_UNPROTECTED;
	}
	public function isHiddenOnFormulaBar(): bool
	{
		if ($this->getDataType() !== DataType::TYPE_FORMULA) {
			return false;
		}
		$protected = ($nullsafeVariable12 = ($nullsafeVariable13 = ($nullsafeVariable14 = $this->parent) ? $nullsafeVariable14->getParent() : null) ? $nullsafeVariable13->getProtection() : null) ? $nullsafeVariable12->getSheet() : null;
		if ($protected !== true) {
			return false;
		}
		$hidden = $this->getStyle()->getProtection()->getHidden();

		return $hidden !== Protection::PROTECTION_UNPROTECTED;
	}
}