From 5e44fa2517f216498657fa67251c1df5f91b6f07 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 18 Jul 2012 21:12:02 +0100 Subject: [PATCH] Issue #5 - Refactor autoFilter range into an autofilter class in preparation for adding support for autofilter expressions --- Classes/PHPExcel/Reader/Excel2007.php | 4 +- Classes/PHPExcel/ReferenceHelper.php | 4 +- Classes/PHPExcel/Worksheet.php | 51 ++++----- Classes/PHPExcel/Worksheet/AutoFilter.php | 107 ++++++++++++++++++ .../PHPExcel/Writer/Excel2007/Workbook.php | 6 +- .../PHPExcel/Writer/Excel2007/Worksheet.php | 4 +- Classes/PHPExcel/Writer/Excel5.php | 24 ++-- Classes/PHPExcel/Writer/Excel5/Workbook.php | 24 ++-- Classes/PHPExcel/Writer/Excel5/Worksheet.php | 14 +-- 9 files changed, 172 insertions(+), 66 deletions(-) create mode 100644 Classes/PHPExcel/Worksheet/AutoFilter.php diff --git a/Classes/PHPExcel/Reader/Excel2007.php b/Classes/PHPExcel/Reader/Excel2007.php index 803b8bd..754cd20 100644 --- a/Classes/PHPExcel/Reader/Excel2007.php +++ b/Classes/PHPExcel/Reader/Excel2007.php @@ -1098,7 +1098,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } if ($xmlSheet && $xmlSheet->autoFilter && !$this->_readDataOnly) { - $docSheet->setAutoFilter((string) $xmlSheet->autoFilter["ref"]); + $docSheet->getAutoFilter()->setRange((string) $xmlSheet->autoFilter["ref"]); } if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->_readDataOnly) { @@ -1560,7 +1560,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader switch ((string)$definedName['name']) { case '_xlnm._FilterDatabase': - $docSheet->setAutoFilter($extractedRange); + $docSheet->getAutoFilter()->setRange($extractedRange); break; case '_xlnm.Print_Titles': diff --git a/Classes/PHPExcel/ReferenceHelper.php b/Classes/PHPExcel/ReferenceHelper.php index 8955ece..c7b9e65 100644 --- a/Classes/PHPExcel/ReferenceHelper.php +++ b/Classes/PHPExcel/ReferenceHelper.php @@ -312,8 +312,8 @@ class PHPExcel_ReferenceHelper // Update worksheet: autofilter - if ($pSheet->getAutoFilter() != '') { - $pSheet->setAutoFilter( $this->updateCellReference($pSheet->getAutoFilter(), $pBefore, $pNumCols, $pNumRows) ); + if ($pSheet->getAutoFilter()->getRange() !== '') { + $pSheet->setAutoFilter( $this->updateCellReference($pSheet->getAutoFilter()->getRange(), $pBefore, $pNumCols, $pNumRows) ); } diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index eb90590..b52ccb3 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -200,11 +200,11 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable private $_protectedCells = array(); /** - * Autofilter Range + * Autofilter Range and selection * - * @var string + * @var PHPExcel_Worksheet_AutoFilter */ - private $_autoFilter = ''; + private $_autoFilter = NULL; /** * Freeze pane @@ -365,7 +365,9 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_defaultRowDimension = new PHPExcel_Worksheet_RowDimension(null); // Default column dimension - $this->_defaultColumnDimension = new PHPExcel_Worksheet_ColumnDimension(null); + $this->_defaultColumnDimension = new PHPExcel_Worksheet_ColumnDimension(null); + + $this->_autoFilter = new PHPExcel_Worksheet_AutoFilter(); } @@ -1832,9 +1834,9 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } /** - * Get Autofilter Range + * Get Autofilter * - * @return string + * @return PHPExcel_Worksheet_AutoFilter */ public function getAutoFilter() { @@ -1842,35 +1844,32 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } /** - * Set Autofilter Range + * Set AutoFilter * - * @param string $pRange Cell range (i.e. A1:E10) - * @throws Exception - * @return PHPExcel_Worksheet + * @param PHPExcel_Worksheet_AutoFilter|string $pValue + * A simple string containing a Cell range like 'A1:E10' is permitted for backward compatibility + * @throws Exception + * @return PHPExcel_Worksheet */ - public function setAutoFilter($pRange = '') + public function setAutoFilter($pValue) { - // Uppercase coordinate - $pRange = strtoupper($pRange); - - if (strpos($pRange,':') !== false) { - $this->_autoFilter = $pRange; - $this->_dirty = true; - } else { - throw new Exception('Autofilter must be set on a range of cells.'); + if (is_string($pValue)) { + $this->_autoFilter->setRange($pValue); + } elseif(is_object($pValue) && ($pValue instanceof PHPExcel_Worksheet_AutoFilter)) { + $this->_autoFilter = $pValue; } return $this; } /** - * Set Autofilter Range by using numeric cell coordinates + * Set Autofilter Range by using numeric cell coordinates * - * @param int $pColumn1 Numeric column coordinate of the first cell - * @param int $pRow1 Numeric row coordinate of the first cell - * @param int $pColumn2 Numeric column coordinate of the second cell - * @param int $pRow2 Numeric row coordinate of the second cell - * @throws Exception - * @return PHPExcel_Worksheet + * @param int $pColumn1 Numeric column coordinate of the first cell + * @param int $pRow1 Numeric row coordinate of the first cell + * @param int $pColumn2 Numeric column coordinate of the second cell + * @param int $pRow2 Numeric row coordinate of the second cell + * @throws Exception + * @return PHPExcel_Worksheet */ public function setAutoFilterByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1) { diff --git a/Classes/PHPExcel/Worksheet/AutoFilter.php b/Classes/PHPExcel/Worksheet/AutoFilter.php new file mode 100644 index 0000000..c0055a5 --- /dev/null +++ b/Classes/PHPExcel/Worksheet/AutoFilter.php @@ -0,0 +1,107 @@ +_range = $pRange; + } + + /** + * Get AutoFilter Range + * + * @return string + */ + public function getRange() { + return $this->_range; + } + + /** + * Set AutoFilter Range + * + * @param string $pRange Cell range (i.e. A1:E10) + * @throws Exception + * @return PHPExcel_Worksheet_AutoFilter + */ + public function setRange($pRange = '') { + // Uppercase coordinate + $pRange = strtoupper($pRange); + + if (strpos($pRange,':') !== FALSE) { + $this->_range = $pRange; + } elseif(empty($pRange)) { + $this->_range = ''; + } else { + throw new Exception('Autofilter must be set on a range of cells.'); + } + + return $this; + } + + /** + * Implement PHP __clone to create a deep clone, not just a shallow copy. + */ + public function __clone() { + $vars = get_object_vars($this); + foreach ($vars as $key => $value) { + if (is_object($value)) { + $this->$key = clone $value; + } else { + $this->$key = $value; + } + } + } + + /** + * toString method replicates previous behavior by returning the range if object is + * referenced as a property of its parent. + */ + public function __toString() { + return $this->_range; + } + +} diff --git a/Classes/PHPExcel/Writer/Excel2007/Workbook.php b/Classes/PHPExcel/Writer/Excel2007/Workbook.php index bd02832..59622fd 100644 --- a/Classes/PHPExcel/Writer/Excel2007/Workbook.php +++ b/Classes/PHPExcel/Writer/Excel2007/Workbook.php @@ -306,7 +306,7 @@ class PHPExcel_Writer_Excel2007_Workbook extends PHPExcel_Writer_Excel2007_Write } /** - * Write Defined Name for autoFilter + * Write Defined Name for named range * * @param PHPExcel_Shared_XMLWriter $objWriter XML Writer * @param PHPExcel_NamedRange $pNamedRange @@ -347,14 +347,14 @@ class PHPExcel_Writer_Excel2007_Workbook extends PHPExcel_Writer_Excel2007_Write private function _writeDefinedNameForAutofilter(PHPExcel_Shared_XMLWriter $objWriter = null, PHPExcel_Worksheet $pSheet = null, $pSheetId = 0) { // definedName for autoFilter - if ($pSheet->getAutoFilter() != '') { + if ($pSheet->getAutoFilter()->getRange() !== '') { $objWriter->startElement('definedName'); $objWriter->writeAttribute('name', '_xlnm._FilterDatabase'); $objWriter->writeAttribute('localSheetId', $pSheetId); $objWriter->writeAttribute('hidden', '1'); // Create absolute coordinate and write as raw text - $range = PHPExcel_Cell::splitRange($pSheet->getAutoFilter()); + $range = PHPExcel_Cell::splitRange($pSheet->getAutoFilter()->getRange()); $range = $range[0]; // Strip any worksheet ref so we can make the cell ref absolute if (strpos($range[0],'!') !== false) { diff --git a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php index b97648d..37c39f2 100644 --- a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php +++ b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php @@ -725,12 +725,12 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ */ private function _writeAutoFilter(PHPExcel_Shared_XMLWriter $objWriter = null, PHPExcel_Worksheet $pSheet = null) { - if ($pSheet->getAutoFilter() != '') { + if ($pSheet->getAutoFilter()->getRange() !== '') { // autoFilter $objWriter->startElement('autoFilter'); // Strip any worksheet reference from the filter coordinates - $range = PHPExcel_Cell::splitRange($pSheet->getAutoFilter()); + $range = PHPExcel_Cell::splitRange($pSheet->getAutoFilter()->getRange()); $range = $range[0]; // Strip any worksheet ref if (strpos($range[0],'!') !== false) { diff --git a/Classes/PHPExcel/Writer/Excel5.php b/Classes/PHPExcel/Writer/Excel5.php index 599d0d4..6eb6994 100644 --- a/Classes/PHPExcel/Writer/Excel5.php +++ b/Classes/PHPExcel/Writer/Excel5.php @@ -282,7 +282,7 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter $escher = null; // check if there are any shapes for this sheet - if (count($sheet->getDrawingCollection()) == 0 && $sheet->getAutoFilter() == '') { + if (count($sheet->getDrawingCollection()) == 0 && $sheet->getAutoFilter()->getRange() === '') { continue; } @@ -358,43 +358,43 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter $spgrContainer->addChild($spContainer); } - + // AutoFilters - if($sheet->getAutoFilter() != ''){ - $rangeBounds = PHPExcel_Cell::rangeBoundaries($sheet->getAutoFilter()); + if($sheet->getAutoFilter()->getRange() !== ''){ + $rangeBounds = PHPExcel_Cell::rangeBoundaries($sheet->getAutoFilter()->getRange()); $iNumColStart = $rangeBounds[0][0]; $iNumColEnd = $rangeBounds[1][0]; - + $iInc = $iNumColStart; while($iInc <= $iNumColEnd){ ++$countShapes[$sheetIndex]; - + // create an Drawing Object for the dropdown $oDrawing = new PHPExcel_Worksheet_BaseDrawing(); // get the coordinates of drawing $cDrawing = PHPExcel_Cell::stringFromColumnIndex($iInc - 1) . $rangeBounds[0][1]; $oDrawing->setCoordinates($cDrawing); $oDrawing->setWorksheet($sheet); - + // add the shape $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer(); // set the shape type $spContainer->setSpType(0x00C9); // set the shape flag $spContainer->setSpFlag(0x01); - + // set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index) $reducedSpId = $countShapes[$sheetIndex]; $spId = $reducedSpId | ($sheet->getParent()->getIndex($sheet) + 1) << 10; $spContainer->setSpId($spId); - + // keep track of last reducedSpId $lastReducedSpId = $reducedSpId; - + // keep track of last spId $lastSpId = $spId; - + $spContainer->setOPT(0x007F, 0x01040104); // Protection -> fLockAgainstGrouping $spContainer->setOPT(0x00BF, 0x00080008); // Text -> fFitTextToShape $spContainer->setOPT(0x01BF, 0x00010000); // Fill Style -> fNoFillHitTest @@ -411,7 +411,7 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter $spContainer->setEndCoordinates($endCoordinates); $spContainer->setEndOffsetX(0); $spContainer->setEndOffsetY(0); - + $spgrContainer->addChild($spContainer); $iInc++; } diff --git a/Classes/PHPExcel/Writer/Excel5/Workbook.php b/Classes/PHPExcel/Writer/Excel5/Workbook.php index fafc123..4fdcada 100644 --- a/Classes/PHPExcel/Writer/Excel5/Workbook.php +++ b/Classes/PHPExcel/Writer/Excel5/Workbook.php @@ -779,16 +779,16 @@ class PHPExcel_Writer_Excel5_Workbook extends PHPExcel_Writer_Excel5_BIFFwriter $chunk .= $this->writeData($this->_writeDefinedNameBiff8(pack('C', 0x06), $formulaData, $i + 1, true)); } } - + // write autofilters, if any for ($i = 0; $i < $total_worksheets; ++$i) { $sheetAutoFilter = $this->_phpExcel->getSheet($i)->getAutoFilter(); - if($sheetAutoFilter != ''){ - $rangeBounds = PHPExcel_Cell::rangeBoundaries($sheetAutoFilter); - + if($sheetAutoFilter->getRange() !== ''){ + $rangeBounds = PHPExcel_Cell::rangeBoundaries($sheetAutoFilter->getRange()); + //Autofilter built in name $name = pack('C', 0x0D); - + $chunk .= $this->writeData($this->_writeShortNameBiff8($name, $i + 1, $rangeBounds, true)); } } @@ -830,7 +830,7 @@ class PHPExcel_Writer_Excel5_Workbook extends PHPExcel_Writer_Excel5_BIFFwriter return $header . $data; } - + /** * Write a short NAME record * @@ -842,10 +842,10 @@ class PHPExcel_Writer_Excel5_Workbook extends PHPExcel_Writer_Excel5_BIFFwriter * */ private function _writeShortNameBiff8($name, $sheetIndex = 0, $rangeBounds, $isHidden = false){ $record = 0x0018; - + // option flags $options = ($isHidden ? 0x21 : 0x00); - + $extra = pack('Cvvvvv', 0x3B, $sheetIndex - 1, @@ -853,17 +853,17 @@ class PHPExcel_Writer_Excel5_Workbook extends PHPExcel_Writer_Excel5_BIFFwriter $rangeBounds[1][1] - 1, $rangeBounds[0][0] - 1, $rangeBounds[1][0] - 1); - + // size of the formula (in bytes) $sz = strlen($extra); - + // combine the parts $data = pack('vCCvvvCCCCC', $options, 0, 1, $sz, 0, $sheetIndex, 0, 0, 0, 0, 0) . $name . $extra; $length = strlen($data); - + $header = pack('vv', $record, $length); - + return $header . $data; } diff --git a/Classes/PHPExcel/Writer/Excel5/Worksheet.php b/Classes/PHPExcel/Writer/Excel5/Worksheet.php index ec1f34d..b079da5 100644 --- a/Classes/PHPExcel/Writer/Excel5/Worksheet.php +++ b/Classes/PHPExcel/Writer/Excel5/Worksheet.php @@ -390,8 +390,8 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter $this->_writeColinfo($this->_colinfo[$i]); } } - - if ($_phpSheet->getAutoFilter() != '') { + + if ($_phpSheet->getAutoFilter()->getRange() !== '') { // Write AUTOFILTERINFO $this->_writeAutoFilterInfo(); } @@ -2048,15 +2048,15 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter private function _writeAutoFilterInfo(){ $record = 0x009D; // Record identifier $length = 0x0002; // Bytes to follow - - $rangeBounds = PHPExcel_Cell::rangeBoundaries($this->_phpSheet->getAutoFilter()); + + $rangeBounds = PHPExcel_Cell::rangeBoundaries($this->_phpSheet->getAutoFilter()->getRange()); $iNumFilters = 1 + $rangeBounds[1][0] - $rangeBounds[0][0]; $header = pack("vv", $record, $length); $data = pack("v", $iNumFilters); $this->_append($header . $data); } - + /** * Write the GUTS BIFF record. This is used to configure the gutter margins * where Excel outline symbols are displayed. The visibility of the gutters is @@ -2737,7 +2737,7 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter , 0 // reserved , 0 // reserved ); - + // Add ftSbs Scroll bar subobject $objData .= pack('vv', 0x00C, 0x0014); $objData .= pack('H*', '0000000000000000640001000A00000010000100'); @@ -2759,7 +2759,7 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter , 0 // reserved ); } - + // ftEnd $objData .= pack('vv'