ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
Cell.php
Go to the documentation of this file.
1 <?php
37 {
43  private static $_valueBinder = null;
44 
50  private $_column;
51 
57  private $_row;
58 
64  private $_value;
65 
71  private $_calculatedValue = null;
72 
78  private $_dataType;
79 
85  private $_parent;
86 
92  private $_xfIndex;
93 
100 
101 
106  public function notifyCacheController() {
107  $this->_parent->getCellCacheController()->updateCacheData($this);
108  return $this;
109  }
110 
111  public function detach() {
112  $this->_parent = null;
113  }
114 
115  public function attach($parent) {
116  $this->_parent = $parent;
117  }
118 
119 
130  public function __construct($pColumn = 'A', $pRow = 1, $pValue = null, $pDataType = null, PHPExcel_Worksheet $pSheet = null)
131  {
132  // Initialise cell coordinate
133  $this->_column = strtoupper($pColumn);
134  $this->_row = $pRow;
135 
136  // Initialise cell value
137  $this->_value = $pValue;
138 
139  // Set worksheet
140  $this->_parent = $pSheet;
141 
142  // Set datatype?
143  if ($pDataType !== null) {
144  if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2)
146  $this->_dataType = $pDataType;
147  } else {
148  if (!self::getValueBinder()->bindValue($this, $pValue)) {
149  throw new Exception("Value could not be bound to cell.");
150  }
151  }
152 
153  // set default index to cellXf
154  $this->_xfIndex = 0;
155  }
156 
162  public function getColumn()
163  {
164  return $this->_column;
165  }
166 
172  public function getRow()
173  {
174  return $this->_row;
175  }
176 
182  public function getCoordinate()
183  {
184  return $this->_column . $this->_row;
185  }
186 
192  public function getValue()
193  {
194  return $this->_value;
195  }
196 
202  public function getFormattedValue()
203  {
205  $this->_parent->getParent()->getCellXfByIndex($this->getXfIndex())->getNumberFormat()->getFormatCode()
206  );
207  }
208 
217  public function setValue($pValue = null)
218  {
219  if (!self::getValueBinder()->bindValue($this, $pValue)) {
220  throw new Exception("Value could not be bound to cell.");
221  }
222  return $this;
223  }
224 
233  public function setValueExplicit($pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
234  {
235  // set the value according to data type
236  switch ($pDataType) {
242  $this->_value = PHPExcel_Cell_DataType::checkString($pValue);
243  break;
244 
246  $this->_value = (float)$pValue;
247  break;
248 
250  $this->_value = (string)$pValue;
251  break;
252 
254  $this->_value = (bool)$pValue;
255  break;
256 
258  $this->_value = PHPExcel_Cell_DataType::checkErrorCode($pValue);
259  break;
260 
261  default:
262  throw new Exception('Invalid datatype: ' . $pDataType);
263  break;
264  }
265 
266  // set the datatype
267  $this->_dataType = $pDataType;
268 
269  return $this->notifyCacheController();
270  }
271 
277  public function getCalculatedValue($resetLog=true)
278  {
279 // echo 'Cell '.$this->getCoordinate().' value is a '.$this->_dataType.' with a value of '.$this->getValue().'<br />';
280  if ($this->_dataType == PHPExcel_Cell_DataType::TYPE_FORMULA) {
281  try {
282 // echo 'Cell value for '.$this->getCoordinate().' is a formula: Calculating value<br />';
283  $result = PHPExcel_Calculation::getInstance()->calculateCellValue($this,$resetLog);
284 // echo $this->getCoordinate().' calculation result is '.$result.'<br />';
285  } catch ( Exception $ex ) {
286 // echo 'Calculation Exception: '.$ex->getMessage().'<br />';
287  $result = '#N/A';
288  throw(new Exception($this->getParent()->getTitle().'!'.$this->getCoordinate().' -> '.$ex->getMessage()));
289  }
290 
291  if ($result === '#Not Yet Implemented') {
292 // echo 'Returning fallback value of '.$this->_calculatedValue.' for cell '.$this->getCoordinate().'<br />';
293  return $this->_calculatedValue; // Fallback if calculation engine does not support the formula.
294  }
295 // echo 'Returning calculated value of '.$result.' for cell '.$this->getCoordinate().'<br />';
296  return $result;
297  }
298 
299 // if (is_null($this->_value)) {
300 // echo 'Cell '.$this->getCoordinate().' has no value, formula or otherwise<br />';
301 // return null;
302 // }
303 // echo 'Cell value for '.$this->getCoordinate().' is not a formula: Returning data value of '.$this->_value.'<br />';
304  return $this->_value;
305  }
306 
313  public function setCalculatedValue($pValue = null)
314  {
315  if (!is_null($pValue)) {
316  $this->_calculatedValue = $pValue;
317  }
318 
319  return $this->notifyCacheController();
320  }
321 
327  public function getOldCalculatedValue()
328  {
330  }
331 
337  public function getDataType()
338  {
339  return $this->_dataType;
340  }
341 
348  public function setDataType($pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
349  {
350  if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2)
352 
353  $this->_dataType = $pDataType;
354 
355  return $this->notifyCacheController();
356  }
357 
363  public function hasDataValidation()
364  {
365  if (!isset($this->_parent)) {
366  throw new Exception('Cannot check for data validation when cell is not bound to a worksheet');
367  }
368 
369  return $this->_parent->dataValidationExists($this->getCoordinate());
370  }
371 
377  public function getDataValidation()
378  {
379  if (!isset($this->_parent)) {
380  throw new Exception('Cannot get data validation for cell that is not bound to a worksheet');
381  }
382 
383  return $this->_parent->getDataValidation($this->getCoordinate());
384  }
385 
393  public function setDataValidation(PHPExcel_Cell_DataValidation $pDataValidation = null)
394  {
395  if (!isset($this->_parent)) {
396  throw new Exception('Cannot set data validation for cell that is not bound to a worksheet');
397  }
398 
399  $this->_parent->setDataValidation($this->getCoordinate(), $pDataValidation);
400 
401  return $this->notifyCacheController();
402  }
403 
409  public function hasHyperlink()
410  {
411  if (!isset($this->_parent)) {
412  throw new Exception('Cannot check for hyperlink when cell is not bound to a worksheet');
413  }
414 
415  return $this->_parent->hyperlinkExists($this->getCoordinate());
416  }
417 
424  public function getHyperlink()
425  {
426  if (!isset($this->_parent)) {
427  throw new Exception('Cannot get hyperlink for cell that is not bound to a worksheet');
428  }
429 
430  return $this->_parent->getHyperlink($this->getCoordinate());
431  }
432 
440  public function setHyperlink(PHPExcel_Cell_Hyperlink $pHyperlink = null)
441  {
442  if (!isset($this->_parent)) {
443  throw new Exception('Cannot set hyperlink for cell that is not bound to a worksheet');
444  }
445 
446  $this->_parent->setHyperlink($this->getCoordinate(), $pHyperlink);
447 
448  return $this->notifyCacheController();
449  }
450 
456  public function getParent() {
457  return $this->_parent;
458  }
459 
466  public function rebindParent(PHPExcel_Worksheet $parent) {
467  $this->_parent = $parent;
468 
469  return $this->notifyCacheController();
470  }
471 
478  public function isInRange($pRange = 'A1:A1')
479  {
480  list($rangeStart,$rangeEnd) = PHPExcel_Cell::rangeBoundaries($pRange);
481 
482  // Translate properties
483  $myColumn = PHPExcel_Cell::columnIndexFromString($this->getColumn());
484  $myRow = $this->getRow();
485 
486  // Verify if cell is in range
487  return (($rangeStart[0] <= $myColumn) && ($rangeEnd[0] >= $myColumn) &&
488  ($rangeStart[1] <= $myRow) && ($rangeEnd[1] >= $myRow)
489  );
490  }
491 
499  public static function coordinateFromString($pCoordinateString = 'A1')
500  {
501  if (preg_match("/^([$]?[A-Z]{1,3})([$]?\d{1,7})$/", $pCoordinateString, $matches)) {
502  return array($matches[1],$matches[2]);
503  } elseif ((strpos($pCoordinateString,':') !== false) || (strpos($pCoordinateString,',') !== false)) {
504  throw new Exception('Cell coordinate string can not be a range of cells.');
505  } elseif ($pCoordinateString == '') {
506  throw new Exception('Cell coordinate can not be zero-length string.');
507  } else {
508  throw new Exception('Invalid cell coordinate '.$pCoordinateString);
509  }
510  }
511 
519  public static function absoluteReference($pCoordinateString = 'A1')
520  {
521  if (strpos($pCoordinateString,':') === false && strpos($pCoordinateString,',') === false) {
522  // Create absolute coordinate
523  if (ctype_digit($pCoordinateString)) {
524  return '$'.$pCoordinateString;
525  } elseif (ctype_alpha($pCoordinateString)) {
526  return '$'.strtoupper($pCoordinateString);
527  }
528  return self::absoluteCoordinate($pCoordinateString);
529  } else {
530  throw new Exception("Coordinate string should not be a cell range.");
531  }
532  }
533 
541  public static function absoluteCoordinate($pCoordinateString = 'A1')
542  {
543  if (strpos($pCoordinateString,':') === false && strpos($pCoordinateString,',') === false) {
544  // Create absolute coordinate
545  list($column, $row) = PHPExcel_Cell::coordinateFromString($pCoordinateString);
546  if ($column[0] == '$') $column = substr($column,1);
547  if ($row[0] == '$') $row = substr($row,1);
548  return '$' . $column . '$' . $row;
549  } else {
550  throw new Exception("Coordinate string should not be a cell range.");
551  }
552  }
553 
560  public static function splitRange($pRange = 'A1:A1')
561  {
562  $exploded = explode(',', $pRange);
563  $counter = count($exploded);
564  for ($i = 0; $i < $counter; ++$i) {
565  $exploded[$i] = explode(':', $exploded[$i]);
566  }
567  return $exploded;
568  }
569 
577  public static function buildRange($pRange)
578  {
579  // Verify range
580  if (!is_array($pRange) || count($pRange) == 0 || !is_array($pRange[0])) {
581  throw new Exception('Range does not contain any information.');
582  }
583 
584  // Build range
585  $imploded = array();
586  $counter = count($pRange);
587  for ($i = 0; $i < $counter; ++$i) {
588  $pRange[$i] = implode(':', $pRange[$i]);
589  }
590  $imploded = implode(',', $pRange);
591 
592  return $imploded;
593  }
594 
601  public static function rangeBoundaries($pRange = 'A1:A1')
602  {
603  // Uppercase coordinate
604  $pRange = strtoupper($pRange);
605 
606  // Extract range
607  if (strpos($pRange, ':') === false) {
608  $rangeA = $rangeB = $pRange;
609  } else {
610  list($rangeA, $rangeB) = explode(':', $pRange);
611  }
612 
613  // Calculate range outer borders
614  $rangeStart = PHPExcel_Cell::coordinateFromString($rangeA);
615  $rangeEnd = PHPExcel_Cell::coordinateFromString($rangeB);
616 
617  // Translate column into index
618  $rangeStart[0] = PHPExcel_Cell::columnIndexFromString($rangeStart[0]);
619  $rangeEnd[0] = PHPExcel_Cell::columnIndexFromString($rangeEnd[0]);
620 
621  return array($rangeStart, $rangeEnd);
622  }
623 
630  public static function rangeDimension($pRange = 'A1:A1')
631  {
632  // Calculate range outer borders
633  list($rangeStart,$rangeEnd) = PHPExcel_Cell::rangeBoundaries($pRange);
634 
635  return array( ($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1) );
636  }
637 
644  public static function getRangeBoundaries($pRange = 'A1:A1')
645  {
646  // Uppercase coordinate
647  $pRange = strtoupper($pRange);
648 
649  // Extract range
650  if (strpos($pRange, ':') === false) {
651  $rangeA = $rangeB = $pRange;
652  } else {
653  list($rangeA, $rangeB) = explode(':', $pRange);
654  }
655 
656  return array( self::coordinateFromString($rangeA), self::coordinateFromString($rangeB));
657  }
658 
666  public static function columnIndexFromString($pString = 'A')
667  {
668  // It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array rather than use ord()
669  // and make it case insensitive to get rid of the strtoupper() as well. Because it's a static, there's no significant
670  // memory overhead either
671  static $_columnLookup = array(
672  'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8, 'I' => 9, 'J' => 10, 'K' => 11, 'L' => 12, 'M' => 13,
673  'N' => 14, 'O' => 15, 'P' => 16, 'Q' => 17, 'R' => 18, 'S' => 19, 'T' => 20, 'U' => 21, 'V' => 22, 'W' => 23, 'X' => 24, 'Y' => 25, 'Z' => 26,
674  'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7, 'h' => 8, 'i' => 9, 'j' => 10, 'k' => 11, 'l' => 12, 'm' => 13,
675  'n' => 14, 'o' => 15, 'p' => 16, 'q' => 17, 'r' => 18, 's' => 19, 't' => 20, 'u' => 21, 'v' => 22, 'w' => 23, 'x' => 24, 'y' => 25, 'z' => 26
676  );
677 
678  // We also use the language construct isset() rather than the more costly strlen() function to match the length of $pString
679  // for improved performance
680  if (isset($pString{0})) {
681  if (!isset($pString{1})) {
682  return $_columnLookup[$pString];
683  } elseif(!isset($pString{2})) {
684  return $_columnLookup[$pString{0}] * 26 + $_columnLookup[$pString{1}];
685  } elseif(!isset($pString{3})) {
686  return $_columnLookup[$pString{0}] * 676 + $_columnLookup[$pString{1}] * 26 + $_columnLookup[$pString{2}];
687  }
688  }
689  throw new Exception("Column string index can not be " . ((isset($pString{0})) ? "longer than 3 characters" : "empty") . ".");
690  }
691 
698  public static function stringFromColumnIndex($pColumnIndex = 0)
699  {
700  // Determine column string
701  if ($pColumnIndex < 26) {
702  return chr(65 + $pColumnIndex);
703  } elseif ($pColumnIndex < 702) {
704  return chr(64 + ($pColumnIndex / 26)).chr(65 + $pColumnIndex % 26);
705  }
706  return chr(64 + (($pColumnIndex - 26) / 676)).chr(65 + ((($pColumnIndex - 26) % 676) / 26)).chr(65 + $pColumnIndex % 26);
707  }
708 
715  public static function extractAllCellReferencesInRange($pRange = 'A1') {
716  // Returnvalue
717  $returnValue = array();
718 
719  // Explode spaces
720  $cellBlocks = explode(' ', str_replace('$', '', strtoupper($pRange)));
721  foreach ($cellBlocks as $cellBlock) {
722  // Single cell?
723  if (strpos($cellBlock,':') === false && strpos($cellBlock,',') === false) {
724  $returnValue[] = $cellBlock;
725  continue;
726  }
727 
728  // Range...
729  $ranges = PHPExcel_Cell::splitRange($cellBlock);
730  foreach($ranges as $range) {
731  // Single cell?
732  if (!isset($range[1])) {
733  $returnValue[] = $range[0];
734  continue;
735  }
736 
737  // Range...
738  list($rangeStart, $rangeEnd) = $range;
739  list($startCol, $startRow) = sscanf($rangeStart,'%[A-Z]%d');
740  list($endCol, $endRow) = sscanf($rangeEnd,'%[A-Z]%d');
741  $endCol++;
742 
743  // Current data
744  $currentCol = $startCol;
745  $currentRow = $startRow;
746 
747  // Loop cells
748  while ($currentCol != $endCol) {
749  while ($currentRow <= $endRow) {
750  $returnValue[] = $currentCol.$currentRow;
751  ++$currentRow;
752  }
753  ++$currentCol;
754  $currentRow = $startRow;
755  }
756  }
757  }
758 
759  // Return value
760  return $returnValue;
761  }
762 
770  public static function compareCells(PHPExcel_Cell $a, PHPExcel_Cell $b)
771  {
772  if ($a->_row < $b->_row) {
773  return -1;
774  } elseif ($a->_row > $b->_row) {
775  return 1;
776  } elseif (PHPExcel_Cell::columnIndexFromString($a->_column) < PHPExcel_Cell::columnIndexFromString($b->_column)) {
777  return -1;
778  } else {
779  return 1;
780  }
781  }
782 
788  public static function getValueBinder() {
789  if (is_null(self::$_valueBinder)) {
790  self::$_valueBinder = new PHPExcel_Cell_DefaultValueBinder();
791  }
792 
793  return self::$_valueBinder;
794  }
795 
802  public static function setValueBinder(PHPExcel_Cell_IValueBinder $binder = null) {
803  if (is_null($binder)) {
804  throw new Exception("A PHPExcel_Cell_IValueBinder is required for PHPExcel to function correctly.");
805  }
806 
807  self::$_valueBinder = $binder;
808  }
809 
813  public function __clone() {
814  $vars = get_object_vars($this);
815  foreach ($vars as $key => $value) {
816  if ((is_object($value)) && ($key != '_parent')) {
817  $this->$key = clone $value;
818  } else {
819  $this->$key = $value;
820  }
821  }
822  }
823 
829  public function getXfIndex()
830  {
831  return $this->_xfIndex;
832  }
833 
840  public function setXfIndex($pValue = 0)
841  {
842  $this->_xfIndex = $pValue;
843 
844  return $this->notifyCacheController();
845  }
846 
847 
848  public function setFormulaAttributes($pAttributes)
849  {
850  $this->_formulaAttributes = $pAttributes;
851  return $this;
852  }
853 
854  public function getFormulaAttributes()
855  {
857  }
858 
859 }
860