diff --git a/Classes/PHPExcel/Reader/Excel2007.php b/Classes/PHPExcel/Reader/Excel2007.php index 137df9b4..94655a0e 100644 --- a/Classes/PHPExcel/Reader/Excel2007.php +++ b/Classes/PHPExcel/Reader/Excel2007.php @@ -1106,31 +1106,49 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader $autoFilter->setRange((string) $xmlSheet->autoFilter["ref"]); foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) { $column = $autoFilter->getColumnByOffset((integer) $filterColumn["colId"]); + // Check for standard filters if ($filterColumn->filters) { $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_FILTER); $filters = $filterColumn->filters; - // Standard filters are always an OR join, so no join rule needed + if ((isset($filters["blank"])) && ($filters["blank"] == 1)) { + $column->createRule()->setRule( + NULL, // Operator is undefined, but always treated as EQUAL + '' + ) + ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER); + } + // Standard filters are always an OR join, so no join rule needs to be set + // Entries can be either filter elements foreach ($filters->filter as $filterRule) { $column->createRule()->setRule( - (string) $filterRule["operator"], + NULL, // Operator is undefined, but always treated as EQUAL (string) $filterRule["val"] - ); + ) + ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER); } - } - if ($filterColumn->dynamicFilter) { - $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); - // We should only ever have one dynamic filter - foreach ($filterColumn->dynamicFilter as $filterRule) { + // Or Date Group elements + foreach ($filters->dateGroupItem as $dateGroupItem) { $column->createRule()->setRule( - (string) $filterRule["operator"], - (string) $filterRule["val"] - ); + NULL, // Operator is undefined, but always treated as EQUAL + array( + 'year' => (string) $dateGroupItem["year"], + 'month' => (string) $dateGroupItem["month"], + 'day' => (string) $dateGroupItem["day"], + 'hour' => (string) $dateGroupItem["hour"], + 'minute' => (string) $dateGroupItem["minute"], + 'second' => (string) $dateGroupItem["second"], + ), + (string) $dateGroupItem["dateTimeGrouping"] + ) + ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DATEGROUP); } } + // Check for custom filters if ($filterColumn->customFilters) { $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER); $customFilters = $filterColumn->customFilters; - // Custom filters can an AND or an OR join + // Custom filters can an AND or an OR join; + // and there should only ever be one or two entries if ((isset($customFilters["and"])) && ($customFilters["and"] == 1)) { $column->setAndOr(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_COLUMN_ANDOR_AND); } @@ -1138,7 +1156,40 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader $column->createRule()->setRule( (string) $filterRule["operator"], (string) $filterRule["val"] - ); + ) + ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); + } + } + // Check for dynamic filters + if ($filterColumn->dynamicFilter) { + $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); + // We should only ever have one dynamic filter + foreach ($filterColumn->dynamicFilter as $filterRule) { + $column->createRule()->setRule( + NULL, // Operator is undefined, but always treated as EQUAL + (string) $filterRule["val"], + (string) $filterRule["type"] + ) + ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER); + } + } + // Check for dynamic filters + if ($filterColumn->top10) { + $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER); + // We should only ever have one top10 filter + foreach ($filterColumn->top10 as $filterRule) { + $column->createRule()->setRule( + (((isset($filterRule["percent"])) && ($filterRule["percent"] == 1)) + ? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT + : PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE + ), + (string) $filterRule["val"], + (((isset($filterRule["top"])) && ($filterRule["top"] == 1)) + ? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP + : PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM + ) + ) + ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_TOPTENFILTER); } } } diff --git a/Classes/PHPExcel/Worksheet/AutoFilter/Column.php b/Classes/PHPExcel/Worksheet/AutoFilter/Column.php index ceac93f5..c4b003b2 100644 --- a/Classes/PHPExcel/Worksheet/AutoFilter/Column.php +++ b/Classes/PHPExcel/Worksheet/AutoFilter/Column.php @@ -35,13 +35,14 @@ */ class PHPExcel_Worksheet_AutoFilter_Column { - const AUTOFILTER_FILTERTYPE_FILTER = 'filter'; - const AUTOFILTER_FILTERTYPE_CUSTOMFILTER = 'customFilter'; + const AUTOFILTER_FILTERTYPE_FILTER = 'filters'; + const AUTOFILTER_FILTERTYPE_CUSTOMFILTER = 'customFilters'; // Supports no more than 2 rules, with an And/Or join criteria // if more than 1 rule is defined const AUTOFILTER_FILTERTYPE_DYNAMICFILTER = 'dynamicFilter'; // Even though the filter rule is constant, the filtered data can vary // e.g. filtered by date = TODAY + const AUTOFILTER_FILTERTYPE_TOPTENFILTER = 'top10'; private static $_filterTypes = array( // Currently we're not handling @@ -52,6 +53,7 @@ class PHPExcel_Worksheet_AutoFilter_Column self::AUTOFILTER_FILTERTYPE_FILTER, self::AUTOFILTER_FILTERTYPE_CUSTOMFILTER, self::AUTOFILTER_FILTERTYPE_DYNAMICFILTER, + self::AUTOFILTER_FILTERTYPE_TOPTENFILTER, ); /* Multiple Rule Connections */ @@ -173,16 +175,16 @@ class PHPExcel_Worksheet_AutoFilter_Column /** * Set AutoFilter Type * - * @param string $pfilterType + * @param string $pFilterType * @throws Exception * @return PHPExcel_Worksheet_AutoFilter_Column */ - public function setFilterType($pfilterType = self::AUTOFILTER_FILTERTYPE_FILTER) { - if (!in_array($pfilterType,self::$_filterTypes)) { + public function setFilterType($pFilterType = self::AUTOFILTER_FILTERTYPE_FILTER) { + if (!in_array($pFilterType,self::$_filterTypes)) { throw new PHPExcel_Exception('Invalid filter type for column AutoFilter.'); } - $this->_filterType = $pfilterType; + $this->_filterType = $pFilterType; return $this; } @@ -282,6 +284,18 @@ class PHPExcel_Worksheet_AutoFilter_Column return $this; } + /** + * Delete all AutoFilter Column Rules + * + * @return PHPExcel_Worksheet_AutoFilter_Column + */ + public function clearRules() { + $this->_ruleset = array(); + $this->setAndOr(self::AUTOFILTER_COLUMN_ANDOR_OR); + + return $this; + } + /** * Implement PHP __clone to create a deep clone, not just a shallow copy. */ diff --git a/Classes/PHPExcel/Worksheet/AutoFilter/Column/Rule.php b/Classes/PHPExcel/Worksheet/AutoFilter/Column/Rule.php index e44d9225..67f01259 100644 --- a/Classes/PHPExcel/Worksheet/AutoFilter/Column/Rule.php +++ b/Classes/PHPExcel/Worksheet/AutoFilter/Column/Rule.php @@ -35,46 +35,199 @@ */ class PHPExcel_Worksheet_AutoFilter_Column_Rule { - /* Rule Operators (Numeric and String) */ + const AUTOFILTER_RULETYPE_FILTER = 'filter'; + const AUTOFILTER_RULETYPE_DATEGROUP = 'dateGroupItem'; + const AUTOFILTER_RULETYPE_CUSTOMFILTER = 'customFilter'; + const AUTOFILTER_RULETYPE_DYNAMICFILTER = 'dynamicFilter'; + const AUTOFILTER_RULETYPE_TOPTENFILTER = 'top10Filter'; + + private static $_ruleTypes = array( + // Currently we're not handling + // colorFilter + // extLst + // iconFilter + self::AUTOFILTER_RULETYPE_FILTER, + self::AUTOFILTER_RULETYPE_DATEGROUP, + self::AUTOFILTER_RULETYPE_CUSTOMFILTER, + self::AUTOFILTER_RULETYPE_DYNAMICFILTER, + self::AUTOFILTER_RULETYPE_TOPTENFILTER, + ); + + const AUTOFILTER_RULETYPE_DATEGROUP_YEAR = 'year'; + const AUTOFILTER_RULETYPE_DATEGROUP_MONTH = 'month'; + const AUTOFILTER_RULETYPE_DATEGROUP_DAY = 'day'; + const AUTOFILTER_RULETYPE_DATEGROUP_HOUR = 'hour'; + const AUTOFILTER_RULETYPE_DATEGROUP_MINUTE = 'minute'; + const AUTOFILTER_RULETYPE_DATEGROUP_SECOND = 'second'; + + private static $_dateTimeGroups = array( + self::AUTOFILTER_RULETYPE_DATEGROUP_YEAR, + self::AUTOFILTER_RULETYPE_DATEGROUP_MONTH, + self::AUTOFILTER_RULETYPE_DATEGROUP_DAY, + self::AUTOFILTER_RULETYPE_DATEGROUP_HOUR, + self::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE, + self::AUTOFILTER_RULETYPE_DATEGROUP_SECOND, + ); + + const AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY = 'yesterday'; + const AUTOFILTER_RULETYPE_DYNAMIC_TODAY = 'today'; + const AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW = 'tomorrow'; + const AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE = 'yearToDate'; + const AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR = 'thisYear'; + const AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER = 'thisQuarter'; + const AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH = 'thisMonth'; + const AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK = 'thisWeek'; + const AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR = 'lastYear'; + const AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER = 'lastQuarter'; + const AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH = 'lastMonth'; + const AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK = 'lastWeek'; + const AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR = 'nextYear'; + const AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER = 'nextQuarter'; + const AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH = 'nextMonth'; + const AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK = 'nextWeek'; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_1 = 'M1'; + const AUTOFILTER_RULETYPE_DYNAMIC_JANUARY = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_1; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2 = 'M2'; + const AUTOFILTER_RULETYPE_DYNAMIC_FEBRUARY = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_3 = 'M3'; + const AUTOFILTER_RULETYPE_DYNAMIC_MARCH = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_3; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_4 = 'M4'; + const AUTOFILTER_RULETYPE_DYNAMIC_APRIL = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_4; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_5 = 'M5'; + const AUTOFILTER_RULETYPE_DYNAMIC_MAY = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_5; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_6 = 'M6'; + const AUTOFILTER_RULETYPE_DYNAMIC_JUNE = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_6; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_7 = 'M7'; + const AUTOFILTER_RULETYPE_DYNAMIC_JULY = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_7; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_8 = 'M8'; + const AUTOFILTER_RULETYPE_DYNAMIC_AUGUST = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_8; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_9 = 'M9'; + const AUTOFILTER_RULETYPE_DYNAMIC_SEPTEMBER = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_9; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_10 = 'M10'; + const AUTOFILTER_RULETYPE_DYNAMIC_OCTOBER = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_10; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11 = 'M11'; + const AUTOFILTER_RULETYPE_DYNAMIC_NOVEMBER = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11; + const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_12 = 'M12'; + const AUTOFILTER_RULETYPE_DYNAMIC_DECEMBER = self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_12; + const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_1 = 'Q1'; + const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_2 = 'Q2'; + const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_3 = 'Q3'; + const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_4 = 'Q4'; + const AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE = 'aboveAverage'; + const AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE = 'belowAverage'; + + private static $_dynamicTypes = array( + self::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY, + self::AUTOFILTER_RULETYPE_DYNAMIC_TODAY, + self::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW, + self::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE, + self::AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR, + self::AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER, + self::AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH, + self::AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK, + self::AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR, + self::AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER, + self::AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH, + self::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK, + self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR, + self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER, + self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH, + self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_1, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_3, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_4, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_5, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_6, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_7, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_8, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_9, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_10, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11, + self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_12, + self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_1, + self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_2, + self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_3, + self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_4, + self::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE, + self::AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE, + ); + + /* + * The only valid filter rule operators for filter and customFilter types are: + * + * + * + * + * + * + */ const AUTOFILTER_COLUMN_RULE_EQUAL = 'equal'; - /* Rule Operators (Numeric, Boolean etc) */ const AUTOFILTER_COLUMN_RULE_NOTEQUAL = 'notEqual'; const AUTOFILTER_COLUMN_RULE_GREATERTHAN = 'greaterThan'; const AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL = 'greaterThanOrEqual'; const AUTOFILTER_COLUMN_RULE_LESSTHAN = 'lessThan'; const AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL = 'lessThanOrEqual'; - const AUTOFILTER_COLUMN_RULE_BETWEEN = 'between'; // greaterThanOrEqual 1 && lessThanOrEqual 2 + + private static $_operators = array( + self::AUTOFILTER_COLUMN_RULE_EQUAL, + self::AUTOFILTER_COLUMN_RULE_NOTEQUAL, + self::AUTOFILTER_COLUMN_RULE_GREATERTHAN, + self::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL, + self::AUTOFILTER_COLUMN_RULE_LESSTHAN, + self::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL, + ); + + const AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE = 'byValue'; + const AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT = 'byPercent'; + + private static $_topTenValue = array( + self::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, + self::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT, + ); + + const AUTOFILTER_COLUMN_RULE_TOPTEN_TOP = 'top'; + const AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM = 'bottom'; + + private static $_topTenType = array( + self::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP, + self::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM, + ); + + + /* Rule Operators (Numeric, Boolean etc) */ +// const AUTOFILTER_COLUMN_RULE_BETWEEN = 'between'; // greaterThanOrEqual 1 && lessThanOrEqual 2 /* Rule Operators (Numeric Special) which are translated to standard numeric operators with calculated values */ - const AUTOFILTER_COLUMN_RULE_TOPTEN = 'topTen'; // greaterThan calculated value - const AUTOFILTER_COLUMN_RULE_TOPTENPERCENT = 'topTenPercent'; // greaterThan calculated value - const AUTOFILTER_COLUMN_RULE_ABOVEAVERAGE = 'aboveAverage'; // Value is calculated as the average - const AUTOFILTER_COLUMN_RULE_BELOWAVERAGE = 'belowAverage'; // Value is calculated as the average +// const AUTOFILTER_COLUMN_RULE_TOPTEN = 'topTen'; // greaterThan calculated value +// const AUTOFILTER_COLUMN_RULE_TOPTENPERCENT = 'topTenPercent'; // greaterThan calculated value +// const AUTOFILTER_COLUMN_RULE_ABOVEAVERAGE = 'aboveAverage'; // Value is calculated as the average +// const AUTOFILTER_COLUMN_RULE_BELOWAVERAGE = 'belowAverage'; // Value is calculated as the average /* Rule Operators (String) which are set as wild-carded values */ - const AUTOFILTER_COLUMN_RULE_BEGINSWITH = 'beginsWith'; // A* - const AUTOFILTER_COLUMN_RULE_ENDSWITH = 'endsWith'; // *Z - const AUTOFILTER_COLUMN_RULE_CONTAINS = 'contains'; // *B* - const AUTOFILTER_COLUMN_RULE_DOESNTCONTAIN = 'notEqual'; // notEqual *B* +// const AUTOFILTER_COLUMN_RULE_BEGINSWITH = 'beginsWith'; // A* +// const AUTOFILTER_COLUMN_RULE_ENDSWITH = 'endsWith'; // *Z +// const AUTOFILTER_COLUMN_RULE_CONTAINS = 'contains'; // *B* +// const AUTOFILTER_COLUMN_RULE_DOESNTCONTAIN = 'notEqual'; // notEqual *B* /* Rule Operators (Date Special) which are translated to standard numeric operators with calculated values */ - const AUTOFILTER_COLUMN_RULE_BEFORE = 'lessThan'; - const AUTOFILTER_COLUMN_RULE_AFTER = 'greaterThan'; - const AUTOFILTER_COLUMN_RULE_YESTERDAY = 'yesterday'; - const AUTOFILTER_COLUMN_RULE_TODAY = 'today'; - const AUTOFILTER_COLUMN_RULE_TOMORROW = 'tomorrow'; - const AUTOFILTER_COLUMN_RULE_LASTWEEK = 'lastWeek'; - const AUTOFILTER_COLUMN_RULE_THISWEEK = 'thisWeek'; - const AUTOFILTER_COLUMN_RULE_NEXTWEEK = 'nextWeek'; - const AUTOFILTER_COLUMN_RULE_LASTMONTH = 'lastMonth'; - const AUTOFILTER_COLUMN_RULE_THISMONTH = 'thisMonth'; - const AUTOFILTER_COLUMN_RULE_NEXTMONTH = 'nextMonth'; - const AUTOFILTER_COLUMN_RULE_LASTQUARTER = 'lastQuarter'; - const AUTOFILTER_COLUMN_RULE_THISQUARTER = 'thisQuarter'; - const AUTOFILTER_COLUMN_RULE_NEXTQUARTER = 'nextQuarter'; - const AUTOFILTER_COLUMN_RULE_LASTYEAR = 'lastYear'; - const AUTOFILTER_COLUMN_RULE_THISYEAR = 'thisYear'; - const AUTOFILTER_COLUMN_RULE_NEXTYEAR = 'nextYear'; - const AUTOFILTER_COLUMN_RULE_YEARTODATE = 'yearToDate'; // - const AUTOFILTER_COLUMN_RULE_ALLDATESINMONTH = 'allDatesInMonth'; // for Month/February - const AUTOFILTER_COLUMN_RULE_ALLDATESINQUARTER = 'allDatesInQuarter'; // for Quarter 2 +// const AUTOFILTER_COLUMN_RULE_BEFORE = 'lessThan'; +// const AUTOFILTER_COLUMN_RULE_AFTER = 'greaterThan'; +// const AUTOFILTER_COLUMN_RULE_YESTERDAY = 'yesterday'; +// const AUTOFILTER_COLUMN_RULE_TODAY = 'today'; +// const AUTOFILTER_COLUMN_RULE_TOMORROW = 'tomorrow'; +// const AUTOFILTER_COLUMN_RULE_LASTWEEK = 'lastWeek'; +// const AUTOFILTER_COLUMN_RULE_THISWEEK = 'thisWeek'; +// const AUTOFILTER_COLUMN_RULE_NEXTWEEK = 'nextWeek'; +// const AUTOFILTER_COLUMN_RULE_LASTMONTH = 'lastMonth'; +// const AUTOFILTER_COLUMN_RULE_THISMONTH = 'thisMonth'; +// const AUTOFILTER_COLUMN_RULE_NEXTMONTH = 'nextMonth'; +// const AUTOFILTER_COLUMN_RULE_LASTQUARTER = 'lastQuarter'; +// const AUTOFILTER_COLUMN_RULE_THISQUARTER = 'thisQuarter'; +// const AUTOFILTER_COLUMN_RULE_NEXTQUARTER = 'nextQuarter'; +// const AUTOFILTER_COLUMN_RULE_LASTYEAR = 'lastYear'; +// const AUTOFILTER_COLUMN_RULE_THISYEAR = 'thisYear'; +// const AUTOFILTER_COLUMN_RULE_NEXTYEAR = 'nextYear'; +// const AUTOFILTER_COLUMN_RULE_YEARTODATE = 'yearToDate'; // +// const AUTOFILTER_COLUMN_RULE_ALLDATESINMONTH = 'allDatesInMonth'; // for Month/February +// const AUTOFILTER_COLUMN_RULE_ALLDATESINQUARTER = 'allDatesInQuarter'; // for Quarter 2 /** * Autofilter Column @@ -84,19 +237,34 @@ class PHPExcel_Worksheet_AutoFilter_Column_Rule private $_parent = NULL; + /** + * Autofilter Rule Type + * + * @var string + */ + private $_ruleType = self::AUTOFILTER_RULETYPE_FILTER; + + /** * Autofilter Rule Value * * @var string */ - private $_ruleValue = ''; + private $_value = ''; /** * Autofilter Rule Operator * * @var string */ - private $_ruleOperator = ''; + private $_operator = ''; + + /** + * DateTimeGrouping Group Value + * + * @var string + */ + private $_grouping = ''; /** @@ -107,6 +275,32 @@ class PHPExcel_Worksheet_AutoFilter_Column_Rule $this->_parent = $pParent; } + /** + * Get AutoFilter Rule Type + * + * @return string + */ + public function getRuleType() { + return $this->_ruleType; + } + + /** + * Set AutoFilter Rule Type + * + * @param string $pRuleType + * @throws Exception + * @return PHPExcel_Worksheet_AutoFilter_Column + */ + public function setRuleType($pRuleType = self::AUTOFILTER_RULETYPE_FILTER) { + if (!in_array($pRuleType,self::$_ruleTypes)) { + throw new PHPExcel_Exception('Invalid rule type for column AutoFilter Rule.'); + } + + $this->_ruleType = $pRuleType; + + return $this; + } + /** * Get AutoFilter Rule Value * @@ -119,11 +313,29 @@ class PHPExcel_Worksheet_AutoFilter_Column_Rule /** * Set AutoFilter Rule Value * - * @param string $pValue + * @param string|string[] $pValue * @throws Exception * @return PHPExcel_Worksheet_AutoFilter_Column_Rule */ public function setValue($pValue = '') { + if (is_array($pValue)) { + $grouping = -1; + foreach($pValue as $key => $value) { + // Validate array entries + if (!in_array($key,self::$_dateTimeGroups)) { + // Remove any invalid entries from the value array + unset($pValue[$key]); + } else { + // Work out what the dateTime grouping will be + $grouping = max($grouping,array_search($key,self::$_dateTimeGroups)); + } + } + if (count($pValue) == 0) { + throw new PHPExcel_Exception('Invalid rule value for column AutoFilter Rule.'); + } + // Set the dateTime grouping that we've anticipated + $this->setGrouping(self::$_dateTimeGroups[$grouping]); + } $this->_value = $pValue; return $this; @@ -148,21 +360,61 @@ class PHPExcel_Worksheet_AutoFilter_Column_Rule public function setOperator($pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL) { if (empty($pOperator)) $pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL; + if ((!in_array($pOperator,self::$_operators)) && + (!in_array($pOperator,self::$_topTenValue))) { + throw new PHPExcel_Exception('Invalid operator for column AutoFilter Rule.'); + } $this->_operator = $pOperator; return $this; } /** - * Set AutoFilter Rule Operator + * Get AutoFilter Rule Grouping * - * @param string $pOperator + * @return string + */ + public function getGrouping() { + return $this->_grouping; + } + + /** + * Set AutoFilter Rule Grouping + * + * @param string $pGrouping * @throws Exception * @return PHPExcel_Worksheet_AutoFilter_Column_Rule */ - public function setRule($pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL, $pValue = '') { + public function setGrouping($pGrouping = NULL) { + if (($pGrouping !== NULL) && + (!in_array($pGrouping,self::$_dateTimeGroups)) && + (!in_array($pGrouping,self::$_dynamicTypes)) && + (!in_array($pGrouping,self::$_topTenType))) { + throw new PHPExcel_Exception('Invalid rule type for column AutoFilter Rule.'); + } + + $this->_grouping = $pGrouping; + + return $this; + } + + /** + * Set AutoFilter Rule + * + * @param string $pOperator + * @param string|string[] $pValue + * @param string $pGrouping + * @throws Exception + * @return PHPExcel_Worksheet_AutoFilter_Column_Rule + */ + public function setRule($pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL, $pValue = '', $pGrouping = NULL) { $this->setOperator($pOperator); $this->setValue($pValue); + // Only set grouping if it's been passed in as a user-supplied argument, + // otherwise we're calculating it when we setValue() and don't want to overwrite that + // If the user supplies an argumnet for grouping, then on their own head be it + if ($pGrouping !== NULL) + $this->setGrouping($pGrouping); return $this; } diff --git a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php index 883f4e06..80934372 100644 --- a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php +++ b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php @@ -149,6 +149,10 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->startElement('sheetPr'); //$objWriter->writeAttribute('codeName', $pSheet->getTitle()); + if ($pSheet->getAutoFilter()->getRange() !== '') { + $objWriter->writeAttribute('filterMode', 1); + } + // tabColor if ($pSheet->isTabColorSet()) { $objWriter->startElement('tabColor'); @@ -421,21 +425,21 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword()); } - $objWriter->writeAttribute('sheet', ($pSheet->getProtection()->getSheet() ? 'true' : 'false')); - $objWriter->writeAttribute('objects', ($pSheet->getProtection()->getObjects() ? 'true' : 'false')); - $objWriter->writeAttribute('scenarios', ($pSheet->getProtection()->getScenarios() ? 'true' : 'false')); - $objWriter->writeAttribute('formatCells', ($pSheet->getProtection()->getFormatCells() ? 'true' : 'false')); - $objWriter->writeAttribute('formatColumns', ($pSheet->getProtection()->getFormatColumns() ? 'true' : 'false')); + $objWriter->writeAttribute('sheet', ($pSheet->getProtection()->getSheet() ? 'true' : 'false')); + $objWriter->writeAttribute('objects', ($pSheet->getProtection()->getObjects() ? 'true' : 'false')); + $objWriter->writeAttribute('scenarios', ($pSheet->getProtection()->getScenarios() ? 'true' : 'false')); + $objWriter->writeAttribute('formatCells', ($pSheet->getProtection()->getFormatCells() ? 'true' : 'false')); + $objWriter->writeAttribute('formatColumns', ($pSheet->getProtection()->getFormatColumns() ? 'true' : 'false')); $objWriter->writeAttribute('formatRows', ($pSheet->getProtection()->getFormatRows() ? 'true' : 'false')); - $objWriter->writeAttribute('insertColumns', ($pSheet->getProtection()->getInsertColumns() ? 'true' : 'false')); + $objWriter->writeAttribute('insertColumns', ($pSheet->getProtection()->getInsertColumns() ? 'true' : 'false')); $objWriter->writeAttribute('insertRows', ($pSheet->getProtection()->getInsertRows() ? 'true' : 'false')); $objWriter->writeAttribute('insertHyperlinks', ($pSheet->getProtection()->getInsertHyperlinks() ? 'true' : 'false')); - $objWriter->writeAttribute('deleteColumns', ($pSheet->getProtection()->getDeleteColumns() ? 'true' : 'false')); + $objWriter->writeAttribute('deleteColumns', ($pSheet->getProtection()->getDeleteColumns() ? 'true' : 'false')); $objWriter->writeAttribute('deleteRows', ($pSheet->getProtection()->getDeleteRows() ? 'true' : 'false')); - $objWriter->writeAttribute('selectLockedCells', ($pSheet->getProtection()->getSelectLockedCells() ? 'true' : 'false')); + $objWriter->writeAttribute('selectLockedCells', ($pSheet->getProtection()->getSelectLockedCells() ? 'true' : 'false')); $objWriter->writeAttribute('sort', ($pSheet->getProtection()->getSort() ? 'true' : 'false')); $objWriter->writeAttribute('autoFilter', ($pSheet->getProtection()->getAutoFilter() ? 'true' : 'false')); - $objWriter->writeAttribute('pivotTables', ($pSheet->getProtection()->getPivotTables() ? 'true' : 'false')); + $objWriter->writeAttribute('pivotTables', ($pSheet->getProtection()->getPivotTables() ? 'true' : 'false')); $objWriter->writeAttribute('selectUnlockedCells', ($pSheet->getProtection()->getSelectUnlockedCells() ? 'true' : 'false')); $objWriter->endElement(); } @@ -753,21 +757,43 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->startElement('filterColumn'); $objWriter->writeAttribute('colId', $pSheet->getAutoFilter()->getColumnOffset($columnID)); - // We'll keep things simple and always group our filters, even if there's only one - $objWriter->startElement( $column->getFilterType() . 's'); + $objWriter->startElement( $column->getFilterType()); if ($column->getAndOr() == PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_COLUMN_ANDOR_AND) { $objWriter->writeAttribute('and', 1); } foreach ($rules as $rule) { - $objWriter->startElement($column->getFilterType()); - - if ($rule->getOperator() !== PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_EQUAL) { - $objWriter->writeAttribute('operator', $rule->getOperator()); - } + if (($rule->getOperator() === PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_EQUAL) && + ($rule->getValue() === '')) { + // Filter rule for Blanks + $objWriter->writeAttribute('blank', 1); + } elseif($rule->getRuleType() === PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) { + // Dynamic Filter Rule + $objWriter->writeAttribute('type', $rule->getGrouping()); + } elseif($rule->getRuleType() === PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) { + // Top 10 Filter Rule $objWriter->writeAttribute('val', $rule->getValue()); + $objWriter->writeAttribute('percent', (($rule->getOperator() === PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0')); + $objWriter->writeAttribute('top', (($rule->getGrouping() === PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1': '0')); + } else { + // Filter, DateGroupItem or CustomFilter + $objWriter->startElement($rule->getRuleType()); - $objWriter->endElement(); + if ($rule->getOperator() !== PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_EQUAL) { + $objWriter->writeAttribute('operator', $rule->getOperator()); + } + if ($rule->getRuleType() === PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DATEGROUP) { + // Date Group filters + foreach($rule->getValue() as $key => $value) { + if ($value > '') $objWriter->writeAttribute($key, $value); + } + $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping()); + } else { + $objWriter->writeAttribute('val', $rule->getValue()); + } + + $objWriter->endElement(); + } } $objWriter->endElement(); diff --git a/Documentation/Functionality Cross-Reference.xls b/Documentation/Functionality Cross-Reference.xls index 8df18cd5..905f9443 100644 Binary files a/Documentation/Functionality Cross-Reference.xls and b/Documentation/Functionality Cross-Reference.xls differ diff --git a/Documentation/PHPExcel AutoFilter Reference developer documentation.doc b/Documentation/PHPExcel AutoFilter Reference developer documentation.doc new file mode 100644 index 00000000..2024f77c Binary files /dev/null and b/Documentation/PHPExcel AutoFilter Reference developer documentation.doc differ