PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.1.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.1.0
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpexcel / Classes / PHPExcel / Cell.php

Cell.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.1.0, at vendor/phpoffice/phpexcel/Classes/PHPExcel/Cell.php

1,033 lines 32.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * PHPExcel_Cell
5 *
6 * Copyright (c) 2006 - 2015 PHPExcel
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * @category PHPExcel
23 * @package PHPExcel_Cell
24 * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
25 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
26 * @version ##VERSION##, ##DATE##
27 */
28 class PHPExcel_Cell
29 {
30 /**
31 * Default range variable constant
32 *
33 * @var string
34 */
35 const DEFAULT_RANGE = 'A1:A1';
36
37 /**
38 * Value binder to use
39 *
40 * @var PHPExcel_Cell_IValueBinder
41 */
42 private static $valueBinder;
43
44 /**
45 * Value of the cell
46 *
47 * @var mixed
48 */
49 private $value;
50
51 /**
52 * Calculated value of the cell (used for caching)
53 * This returns the value last calculated by MS Excel or whichever spreadsheet program was used to
54 * create the original spreadsheet file.
55 * Note that this value is not guaranteed to reflect the actual calculated value because it is
56 * possible that auto-calculation was disabled in the original spreadsheet, and underlying data
57 * values used by the formula have changed since it was last calculated.
58 *
59 * @var mixed
60 */
61 private $calculatedValue;
62
63 /**
64 * Type of the cell data
65 *
66 * @var string
67 */
68 private $dataType;
69
70 /**
71 * Parent worksheet
72 *
73 * @var PHPExcel_CachedObjectStorage_CacheBase
74 */
75 private $parent;
76
77 /**
78 * Index to cellXf
79 *
80 * @var int
81 */
82 private $xfIndex = 0;
83
84 /**
85 * Attributes of the formula
86 *
87 */
88 private $formulaAttributes;
89
90
91 /**
92 * Send notification to the cache controller
93 *
94 * @return void
95 **/
96 public function notifyCacheController()
97 {
98 $this->parent->updateCacheData($this);
99
100 return $this;
101 }
102
103 public function detach()
104 {
105 $this->parent = null;
106 }
107
108 public function attach(PHPExcel_CachedObjectStorage_CacheBase $parent)
109 {
110 $this->parent = $parent;
111 }
112
113
114 /**
115 * Create a new Cell
116 *
117 * @param mixed $pValue
118 * @param string $pDataType
119 * @param PHPExcel_Worksheet $pSheet
120 * @throws PHPExcel_Exception
121 */
122 public function __construct($pValue = null, $pDataType = null, PHPExcel_Worksheet $pSheet = null)
123 {
124 // Initialise cell value
125 $this->value = $pValue;
126
127 // Set worksheet cache
128 $this->parent = $pSheet->getCellCacheController();
129
130 // Set datatype?
131 if ($pDataType !== null) {
132 if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2) {
133 $pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
134 }
135 $this->dataType = $pDataType;
136 } elseif (!self::getValueBinder()->bindValue($this, $pValue)) {
137 throw new PHPExcel_Exception("Value could not be bound to cell.");
138 }
139 }
140
141 /**
142 * Get cell coordinate column
143 *
144 * @return string
145 */
146 public function getColumn()
147 {
148 return $this->parent->getCurrentColumn();
149 }
150
151 /**
152 * Get cell coordinate row
153 *
154 * @return int
155 */
156 public function getRow()
157 {
158 return $this->parent->getCurrentRow();
159 }
160
161 /**
162 * Get cell coordinate
163 *
164 * @return string
165 */
166 public function getCoordinate()
167 {
168 return $this->parent->getCurrentAddress();
169 }
170
171 /**
172 * Get cell value
173 *
174 * @return mixed
175 */
176 public function getValue()
177 {
178 return $this->value;
179 }
180
181 /**
182 * Get cell value with formatting
183 *
184 * @return string
185 */
186 public function getFormattedValue()
187 {
188 return (string) PHPExcel_Style_NumberFormat::toFormattedString(
189 $this->getCalculatedValue(),
190 $this->getStyle()
191 ->getNumberFormat()->getFormatCode()
192 );
193 }
194
195 /**
196 * Set cell value
197 *
198 * Sets the value for a cell, automatically determining the datatype using the value binder
199 *
200 * @param mixed $pValue Value
201 * @return PHPExcel_Cell
202 * @throws PHPExcel_Exception
203 */
204 public function setValue($pValue = null)
205 {
206 if (!self::getValueBinder()->bindValue($this, $pValue)) {
207 throw new PHPExcel_Exception("Value could not be bound to cell.");
208 }
209 return $this;
210 }
211
212 /**
213 * Set the value for a cell, with the explicit data type passed to the method (bypassing any use of the value binder)
214 *
215 * @param mixed $pValue Value
216 * @param string $pDataType Explicit data type
217 * @return PHPExcel_Cell
218 * @throws PHPExcel_Exception
219 */
220 public function setValueExplicit($pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
221 {
222 // set the value according to data type
223 switch ($pDataType) {
224 case PHPExcel_Cell_DataType::TYPE_NULL:
225 $this->value = $pValue;
226 break;
227 case PHPExcel_Cell_DataType::TYPE_STRING2:
228 $pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
229 // no break
230 case PHPExcel_Cell_DataType::TYPE_STRING:
231 // Synonym for string
232 case PHPExcel_Cell_DataType::TYPE_INLINE:
233 // Rich text
234 $this->value = PHPExcel_Cell_DataType::checkString($pValue);
235 break;
236 case PHPExcel_Cell_DataType::TYPE_NUMERIC:
237 $this->value = (float) $pValue;
238 break;
239 case PHPExcel_Cell_DataType::TYPE_FORMULA:
240 $this->value = (string) $pValue;
241 break;
242 case PHPExcel_Cell_DataType::TYPE_BOOL:
243 $this->value = (bool) $pValue;
244 break;
245 case PHPExcel_Cell_DataType::TYPE_ERROR:
246 $this->value = PHPExcel_Cell_DataType::checkErrorCode($pValue);
247 break;
248 default:
249 throw new PHPExcel_Exception('Invalid datatype: ' . $pDataType);
250 break;
251 }
252
253 // set the datatype
254 $this->dataType = $pDataType;
255
256 return $this->notifyCacheController();
257 }
258
259 /**
260 * Get calculated cell value
261 *
262 * @deprecated Since version 1.7.8 for planned changes to cell for array formula handling
263 *
264 * @param boolean $resetLog Whether the calculation engine logger should be reset or not
265 * @return mixed
266 * @throws PHPExcel_Exception
267 */
268 public function getCalculatedValue($resetLog = true)
269 {
270 //echo 'Cell '.$this->getCoordinate().' value is a '.$this->dataType.' with a value of '.$this->getValue().PHP_EOL;
271 if ($this->dataType == PHPExcel_Cell_DataType::TYPE_FORMULA) {
272 try {
273 //echo 'Cell value for '.$this->getCoordinate().' is a formula: Calculating value'.PHP_EOL;
274 $result = PHPExcel_Calculation::getInstance(
275 $this->getWorksheet()->getParent()
276 )->calculateCellValue($this, $resetLog);
277 //echo $this->getCoordinate().' calculation result is '.$result.PHP_EOL;
278 // We don't yet handle array returns
279 if (is_array($result)) {
280 while (is_array($result)) {
281 $result = array_pop($result);
282 }
283 }
284 } catch (PHPExcel_Exception $ex) {
285 if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->calculatedValue !== null)) {
286 //echo 'Returning fallback value of '.$this->calculatedValue.' for cell '.$this->getCoordinate().PHP_EOL;
287 return $this->calculatedValue; // Fallback for calculations referencing external files.
288 }
289 //echo 'Calculation Exception: '.$ex->getMessage().PHP_EOL;
290 $result = '#N/A';
291 throw new PHPExcel_Calculation_Exception(
292 $this->getWorksheet()->getTitle().'!'.$this->getCoordinate().' -> '.$ex->getMessage()
293 );
294 }
295
296 if ($result === '#Not Yet Implemented') {
297 //echo 'Returning fallback value of '.$this->calculatedValue.' for cell '.$this->getCoordinate().PHP_EOL;
298 return $this->calculatedValue; // Fallback if calculation engine does not support the formula.
299 }
300 //echo 'Returning calculated value of '.$result.' for cell '.$this->getCoordinate().PHP_EOL;
301 return $result;
302 } elseif ($this->value instanceof PHPExcel_RichText) {
303 // echo 'Cell value for '.$this->getCoordinate().' is rich text: Returning data value of '.$this->value.'<br />';
304 return $this->value->getPlainText();
305 }
306 // echo 'Cell value for '.$this->getCoordinate().' is not a formula: Returning data value of '.$this->value.'<br />';
307 return $this->value;
308 }
309
310 /**
311 * Set old calculated value (cached)
312 *
313 * @param mixed $pValue Value
314 * @return PHPExcel_Cell
315 */
316 public function setCalculatedValue($pValue = null)
317 {
318 if ($pValue !== null) {
319 $this->calculatedValue = (is_numeric($pValue)) ? (float) $pValue : $pValue;
320 }
321
322 return $this->notifyCacheController();
323 }
324
325 /**
326 * Get old calculated value (cached)
327 * This returns the value last calculated by MS Excel or whichever spreadsheet program was used to
328 * create the original spreadsheet file.
329 * Note that this value is not guaranteed to refelect the actual calculated value because it is
330 * possible that auto-calculation was disabled in the original spreadsheet, and underlying data
331 * values used by the formula have changed since it was last calculated.
332 *
333 * @return mixed
334 */
335 public function getOldCalculatedValue()
336 {
337 return $this->calculatedValue;
338 }
339
340 /**
341 * Get cell data type
342 *
343 * @return string
344 */
345 public function getDataType()
346 {
347 return $this->dataType;
348 }
349
350 /**
351 * Set cell data type
352 *
353 * @param string $pDataType
354 * @return PHPExcel_Cell
355 */
356 public function setDataType($pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
357 {
358 if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2) {
359 $pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
360 }
361 $this->dataType = $pDataType;
362
363 return $this->notifyCacheController();
364 }
365
366 /**
367 * Identify if the cell contains a formula
368 *
369 * @return boolean
370 */
371 public function isFormula()
372 {
373 return $this->dataType == PHPExcel_Cell_DataType::TYPE_FORMULA;
374 }
375
376 /**
377 * Does this cell contain Data validation rules?
378 *
379 * @return boolean
380 * @throws PHPExcel_Exception
381 */
382 public function hasDataValidation()
383 {
384 if (!isset($this->parent)) {
385 throw new PHPExcel_Exception('Cannot check for data validation when cell is not bound to a worksheet');
386 }
387
388 return $this->getWorksheet()->dataValidationExists($this->getCoordinate());
389 }
390
391 /**
392 * Get Data validation rules
393 *
394 * @return PHPExcel_Cell_DataValidation
395 * @throws PHPExcel_Exception
396 */
397 public function getDataValidation()
398 {
399 if (!isset($this->parent)) {
400 throw new PHPExcel_Exception('Cannot get data validation for cell that is not bound to a worksheet');
401 }
402
403 return $this->getWorksheet()->getDataValidation($this->getCoordinate());
404 }
405
406 /**
407 * Set Data validation rules
408 *
409 * @param PHPExcel_Cell_DataValidation $pDataValidation
410 * @return PHPExcel_Cell
411 * @throws PHPExcel_Exception
412 */
413 public function setDataValidation(PHPExcel_Cell_DataValidation $pDataValidation = null)
414 {
415 if (!isset($this->parent)) {
416 throw new PHPExcel_Exception('Cannot set data validation for cell that is not bound to a worksheet');
417 }
418
419 $this->getWorksheet()->setDataValidation($this->getCoordinate(), $pDataValidation);
420
421 return $this->notifyCacheController();
422 }
423
424 /**
425 * Does this cell contain a Hyperlink?
426 *
427 * @return boolean
428 * @throws PHPExcel_Exception
429 */
430 public function hasHyperlink()
431 {
432 if (!isset($this->parent)) {
433 throw new PHPExcel_Exception('Cannot check for hyperlink when cell is not bound to a worksheet');
434 }
435
436 return $this->getWorksheet()->hyperlinkExists($this->getCoordinate());
437 }
438
439 /**
440 * Get Hyperlink
441 *
442 * @return PHPExcel_Cell_Hyperlink
443 * @throws PHPExcel_Exception
444 */
445 public function getHyperlink()
446 {
447 if (!isset($this->parent)) {
448 throw new PHPExcel_Exception('Cannot get hyperlink for cell that is not bound to a worksheet');
449 }
450
451 return $this->getWorksheet()->getHyperlink($this->getCoordinate());
452 }
453
454 /**
455 * Set Hyperlink
456 *
457 * @param PHPExcel_Cell_Hyperlink $pHyperlink
458 * @return PHPExcel_Cell
459 * @throws PHPExcel_Exception
460 */
461 public function setHyperlink(PHPExcel_Cell_Hyperlink $pHyperlink = null)
462 {
463 if (!isset($this->parent)) {
464 throw new PHPExcel_Exception('Cannot set hyperlink for cell that is not bound to a worksheet');
465 }
466
467 $this->getWorksheet()->setHyperlink($this->getCoordinate(), $pHyperlink);
468
469 return $this->notifyCacheController();
470 }
471
472 /**
473 * Get parent worksheet
474 *
475 * @return PHPExcel_CachedObjectStorage_CacheBase
476 */
477 public function getParent()
478 {
479 return $this->parent;
480 }
481
482 /**
483 * Get parent worksheet
484 *
485 * @return PHPExcel_Worksheet
486 */
487 public function getWorksheet()
488 {
489 return $this->parent->getParent();
490 }
491
492 /**
493 * Is this cell in a merge range
494 *
495 * @return boolean
496 */
497 public function isInMergeRange()
498 {
499 return (boolean) $this->getMergeRange();
500 }
501
502 /**
503 * Is this cell the master (top left cell) in a merge range (that holds the actual data value)
504 *
505 * @return boolean
506 */
507 public function isMergeRangeValueCell()
508 {
509 if ($mergeRange = $this->getMergeRange()) {
510 $mergeRange = PHPExcel_Cell::splitRange($mergeRange);
511 list($startCell) = $mergeRange[0];
512 if ($this->getCoordinate() === $startCell) {
513 return true;
514 }
515 }
516 return false;
517 }
518
519 /**
520 * If this cell is in a merge range, then return the range
521 *
522 * @return string
523 */
524 public function getMergeRange()
525 {
526 foreach ($this->getWorksheet()->getMergeCells() as $mergeRange) {
527 if ($this->isInRange($mergeRange)) {
528 return $mergeRange;
529 }
530 }
531 return false;
532 }
533
534 /**
535 * Get cell style
536 *
537 * @return PHPExcel_Style
538 */
539 public function getStyle()
540 {
541 return $this->getWorksheet()->getStyle($this->getCoordinate());
542 }
543
544 /**
545 * Re-bind parent
546 *
547 * @param PHPExcel_Worksheet $parent
548 * @return PHPExcel_Cell
549 */
550 public function rebindParent(PHPExcel_Worksheet $parent)
551 {
552 $this->parent = $parent->getCellCacheController();
553
554 return $this->notifyCacheController();
555 }
556
557 /**
558 * Is cell in a specific range?
559 *
560 * @param string $pRange Cell range (e.g. A1:A1)
561 * @return boolean
562 */
563 public function isInRange($pRange = 'A1:A1')
564 {
565 list($rangeStart, $rangeEnd) = self::rangeBoundaries($pRange);
566
567 // Translate properties
568 $myColumn = self::columnIndexFromString($this->getColumn());
569 $myRow = $this->getRow();
570
571 // Verify if cell is in range
572 return (($rangeStart[0] <= $myColumn) && ($rangeEnd[0] >= $myColumn) &&
573 ($rangeStart[1] <= $myRow) && ($rangeEnd[1] >= $myRow)
574 );
575 }
576
577 /**
578 * Coordinate from string
579 *
580 * @param string $pCoordinateString
581 * @return array Array containing column and row (indexes 0 and 1)
582 * @throws PHPExcel_Exception
583 */
584 public static function coordinateFromString($pCoordinateString = 'A1')
585 {
586 if (preg_match("/^([$]?[A-Z]{1,3})([$]?\d{1,7})$/", $pCoordinateString, $matches)) {
587 return array($matches[1],$matches[2]);
588 } elseif ((strpos($pCoordinateString, ':') !== false) || (strpos($pCoordinateString, ',') !== false)) {
589 throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
590 } elseif ($pCoordinateString == '') {
591 throw new PHPExcel_Exception('Cell coordinate can not be zero-length string');
592 }
593
594 throw new PHPExcel_Exception('Invalid cell coordinate '.$pCoordinateString);
595 }
596
597 /**
598 * Make string row, column or cell coordinate absolute
599 *
600 * @param string $pCoordinateString e.g. 'A' or '1' or 'A1'
601 * Note that this value can be a row or column reference as well as a cell reference
602 * @return string Absolute coordinate e.g. '$A' or '$1' or '$A$1'
603 * @throws PHPExcel_Exception
604 */
605 public static function absoluteReference($pCoordinateString = 'A1')
606 {
607 if (strpos($pCoordinateString, ':') === false && strpos($pCoordinateString, ',') === false) {
608 // Split out any worksheet name from the reference
609 $worksheet = '';
610 $cellAddress = explode('!', $pCoordinateString);
611 if (count($cellAddress) > 1) {
612 list($worksheet, $pCoordinateString) = $cellAddress;
613 }
614 if ($worksheet > '') {
615 $worksheet .= '!';
616 }
617
618 // Create absolute coordinate
619 if (ctype_digit($pCoordinateString)) {
620 return $worksheet . '$' . $pCoordinateString;
621 } elseif (ctype_alpha($pCoordinateString)) {
622 return $worksheet . '$' . strtoupper($pCoordinateString);
623 }
624 return $worksheet . self::absoluteCoordinate($pCoordinateString);
625 }
626
627 throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
628 }
629
630 /**
631 * Make string coordinate absolute
632 *
633 * @param string $pCoordinateString e.g. 'A1'
634 * @return string Absolute coordinate e.g. '$A$1'
635 * @throws PHPExcel_Exception
636 */
637 public static function absoluteCoordinate($pCoordinateString = 'A1')
638 {
639 if (strpos($pCoordinateString, ':') === false && strpos($pCoordinateString, ',') === false) {
640 // Split out any worksheet name from the coordinate
641 $worksheet = '';
642 $cellAddress = explode('!', $pCoordinateString);
643 if (count($cellAddress) > 1) {
644 list($worksheet, $pCoordinateString) = $cellAddress;
645 }
646 if ($worksheet > '') {
647 $worksheet .= '!';
648 }
649
650 // Create absolute coordinate
651 list($column, $row) = self::coordinateFromString($pCoordinateString);
652 $column = ltrim($column, '$');
653 $row = ltrim($row, '$');
654 return $worksheet . '$' . $column . '$' . $row;
655 }
656
657 throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
658 }
659
660 /**
661 * Split range into coordinate strings
662 *
663 * @param string $pRange e.g. 'B4:D9' or 'B4:D9,H2:O11' or 'B4'
664 * @return array Array containg one or more arrays containing one or two coordinate strings
665 * e.g. array('B4','D9') or array(array('B4','D9'),array('H2','O11'))
666 * or array('B4')
667 */
668 public static function splitRange($pRange = 'A1:A1')
669 {
670 // Ensure $pRange is a valid range
671 if (empty($pRange)) {
672 $pRange = self::DEFAULT_RANGE;
673 }
674
675 $exploded = explode(',', $pRange);
676 $counter = count($exploded);
677 for ($i = 0; $i < $counter; ++$i) {
678 $exploded[$i] = explode(':', $exploded[$i]);
679 }
680 return $exploded;
681 }
682
683 /**
684 * Build range from coordinate strings
685 *
686 * @param array $pRange Array containg one or more arrays containing one or two coordinate strings
687 * @return string String representation of $pRange
688 * @throws PHPExcel_Exception
689 */
690 public static function buildRange($pRange)
691 {
692 // Verify range
693 if (!is_array($pRange) || empty($pRange) || !is_array($pRange[0])) {
694 throw new PHPExcel_Exception('Range does not contain any information');
695 }
696
697 // Build range
698 $imploded = array();
699 $counter = count($pRange);
700 for ($i = 0; $i < $counter; ++$i) {
701 $pRange[$i] = implode(':', $pRange[$i]);
702 }
703 $imploded = implode(',', $pRange);
704
705 return $imploded;
706 }
707
708 /**
709 * Calculate range boundaries
710 *
711 * @param string $pRange Cell range (e.g. A1:A1)
712 * @return array Range coordinates array(Start Cell, End Cell)
713 * where Start Cell and End Cell are arrays (Column Number, Row Number)
714 */
715 public static function rangeBoundaries($pRange = 'A1:A1')
716 {
717 // Ensure $pRange is a valid range
718 if (empty($pRange)) {
719 $pRange = self::DEFAULT_RANGE;
720 }
721
722 // Uppercase coordinate
723 $pRange = strtoupper($pRange);
724
725 // Extract range
726 if (strpos($pRange, ':') === false) {
727 $rangeA = $rangeB = $pRange;
728 } else {
729 list($rangeA, $rangeB) = explode(':', $pRange);
730 }
731
732 // Calculate range outer borders
733 $rangeStart = self::coordinateFromString($rangeA);
734 $rangeEnd = self::coordinateFromString($rangeB);
735
736 // Translate column into index
737 $rangeStart[0] = self::columnIndexFromString($rangeStart[0]);
738 $rangeEnd[0] = self::columnIndexFromString($rangeEnd[0]);
739
740 return array($rangeStart, $rangeEnd);
741 }
742
743 /**
744 * Calculate range dimension
745 *
746 * @param string $pRange Cell range (e.g. A1:A1)
747 * @return array Range dimension (width, height)
748 */
749 public static function rangeDimension($pRange = 'A1:A1')
750 {
751 // Calculate range outer borders
752 list($rangeStart, $rangeEnd) = self::rangeBoundaries($pRange);
753
754 return array( ($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1) );
755 }
756
757 /**
758 * Calculate range boundaries
759 *
760 * @param string $pRange Cell range (e.g. A1:A1)
761 * @return array Range coordinates array(Start Cell, End Cell)
762 * where Start Cell and End Cell are arrays (Column ID, Row Number)
763 */
764 public static function getRangeBoundaries($pRange = 'A1:A1')
765 {
766 // Ensure $pRange is a valid range
767 if (empty($pRange)) {
768 $pRange = self::DEFAULT_RANGE;
769 }
770
771 // Uppercase coordinate
772 $pRange = strtoupper($pRange);
773
774 // Extract range
775 if (strpos($pRange, ':') === false) {
776 $rangeA = $rangeB = $pRange;
777 } else {
778 list($rangeA, $rangeB) = explode(':', $pRange);
779 }
780
781 return array( self::coordinateFromString($rangeA), self::coordinateFromString($rangeB));
782 }
783
784 /**
785 * Column index from string
786 *
787 * @param string $pString
788 * @return int Column index (base 1 !!!)
789 */
790 public static function columnIndexFromString($pString = 'A')
791 {
792 // Using a lookup cache adds a slight memory overhead, but boosts speed
793 // caching using a static within the method is faster than a class static,
794 // though it's additional memory overhead
795 static $_indexCache = array();
796
797 if (isset($_indexCache[$pString])) {
798 return $_indexCache[$pString];
799 }
800 // It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array rather than use ord()
801 // and make it case insensitive to get rid of the strtoupper() as well. Because it's a static, there's no significant
802 // memory overhead either
803 static $_columnLookup = array(
804 '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,
805 '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,
806 '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,
807 '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
808 );
809
810 // We also use the language construct isset() rather than the more costly strlen() function to match the length of $pString
811 // for improved performance
812 if (isset($pString{0})) {
813 if (!isset($pString{1})) {
814 $_indexCache[$pString] = $_columnLookup[$pString];
815 return $_indexCache[$pString];
816 } elseif (!isset($pString{2})) {
817 $_indexCache[$pString] = $_columnLookup[$pString{0}] * 26 + $_columnLookup[$pString{1}];
818 return $_indexCache[$pString];
819 } elseif (!isset($pString{3})) {
820 $_indexCache[$pString] = $_columnLookup[$pString{0}] * 676 + $_columnLookup[$pString{1}] * 26 + $_columnLookup[$pString{2}];
821 return $_indexCache[$pString];
822 }
823 }
824 throw new PHPExcel_Exception("Column string index can not be " . ((isset($pString{0})) ? "longer than 3 characters" : "empty"));
825 }
826
827 /**
828 * String from columnindex
829 *
830 * @param int $pColumnIndex Column index (base 0 !!!)
831 * @return string
832 */
833 public static function stringFromColumnIndex($pColumnIndex = 0)
834 {
835 // Using a lookup cache adds a slight memory overhead, but boosts speed
836 // caching using a static within the method is faster than a class static,
837 // though it's additional memory overhead
838 static $_indexCache = array();
839
840 if (!isset($_indexCache[$pColumnIndex])) {
841 // Determine column string
842 if ($pColumnIndex < 26) {
843 $_indexCache[$pColumnIndex] = chr(65 + $pColumnIndex);
844 } elseif ($pColumnIndex < 702) {
845 $_indexCache[$pColumnIndex] = chr(64 + ($pColumnIndex / 26)) .
846 chr(65 + $pColumnIndex % 26);
847 } else {
848 $_indexCache[$pColumnIndex] = chr(64 + (($pColumnIndex - 26) / 676)) .
849 chr(65 + ((($pColumnIndex - 26) % 676) / 26)) .
850 chr(65 + $pColumnIndex % 26);
851 }
852 }
853 return $_indexCache[$pColumnIndex];
854 }
855
856 /**
857 * Extract all cell references in range
858 *
859 * @param string $pRange Range (e.g. A1 or A1:C10 or A1:E10 A20:E25)
860 * @return array Array containing single cell references
861 */
862 public static function extractAllCellReferencesInRange($pRange = 'A1')
863 {
864 // Returnvalue
865 $returnValue = array();
866
867 // Explode spaces
868 $cellBlocks = explode(' ', str_replace('$', '', strtoupper($pRange)));
869 foreach ($cellBlocks as $cellBlock) {
870 // Single cell?
871 if (strpos($cellBlock, ':') === false && strpos($cellBlock, ',') === false) {
872 $returnValue[] = $cellBlock;
873 continue;
874 }
875
876 // Range...
877 $ranges = self::splitRange($cellBlock);
878 foreach ($ranges as $range) {
879 // Single cell?
880 if (!isset($range[1])) {
881 $returnValue[] = $range[0];
882 continue;
883 }
884
885 // Range...
886 list($rangeStart, $rangeEnd) = $range;
887 sscanf($rangeStart, '%[A-Z]%d', $startCol, $startRow);
888 sscanf($rangeEnd, '%[A-Z]%d', $endCol, $endRow);
889 ++$endCol;
890
891 // Current data
892 $currentCol = $startCol;
893 $currentRow = $startRow;
894
895 // Loop cells
896 while ($currentCol != $endCol) {
897 while ($currentRow <= $endRow) {
898 $returnValue[] = $currentCol.$currentRow;
899 ++$currentRow;
900 }
901 ++$currentCol;
902 $currentRow = $startRow;
903 }
904 }
905 }
906
907 // Sort the result by column and row
908 $sortKeys = array();
909 foreach (array_unique($returnValue) as $coord) {
910 sscanf($coord, '%[A-Z]%d', $column, $row);
911 $sortKeys[sprintf('%3s%09d', $column, $row)] = $coord;
912 }
913 ksort($sortKeys);
914
915 // Return value
916 return array_values($sortKeys);
917 }
918
919 /**
920 * Compare 2 cells
921 *
922 * @param PHPExcel_Cell $a Cell a
923 * @param PHPExcel_Cell $b Cell b
924 * @return int Result of comparison (always -1 or 1, never zero!)
925 */
926 public static function compareCells(PHPExcel_Cell $a, PHPExcel_Cell $b)
927 {
928 if ($a->getRow() < $b->getRow()) {
929 return -1;
930 } elseif ($a->getRow() > $b->getRow()) {
931 return 1;
932 } elseif (self::columnIndexFromString($a->getColumn()) < self::columnIndexFromString($b->getColumn())) {
933 return -1;
934 } else {
935 return 1;
936 }
937 }
938
939 /**
940 * Get value binder to use
941 *
942 * @return PHPExcel_Cell_IValueBinder
943 */
944 public static function getValueBinder()
945 {
946 if (self::$valueBinder === null) {
947 self::$valueBinder = new PHPExcel_Cell_DefaultValueBinder();
948 }
949
950 return self::$valueBinder;
951 }
952
953 /**
954 * Set value binder to use
955 *
956 * @param PHPExcel_Cell_IValueBinder $binder
957 * @throws PHPExcel_Exception
958 */
959 public static function setValueBinder(PHPExcel_Cell_IValueBinder $binder = null)
960 {
961 if ($binder === null) {
962 throw new PHPExcel_Exception("A PHPExcel_Cell_IValueBinder is required for PHPExcel to function correctly.");
963 }
964
965 self::$valueBinder = $binder;
966 }
967
968 /**
969 * Implement PHP __clone to create a deep clone, not just a shallow copy.
970 */
971 public function __clone()
972 {
973 $vars = get_object_vars($this);
974 foreach ($vars as $key => $value) {
975 if ((is_object($value)) && ($key != 'parent')) {
976 $this->$key = clone $value;
977 } else {
978 $this->$key = $value;
979 }
980 }
981 }
982
983 /**
984 * Get index to cellXf
985 *
986 * @return int
987 */
988 public function getXfIndex()
989 {
990 return $this->xfIndex;
991 }
992
993 /**
994 * Set index to cellXf
995 *
996 * @param int $pValue
997 * @return PHPExcel_Cell
998 */
999 public function setXfIndex($pValue = 0)
1000 {
1001 $this->xfIndex = $pValue;
1002
1003 return $this->notifyCacheController();
1004 }
1005
1006 /**
1007 * @deprecated Since version 1.7.8 for planned changes to cell for array formula handling
1008 */
1009 public function setFormulaAttributes($pAttributes)
1010 {
1011 $this->formulaAttributes = $pAttributes;
1012 return $this;
1013 }
1014
1015 /**
1016 * @deprecated Since version 1.7.8 for planned changes to cell for array formula handling
1017 */
1018 public function getFormulaAttributes()
1019 {
1020 return $this->formulaAttributes;
1021 }
1022
1023 /**
1024 * Convert to string
1025 *
1026 * @return string
1027 */
1028 public function __toString()
1029 {
1030 return (string) $this->getValue();
1031 }
1032 }
1033