5 * Copyright (c) 2006 - 2011 PHPExcel
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.
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.
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
23 * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25 * @version 1.7.6, 2011-02-27
29 /** PHPExcel root directory */
30 if (!defined('PHPEXCEL_ROOT')) {
31 define('PHPEXCEL_ROOT', dirname(__FILE__
) . '/');
32 require(PHPEXCEL_ROOT
. 'PHPExcel/Autoloader.php');
41 * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
48 * @var PHPExcel_DocumentProperties
55 * @var PHPExcel_DocumentSecurity
60 * Collection of Worksheet objects
62 * @var PHPExcel_Worksheet[]
64 private $_workSheetCollection = array();
71 private $_activeSheetIndex = 0;
76 * @var PHPExcel_NamedRange[]
78 private $_namedRanges = array();
85 private $_cellXfSupervisor;
90 * @var PHPExcel_Style[]
92 private $_cellXfCollection = array();
95 * CellStyleXf collection
97 * @var PHPExcel_Style[]
99 private $_cellStyleXfCollection = array();
102 * Create a new PHPExcel with one Worksheet
104 public function __construct()
106 // Initialise worksheet collection and add one worksheet
107 $this->_workSheetCollection
= array();
108 $this->_workSheetCollection
[] = new PHPExcel_Worksheet($this);
109 $this->_activeSheetIndex
= 0;
111 // Create document properties
112 $this->_properties
= new PHPExcel_DocumentProperties();
114 // Create document security
115 $this->_security
= new PHPExcel_DocumentSecurity();
118 $this->_namedRanges
= array();
120 // Create the cellXf supervisor
121 $this->_cellXfSupervisor
= new PHPExcel_Style(true);
122 $this->_cellXfSupervisor
->bindParent($this);
124 // Create the default style
125 $this->addCellXf(new PHPExcel_Style
);
126 $this->addCellStyleXf(new PHPExcel_Style
);
130 public function disconnectWorksheets() {
131 foreach($this->_workSheetCollection
as $k => &$worksheet) {
132 $worksheet->disconnectCells();
133 $this->_workSheetCollection
[$k] = null;
136 $this->_workSheetCollection
= array();
142 * @return PHPExcel_DocumentProperties
144 public function getProperties()
146 return $this->_properties
;
152 * @param PHPExcel_DocumentProperties $pValue
154 public function setProperties(PHPExcel_DocumentProperties
$pValue)
156 $this->_properties
= $pValue;
162 * @return PHPExcel_DocumentSecurity
164 public function getSecurity()
166 return $this->_security
;
172 * @param PHPExcel_DocumentSecurity $pValue
174 public function setSecurity(PHPExcel_DocumentSecurity
$pValue)
176 $this->_security
= $pValue;
182 * @return PHPExcel_Worksheet
184 public function getActiveSheet()
186 return $this->_workSheetCollection
[$this->_activeSheetIndex
];
190 * Create sheet and add it to this workbook
192 * @return PHPExcel_Worksheet
194 public function createSheet($iSheetIndex = null)
196 $newSheet = new PHPExcel_Worksheet($this);
197 $this->addSheet($newSheet, $iSheetIndex);
204 * @param PHPExcel_Worksheet $pSheet
205 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
206 * @return PHPExcel_Worksheet
209 public function addSheet(PHPExcel_Worksheet
$pSheet = null, $iSheetIndex = null)
211 if(is_null($iSheetIndex))
213 $this->_workSheetCollection
[] = $pSheet;
217 // Insert the sheet at the requested index
219 $this->_workSheetCollection
,
225 // Adjust active sheet index if necessary
226 if ($this->_activeSheetIndex
>= $iSheetIndex) {
227 ++
$this->_activeSheetIndex
;
235 * Remove sheet by index
237 * @param int $pIndex Active sheet index
240 public function removeSheetByIndex($pIndex = 0)
242 if ($pIndex > count($this->_workSheetCollection
) - 1) {
243 throw new Exception("Sheet index is out of bounds.");
245 array_splice($this->_workSheetCollection
, $pIndex, 1);
252 * @param int $pIndex Sheet index
253 * @return PHPExcel_Worksheet
256 public function getSheet($pIndex = 0)
258 if ($pIndex > count($this->_workSheetCollection
) - 1) {
259 throw new Exception("Sheet index is out of bounds.");
261 return $this->_workSheetCollection
[$pIndex];
268 * @return PHPExcel_Worksheet[]
270 public function getAllSheets()
272 return $this->_workSheetCollection
;
278 * @param string $pName Sheet name
279 * @return PHPExcel_Worksheet
282 public function getSheetByName($pName = '')
284 $worksheetCount = count($this->_workSheetCollection
);
285 for ($i = 0; $i < $worksheetCount; ++
$i) {
286 if ($this->_workSheetCollection
[$i]->getTitle() == $pName) {
287 return $this->_workSheetCollection
[$i];
295 * Get index for sheet
297 * @param PHPExcel_Worksheet $pSheet
298 * @return Sheet index
301 public function getIndex(PHPExcel_Worksheet
$pSheet)
303 foreach ($this->_workSheetCollection
as $key => $value) {
304 if ($value->getHashCode() == $pSheet->getHashCode()) {
311 * Set index for sheet by sheet name.
313 * @param string $sheetName Sheet name to modify index for
314 * @param int $newIndex New index for the sheet
315 * @return New sheet index
318 public function setIndexByName($sheetName, $newIndex)
320 $oldIndex = $this->getIndex($this->getSheetByName($sheetName));
321 $pSheet = array_splice(
322 $this->_workSheetCollection
,
327 $this->_workSheetCollection
,
340 public function getSheetCount()
342 return count($this->_workSheetCollection
);
346 * Get active sheet index
348 * @return int Active sheet index
350 public function getActiveSheetIndex()
352 return $this->_activeSheetIndex
;
356 * Set active sheet index
358 * @param int $pIndex Active sheet index
360 * @return PHPExcel_Worksheet
362 public function setActiveSheetIndex($pIndex = 0)
364 if ($pIndex > count($this->_workSheetCollection
) - 1) {
365 throw new Exception("Active sheet index is out of bounds.");
367 $this->_activeSheetIndex
= $pIndex;
369 return $this->getActiveSheet();
373 * Set active sheet index by name
375 * @param string $pValue Sheet title
376 * @return PHPExcel_Worksheet
379 public function setActiveSheetIndexByName($pValue = '')
381 if (($worksheet = $this->getSheetByName($pValue)) instanceof PHPExcel_Worksheet
) {
382 $this->setActiveSheetIndex($worksheet->getParent()->getIndex($worksheet));
386 throw new Exception('Workbook does not contain sheet:' . $pValue);
394 public function getSheetNames()
396 $returnValue = array();
397 $worksheetCount = $this->getSheetCount();
398 for ($i = 0; $i < $worksheetCount; ++
$i) {
399 array_push($returnValue, $this->getSheet($i)->getTitle());
408 * @param PHPExcel_Worksheet $pSheet External sheet to add
409 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
411 * @return PHPExcel_Worksheet
413 public function addExternalSheet(PHPExcel_Worksheet
$pSheet, $iSheetIndex = null) {
414 if (!is_null($this->getSheetByName($pSheet->getTitle()))) {
415 throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
418 // count how many cellXfs there are in this workbook currently, we will need this below
419 $countCellXfs = count($this->_cellXfCollection
);
421 // copy all the shared cellXfs from the external workbook and append them to the current
422 foreach ($pSheet->getParent()->getCellXfCollection() as $cellXf) {
423 $this->addCellXf(clone $cellXf);
426 // move sheet to this workbook
427 $pSheet->rebindParent($this);
429 // update the cellXfs
430 foreach ($pSheet->getCellCollection(false) as $cellID) {
431 $cell = $pSheet->getCell($cellID);
432 $cell->setXfIndex( $cell->getXfIndex() +
$countCellXfs );
435 return $this->addSheet($pSheet, $iSheetIndex);
441 * @return PHPExcel_NamedRange[]
443 public function getNamedRanges() {
444 return $this->_namedRanges
;
450 * @param PHPExcel_NamedRange $namedRange
453 public function addNamedRange(PHPExcel_NamedRange
$namedRange) {
454 if ($namedRange->getScope() == null) {
456 $this->_namedRanges
[$namedRange->getName()] = $namedRange;
459 $this->_namedRanges
[$namedRange->getScope()->getTitle().'!'.$namedRange->getName()] = $namedRange;
467 * @param string $namedRange
468 * @param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
469 * @return PHPExcel_NamedRange|null
471 public function getNamedRange($namedRange, PHPExcel_Worksheet
$pSheet = null) {
474 if ($namedRange != '' && !is_null($namedRange)) {
475 // first look for global defined name
476 if (isset($this->_namedRanges
[$namedRange])) {
477 $returnValue = $this->_namedRanges
[$namedRange];
480 // then look for local defined name (has priority over global defined name if both names exist)
481 if (!is_null($pSheet) && isset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange])) {
482 $returnValue = $this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange];
492 * @param string $namedRange
493 * @param PHPExcel_Worksheet|null $pSheet. Scope. Use null for global scope.
496 public function removeNamedRange($namedRange, PHPExcel_Worksheet
$pSheet = null) {
497 if (is_null($pSheet)) {
498 if (isset($this->_namedRanges
[$namedRange])) {
499 unset($this->_namedRanges
[$namedRange]);
502 if (isset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange])) {
503 unset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange]);
510 * Get worksheet iterator
512 * @return PHPExcel_WorksheetIterator
514 public function getWorksheetIterator() {
515 return new PHPExcel_WorksheetIterator($this);
519 * Copy workbook (!= clone!)
523 public function copy() {
524 $copied = clone $this;
526 $worksheetCount = count($this->_workSheetCollection
);
527 for ($i = 0; $i < $worksheetCount; ++
$i) {
528 $this->_workSheetCollection
[$i] = $this->_workSheetCollection
[$i]->copy();
529 $this->_workSheetCollection
[$i]->rebindParent($this);
536 * Implement PHP __clone to create a deep clone, not just a shallow copy.
538 public function __clone() {
539 foreach($this as $key => $val) {
540 if (is_object($val) ||
(is_array($val))) {
541 $this->{$key} = unserialize(serialize($val));
547 * Get the workbook collection of cellXfs
549 * @return PHPExcel_Style[]
551 public function getCellXfCollection()
553 return $this->_cellXfCollection
;
557 * Get cellXf by index
560 * @return PHPExcel_Style
562 public function getCellXfByIndex($pIndex = 0)
564 return $this->_cellXfCollection
[$pIndex];
568 * Get cellXf by hash code
570 * @param string $pValue
571 * @return PHPExcel_Style|false
573 public function getCellXfByHashCode($pValue = '')
575 foreach ($this->_cellXfCollection
as $cellXf) {
576 if ($cellXf->getHashCode() == $pValue) {
586 * @return PHPExcel_Style
589 public function getDefaultStyle()
591 if (isset($this->_cellXfCollection
[0])) {
592 return $this->_cellXfCollection
[0];
594 throw new Exception('No default style found for this workbook');
598 * Add a cellXf to the workbook
600 * @param PHPExcel_Style
602 public function addCellXf(PHPExcel_Style
$style)
604 $this->_cellXfCollection
[] = $style;
605 $style->setIndex(count($this->_cellXfCollection
) - 1);
609 * Remove cellXf by index. It is ensured that all cells get their xf index updated.
611 * @param int $pIndex Index to cellXf
614 public function removeCellXfByIndex($pIndex = 0)
616 if ($pIndex > count($this->_cellXfCollection
) - 1) {
617 throw new Exception("CellXf index is out of bounds.");
619 // first remove the cellXf
620 array_splice($this->_cellXfCollection
, $pIndex, 1);
622 // then update cellXf indexes for cells
623 foreach ($this->_workSheetCollection
as $worksheet) {
624 foreach ($worksheet->getCellCollection(false) as $cellID) {
625 $cell = $worksheet->getCell($cellID);
626 $xfIndex = $cell->getXfIndex();
627 if ($xfIndex > $pIndex ) {
628 // decrease xf index by 1
629 $cell->setXfIndex($xfIndex - 1);
630 } else if ($xfIndex == $pIndex) {
631 // set to default xf index 0
632 $cell->setXfIndex(0);
640 * Get the cellXf supervisor
642 * @return PHPExcel_Style
644 public function getCellXfSupervisor()
646 return $this->_cellXfSupervisor
;
650 * Get the workbook collection of cellStyleXfs
652 * @return PHPExcel_Style[]
654 public function getCellStyleXfCollection()
656 return $this->_cellStyleXfCollection
;
660 * Get cellStyleXf by index
663 * @return PHPExcel_Style
665 public function getCellStyleXfByIndex($pIndex = 0)
667 return $this->_cellStyleXfCollection
[$pIndex];
671 * Get cellStyleXf by hash code
673 * @param string $pValue
674 * @return PHPExcel_Style|false
676 public function getCellStyleXfByHashCode($pValue = '')
678 foreach ($this->_cellXfStyleCollection
as $cellStyleXf) {
679 if ($cellStyleXf->getHashCode() == $pValue) {
687 * Add a cellStyleXf to the workbook
689 * @param PHPExcel_Style $pStyle
691 public function addCellStyleXf(PHPExcel_Style
$pStyle)
693 $this->_cellStyleXfCollection
[] = $pStyle;
694 $pStyle->setIndex(count($this->_cellStyleXfCollection
) - 1);
698 * Remove cellStyleXf by index
703 public function removeCellStyleXfByIndex($pIndex = 0)
705 if ($pIndex > count($this->_cellStyleXfCollection
) - 1) {
706 throw new Exception("CellStyleXf index is out of bounds.");
708 array_splice($this->_cellStyleXfCollection
, $pIndex, 1);
713 * Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
714 * and columns in the workbook
716 public function garbageCollect()
718 // how many references are there to each cellXf ?
719 $countReferencesCellXf = array();
720 foreach ($this->_cellXfCollection
as $index => $cellXf) {
721 $countReferencesCellXf[$index] = 0;
724 foreach ($this->getWorksheetIterator() as $sheet) {
727 foreach ($sheet->getCellCollection(false) as $cellID) {
728 $cell = $sheet->getCell($cellID);
729 ++
$countReferencesCellXf[$cell->getXfIndex()];
732 // from row dimensions
733 foreach ($sheet->getRowDimensions() as $rowDimension) {
734 if ($rowDimension->getXfIndex() !== null) {
735 ++
$countReferencesCellXf[$rowDimension->getXfIndex()];
739 // from column dimensions
740 foreach ($sheet->getColumnDimensions() as $columnDimension) {
741 ++
$countReferencesCellXf[$columnDimension->getXfIndex()];
745 // remove cellXfs without references and create mapping so we can update xfIndex
746 // for all cells and columns
747 $countNeededCellXfs = 0;
748 foreach ($this->_cellXfCollection
as $index => $cellXf) {
749 if ($countReferencesCellXf[$index] > 0 ||
$index == 0) { // we must never remove the first cellXf
750 ++
$countNeededCellXfs;
752 unset($this->_cellXfCollection
[$index]);
754 $map[$index] = $countNeededCellXfs - 1;
756 $this->_cellXfCollection
= array_values($this->_cellXfCollection
);
758 // update the index for all cellXfs
759 foreach ($this->_cellXfCollection
as $i => $cellXf) {
760 $cellXf->setIndex($i);
763 // make sure there is always at least one cellXf (there should be)
764 if (count($this->_cellXfCollection
) == 0) {
765 $this->_cellXfCollection
[] = new PHPExcel_Style();
768 // update the xfIndex for all cells, row dimensions, column dimensions
769 foreach ($this->getWorksheetIterator() as $sheet) {
772 foreach ($sheet->getCellCollection(false) as $cellID) {
773 $cell = $sheet->getCell($cellID);
774 $cell->setXfIndex( $map[$cell->getXfIndex()] );
777 // for all row dimensions
778 foreach ($sheet->getRowDimensions() as $rowDimension) {
779 if ($rowDimension->getXfIndex() !== null) {
780 $rowDimension->setXfIndex( $map[$rowDimension->getXfIndex()] );
784 // for all column dimensions
785 foreach ($sheet->getColumnDimensions() as $columnDimension) {
786 $columnDimension->setXfIndex( $map[$columnDimension->getXfIndex()] );
790 // also do garbage collection for all the sheets
791 foreach ($this->getWorksheetIterator() as $sheet) {
792 $sheet->garbageCollect();