5 * Copyright (c) 2006 - 2012 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 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25 * @version ##VERSION##, ##DATE##
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 - 2012 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
);
131 * Disconnect all worksheets from this PHPExcel workbook object,
132 * typically so that the PHPExcel object can be unset
135 public function disconnectWorksheets() {
136 foreach($this->_workSheetCollection
as $k => &$worksheet) {
137 $worksheet->disconnectCells();
138 $this->_workSheetCollection
[$k] = null;
141 $this->_workSheetCollection
= array();
147 * @return PHPExcel_DocumentProperties
149 public function getProperties()
151 return $this->_properties
;
157 * @param PHPExcel_DocumentProperties $pValue
159 public function setProperties(PHPExcel_DocumentProperties
$pValue)
161 $this->_properties
= $pValue;
167 * @return PHPExcel_DocumentSecurity
169 public function getSecurity()
171 return $this->_security
;
177 * @param PHPExcel_DocumentSecurity $pValue
179 public function setSecurity(PHPExcel_DocumentSecurity
$pValue)
181 $this->_security
= $pValue;
187 * @return PHPExcel_Worksheet
189 public function getActiveSheet()
191 return $this->_workSheetCollection
[$this->_activeSheetIndex
];
195 * Create sheet and add it to this workbook
197 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
198 * @return PHPExcel_Worksheet
201 public function createSheet($iSheetIndex = NULL)
203 $newSheet = new PHPExcel_Worksheet($this);
204 $this->addSheet($newSheet, $iSheetIndex);
209 * Chech if a sheet with a specified name already exists
211 * @param string $pSheetName Name of the worksheet to check
214 public function sheetNameExists($pSheetName)
216 return ($this->getSheetByName($pSheetName) !== NULL);
222 * @param PHPExcel_Worksheet $pSheet
223 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
224 * @return PHPExcel_Worksheet
227 public function addSheet(PHPExcel_Worksheet
$pSheet, $iSheetIndex = NULL)
229 if ($this->sheetNameExists($pSheet->getTitle())) {
230 throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename this worksheet first.");
233 if($iSheetIndex === NULL) {
234 if ($this->_activeSheetIndex
< 0) {
235 $this->_activeSheetIndex
= 0;
237 $this->_workSheetCollection
[] = $pSheet;
239 // Insert the sheet at the requested index
241 $this->_workSheetCollection
,
247 // Adjust active sheet index if necessary
248 if ($this->_activeSheetIndex
>= $iSheetIndex) {
249 ++
$this->_activeSheetIndex
;
256 * Remove sheet by index
258 * @param int $pIndex Active sheet index
261 public function removeSheetByIndex($pIndex = 0)
263 if ($pIndex > count($this->_workSheetCollection
) - 1) {
264 throw new Exception("Sheet index is out of bounds.");
266 array_splice($this->_workSheetCollection
, $pIndex, 1);
268 // Adjust active sheet index if necessary
269 if (($this->_activeSheetIndex
>= $pIndex) &&
270 ($pIndex > count($this->_workSheetCollection
) - 1)) {
271 --$this->_activeSheetIndex
;
279 * @param int $pIndex Sheet index
280 * @return PHPExcel_Worksheet
283 public function getSheet($pIndex = 0)
285 if ($pIndex > count($this->_workSheetCollection
) - 1) {
286 throw new Exception("Sheet index is out of bounds.");
288 return $this->_workSheetCollection
[$pIndex];
295 * @return PHPExcel_Worksheet[]
297 public function getAllSheets()
299 return $this->_workSheetCollection
;
305 * @param string $pName Sheet name
306 * @return PHPExcel_Worksheet
309 public function getSheetByName($pName = '')
311 $worksheetCount = count($this->_workSheetCollection
);
312 for ($i = 0; $i < $worksheetCount; ++
$i) {
313 if ($this->_workSheetCollection
[$i]->getTitle() == $pName) {
314 return $this->_workSheetCollection
[$i];
322 * Get index for sheet
324 * @param PHPExcel_Worksheet $pSheet
325 * @return Sheet index
328 public function getIndex(PHPExcel_Worksheet
$pSheet)
330 foreach ($this->_workSheetCollection
as $key => $value) {
331 if ($value->getHashCode() == $pSheet->getHashCode()) {
338 * Set index for sheet by sheet name.
340 * @param string $sheetName Sheet name to modify index for
341 * @param int $newIndex New index for the sheet
342 * @return New sheet index
345 public function setIndexByName($sheetName, $newIndex)
347 $oldIndex = $this->getIndex($this->getSheetByName($sheetName));
348 $pSheet = array_splice(
349 $this->_workSheetCollection
,
354 $this->_workSheetCollection
,
367 public function getSheetCount()
369 return count($this->_workSheetCollection
);
373 * Get active sheet index
375 * @return int Active sheet index
377 public function getActiveSheetIndex()
379 return $this->_activeSheetIndex
;
383 * Set active sheet index
385 * @param int $pIndex Active sheet index
387 * @return PHPExcel_Worksheet
389 public function setActiveSheetIndex($pIndex = 0)
391 if ($pIndex > count($this->_workSheetCollection
) - 1) {
392 throw new Exception("Active sheet index is out of bounds.");
394 $this->_activeSheetIndex
= $pIndex;
396 return $this->getActiveSheet();
400 * Set active sheet index by name
402 * @param string $pValue Sheet title
403 * @return PHPExcel_Worksheet
406 public function setActiveSheetIndexByName($pValue = '')
408 if (($worksheet = $this->getSheetByName($pValue)) instanceof PHPExcel_Worksheet
) {
409 $this->setActiveSheetIndex($this->getIndex($worksheet));
413 throw new Exception('Workbook does not contain sheet:' . $pValue);
421 public function getSheetNames()
423 $returnValue = array();
424 $worksheetCount = $this->getSheetCount();
425 for ($i = 0; $i < $worksheetCount; ++
$i) {
426 $returnValue[] = $this->getSheet($i)->getTitle();
435 * @param PHPExcel_Worksheet $pSheet External sheet to add
436 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
438 * @return PHPExcel_Worksheet
440 public function addExternalSheet(PHPExcel_Worksheet
$pSheet, $iSheetIndex = null) {
441 if ($this->sheetNameExists($pSheet->getTitle())) {
442 throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
445 // count how many cellXfs there are in this workbook currently, we will need this below
446 $countCellXfs = count($this->_cellXfCollection
);
448 // copy all the shared cellXfs from the external workbook and append them to the current
449 foreach ($pSheet->getParent()->getCellXfCollection() as $cellXf) {
450 $this->addCellXf(clone $cellXf);
453 // move sheet to this workbook
454 $pSheet->rebindParent($this);
456 // update the cellXfs
457 foreach ($pSheet->getCellCollection(false) as $cellID) {
458 $cell = $pSheet->getCell($cellID);
459 $cell->setXfIndex( $cell->getXfIndex() +
$countCellXfs );
462 return $this->addSheet($pSheet, $iSheetIndex);
468 * @return PHPExcel_NamedRange[]
470 public function getNamedRanges() {
471 return $this->_namedRanges
;
477 * @param PHPExcel_NamedRange $namedRange
480 public function addNamedRange(PHPExcel_NamedRange
$namedRange) {
481 if ($namedRange->getScope() == null) {
483 $this->_namedRanges
[$namedRange->getName()] = $namedRange;
486 $this->_namedRanges
[$namedRange->getScope()->getTitle().'!'.$namedRange->getName()] = $namedRange;
494 * @param string $namedRange
495 * @param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
496 * @return PHPExcel_NamedRange|null
498 public function getNamedRange($namedRange, PHPExcel_Worksheet
$pSheet = null) {
501 if ($namedRange != '' && ($namedRange !== NULL)) {
502 // first look for global defined name
503 if (isset($this->_namedRanges
[$namedRange])) {
504 $returnValue = $this->_namedRanges
[$namedRange];
507 // then look for local defined name (has priority over global defined name if both names exist)
508 if (($pSheet !== NULL) && isset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange])) {
509 $returnValue = $this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange];
519 * @param string $namedRange
520 * @param PHPExcel_Worksheet|null $pSheet Scope: use null for global scope.
523 public function removeNamedRange($namedRange, PHPExcel_Worksheet
$pSheet = null) {
524 if ($pSheet === NULL) {
525 if (isset($this->_namedRanges
[$namedRange])) {
526 unset($this->_namedRanges
[$namedRange]);
529 if (isset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange])) {
530 unset($this->_namedRanges
[$pSheet->getTitle() . '!' . $namedRange]);
537 * Get worksheet iterator
539 * @return PHPExcel_WorksheetIterator
541 public function getWorksheetIterator() {
542 return new PHPExcel_WorksheetIterator($this);
546 * Copy workbook (!= clone!)
550 public function copy() {
551 $copied = clone $this;
553 $worksheetCount = count($this->_workSheetCollection
);
554 for ($i = 0; $i < $worksheetCount; ++
$i) {
555 $this->_workSheetCollection
[$i] = $this->_workSheetCollection
[$i]->copy();
556 $this->_workSheetCollection
[$i]->rebindParent($this);
563 * Implement PHP __clone to create a deep clone, not just a shallow copy.
565 public function __clone() {
566 foreach($this as $key => $val) {
567 if (is_object($val) ||
(is_array($val))) {
568 $this->{$key} = unserialize(serialize($val));
574 * Get the workbook collection of cellXfs
576 * @return PHPExcel_Style[]
578 public function getCellXfCollection()
580 return $this->_cellXfCollection
;
584 * Get cellXf by index
587 * @return PHPExcel_Style
589 public function getCellXfByIndex($pIndex = 0)
591 return $this->_cellXfCollection
[$pIndex];
595 * Get cellXf by hash code
597 * @param string $pValue
598 * @return PHPExcel_Style|false
600 public function getCellXfByHashCode($pValue = '')
602 foreach ($this->_cellXfCollection
as $cellXf) {
603 if ($cellXf->getHashCode() == $pValue) {
613 * @return PHPExcel_Style
616 public function getDefaultStyle()
618 if (isset($this->_cellXfCollection
[0])) {
619 return $this->_cellXfCollection
[0];
621 throw new Exception('No default style found for this workbook');
625 * Add a cellXf to the workbook
627 * @param PHPExcel_Style $style
629 public function addCellXf(PHPExcel_Style
$style)
631 $this->_cellXfCollection
[] = $style;
632 $style->setIndex(count($this->_cellXfCollection
) - 1);
636 * Remove cellXf by index. It is ensured that all cells get their xf index updated.
638 * @param int $pIndex Index to cellXf
641 public function removeCellXfByIndex($pIndex = 0)
643 if ($pIndex > count($this->_cellXfCollection
) - 1) {
644 throw new Exception("CellXf index is out of bounds.");
646 // first remove the cellXf
647 array_splice($this->_cellXfCollection
, $pIndex, 1);
649 // then update cellXf indexes for cells
650 foreach ($this->_workSheetCollection
as $worksheet) {
651 foreach ($worksheet->getCellCollection(false) as $cellID) {
652 $cell = $worksheet->getCell($cellID);
653 $xfIndex = $cell->getXfIndex();
654 if ($xfIndex > $pIndex ) {
655 // decrease xf index by 1
656 $cell->setXfIndex($xfIndex - 1);
657 } else if ($xfIndex == $pIndex) {
658 // set to default xf index 0
659 $cell->setXfIndex(0);
667 * Get the cellXf supervisor
669 * @return PHPExcel_Style
671 public function getCellXfSupervisor()
673 return $this->_cellXfSupervisor
;
677 * Get the workbook collection of cellStyleXfs
679 * @return PHPExcel_Style[]
681 public function getCellStyleXfCollection()
683 return $this->_cellStyleXfCollection
;
687 * Get cellStyleXf by index
690 * @return PHPExcel_Style
692 public function getCellStyleXfByIndex($pIndex = 0)
694 return $this->_cellStyleXfCollection
[$pIndex];
698 * Get cellStyleXf by hash code
700 * @param string $pValue
701 * @return PHPExcel_Style|false
703 public function getCellStyleXfByHashCode($pValue = '')
705 foreach ($this->_cellXfStyleCollection
as $cellStyleXf) {
706 if ($cellStyleXf->getHashCode() == $pValue) {
714 * Add a cellStyleXf to the workbook
716 * @param PHPExcel_Style $pStyle
718 public function addCellStyleXf(PHPExcel_Style
$pStyle)
720 $this->_cellStyleXfCollection
[] = $pStyle;
721 $pStyle->setIndex(count($this->_cellStyleXfCollection
) - 1);
725 * Remove cellStyleXf by index
730 public function removeCellStyleXfByIndex($pIndex = 0)
732 if ($pIndex > count($this->_cellStyleXfCollection
) - 1) {
733 throw new Exception("CellStyleXf index is out of bounds.");
735 array_splice($this->_cellStyleXfCollection
, $pIndex, 1);
740 * Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
741 * and columns in the workbook
743 public function garbageCollect()
745 // how many references are there to each cellXf ?
746 $countReferencesCellXf = array();
747 foreach ($this->_cellXfCollection
as $index => $cellXf) {
748 $countReferencesCellXf[$index] = 0;
751 foreach ($this->getWorksheetIterator() as $sheet) {
754 foreach ($sheet->getCellCollection(false) as $cellID) {
755 $cell = $sheet->getCell($cellID);
756 ++
$countReferencesCellXf[$cell->getXfIndex()];
759 // from row dimensions
760 foreach ($sheet->getRowDimensions() as $rowDimension) {
761 if ($rowDimension->getXfIndex() !== null) {
762 ++
$countReferencesCellXf[$rowDimension->getXfIndex()];
766 // from column dimensions
767 foreach ($sheet->getColumnDimensions() as $columnDimension) {
768 ++
$countReferencesCellXf[$columnDimension->getXfIndex()];
772 // remove cellXfs without references and create mapping so we can update xfIndex
773 // for all cells and columns
774 $countNeededCellXfs = 0;
775 foreach ($this->_cellXfCollection
as $index => $cellXf) {
776 if ($countReferencesCellXf[$index] > 0 ||
$index == 0) { // we must never remove the first cellXf
777 ++
$countNeededCellXfs;
779 unset($this->_cellXfCollection
[$index]);
781 $map[$index] = $countNeededCellXfs - 1;
783 $this->_cellXfCollection
= array_values($this->_cellXfCollection
);
785 // update the index for all cellXfs
786 foreach ($this->_cellXfCollection
as $i => $cellXf) {
787 $cellXf->setIndex($i);
790 // make sure there is always at least one cellXf (there should be)
791 if (empty($this->_cellXfCollection
)) {
792 $this->_cellXfCollection
[] = new PHPExcel_Style();
795 // update the xfIndex for all cells, row dimensions, column dimensions
796 foreach ($this->getWorksheetIterator() as $sheet) {
799 foreach ($sheet->getCellCollection(false) as $cellID) {
800 $cell = $sheet->getCell($cellID);
801 $cell->setXfIndex( $map[$cell->getXfIndex()] );
804 // for all row dimensions
805 foreach ($sheet->getRowDimensions() as $rowDimension) {
806 if ($rowDimension->getXfIndex() !== null) {
807 $rowDimension->setXfIndex( $map[$rowDimension->getXfIndex()] );
811 // for all column dimensions
812 foreach ($sheet->getColumnDimensions() as $columnDimension) {
813 $columnDimension->setXfIndex( $map[$columnDimension->getXfIndex()] );
817 // also do garbage collection for all the sheets
818 foreach ($this->getWorksheetIterator() as $sheet) {
819 $sheet->garbageCollect();