| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 | 
							- <?php
 
- namespace PhpOffice\PhpSpreadsheet\Cell;
 
- use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
 
- use PhpOffice\PhpSpreadsheet\Collection\Cells;
 
- use PhpOffice\PhpSpreadsheet\Exception;
 
- use PhpOffice\PhpSpreadsheet\RichText\RichText;
 
- use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
 
- use PhpOffice\PhpSpreadsheet\Style\Style;
 
- use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 
- class Cell
 
- {
 
-     /**
 
-      * Value binder to use.
 
-      *
 
-      * @var IValueBinder
 
-      */
 
-     private static $valueBinder;
 
-     /**
 
-      * 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.
 
-      *
 
-      * @var string
 
-      */
 
-     private $dataType;
 
-     /**
 
-      * Collection of cells.
 
-      *
 
-      * @var Cells
 
-      */
 
-     private $parent;
 
-     /**
 
-      * Index to cellXf.
 
-      *
 
-      * @var int
 
-      */
 
-     private $xfIndex = 0;
 
-     /**
 
-      * Attributes of the formula.
 
-      */
 
-     private $formulaAttributes;
 
-     /**
 
-      * Update the cell into the cell collection.
 
-      *
 
-      * @return self
 
-      */
 
-     public function updateInCollection()
 
-     {
 
-         $this->parent->update($this);
 
-         return $this;
 
-     }
 
-     public function detach()
 
-     {
 
-         $this->parent = null;
 
-     }
 
-     public function attach(Cells $parent)
 
-     {
 
-         $this->parent = $parent;
 
-     }
 
-     /**
 
-      * Create a new Cell.
 
-      *
 
-      * @param mixed $pValue
 
-      * @param string $pDataType
 
-      * @param Worksheet $pSheet
 
-      *
 
-      * @throws Exception
 
-      */
 
-     public function __construct($pValue, $pDataType, Worksheet $pSheet)
 
-     {
 
-         // Initialise cell value
 
-         $this->value = $pValue;
 
-         // Set worksheet cache
 
-         $this->parent = $pSheet->getCellCollection();
 
-         // Set datatype?
 
-         if ($pDataType !== null) {
 
-             if ($pDataType == DataType::TYPE_STRING2) {
 
-                 $pDataType = DataType::TYPE_STRING;
 
-             }
 
-             $this->dataType = $pDataType;
 
-         } elseif (!self::getValueBinder()->bindValue($this, $pValue)) {
 
-             throw new Exception('Value could not be bound to cell.');
 
-         }
 
-     }
 
-     /**
 
-      * Get cell coordinate column.
 
-      *
 
-      * @return string
 
-      */
 
-     public function getColumn()
 
-     {
 
-         return $this->parent->getCurrentColumn();
 
-     }
 
-     /**
 
-      * Get cell coordinate row.
 
-      *
 
-      * @return int
 
-      */
 
-     public function getRow()
 
-     {
 
-         return $this->parent->getCurrentRow();
 
-     }
 
-     /**
 
-      * Get cell coordinate.
 
-      *
 
-      * @return string
 
-      */
 
-     public function getCoordinate()
 
-     {
 
-         return $this->parent->getCurrentCoordinate();
 
-     }
 
-     /**
 
-      * Get cell value.
 
-      *
 
-      * @return mixed
 
-      */
 
-     public function getValue()
 
-     {
 
-         return $this->value;
 
-     }
 
-     /**
 
-      * Get cell value with formatting.
 
-      *
 
-      * @return string
 
-      */
 
-     public function getFormattedValue()
 
-     {
 
-         return (string) NumberFormat::toFormattedString(
 
-             $this->getCalculatedValue(),
 
-             $this->getStyle()
 
-                 ->getNumberFormat()->getFormatCode()
 
-         );
 
-     }
 
-     /**
 
-      * Set cell value.
 
-      *
 
-      *    Sets the value for a cell, automatically determining the datatype using the value binder
 
-      *
 
-      * @param mixed $pValue Value
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setValue($pValue)
 
-     {
 
-         if (!self::getValueBinder()->bindValue($this, $pValue)) {
 
-             throw new Exception('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 $pValue Value
 
-      * @param string $pDataType Explicit data type, see DataType::TYPE_*
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setValueExplicit($pValue, $pDataType)
 
-     {
 
-         // set the value according to data type
 
-         switch ($pDataType) {
 
-             case DataType::TYPE_NULL:
 
-                 $this->value = $pValue;
 
-                 break;
 
-             case DataType::TYPE_STRING2:
 
-                 $pDataType = DataType::TYPE_STRING;
 
-                 // no break
 
-             case DataType::TYPE_STRING:
 
-                 // Synonym for string
 
-             case DataType::TYPE_INLINE:
 
-                 // Rich text
 
-                 $this->value = DataType::checkString($pValue);
 
-                 break;
 
-             case DataType::TYPE_NUMERIC:
 
-                 $this->value = (float) $pValue;
 
-                 break;
 
-             case DataType::TYPE_FORMULA:
 
-                 $this->value = (string) $pValue;
 
-                 break;
 
-             case DataType::TYPE_BOOL:
 
-                 $this->value = (bool) $pValue;
 
-                 break;
 
-             case DataType::TYPE_ERROR:
 
-                 $this->value = DataType::checkErrorCode($pValue);
 
-                 break;
 
-             default:
 
-                 throw new Exception('Invalid datatype: ' . $pDataType);
 
-                 break;
 
-         }
 
-         // set the datatype
 
-         $this->dataType = $pDataType;
 
-         return $this->updateInCollection();
 
-     }
 
-     /**
 
-      * Get calculated cell value.
 
-      *
 
-      * @param bool $resetLog Whether the calculation engine logger should be reset or not
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return mixed
 
-      */
 
-     public function getCalculatedValue($resetLog = true)
 
-     {
 
-         if ($this->dataType == DataType::TYPE_FORMULA) {
 
-             try {
 
-                 $result = Calculation::getInstance(
 
-                     $this->getWorksheet()->getParent()
 
-                 )->calculateCellValue($this, $resetLog);
 
-                 //    We don't yet handle array returns
 
-                 if (is_array($result)) {
 
-                     while (is_array($result)) {
 
-                         $result = array_pop($result);
 
-                     }
 
-                 }
 
-             } catch (Exception $ex) {
 
-                 if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->calculatedValue !== null)) {
 
-                     return $this->calculatedValue; // Fallback for calculations referencing external files.
 
-                 }
 
-                 throw new \PhpOffice\PhpSpreadsheet\Calculation\Exception(
 
-                     $this->getWorksheet()->getTitle() . '!' . $this->getCoordinate() . ' -> ' . $ex->getMessage()
 
-                 );
 
-             }
 
-             if ($result === '#Not Yet Implemented') {
 
-                 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->value;
 
-     }
 
-     /**
 
-      * Set old calculated value (cached).
 
-      *
 
-      * @param mixed $pValue Value
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setCalculatedValue($pValue)
 
-     {
 
-         if ($pValue !== null) {
 
-             $this->calculatedValue = (is_numeric($pValue)) ? (float) $pValue : $pValue;
 
-         }
 
-         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.
 
-      *
 
-      * @return string
 
-      */
 
-     public function getDataType()
 
-     {
 
-         return $this->dataType;
 
-     }
 
-     /**
 
-      * Set cell data type.
 
-      *
 
-      * @param string $pDataType see DataType::TYPE_*
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setDataType($pDataType)
 
-     {
 
-         if ($pDataType == DataType::TYPE_STRING2) {
 
-             $pDataType = DataType::TYPE_STRING;
 
-         }
 
-         $this->dataType = $pDataType;
 
-         return $this->updateInCollection();
 
-     }
 
-     /**
 
-      * Identify if the cell contains a formula.
 
-      *
 
-      * @return bool
 
-      */
 
-     public function isFormula()
 
-     {
 
-         return $this->dataType == DataType::TYPE_FORMULA;
 
-     }
 
-     /**
 
-      *    Does this cell contain Data validation rules?
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return bool
 
-      */
 
-     public function hasDataValidation()
 
-     {
 
-         if (!isset($this->parent)) {
 
-             throw new Exception('Cannot check for data validation when cell is not bound to a worksheet');
 
-         }
 
-         return $this->getWorksheet()->dataValidationExists($this->getCoordinate());
 
-     }
 
-     /**
 
-      * Get Data validation rules.
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return DataValidation
 
-      */
 
-     public function getDataValidation()
 
-     {
 
-         if (!isset($this->parent)) {
 
-             throw new Exception('Cannot get data validation for cell that is not bound to a worksheet');
 
-         }
 
-         return $this->getWorksheet()->getDataValidation($this->getCoordinate());
 
-     }
 
-     /**
 
-      * Set Data validation rules.
 
-      *
 
-      * @param DataValidation $pDataValidation
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setDataValidation(DataValidation $pDataValidation = null)
 
-     {
 
-         if (!isset($this->parent)) {
 
-             throw new Exception('Cannot set data validation for cell that is not bound to a worksheet');
 
-         }
 
-         $this->getWorksheet()->setDataValidation($this->getCoordinate(), $pDataValidation);
 
-         return $this->updateInCollection();
 
-     }
 
-     /**
 
-      * Does this cell contain valid value?
 
-      *
 
-      * @return bool
 
-      */
 
-     public function hasValidValue()
 
-     {
 
-         $validator = new DataValidator();
 
-         return $validator->isValid($this);
 
-     }
 
-     /**
 
-      * Does this cell contain a Hyperlink?
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return bool
 
-      */
 
-     public function hasHyperlink()
 
-     {
 
-         if (!isset($this->parent)) {
 
-             throw new Exception('Cannot check for hyperlink when cell is not bound to a worksheet');
 
-         }
 
-         return $this->getWorksheet()->hyperlinkExists($this->getCoordinate());
 
-     }
 
-     /**
 
-      * Get Hyperlink.
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return Hyperlink
 
-      */
 
-     public function getHyperlink()
 
-     {
 
-         if (!isset($this->parent)) {
 
-             throw new Exception('Cannot get hyperlink for cell that is not bound to a worksheet');
 
-         }
 
-         return $this->getWorksheet()->getHyperlink($this->getCoordinate());
 
-     }
 
-     /**
 
-      * Set Hyperlink.
 
-      *
 
-      * @param Hyperlink $pHyperlink
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setHyperlink(Hyperlink $pHyperlink = null)
 
-     {
 
-         if (!isset($this->parent)) {
 
-             throw new Exception('Cannot set hyperlink for cell that is not bound to a worksheet');
 
-         }
 
-         $this->getWorksheet()->setHyperlink($this->getCoordinate(), $pHyperlink);
 
-         return $this->updateInCollection();
 
-     }
 
-     /**
 
-      * Get cell collection.
 
-      *
 
-      * @return Cells
 
-      */
 
-     public function getParent()
 
-     {
 
-         return $this->parent;
 
-     }
 
-     /**
 
-      * Get parent worksheet.
 
-      *
 
-      * @return Worksheet
 
-      */
 
-     public function getWorksheet()
 
-     {
 
-         return $this->parent->getParent();
 
-     }
 
-     /**
 
-      * Is this cell in a merge range.
 
-      *
 
-      * @return bool
 
-      */
 
-     public function isInMergeRange()
 
-     {
 
-         return (bool) $this->getMergeRange();
 
-     }
 
-     /**
 
-      * Is this cell the master (top left cell) in a merge range (that holds the actual data value).
 
-      *
 
-      * @return bool
 
-      */
 
-     public function isMergeRangeValueCell()
 
-     {
 
-         if ($mergeRange = $this->getMergeRange()) {
 
-             $mergeRange = Coordinate::splitRange($mergeRange);
 
-             list($startCell) = $mergeRange[0];
 
-             if ($this->getCoordinate() === $startCell) {
 
-                 return true;
 
-             }
 
-         }
 
-         return false;
 
-     }
 
-     /**
 
-      * If this cell is in a merge range, then return the range.
 
-      *
 
-      * @return string
 
-      */
 
-     public function getMergeRange()
 
-     {
 
-         foreach ($this->getWorksheet()->getMergeCells() as $mergeRange) {
 
-             if ($this->isInRange($mergeRange)) {
 
-                 return $mergeRange;
 
-             }
 
-         }
 
-         return false;
 
-     }
 
-     /**
 
-      * Get cell style.
 
-      *
 
-      * @return Style
 
-      */
 
-     public function getStyle()
 
-     {
 
-         return $this->getWorksheet()->getStyle($this->getCoordinate());
 
-     }
 
-     /**
 
-      * Re-bind parent.
 
-      *
 
-      * @param Worksheet $parent
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function rebindParent(Worksheet $parent)
 
-     {
 
-         $this->parent = $parent->getCellCollection();
 
-         return $this->updateInCollection();
 
-     }
 
-     /**
 
-      *    Is cell in a specific range?
 
-      *
 
-      * @param string $pRange Cell range (e.g. A1:A1)
 
-      *
 
-      * @return bool
 
-      */
 
-     public function isInRange($pRange)
 
-     {
 
-         list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($pRange);
 
-         // 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)
 
-     {
 
-         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.
 
-      *
 
-      * @return IValueBinder
 
-      */
 
-     public static function getValueBinder()
 
-     {
 
-         if (self::$valueBinder === null) {
 
-             self::$valueBinder = new DefaultValueBinder();
 
-         }
 
-         return self::$valueBinder;
 
-     }
 
-     /**
 
-      * Set value binder to use.
 
-      *
 
-      * @param IValueBinder $binder
 
-      */
 
-     public static function setValueBinder(IValueBinder $binder)
 
-     {
 
-         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 $key => $value) {
 
-             if ((is_object($value)) && ($key != 'parent')) {
 
-                 $this->$key = clone $value;
 
-             } else {
 
-                 $this->$key = $value;
 
-             }
 
-         }
 
-     }
 
-     /**
 
-      * Get index to cellXf.
 
-      *
 
-      * @return int
 
-      */
 
-     public function getXfIndex()
 
-     {
 
-         return $this->xfIndex;
 
-     }
 
-     /**
 
-      * Set index to cellXf.
 
-      *
 
-      * @param int $pValue
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setXfIndex($pValue)
 
-     {
 
-         $this->xfIndex = $pValue;
 
-         return $this->updateInCollection();
 
-     }
 
-     /**
 
-      * Set the formula attributes.
 
-      *
 
-      * @param mixed $pAttributes
 
-      *
 
-      * @return Cell
 
-      */
 
-     public function setFormulaAttributes($pAttributes)
 
-     {
 
-         $this->formulaAttributes = $pAttributes;
 
-         return $this;
 
-     }
 
-     /**
 
-      * Get the formula attributes.
 
-      */
 
-     public function getFormulaAttributes()
 
-     {
 
-         return $this->formulaAttributes;
 
-     }
 
-     /**
 
-      * Convert to string.
 
-      *
 
-      * @return string
 
-      */
 
-     public function __toString()
 
-     {
 
-         return (string) $this->getValue();
 
-     }
 
- }
 
 
  |