PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.0.3
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.0.3
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.0.3, at vendor/phpoffice/phpexcel/Classes/PHPExcel/Cell.php

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