diff --git a/docs/topics/autofilters.md b/docs/topics/autofilters.md index 16efb8ff10..cd4291f4c0 100644 --- a/docs/topics/autofilters.md +++ b/docs/topics/autofilters.md @@ -251,16 +251,16 @@ $columnFilter->createRule() ); ``` -MS Excel uses \* as a wildcard to match any number of characters, and ? -as a wildcard to match a single character. 'U\*' equates to "begins with -a 'U'"; '\*U' equates to "ends with a 'U'"; and '\*U\*' equates to -"contains a 'U'" - -If you want to match explicitly against a \* or a ? character, you can -escape it with a tilde (\~), so ?\~\*\* would explicitly match for a \* -character as the second character in the cell value, followed by any +MS Excel uses `*` as a wildcard to match any number of characters, and `?` +as a wildcard to match a single character. `U*` equates to "begins with +a 'U'"; `*U` equates to "ends with a 'U'"; and `*U*` equates to +"contains a 'U'". + +If you want to match explicitly against `*` or `?`, you can +escape it with a tilde `~`, so `?~**` would explicitly match for `*` +as the second character in the cell value, followed by any number of other characters. The only other character that needs escaping -is the \~ itself. +is the `~` itself. To create a "between" condition, we need to define two rules: diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 9dee7fae19..5e19caeab6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -755,16 +755,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:wildcard\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:compare\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php - - message: "#^Call to function is_string\\(\\) with null will always evaluate to false\\.$#" count: 3 @@ -5290,156 +5280,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Style.php - - - message: "#^Result of && is always true\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Parameter \\#1 \\$excelTimestamp of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:excelToTimestamp\\(\\) expects float\\|int, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\<1, max\\>\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:\\$toReplace has no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$columnID with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$endRow with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$ruleType with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$ruleValue with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$startRow with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot call method rangeToArray\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot call method getRowDimension\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot assign offset 'year' to array\\\\|string\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot assign offset 'month' to array\\\\|string\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot assign offset 'day' to array\\\\|string\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot assign offset 'hour' to array\\\\|string\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot assign offset 'minute' to array\\\\|string\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot assign offset 'second' to array\\\\|string\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Parameter \\#1 \\$str of function preg_quote expects string, array\\\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Binary operation \"\\*\" between 0\\|array\\\\|string and float\\|int results in an error\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Left side of && is always true\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Parameter \\#1 \\$function of function call_user_func_array expects callable\\(\\)\\: mixed, array\\('PhpOffice\\\\\\\\PhpSpreadsheet\\\\\\\\Worksheet\\\\\\\\AutoFilter', mixed\\) given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$ruleTypes has no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$dateTimeGroups has no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$dynamicTypes has no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$operators has no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$topTenValue has no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$topTenType has no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$parent \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 1 @@ -7030,16 +6870,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\\\|string given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - - - message: "#^Argument of an invalid type array\\\\|string supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - message: "#^Parameter \\#2 \\$content of method XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, int\\|string given\\.$#" count: 1 @@ -7270,11 +7100,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Style/ConditionalTest.php - - - message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:setValue\\(\\) expects array\\\\|string, int given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php - - message: "#^Parameter \\#2 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\:\\:setAttribute\\(\\) expects string, int given\\.$#" count: 1 diff --git a/samples/Autofilter/10_Autofilter_selection_1.php b/samples/Autofilter/10_Autofilter_selection_1.php index 556ef61cdc..511417f0a0 100644 --- a/samples/Autofilter/10_Autofilter_selection_1.php +++ b/samples/Autofilter/10_Autofilter_selection_1.php @@ -31,7 +31,8 @@ ->setCellValue('D1', 'Date') ->setCellValue('E1', 'Sales Value') ->setCellValue('F1', 'Expenditure'); -$startYear = $endYear = $currentYear = date('Y'); +$dateTime = new DateTime(); +$startYear = $endYear = $currentYear = (int) $dateTime->format('Y'); --$startYear; ++$endYear; @@ -52,7 +53,9 @@ foreach ($years as $year) { foreach ($periods as $period) { foreach ($countries as $country) { - $endDays = date('t', mktime(0, 0, 0, $period, 1, (int) $year)); + $dateString = sprintf('%04d-%02d-01T00:00:00', $year, $period); + $dateTime = new DateTime($dateString); + $endDays = (int) $dateTime->format('t'); for ($i = 1; $i <= $endDays; ++$i) { $eDate = Date::formattedPHPToExcel( $year, @@ -124,10 +127,12 @@ 'japan' ) ->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); -// Filter the Date column on a filter value of the first day of every period of the current year +// Filter the Date column on a filter value of the last day of every period of the current year // We us a dateGroup ruletype for this, although it is still a standard filter foreach ($periods as $period) { - $endDate = date('t', mktime(0, 0, 0, $period, 1, (int) $currentYear)); + $dateString = sprintf('%04d-%02d-01T00:00:00', $currentYear, $period); + $dateTime = new DateTime($dateString); + $endDate = (int) $dateTime->format('t'); $autoFilter->getColumn('D') ->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER) diff --git a/samples/Autofilter/10_Autofilter_selection_2.php b/samples/Autofilter/10_Autofilter_selection_2.php index 4bae0abaf5..9e0680fc72 100644 --- a/samples/Autofilter/10_Autofilter_selection_2.php +++ b/samples/Autofilter/10_Autofilter_selection_2.php @@ -31,7 +31,8 @@ ->setCellValue('D1', 'Date') ->setCellValue('E1', 'Sales Value') ->setCellValue('F1', 'Expenditure'); -$startYear = $endYear = $currentYear = date('Y'); +$dateTime = new DateTime(); +$startYear = $endYear = $currentYear = (int) $dateTime->format('Y'); --$startYear; ++$endYear; @@ -52,7 +53,9 @@ foreach ($years as $year) { foreach ($periods as $period) { foreach ($countries as $country) { - $endDays = date('t', mktime(0, 0, 0, $period, 1, (int) $year)); + $dateString = sprintf('%04d-%02d-01T00:00:00', $year, $period); + $dateTime = new DateTime($dateString); + $endDays = (int) $dateTime->format('t'); for ($i = 1; $i <= $endDays; ++$i) { $eDate = Date::formattedPHPToExcel( $year, diff --git a/samples/Autofilter/10_Autofilter_selection_display.php b/samples/Autofilter/10_Autofilter_selection_display.php index 4810348c58..b07266b968 100644 --- a/samples/Autofilter/10_Autofilter_selection_display.php +++ b/samples/Autofilter/10_Autofilter_selection_display.php @@ -31,7 +31,8 @@ ->setCellValue('D1', 'Date') ->setCellValue('E1', 'Sales Value') ->setCellValue('F1', 'Expenditure'); -$startYear = $endYear = $currentYear = date('Y'); +$dateTime = new DateTime(); +$startYear = $endYear = $currentYear = (int) $dateTime->format('Y'); --$startYear; ++$endYear; @@ -52,7 +53,9 @@ foreach ($years as $year) { foreach ($periods as $period) { foreach ($countries as $country) { - $endDays = date('t', mktime(0, 0, 0, $period, 1, (int) $year)); + $dateString = sprintf('%04d-%02d-01T00:00:00', $year, $period); + $dateTime = new DateTime($dateString); + $endDays = (int) $dateTime->format('t'); for ($i = 1; $i <= $endDays; ++$i) { $eDate = Date::formattedPHPToExcel( $year, @@ -124,10 +127,12 @@ 'japan' ) ->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); -// Filter the Date column on a filter value of the first day of every period of the current year +// Filter the Date column on a filter value of the last day of every period of the current year // We us a dateGroup ruletype for this, although it is still a standard filter foreach ($periods as $period) { - $endDate = date('t', mktime(0, 0, 0, $period, 1, (int) $currentYear)); + $dateString = sprintf('%04d-%02d-01T00:00:00', $currentYear, $period); + $dateTime = new DateTime($dateString); + $endDate = (int) $dateTime->format('t'); $autoFilter->getColumn('D') ->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER) diff --git a/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php b/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php index 2ba2034686..5731569f7a 100644 --- a/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php +++ b/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php @@ -5,30 +5,30 @@ class WildcardMatch { private const SEARCH_SET = [ - '/(?range = $pRange; - } elseif (empty($pRange)) { + if (empty($pRange)) { + // Discard all column rules + $this->columns = []; $this->range = ''; - } else { + + return $this; + } + + if (strpos($pRange, ':') === false) { throw new PhpSpreadsheetException('Autofilter must be set on a range of cells.'); } - if (empty($pRange)) { - // Discard all column rules - $this->columns = []; - } else { - // Discard any column rules that are no longer valid within this range - [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range); - foreach ($this->columns as $key => $value) { - $colIndex = Coordinate::columnIndexFromString($key); - if (($rangeStart[0] > $colIndex) || ($rangeEnd[0] < $colIndex)) { - unset($this->columns[$key]); - } + $this->range = $pRange; + // Discard any column rules that are no longer valid within this range + [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range); + foreach ($this->columns as $key => $value) { + $colIndex = Coordinate::columnIndexFromString($key); + if (($rangeStart[0] > $colIndex) || ($rangeEnd[0] < $colIndex)) { + unset($this->columns[$key]); } } @@ -215,7 +215,7 @@ public function setColumn($pColumn) if (is_string($pColumn)) { $this->columns[$pColumn] = new AutoFilter\Column($pColumn, $this); - } elseif (is_object($pColumn) && ($pColumn instanceof AutoFilter\Column)) { + } else { $pColumn->setParent($this); $this->columns[$column] = $pColumn; } @@ -306,20 +306,22 @@ private static function filterTestInDateGroupSet($cellValue, $dataSet) if (($cellValue == '') || ($cellValue === null)) { return $blanks; } + $timeZone = new DateTimeZone('UTC'); if (is_numeric($cellValue)) { - $dateValue = Date::excelToTimestamp($cellValue); + $dateTime = Date::excelToDateTimeObject((float) $cellValue, $timeZone); + $cellValue = (float) $cellValue; if ($cellValue < 1) { // Just the time part - $dtVal = date('His', $dateValue); + $dtVal = $dateTime->format('His'); $dateSet = $dateSet['time']; } elseif ($cellValue == floor($cellValue)) { // Just the date part - $dtVal = date('Ymd', $dateValue); + $dtVal = $dateTime->format('Ymd'); $dateSet = $dateSet['date']; } else { // date and time parts - $dtVal = date('YmdHis', $dateValue); + $dtVal = $dateTime->format('YmdHis'); $dateSet = $dateSet['dateTime']; } foreach ($dateSet as $dateValue) { @@ -451,15 +453,6 @@ private static function filterTestInPeriodDateSet($cellValue, $monthSet) return false; } - /** - * Search/Replace arrays to convert Excel wildcard syntax to a regexp syntax for preg_matching. - * - * @var array - */ - private static $fromReplace = ['\*', '\?', '~~', '~.*', '~.?']; - - private static $toReplace = ['.*', '.', '~', '\*', '\?']; - private static function makeDateObject(int $year, int $month, int $day, int $hour = 0, int $minute = 0, int $second = 0): DateTime { $baseDate = new DateTime(); @@ -710,21 +703,37 @@ private function dynamicFilterDateRange($dynamicRuleType, &$filterColumn) return ['method' => 'filterTestInCustomDataSet', 'arguments' => ['filterRules' => $ruleValues, 'join' => AutoFilter\Column::AUTOFILTER_COLUMN_JOIN_AND]]; } + /** + * Apply the AutoFilter rules to the AutoFilter Range. + * + * @param string $columnID + * @param int $startRow + * @param int $endRow + * @param ?string $ruleType + * @param mixed $ruleValue + * + * @return mixed + */ private function calculateTopTenValue($columnID, $startRow, $endRow, $ruleType, $ruleValue) { $range = $columnID . $startRow . ':' . $columnID . $endRow; - $dataValues = Functions::flattenArray($this->workSheet->rangeToArray($range, null, true, false)); + $retVal = null; + if ($this->workSheet !== null) { + $dataValues = Functions::flattenArray($this->workSheet->rangeToArray($range, null, true, false)); + $dataValues = array_filter($dataValues); - $dataValues = array_filter($dataValues); - if ($ruleType == Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) { - rsort($dataValues); - } else { - sort($dataValues); - } + if ($ruleType == Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) { + rsort($dataValues); + } else { + sort($dataValues); + } - $slice = array_slice($dataValues, 0, $ruleValue); + $slice = array_slice($dataValues, 0, $ruleValue); - return array_pop($slice); + $retVal = array_pop($slice); + } + + return $retVal; } /** @@ -734,6 +743,9 @@ private function calculateTopTenValue($columnID, $startRow, $endRow, $ruleType, */ public function showHideRows() { + if ($this->workSheet === null) { + return $this; + } [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range); // The heading row should always be visible @@ -771,6 +783,9 @@ public function showHideRows() 'dateTime' => [], ]; foreach ($ruleDataSet as $ruleValue) { + if (!is_array($ruleValue)) { + continue; + } $date = $time = ''; if ( (isset($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_YEAR])) && @@ -830,10 +845,9 @@ public function showHideRows() // Build a list of the filter value selections foreach ($rules as $rule) { $ruleValue = $rule->getValue(); - if (!is_numeric($ruleValue)) { + if (!is_array($ruleValue) && !is_numeric($ruleValue)) { // Convert to a regexp allowing for regexp reserved characters, wildcards and escaped wildcards - $ruleValue = preg_quote($ruleValue); - $ruleValue = str_replace(self::$fromReplace, self::$toReplace, $ruleValue); + $ruleValue = WildcardMatch::wildcard($ruleValue); if (trim($ruleValue) == '') { $customRuleForBlanks = true; $ruleValue = trim($ruleValue); @@ -860,7 +874,8 @@ public function showHideRows() // Number (Average) based // Calculate the average $averageFormula = '=AVERAGE(' . $columnID . ($rangeStart[1] + 1) . ':' . $columnID . $rangeEnd[1] . ')'; - $average = Calculation::getInstance()->calculateFormula($averageFormula, null, $this->workSheet->getCell('A1')); + $spreadsheet = ($this->workSheet === null) ? null : $this->workSheet->getParent(); + $average = Calculation::getInstance($spreadsheet)->calculateFormula($averageFormula, null, $this->workSheet->getCell('A1')); // Set above/below rule based on greaterThan or LessTan $operator = ($dynamicRuleType === Rule::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE) ? Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN @@ -915,8 +930,8 @@ public function showHideRows() $ruleValue = $rule->getValue(); $ruleOperator = $rule->getOperator(); } - if ($ruleOperator === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) { - $ruleValue = floor($ruleValue * ($dataRowCount / 100)); + if (is_numeric($ruleValue) && $ruleOperator === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) { + $ruleValue = floor((float) $ruleValue * ($dataRowCount / 100)); } if (!is_array($ruleValue) && $ruleValue < 1) { $ruleValue = 1; @@ -925,7 +940,7 @@ public function showHideRows() $ruleValue = 500; } - $maxVal = $this->calculateTopTenValue($columnID, $rangeStart[1] + 1, $rangeEnd[1], $toptenRuleType, $ruleValue); + $maxVal = $this->calculateTopTenValue($columnID, $rangeStart[1] + 1, (int) $rangeEnd[1], $toptenRuleType, $ruleValue); $operator = ($toptenRuleType == Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL @@ -947,18 +962,16 @@ public function showHideRows() foreach ($columnFilterTests as $columnID => $columnFilterTest) { $cellValue = $this->workSheet->getCell($columnID . $row)->getCalculatedValue(); // Execute the filter test - $result = $result && - call_user_func_array( - [self::class, $columnFilterTest['method']], - [$cellValue, $columnFilterTest['arguments']] - ); + $result = // $result && // phpstan says $result is always true here + // @phpstan-ignore-next-line + call_user_func_array([self::class, $columnFilterTest['method']], [$cellValue, $columnFilterTest['arguments']]); // If filter test has resulted in FALSE, exit the loop straightaway rather than running any more tests if (!$result) { break; } } // Set show/hide for the row based on the result of the autoFilter result - $this->workSheet->getRowDimension($row)->setVisible($result); + $this->workSheet->getRowDimension((int) $row)->setVisible($result); } return $this; diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php index 1309b30fda..6bedceca99 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php @@ -244,7 +244,7 @@ public function setAttribute($pName, $pValue) /** * Get AutoFilter Column Attributes. * - * @return string[] + * @return int[]|string[] */ public function getAttributes() { @@ -256,7 +256,7 @@ public function getAttributes() * * @param string $pName Attribute Name * - * @return null|string + * @return null|int|string */ public function getAttribute($pName) { @@ -370,8 +370,6 @@ public function __clone() $cloned->setParent($this); // attach the new cloned Rule to this new cloned Autofilter Cloned object $this->ruleset[$k] = $cloned; } - } elseif (is_object($value)) { - $this->$key = clone $value; } else { $this->$key = $value; } diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php index 330a164105..37ea070b88 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php @@ -13,7 +13,7 @@ class Rule const AUTOFILTER_RULETYPE_DYNAMICFILTER = 'dynamicFilter'; const AUTOFILTER_RULETYPE_TOPTENFILTER = 'top10Filter'; - private static $ruleTypes = [ + private const RULE_TYPES = [ // Currently we're not handling // colorFilter // extLst @@ -32,7 +32,7 @@ class Rule const AUTOFILTER_RULETYPE_DATEGROUP_MINUTE = 'minute'; const AUTOFILTER_RULETYPE_DATEGROUP_SECOND = 'second'; - private static $dateTimeGroups = [ + private const DATE_TIME_GROUPS = [ self::AUTOFILTER_RULETYPE_DATEGROUP_YEAR, self::AUTOFILTER_RULETYPE_DATEGROUP_MONTH, self::AUTOFILTER_RULETYPE_DATEGROUP_DAY, @@ -88,7 +88,7 @@ class Rule const AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE = 'aboveAverage'; const AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE = 'belowAverage'; - private static $dynamicTypes = [ + private const DYNAMIC_TYPES = [ self::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY, self::AUTOFILTER_RULETYPE_DYNAMIC_TODAY, self::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW, @@ -141,7 +141,7 @@ class Rule const AUTOFILTER_COLUMN_RULE_LESSTHAN = 'lessThan'; const AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL = 'lessThanOrEqual'; - private static $operators = [ + private const OPERATORS = [ self::AUTOFILTER_COLUMN_RULE_EQUAL, self::AUTOFILTER_COLUMN_RULE_NOTEQUAL, self::AUTOFILTER_COLUMN_RULE_GREATERTHAN, @@ -153,7 +153,7 @@ class Rule const AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE = 'byValue'; const AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT = 'byPercent'; - private static $topTenValue = [ + private const TOP_TEN_VALUE = [ self::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, self::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT, ]; @@ -161,7 +161,7 @@ class Rule const AUTOFILTER_COLUMN_RULE_TOPTEN_TOP = 'top'; const AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM = 'bottom'; - private static $topTenType = [ + private const TOP_TEN_TYPE = [ self::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP, self::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM, ]; @@ -203,7 +203,7 @@ class Rule /** * Autofilter Column. * - * @var Column + * @var ?Column */ private $parent; @@ -217,7 +217,7 @@ class Rule /** * Autofilter Rule Value. * - * @var string|string[] + * @var int|int[]|string|string[] */ private $value = ''; @@ -237,8 +237,6 @@ class Rule /** * Create a new Rule. - * - * @param Column $pParent */ public function __construct(?Column $pParent = null) { @@ -264,7 +262,7 @@ public function getRuleType() */ public function setRuleType($pRuleType) { - if (!in_array($pRuleType, self::$ruleTypes)) { + if (!in_array($pRuleType, self::RULE_TYPES)) { throw new PhpSpreadsheetException('Invalid rule type for column AutoFilter Rule.'); } @@ -276,7 +274,7 @@ public function setRuleType($pRuleType) /** * Get AutoFilter Rule Value. * - * @return string|string[] + * @return int|int[]|string|string[] */ public function getValue() { @@ -286,7 +284,7 @@ public function getValue() /** * Set AutoFilter Rule Value. * - * @param string|string[] $pValue + * @param int|int[]|string|string[] $pValue * * @return $this */ @@ -296,19 +294,19 @@ public function setValue($pValue) $grouping = -1; foreach ($pValue as $key => $value) { // Validate array entries - if (!in_array($key, self::$dateTimeGroups)) { + if (!in_array($key, self::DATE_TIME_GROUPS)) { // 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)); + $grouping = max($grouping, array_search($key, self::DATE_TIME_GROUPS)); } } if (count($pValue) == 0) { throw new PhpSpreadsheetException('Invalid rule value for column AutoFilter Rule.'); } // Set the dateTime grouping that we've anticipated - $this->setGrouping(self::$dateTimeGroups[$grouping]); + $this->setGrouping(self::DATE_TIME_GROUPS[$grouping]); } $this->value = $pValue; @@ -338,8 +336,8 @@ public function setOperator($pOperator) $pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL; } if ( - (!in_array($pOperator, self::$operators)) && - (!in_array($pOperator, self::$topTenValue)) + (!in_array($pOperator, self::OPERATORS)) && + (!in_array($pOperator, self::TOP_TEN_VALUE)) ) { throw new PhpSpreadsheetException('Invalid operator for column AutoFilter Rule.'); } @@ -369,11 +367,11 @@ public function setGrouping($pGrouping) { if ( ($pGrouping !== null) && - (!in_array($pGrouping, self::$dateTimeGroups)) && - (!in_array($pGrouping, self::$dynamicTypes)) && - (!in_array($pGrouping, self::$topTenType)) + (!in_array($pGrouping, self::DATE_TIME_GROUPS)) && + (!in_array($pGrouping, self::DYNAMIC_TYPES)) && + (!in_array($pGrouping, self::TOP_TEN_TYPE)) ) { - throw new PhpSpreadsheetException('Invalid rule type for column AutoFilter Rule.'); + throw new PhpSpreadsheetException('Invalid grouping for column AutoFilter Rule.'); } $this->grouping = $pGrouping; @@ -384,7 +382,7 @@ public function setGrouping($pGrouping) * Set AutoFilter Rule. * * @param string $pOperator see self::AUTOFILTER_COLUMN_RULE_* - * @param string|string[] $pValue + * @param int|int[]|string|string[] $pValue * @param string $pGrouping * * @return $this @@ -406,7 +404,7 @@ public function setRule($pOperator, $pValue, $pGrouping = null) /** * Get this Rule's AutoFilter Column Parent. * - * @return Column + * @return ?Column */ public function getParent() { @@ -416,8 +414,6 @@ public function getParent() /** * Set this Rule's AutoFilter Column Parent. * - * @param Column $pParent - * * @return $this */ public function setParent(?Column $pParent = null) @@ -435,11 +431,9 @@ public function __clone() $vars = get_object_vars($this); foreach ($vars as $key => $value) { if (is_object($value)) { - if ($key == 'parent') { + if ($key == 'parent') { // this is only object // Detach from autofilter column parent $this->$key = null; - } else { - $this->$key = clone $value; } } else { $this->$key = $value; diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 70d0a41486..548ea49720 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -917,15 +917,18 @@ private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $ $objWriter->writeAttribute('type', $rule->getGrouping()); $val = $column->getAttribute('val'); if ($val !== null) { - $objWriter->writeAttribute('val', $val); + $objWriter->writeAttribute('val', "$val"); } $maxVal = $column->getAttribute('maxVal'); if ($maxVal !== null) { - $objWriter->writeAttribute('maxVal', $maxVal); + $objWriter->writeAttribute('maxVal', "$maxVal"); } } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) { // Top 10 Filter Rule - $objWriter->writeAttribute('val', $rule->getValue()); + $ruleValue = $rule->getValue(); + if (!is_array($ruleValue)) { + $objWriter->writeAttribute('val', "$ruleValue"); + } $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0')); $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0')); } else { @@ -937,14 +940,18 @@ private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $ } if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) { // Date Group filters - foreach ($rule->getValue() as $key => $value) { - if ($value > '') { - $objWriter->writeAttribute($key, $value); + $ruleValue = $rule->getValue(); + if (is_array($ruleValue)) { + foreach ($ruleValue as $key => $value) { + $objWriter->writeAttribute($key, "$value"); } } $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping()); } else { - $objWriter->writeAttribute('val', $rule->getValue()); + $ruleValue = $rule->getValue(); + if (!is_array($ruleValue)) { + $objWriter->writeAttribute('val', "$ruleValue"); + } } $objWriter->endElement(); diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterAverageTop10Test.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterAverageTop10Test.php new file mode 100644 index 0000000000..79358823c0 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterAverageTop10Test.php @@ -0,0 +1,165 @@ +getSheet(); + $sheet->getCell('A1')->setValue('Header'); + $sheet->getCell('A2')->setValue(1); + $sheet->getCell('A3')->setValue(3); + $sheet->getCell('A4')->setValue(5); + $sheet->getCell('A5')->setValue(7); + $sheet->getCell('A6')->setValue(9); + $sheet->getCell('A7')->setValue(2); + $sheet->getCell('A8')->setValue(4); + $sheet->getCell('A9')->setValue(6); + $sheet->getCell('A10')->setValue(8); + $this->maxRow = 10; + + return $sheet; + } + + public function providerAverage(): array + { + return [ + [[5, 6, 9, 10], Rule::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE], + [[2, 3, 7, 8], Rule::AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE], + ]; + } + + /** + * @dataProvider providerAverage + */ + public function testAboveAverage(array $expectedVisible, string $rule): void + { + $sheet = $this->initSheet(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:A$maxRow"); + $columnFilter = $autoFilter->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + '', + $rule + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER); + + self::assertEquals($expectedVisible, $this->getVisible()); + } + + public function providerTop10(): array + { + return [ + [[6, 10], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP, 2], + [[2, 3, 7], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM, 3], + [[6], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP, 10], + [[2, 3, 7], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM, 40], + ]; + } + + /** + * @dataProvider providerTop10 + */ + public function testTop10(array $expectedVisible, string $rule, string $ruleType, int $count): void + { + $sheet = $this->initSheet(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:A$maxRow"); + $columnFilter = $autoFilter->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER); + $columnFilter->createRule() + ->setRule( + $rule, + $count, + $ruleType + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_TOPTENFILTER); + + self::assertEquals($expectedVisible, $this->getVisible()); + } + + public function initsheetTies(): Worksheet + { + $sheet = $this->getSheet(); + $sheet->getCell('A1')->setValue('Header'); + $sheet->getCell('A2')->setValue(1); + $sheet->getCell('A3')->setValue(3); + $sheet->getCell('A4')->setValue(3); + $sheet->getCell('A5')->setValue(7); + $sheet->getCell('A6')->setValue(9); + $sheet->getCell('A7')->setValue(4); + $sheet->getCell('A8')->setValue(4); + $sheet->getCell('A9')->setValue(8); + $sheet->getCell('A10')->setValue(8); + $this->maxRow = 10; + + return $sheet; + } + + public function providerTop10Ties(): array + { + return [ + [[2, 3, 4], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM, 2], + [[2], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM, 1], + [[5, 6, 7, 8, 9, 10], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP, 5], + [[6], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP, 1], + [[2, 3, 4], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM, 25], + [[6, 9, 10], Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT, Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP, 25], + ]; + } + + /** + * @dataProvider providerTop10Ties + */ + public function testTop10Ties(array $expectedVisible, string $rule, string $ruleType, int $count): void + { + $sheet = $this->initSheetTies(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:A$maxRow"); + $columnFilter = $autoFilter->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER); + $columnFilter->createRule() + ->setRule( + $rule, + $count, + $ruleType + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_TOPTENFILTER); + + self::assertEquals($expectedVisible, $this->getVisible()); + } + + public function testTop10Exceeds500(): void + { + $sheet = $this->getSheet(); + $sheet->getCell('A1')->setValue('Heading'); + for ($row = 2; $row < 602; ++$row) { + $sheet->getCell("A$row")->setValue($row); + } + $maxRow = $this->maxRow = 601; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:A$maxRow"); + $columnFilter = $autoFilter->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE, + 550, + Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_TOPTENFILTER); + + self::assertCount(500, $this->getVisible(), 'Top10 Filter limited to 500 items plus ties'); + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterCustomTextTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterCustomTextTest.php new file mode 100644 index 0000000000..643ffc0f17 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterCustomTextTest.php @@ -0,0 +1,105 @@ +getSheet(); + $sheet->getCell('A1')->setValue('Header'); + $sheet->getCell('A2')->setValue('abc'); + $sheet->getCell('A3')->setValue('cba'); + $sheet->getCell('A4')->setValue('cab'); + // nothing in cell A5 + $sheet->getCell('A6')->setValue('c*b'); + $sheet->getCell('A7')->setValue('c?b'); + $sheet->getCell('A8')->setValue('a'); + $sheet->getCell('A9')->setValue('zzbc'); + $sheet->getCell('A10')->setValue('zzbcd'); + $sheet->getCell('A11')->setValue('~pqr'); + $sheet->getCell('A12')->setValue('pqr~'); + $this->maxRow = 12; + + return $sheet; + } + + public function providerCustomText(): array + { + return [ + 'begins with a' => [[2, 8], 'a*'], + 'ends with b' => [[4, 6, 7], '*b'], + 'contains c' => [[2, 3, 4, 6, 7, 9, 10], '*c*'], + 'empty' => [[5], ''], + 'contains asterisk' => [[6], '*~**'], + 'contains question mark' => [[7], '*~?*'], + 'c followed by character followed by b' => [[4, 6, 7], 'c?b'], + 'one character followed by bc' => [[2], '?bc'], + 'two characters followed by bc' => [[9], '??bc'], + 'starts with z ends with c' => [[9], 'z*c'], + 'starts with tilde' => [[11], '~~*'], + 'contains tilde' => [[11, 12], '*~~*'], + ]; + } + + /** + * @dataProvider providerCustomText + */ + public function testCustomTest(array $expectedVisible, string $pattern): void + { + $sheet = $this->initSheet(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:A$maxRow"); + $columnFilter = $autoFilter->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + $pattern + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); + + self::assertEquals($expectedVisible, $this->getVisible()); + } + + public function testCustomTestNotEqual(): void + { + $sheet = $this->initSheet(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:A$maxRow"); + $columnFilter = $autoFilter->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL, + '' + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); + + self::assertEquals([2, 3, 4, 6, 7, 8, 9, 10, 11, 12], $this->getVisible()); + } + + public function testCustomTestGreaterThan(): void + { + $sheet = $this->initSheet(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:A$maxRow"); + $columnFilter = $autoFilter->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN, + '' + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); + + self::assertEquals([2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], $this->getVisible()); + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterMonthTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterMonthTest.php index 064c0daccc..c13e5a246e 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterMonthTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterMonthTest.php @@ -3,13 +3,11 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; use DateTimeImmutable; -use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -use PHPUnit\Framework\TestCase; -class AutoFilterMonthTest extends TestCase +class AutoFilterMonthTest extends SetupTeardown { public function providerMonth(): array { @@ -20,7 +18,7 @@ public function providerMonth(): array ]; } - private static function setCells(Worksheet $sheet, int $startMonth): void + private function setCells(Worksheet $sheet, int $startMonth): void { $sheet->getCell('A1')->setValue('Date'); $sheet->getCell('A2')->setValue('=TODAY()'); @@ -47,6 +45,7 @@ private static function setCells(Worksheet $sheet, int $startMonth): void } $sheet->getCell('A8')->setValue('=DATE(YEAR(A2) + 1, MONTH(A2), 1)'); $sheet->getCell('A9')->setValue('=DATE(YEAR(A2) - 1, MONTH(A2), 1)'); + $this->maxRow = 9; } /** @@ -57,15 +56,14 @@ public function testMonths(array $expectedVisible, string $rule): void // Loop to avoid rare edge case where first calculation // and second do not take place in same day. do { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $sheet = $this->getSheet(); $dtStart = new DateTimeImmutable(); $startDay = (int) $dtStart->format('d'); $startMonth = (int) $dtStart->format('m'); - self::setCells($sheet, $startMonth); + $this->setCells($sheet, $startMonth); - $maxRow = 9; - $autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); $autoFilter->setRange("A1:A$maxRow"); $columnFilter = $autoFilter->getColumn('A'); $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); @@ -80,12 +78,7 @@ public function testMonths(array $expectedVisible, string $rule): void $dtEnd = new DateTimeImmutable(); $endDay = (int) $dtEnd->format('d'); } while ($startDay !== $endDay); - $actualVisible = []; - for ($row = 2; $row <= $maxRow; ++$row) { - if ($sheet->getRowDimension($row)->getVisible()) { - $actualVisible[] = $row; - } - } - self::assertEquals($expectedVisible, $actualVisible); + + self::assertEquals($expectedVisible, $this->getVisible()); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterQuarterTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterQuarterTest.php index 73c48c4a9e..859f7fdd9f 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterQuarterTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterQuarterTest.php @@ -3,13 +3,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; use DateTimeImmutable; -use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; -use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -use PHPUnit\Framework\TestCase; -class AutoFilterQuarterTest extends TestCase +class AutoFilterQuarterTest extends SetupTeardown { public function providerQuarter(): array { @@ -20,8 +17,9 @@ public function providerQuarter(): array ]; } - private static function setCells(Worksheet $sheet): void + private function setCells(): void { + $sheet = $this->getSheet(); $sheet->getCell('A1')->setValue('Date'); $sheet->getCell('A2')->setValue('=TODAY()'); $sheet->getCell('A3')->setValue('=DATE(YEAR(A2), MONTH(A2), 1)'); @@ -31,6 +29,7 @@ private static function setCells(Worksheet $sheet): void $sheet->getCell('A7')->setValue('=DATE(YEAR(A2), MONTH(A2) - 6, 1)'); $sheet->getCell('A8')->setValue('=DATE(YEAR(A2) + 1, MONTH(A2), 1)'); $sheet->getCell('A9')->setValue('=DATE(YEAR(A2) - 1, MONTH(A2), 1)'); + $this->maxRow = 9; } /** @@ -41,14 +40,13 @@ public function testQuarters(array $expectedVisible, string $rule): void // Loop to avoid rare edge case where first calculation // and second do not take place in same day. do { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $sheet = $this->getSheet(); $dtStart = new DateTimeImmutable(); $startDay = (int) $dtStart->format('d'); - self::setCells($sheet); + $this->setCells(); - $maxRow = 9; - $autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); $autoFilter->setRange("A1:A$maxRow"); $columnFilter = $autoFilter->getColumn('A'); $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); @@ -63,12 +61,7 @@ public function testQuarters(array $expectedVisible, string $rule): void $dtEnd = new DateTimeImmutable(); $endDay = (int) $dtEnd->format('d'); } while ($startDay !== $endDay); - $actualVisible = []; - for ($row = 2; $row <= $maxRow; ++$row) { - if ($sheet->getRowDimension($row)->getVisible()) { - $actualVisible[] = $row; - } - } - self::assertEquals($expectedVisible, $actualVisible); + + self::assertEquals($expectedVisible, $this->getVisible()); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTest.php index a6693d3444..28bbbb87a3 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTest.php @@ -2,95 +2,78 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; -use PhpOffice\PhpSpreadsheet\Collection\Cells; +use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; -class AutoFilterTest extends TestCase +class AutoFilterTest extends SetupTeardown { - /** - * @var string - */ - private $testInitialRange = 'H2:O256'; - - /** - * @var AutoFilter - */ - private $testAutoFilterObject; - - /** - * @var Worksheet&MockObject - */ - private $mockWorksheetObject; - - /** - * @var Cells&MockObject - */ - private $cellCollection; - - protected function setUp(): void - { - $this->mockWorksheetObject = $this->getMockBuilder(Worksheet::class) - ->disableOriginalConstructor() - ->getMock(); - $this->cellCollection = $this->getMockBuilder(Cells::class) - ->disableOriginalConstructor() - ->getMock(); - $this->mockWorksheetObject->expects(self::any()) - ->method('getCellCollection') - ->willReturn($this->cellCollection); - - $this->testAutoFilterObject = new AutoFilter($this->testInitialRange, $this->mockWorksheetObject); - } + private const INITIAL_RANGE = 'H2:O256'; public function testToString(): void { - $expectedResult = $this->testInitialRange; + $expectedResult = self::INITIAL_RANGE; + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // magic __toString should return the active autofilter range - $result = $this->testAutoFilterObject; + $result = (string) $autoFilter; self::assertEquals($expectedResult, $result); } public function testGetParent(): void { - $result = $this->testAutoFilterObject->getParent(); - self::assertInstanceOf(Worksheet::class, $result); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); + $result = $autoFilter->getParent(); + self::assertSame($sheet, $result); } public function testSetParent(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); + $spreadsheet = $this->getSpreadsheet(); + $sheet2 = $spreadsheet->createSheet(); // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterObject->setParent($this->mockWorksheetObject); + $result = $autoFilter->setParent($sheet2); self::assertInstanceOf(AutoFilter::class, $result); } public function testGetRange(): void { - $expectedResult = $this->testInitialRange; + $expectedResult = self::INITIAL_RANGE; + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // Result should be the active autofilter range - $result = $this->testAutoFilterObject->getRange(); + $result = $autoFilter->getRange(); self::assertEquals($expectedResult, $result); } public function testSetRange(): void { + $sheet = $this->getSheet(); + $title = $sheet->getTitle(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); $ranges = [ - 'G1:J512' => 'Worksheet1!G1:J512', + 'G1:J512' => "$title!G1:J512", 'K1:N20' => 'K1:N20', ]; foreach ($ranges as $actualRange => $fullRange) { // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterObject->setRange($fullRange); + $result = $autoFilter->setRange($fullRange); self::assertInstanceOf(AutoFilter::class, $result); // Result should be the new autofilter range - $result = $this->testAutoFilterObject->getRange(); + $result = $autoFilter->getRange(); self::assertEquals($actualRange, $result); } } @@ -98,29 +81,36 @@ public function testSetRange(): void public function testClearRange(): void { $expectedResult = ''; + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterObject->setRange(''); + $result = $autoFilter->setRange(''); self::assertInstanceOf(AutoFilter::class, $result); // Result should be a clear range - $result = $this->testAutoFilterObject->getRange(); + $result = $autoFilter->getRange(); self::assertEquals($expectedResult, $result); } public function testSetRangeInvalidRange(): void { - $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + $this->expectException(PhpSpreadsheetException::class); $expectedResult = 'A1'; - $this->testAutoFilterObject->setRange($expectedResult); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange($expectedResult); } public function testGetColumnsEmpty(): void { // There should be no columns yet defined - $result = $this->testAutoFilterObject->getColumns(); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $result = $autoFilter->getColumns(); self::assertIsArray($result); self::assertCount(0, $result); } @@ -132,33 +122,42 @@ public function testGetColumnOffset(): void 'K' => 3, 'M' => 5, ]; + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // If we request a specific column by its column ID, we should get an // integer returned representing the column offset within the range foreach ($columnIndexes as $columnIndex => $columnOffset) { - $result = $this->testAutoFilterObject->getColumnOffset($columnIndex); + $result = $autoFilter->getColumnOffset($columnIndex); self::assertEquals($columnOffset, $result); } } public function testGetInvalidColumnOffset(): void { - $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + $this->expectException(PhpSpreadsheetException::class); $invalidColumn = 'G'; + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); - $this->testAutoFilterObject->getColumnOffset($invalidColumn); + $autoFilter->getColumnOffset($invalidColumn); } public function testSetColumnWithString(): void { $expectedResult = 'L'; + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterObject->setColumn($expectedResult); + $result = $autoFilter->setColumn($expectedResult); self::assertInstanceOf(AutoFilter::class, $result); - $result = $this->testAutoFilterObject->getColumns(); + $result = $autoFilter->getColumns(); // Result should be an array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter\Column // objects for each column we set indexed by the column ID self::assertIsArray($result); @@ -169,23 +168,29 @@ public function testSetColumnWithString(): void public function testSetInvalidColumnWithString(): void { - $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + $this->expectException(PhpSpreadsheetException::class); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); $invalidColumn = 'A'; - $this->testAutoFilterObject->setColumn($invalidColumn); + $autoFilter->setColumn($invalidColumn); } public function testSetColumnWithColumnObject(): void { $expectedResult = 'M'; - $columnObject = new AutoFilter\Column($expectedResult); + $columnObject = new Column($expectedResult); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterObject->setColumn($columnObject); + $result = $autoFilter->setColumn($columnObject); self::assertInstanceOf(AutoFilter::class, $result); - $result = $this->testAutoFilterObject->getColumns(); + $result = $autoFilter->getColumns(); // Result should be an array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter\Column // objects for each column we set indexed by the column ID self::assertIsArray($result); @@ -196,30 +201,40 @@ public function testSetColumnWithColumnObject(): void public function testSetInvalidColumnWithObject(): void { - $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + $this->expectException(PhpSpreadsheetException::class); $invalidColumn = 'E'; - $this->testAutoFilterObject->setColumn($invalidColumn); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); + $autoFilter->setColumn($invalidColumn); } public function testSetColumnWithInvalidDataType(): void { - $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + $this->expectException(PhpSpreadsheetException::class); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); $invalidColumn = 123.456; // @phpstan-ignore-next-line - $this->testAutoFilterObject->setColumn($invalidColumn); + $autoFilter->setColumn($invalidColumn); } public function testGetColumns(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); + $columnIndexes = ['L', 'M']; foreach ($columnIndexes as $columnIndex) { - $this->testAutoFilterObject->setColumn($columnIndex); + $autoFilter->setColumn($columnIndex); } - $result = $this->testAutoFilterObject->getColumns(); + $result = $autoFilter->getColumns(); // Result should be an array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter\Column // objects for each column we set indexed by the column ID self::assertIsArray($result); @@ -228,26 +243,38 @@ public function testGetColumns(): void self::assertArrayHasKey($columnIndex, $result); self::assertInstanceOf(Column::class, $result[$columnIndex]); } + + $autoFilter->setRange(''); + self::assertCount(0, $autoFilter->getColumns()); + self::assertSame('', $autoFilter->getRange()); } public function testGetColumn(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); + $columnIndexes = ['L', 'M']; foreach ($columnIndexes as $columnIndex) { - $this->testAutoFilterObject->setColumn($columnIndex); + $autoFilter->setColumn($columnIndex); } // If we request a specific column by its column ID, we should // get a \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter\Column object returned foreach ($columnIndexes as $columnIndex) { - $result = $this->testAutoFilterObject->getColumn($columnIndex); + $result = $autoFilter->getColumn($columnIndex); self::assertInstanceOf(Column::class, $result); } } public function testGetColumnByOffset(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); + $columnIndexes = [ 0 => 'H', 3 => 'K', @@ -257,7 +284,7 @@ public function testGetColumnByOffset(): void // If we request a specific column by its offset, we should // get a \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter\Column object returned foreach ($columnIndexes as $columnIndex => $columnID) { - $result = $this->testAutoFilterObject->getColumnByOffset($columnIndex); + $result = $autoFilter->getColumnByOffset($columnIndex); self::assertInstanceOf(Column::class, $result); self::assertEquals($result->getColumnIndex(), $columnID); } @@ -265,83 +292,152 @@ public function testGetColumnByOffset(): void public function testGetColumnIfNotSet(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // If we request a specific column by its column ID, we should // get a \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter\Column object returned - $result = $this->testAutoFilterObject->getColumn('K'); + $result = $autoFilter->getColumn('K'); self::assertInstanceOf(Column::class, $result); } public function testGetColumnWithoutRangeSet(): void { $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); // Clear the range - $this->testAutoFilterObject->setRange(''); - $this->testAutoFilterObject->getColumn('A'); + $autoFilter->setRange(''); + $autoFilter->getColumn('A'); } public function testClearRangeWithExistingColumns(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); $expectedResult = ''; $columnIndexes = ['L', 'M', 'N']; foreach ($columnIndexes as $columnIndex) { - $this->testAutoFilterObject->setColumn($columnIndex); + $autoFilter->setColumn($columnIndex); } // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterObject->setRange(''); + $result = $autoFilter->setRange(''); self::assertInstanceOf(AutoFilter::class, $result); // Range should be cleared - $result = $this->testAutoFilterObject->getRange(); + $result = $autoFilter->getRange(); self::assertEquals($expectedResult, $result); // Column array should be cleared - $result = $this->testAutoFilterObject->getColumns(); + $result = $autoFilter->getColumns(); self::assertIsArray($result); self::assertCount(0, $result); } public function testSetRangeWithExistingColumns(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); $expectedResult = 'G1:J512'; // These columns should be retained $columnIndexes1 = ['I', 'J']; foreach ($columnIndexes1 as $columnIndex) { - $this->testAutoFilterObject->setColumn($columnIndex); + $autoFilter->setColumn($columnIndex); } // These columns should be discarded $columnIndexes2 = ['K', 'L', 'M']; foreach ($columnIndexes2 as $columnIndex) { - $this->testAutoFilterObject->setColumn($columnIndex); + $autoFilter->setColumn($columnIndex); } // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterObject->setRange($expectedResult); + $result = $autoFilter->setRange($expectedResult); self::assertInstanceOf(AutoFilter::class, $result); // Range should be correctly set - $result = $this->testAutoFilterObject->getRange(); + $result = $autoFilter->getRange(); self::assertEquals($expectedResult, $result); // Only columns that existed in the original range and that // still fall within the new range should be retained - $result = $this->testAutoFilterObject->getColumns(); + $result = $autoFilter->getColumns(); self::assertIsArray($result); self::assertCount(count($columnIndexes1), $result); } public function testClone(): void { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); $columnIndexes = ['L', 'M']; foreach ($columnIndexes as $columnIndex) { - $this->testAutoFilterObject->setColumn($columnIndex); + $autoFilter->setColumn($columnIndex); } - $result = clone $this->testAutoFilterObject; + $result = clone $autoFilter; self::assertInstanceOf(AutoFilter::class, $result); + self::assertSame($autoFilter->getRange(), $result->getRange()); + self::assertNull($result->getParent()); + self::assertNotNull($autoFilter->getParent()); + self::assertInstanceOf(Worksheet::class, $autoFilter->getParent()); + $autoColumns = $autoFilter->getColumns(); + $resultColumns = $result->getColumns(); + self::assertIsArray($autoColumns); + self::assertIsArray($resultColumns); + self::assertCount(2, $autoColumns); + self::assertCount(2, $resultColumns); + self::assertArrayHasKey('L', $autoColumns); + self::assertArrayHasKey('L', $resultColumns); + self::assertArrayHasKey('M', $autoColumns); + self::assertArrayHasKey('M', $resultColumns); + self::assertInstanceOf(Column::class, $autoColumns['L']); + self::assertInstanceOf(Column::class, $resultColumns['L']); + self::assertInstanceOf(Column::class, $autoColumns['M']); + self::assertInstanceOf(Column::class, $resultColumns['M']); + } + + public function testNoWorksheet(): void + { + $autoFilter = new AutoFilter(); + self::assertSame($autoFilter, $autoFilter->showHideRows()); + } + + public function testClearColumn(): void + { + $sheet = $this->getSheet(); + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange(self::INITIAL_RANGE); + $columnIndexes = ['J', 'K', 'L', 'M']; + + foreach ($columnIndexes as $columnIndex) { + $autoFilter->setColumn($columnIndex); + } + $columns = $autoFilter->getColumns(); + self::assertCount(4, $columns); + self::assertArrayHasKey('J', $columns); + self::assertArrayHasKey('K', $columns); + self::assertArrayHasKey('L', $columns); + self::assertArrayHasKey('M', $columns); + $autoFilter->clearColumn('K'); + $columns = $autoFilter->getColumns(); + self::assertCount(3, $columns); + self::assertArrayHasKey('J', $columns); + self::assertArrayHasKey('L', $columns); + self::assertArrayHasKey('M', $columns); + $autoFilter->shiftColumn('L', 'K'); + $columns = $autoFilter->getColumns(); + self::assertCount(3, $columns); + self::assertArrayHasKey('J', $columns); + self::assertArrayHasKey('K', $columns); + self::assertArrayHasKey('M', $columns); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTodayTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTodayTest.php index 3875eb8d77..0a8aa723b9 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTodayTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTodayTest.php @@ -3,12 +3,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; use DateTimeImmutable; -use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; -use PHPUnit\Framework\TestCase; -class AutoFilterTodayTest extends TestCase +class AutoFilterTodayTest extends SetupTeardown { public function providerYesterdayTodayTomorrow(): array { @@ -27,8 +25,7 @@ public function testYesterdayTodayTomorrow(array $expectedVisible, string $rule) // Loop to avoid rare edge case where first calculation // and second do not take place in same day. do { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $sheet = $this->getSheet(); $dtStart = new DateTimeImmutable(); $startDay = $dtStart->format('d'); $sheet->getCell('A1')->setValue('Date'); @@ -38,8 +35,8 @@ public function testYesterdayTodayTomorrow(array $expectedVisible, string $rule) $sheet->getCell('A5')->setValue('=TODAY()'); $sheet->getCell('A6')->setValue('=A5+1'); $sheet->getCell('A7')->setValue('=A5-1'); - $maxRow = 7; - $autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter(); + $this->maxRow = $maxRow = 7; + $autoFilter = $sheet->getAutoFilter(); $autoFilter->setRange("A1:A$maxRow"); $columnFilter = $autoFilter->getColumn('A'); $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); @@ -54,12 +51,7 @@ public function testYesterdayTodayTomorrow(array $expectedVisible, string $rule) $dtEnd = new DateTimeImmutable(); $endDay = $dtEnd->format('d'); } while ($startDay !== $endDay); - $actualVisible = []; - for ($row = 2; $row <= $maxRow; ++$row) { - if ($sheet->getRowDimension($row)->getVisible()) { - $actualVisible[] = $row; - } - } - self::assertEquals($expectedVisible, $actualVisible); + + self::assertEquals($expectedVisible, $this->getVisible()); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterWeekTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterWeekTest.php index 765bf11c5e..6784d226c1 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterWeekTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterWeekTest.php @@ -3,13 +3,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; use DateTimeImmutable; -use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; -use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -use PHPUnit\Framework\TestCase; -class AutoFilterWeekTest extends TestCase +class AutoFilterWeekTest extends SetupTeardown { public function providerWeek(): array { @@ -20,8 +17,9 @@ public function providerWeek(): array ]; } - private static function setCells(Worksheet $sheet): void + private function setCells(): void { + $sheet = $this->getSheet(); $sheet->getCell('A1')->setValue('Date'); $sheet->getCell('A2')->setValue('=TODAY()'); $sheet->getCell('B2')->setValue('=WEEKDAY(A2) - 1'); // subtract to get to Sunday @@ -32,6 +30,7 @@ private static function setCells(Worksheet $sheet): void $sheet->getCell('A7')->setValue('=DATE(YEAR(A3), MONTH(A3), DAY(A3) - 12)'); $sheet->getCell('A8')->setValue('=DATE(YEAR(A2) + 1, MONTH(A2), 1)'); $sheet->getCell('A9')->setValue('=DATE(YEAR(A2) - 1, MONTH(A2), 1)'); + $this->maxRow = 9; } /** @@ -42,14 +41,13 @@ public function testWeek(array $expectedVisible, string $rule): void // Loop to avoid rare edge case where first calculation // and second do not take place in same day. do { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $sheet = $this->getSheet(); $dtStart = new DateTimeImmutable(); $startDay = (int) $dtStart->format('d'); - self::setCells($sheet); + $this->setCells(); - $maxRow = 9; - $autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter(); + $maxRow = $this->maxRow; + $autoFilter = $sheet->getAutoFilter(); $autoFilter->setRange("A1:A$maxRow"); $columnFilter = $autoFilter->getColumn('A'); $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); @@ -64,12 +62,7 @@ public function testWeek(array $expectedVisible, string $rule): void $dtEnd = new DateTimeImmutable(); $endDay = (int) $dtEnd->format('d'); } while ($startDay !== $endDay); - $actualVisible = []; - for ($row = 2; $row <= $maxRow; ++$row) { - if ($sheet->getRowDimension($row)->getVisible()) { - $actualVisible[] = $row; - } - } - self::assertEquals($expectedVisible, $actualVisible); + + self::assertEquals($expectedVisible, $this->getVisible()); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterYearTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterYearTest.php index 8c416cc3af..442f846e41 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterYearTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterYearTest.php @@ -3,12 +3,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; use DateTimeImmutable; -use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; -use PHPUnit\Framework\TestCase; -class AutoFilterYearTest extends TestCase +class AutoFilterYearTest extends SetupTeardown { public function providerYear(): array { @@ -30,8 +28,7 @@ public function testYears(array $expectedVisible, string $rule): void // Loop to avoid rare edge case where first calculation // and second do not take place in same day. do { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $sheet = $this->getSheet(); $dtStart = new DateTimeImmutable(); $startDay = (int) $dtStart->format('d'); $sheet->getCell('A1')->setValue('Date'); @@ -48,8 +45,9 @@ public function testYears(array $expectedVisible, string $rule): void } ++$row; $sheet->getCell("A$row")->setValue('=DATE(2041, 1, 1)'); // beyond epoch - $maxRow = $row; - $autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter(); + ++$row; // empty row at end + $this->maxRow = $maxRow = $row; + $autoFilter = $sheet->getAutoFilter(); $autoFilter->setRange("A1:A$maxRow"); $columnFilter = $autoFilter->getColumn('A'); $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); @@ -64,13 +62,8 @@ public function testYears(array $expectedVisible, string $rule): void $dtEnd = new DateTimeImmutable(); $endDay = (int) $dtEnd->format('d'); } while ($startDay !== $endDay); - $actualVisible = []; - for ($row = 2; $row <= $maxRow; ++$row) { - if ($sheet->getRowDimension($row)->getVisible()) { - $actualVisible[] = $row; - } - } - self::assertEquals($expectedVisible, $actualVisible); + + self::assertEquals($expectedVisible, $this->getVisible()); } public function testYearToDate(): void @@ -78,8 +71,7 @@ public function testYearToDate(): void // Loop to avoid rare edge case where first calculation // and second do not take place in same day. do { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $sheet = $this->getSheet(); $dtStart = new DateTimeImmutable(); $startDay = (int) $dtStart->format('d'); $startMonth = (int) $dtStart->format('m'); @@ -90,8 +82,8 @@ public function testYearToDate(): void $sheet->getCell('A5')->setValue('=DATE(YEAR(A2), 1, 1)'); $sheet->getCell('A6')->setValue('=A5 - 1'); - $maxRow = 6; - $autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter(); + $this->maxRow = $maxRow = 6; + $autoFilter = $sheet->getAutoFilter(); $autoFilter->setRange("A1:A$maxRow"); $columnFilter = $autoFilter->getColumn('A'); $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); @@ -106,13 +98,8 @@ public function testYearToDate(): void $dtEnd = new DateTimeImmutable(); $endDay = (int) $dtEnd->format('d'); } while ($startDay !== $endDay); - $actualVisible = []; - for ($row = 2; $row <= $maxRow; ++$row) { - if ($sheet->getRowDimension($row)->getVisible()) { - $actualVisible[] = $row; - } - } + $expected = ($startMonth === 12 && $startDay === 31) ? [2, 3, 5] : [2, 5]; - self::assertEquals($expected, $actualVisible); + self::assertEquals($expected, $this->getVisible()); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php deleted file mode 100644 index 276836c905..0000000000 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php +++ /dev/null @@ -1,111 +0,0 @@ -mockAutoFilterColumnObject = $this->getMockBuilder(Column::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->testAutoFilterRuleObject = new Rule( - $this->mockAutoFilterColumnObject - ); - } - - public function testGetRuleType(): void - { - $result = $this->testAutoFilterRuleObject->getRuleType(); - self::assertEquals(Rule::AUTOFILTER_RULETYPE_FILTER, $result); - } - - public function testSetRuleType(): void - { - $expectedResult = Rule::AUTOFILTER_RULETYPE_DATEGROUP; - - // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterRuleObject->setRuleType($expectedResult); - self::assertInstanceOf(Rule::class, $result); - - $result = $this->testAutoFilterRuleObject->getRuleType(); - self::assertEquals($expectedResult, $result); - } - - public function testSetValue(): void - { - $expectedResult = 100; - - // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterRuleObject->setValue($expectedResult); - self::assertInstanceOf(Rule::class, $result); - - $result = $this->testAutoFilterRuleObject->getValue(); - self::assertEquals($expectedResult, $result); - } - - public function testGetOperator(): void - { - $result = $this->testAutoFilterRuleObject->getOperator(); - self::assertEquals(Rule::AUTOFILTER_COLUMN_RULE_EQUAL, $result); - } - - public function testSetOperator(): void - { - $expectedResult = Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN; - - // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterRuleObject->setOperator($expectedResult); - self::assertInstanceOf(Rule::class, $result); - - $result = $this->testAutoFilterRuleObject->getOperator(); - self::assertEquals($expectedResult, $result); - } - - public function testSetGrouping(): void - { - $expectedResult = Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH; - - // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterRuleObject->setGrouping($expectedResult); - self::assertInstanceOf(Rule::class, $result); - - $result = $this->testAutoFilterRuleObject->getGrouping(); - self::assertEquals($expectedResult, $result); - } - - public function testGetParent(): void - { - $result = $this->testAutoFilterRuleObject->getParent(); - self::assertInstanceOf(Column::class, $result); - } - - public function testSetParent(): void - { - // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterRuleObject->setParent($this->mockAutoFilterColumnObject); - self::assertInstanceOf(Rule::class, $result); - } - - public function testClone(): void - { - $result = clone $this->testAutoFilterRuleObject; - self::assertInstanceOf(Rule::class, $result); - } -} diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php index 933696266d..c94cb3a4b4 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php @@ -2,148 +2,174 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; -use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter; +use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; +use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -class ColumnTest extends TestCase +class ColumnTest extends SetupTeardown { - /** - * @var string - */ - private $testInitialColumn = 'H'; - - /** - * @var Column - */ - private $testAutoFilterColumnObject; - - /** - * @var AutoFilter&MockObject - */ - private $mockAutoFilterObject; - - protected function setUp(): void + protected function initSheet(): Worksheet { - $this->mockAutoFilterObject = $this->getMockBuilder(AutoFilter::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->mockAutoFilterObject->expects(self::any()) - ->method('testColumnInRange') - ->willReturn(3); + $sheet = $this->getSheet(); + $sheet->getCell('G1')->setValue('Heading'); + $sheet->getCell('G2')->setValue(2); + $sheet->getCell('G3')->setValue(3); + $sheet->getCell('G4')->setValue(4); + $sheet->getCell('H1')->setValue('Heading2'); + $sheet->getCell('H2')->setValue(1); + $sheet->getCell('H3')->setValue(2); + $sheet->getCell('H4')->setValue(3); + $this->maxRow = $maxRow = 4; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("G1:H$maxRow"); + + return $sheet; + } - $this->testAutoFilterColumnObject = new Column($this->testInitialColumn, $this->mockAutoFilterObject); + public function testVariousGets(): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $result = $columnFilter->getColumnIndex(); + self::assertEquals('H', $result); } - public function testGetColumnIndex(): void + public function testGetBadColumnIndex(): void { - $result = $this->testAutoFilterColumnObject->getColumnIndex(); - self::assertEquals($this->testInitialColumn, $result); + $this->expectException(PhpSpreadsheetException::class); + $this->expectExceptionMessage('Column is outside of current autofilter range.'); + $sheet = $this->initSheet(); + $sheet->getAutoFilter()->getColumn('B'); } public function testSetColumnIndex(): void { - $expectedResult = 'L'; - - // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterColumnObject->setColumnIndex($expectedResult); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $expectedResult = 'G'; + + $result = $columnFilter->setColumnIndex($expectedResult); self::assertInstanceOf(Column::class, $result); - $result = $this->testAutoFilterColumnObject->getColumnIndex(); + $result = $result->getColumnIndex(); self::assertEquals($expectedResult, $result); } - public function testGetParent(): void - { - $result = $this->testAutoFilterColumnObject->getParent(); - self::assertInstanceOf(AutoFilter::class, $result); - } - public function testSetParent(): void { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterColumnObject->setParent($this->mockAutoFilterObject); + $result = $columnFilter->setParent(null); self::assertInstanceOf(Column::class, $result); } - public function testGetFilterType(): void - { - $result = $this->testAutoFilterColumnObject->getFilterType(); - self::assertEquals(Column::AUTOFILTER_FILTERTYPE_FILTER, $result); - } - - public function testSetFilterType(): void + public function testVariousSets(): void { - $result = $this->testAutoFilterColumnObject->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + + $result = $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); self::assertInstanceOf(Column::class, $result); - $result = $this->testAutoFilterColumnObject->getFilterType(); + $result = $columnFilter->getFilterType(); self::assertEquals(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER, $result); - } - public function testSetInvalidFilterTypeThrowsException(): void - { - $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); - - $expectedResult = 'Unfiltered'; + $result = $columnFilter->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND); + self::assertInstanceOf(Column::class, $result); - $this->testAutoFilterColumnObject->setFilterType($expectedResult); + $result = $columnFilter->getJoin(); + self::assertEquals(Column::AUTOFILTER_COLUMN_JOIN_AND, $result); } - public function testGetJoin(): void + public function testSetInvalidFilterTypeThrowsException(): void { - $result = $this->testAutoFilterColumnObject->getJoin(); - self::assertEquals(Column::AUTOFILTER_COLUMN_JOIN_OR, $result); - } + $this->expectException(PhpSpreadsheetException::class); + $this->expectExceptionMessage('Invalid filter type for column AutoFilter.'); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); - public function testSetJoin(): void - { - $result = $this->testAutoFilterColumnObject->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND); - self::assertInstanceOf(Column::class, $result); + $expectedResult = 'Unfiltered'; - $result = $this->testAutoFilterColumnObject->getJoin(); - self::assertEquals(Column::AUTOFILTER_COLUMN_JOIN_AND, $result); + $columnFilter->setFilterType($expectedResult); } public function testSetInvalidJoinThrowsException(): void { - $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + $this->expectException(PhpSpreadsheetException::class); + $this->expectExceptionMessage('Invalid rule connection for column AutoFilter.'); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); $expectedResult = 'Neither'; - $this->testAutoFilterColumnObject->setJoin($expectedResult); - } - - public function testSetAttributes(): void - { - $attributeSet = [ - 'val' => 100, - 'maxVal' => 200, - ]; - - // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterColumnObject->setAttributes($attributeSet); - self::assertInstanceOf(Column::class, $result); + $columnFilter->setJoin($expectedResult); } public function testGetAttributes(): void { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); $attributeSet = [ 'val' => 100, 'maxVal' => 200, ]; - $this->testAutoFilterColumnObject->setAttributes($attributeSet); + $result = $columnFilter->setAttributes($attributeSet); + self::assertInstanceOf(Column::class, $result); - $result = $this->testAutoFilterColumnObject->getAttributes(); - self::assertIsArray($result); - self::assertCount(count($attributeSet), $result); + $result = $columnFilter->getAttributes(); + self::assertSame($attributeSet, $result); } public function testSetAttribute(): void { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $attributeSet = [ 'val' => 100, 'maxVal' => 200, @@ -151,37 +177,104 @@ public function testSetAttribute(): void foreach ($attributeSet as $attributeName => $attributeValue) { // Setters return the instance to implement the fluent interface - $result = $this->testAutoFilterColumnObject->setAttribute($attributeName, $attributeValue); + $result = $columnFilter->setAttribute($attributeName, $attributeValue); self::assertInstanceOf(Column::class, $result); } + self::assertSame($attributeSet, $columnFilter->getAttributes()); } public function testGetAttribute(): void { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $attributeSet = [ 'val' => 100, 'maxVal' => 200, ]; - $this->testAutoFilterColumnObject->setAttributes($attributeSet); + $columnFilter->setAttributes($attributeSet); foreach ($attributeSet as $attributeName => $attributeValue) { - $result = $this->testAutoFilterColumnObject->getAttribute($attributeName); - self::assertEquals($attributeValue, $result); + $result = $columnFilter->getAttribute($attributeName); + self::assertSame($attributeValue, $result); } - $result = $this->testAutoFilterColumnObject->getAttribute('nonExistentAttribute'); + $result = $columnFilter->getAttribute('nonExistentAttribute'); self::assertNull($result); } public function testClone(): void { - $originalRule = $this->testAutoFilterColumnObject->createRule(); - $result = clone $this->testAutoFilterColumnObject; - self::assertInstanceOf(Column::class, $result); - self::assertCount(1, $result->getRules()); - self::assertContainsOnlyInstancesOf(AutoFilter\Column\Rule::class, $result->getRules()); - $clonedRule = $result->getRules()[0]; - self::assertNotSame($originalRule, $clonedRule); - self::assertSame($result, $clonedRule->getParent()); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $originalRule = $columnFilter->getRules(); + $result = clone $columnFilter; + self::assertSame($columnFilter->getColumnIndex(), $result->getColumnIndex()); + self::assertSame($columnFilter->getFilterType(), $result->getFilterType()); + self::assertSame($columnFilter->getJoin(), $result->getJoin()); + self::assertNull($result->getParent()); + self::assertNotNull($columnFilter->getParent()); + self::assertContainsOnlyInstancesOf(Rule::class, $result->getRules()); + $clonedRule = $result->getRules(); + self::assertCount(1, $clonedRule); + self::assertCount(1, $originalRule); + self::assertNotSame($originalRule[0], $clonedRule[0]); + self::assertSame($originalRule[0]->getRuleType(), $clonedRule[0]->getRuleType()); + self::assertSame($originalRule[0]->getValue(), $clonedRule[0]->getValue()); + self::assertSame($originalRule[0]->getOperator(), $clonedRule[0]->getOperator()); + self::assertSame($originalRule[0]->getGrouping(), $clonedRule[0]->getGrouping()); + self::assertSame($result, $clonedRule[0]->getParent()); + } + + public function testRuleManipulation(): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('H'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $originalRules = $columnFilter->getRules(); + self::assertCount(1, $originalRules); + $rule0 = $columnFilter->getRule(0); + self::assertSame($originalRules[0], $rule0); + $rule1 = $columnFilter->getRule(1); + self::assertInstanceOf(Rule::class, $rule1); + self::assertNotEquals($originalRules[0], $rule1); + self::assertCount(2, $columnFilter->getRules()); + self::assertSame(Column::AUTOFILTER_COLUMN_JOIN_OR, $columnFilter->getJoin()); + $columnFilter->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND); + $rule2 = new Rule(); + $columnFilter->addRule($rule2); + self::assertCount(3, $columnFilter->getRules()); + self::assertSame(Column::AUTOFILTER_COLUMN_JOIN_AND, $columnFilter->getJoin()); + $columnFilter->deleteRule(2); + self::assertCount(2, $columnFilter->getRules()); + self::assertSame(Column::AUTOFILTER_COLUMN_JOIN_AND, $columnFilter->getJoin()); + $columnFilter->deleteRule(1); + self::assertCount(1, $columnFilter->getRules()); + self::assertSame(Column::AUTOFILTER_COLUMN_JOIN_OR, $columnFilter->getJoin()); + $columnFilter->addRule($rule1); + $columnFilter->addRule($rule2); + $columnFilter->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND); + self::assertCount(3, $columnFilter->getRules()); + self::assertSame(Column::AUTOFILTER_COLUMN_JOIN_AND, $columnFilter->getJoin()); + $columnFilter->clearRules(); + self::assertCount(0, $columnFilter->getRules()); + self::assertSame(Column::AUTOFILTER_COLUMN_JOIN_OR, $columnFilter->getJoin()); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/DateGroupTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/DateGroupTest.php new file mode 100644 index 0000000000..a89ebd5b53 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/DateGroupTest.php @@ -0,0 +1,223 @@ +getSheet(); + $sheet->getCell('A1')->setValue('Date'); + $sheet->getCell('B1')->setValue('Time'); + $sheet->getCell('C1')->setValue('DateTime'); + $sheet->getCell('C1')->setValue('Row*10'); + for ($row = 2; $row < 63; ++$row) { + $sheet->getCell("A$row")->setValue("=DATE($year,11,30)+$row"); + $hour = $row % 24; + $minute = $row % 10; + $second = $row % 20; + $sheet->getCell("B$row")->setValue("=TIME($hour,$minute,$second)"); + $sheet->getCell("C$row")->setValue("=A$row+B$row"); + $sheet->getCell("D$row")->setValue("=10*$row"); + } + $this->maxRow = $maxRow = 62; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:C$maxRow"); + + return $sheet; + } + + public function testYearMonthDayGroup(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('C'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => $year, + 'month' => 12, + 'day' => 6, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([6], $this->getVisible()); + } + + public function testYearMonthDayHourMinuteSecond1Group(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('C'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => $year, + 'month' => 12, + 'day' => 6, + 'hour' => 6, + 'minute' => 6, + 'second' => 6, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + $sheet->getCell('C5')->setValue(''); // make an empty cell in range + self::assertEquals([6], $this->getVisible()); + } + + public function testYearMonthDayHourMinuteSecond2Group(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('C'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => $year, + 'month' => 12, + 'day' => 6, + 'hour' => 6, + 'minute' => 6, + 'second' => 7, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([], $this->getVisible()); + } + + public function testDayGroupEpoch(): void + { + $year = 2040; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('C'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => $year, + 'month' => 12, + 'day' => 6, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([6], $this->getVisible()); + } + + public function testDayGroupNonArray(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $cellA2 = $sheet->getCell('A2')->getCalculatedValue(); + $columnFilter = $sheet->getAutoFilter()->getColumn('C'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + $cellA2 + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([], $this->getVisible()); + } + + public function testHourGroup(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('B'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'hour' => 14, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([14, 38, 62], $this->getVisible()); + } + + public function testHourMinuteGroup(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('B'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'hour' => 14, + 'minute' => 8, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([38], $this->getVisible()); + } + + public function testHourMinuteSecondGroup1(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('B'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'hour' => 14, + 'minute' => 8, + 'second' => 18, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([38], $this->getVisible()); + } + + public function testHourMinuteSecondGroup2(): void + { + $year = 2011; + $sheet = $this->initSheet($year); + $columnFilter = $sheet->getAutoFilter()->getColumn('B'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'hour' => 14, + 'minute' => 8, + 'second' => 19, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([], $this->getVisible()); + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleCustomTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleCustomTest.php new file mode 100644 index 0000000000..9f6b48bba6 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleCustomTest.php @@ -0,0 +1,57 @@ +getSheet(); + $sheet->getCell('A1')->setValue('Heading'); + $sheet->getCell('A2')->setValue(2); + $sheet->getCell('A3')->setValue(3); + $sheet->getCell('A4')->setValue(4); + $sheet->getCell('B1')->setValue('Heading2'); + $sheet->getCell('B2')->setValue(1); + $sheet->getCell('B3')->setValue(2); + $sheet->getCell('B4')->setValue(3); + $this->maxRow = $maxRow = 4; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:B$maxRow"); + + return $sheet; + } + + /** + * @dataProvider providerCondition + */ + public function testRuleCondition(array $expectedResult, string $condition): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER); + $columnFilter->createRule() + ->setRule( + $condition, + 3 + ) + ->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER); + self::assertEquals($expectedResult, $this->getVisible()); + } + + public function providerCondition(): array + { + return [ + [[3], Rule::AUTOFILTER_COLUMN_RULE_EQUAL], + [[2, 4], Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL], + [[4], Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN], + [[3, 4], Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL], + [[2], Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN], + [[2, 3], Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleDateGroupTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleDateGroupTest.php new file mode 100644 index 0000000000..3a32a9ebfd --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleDateGroupTest.php @@ -0,0 +1,132 @@ +getSheet(); + $sheet->getCell('A1')->setValue('Date'); + $sheet->getCell('A2')->setValue('=DATE(2011,1,10)'); + $sheet->getCell('A3')->setValue('=DATE(2012,1,10)'); + $sheet->getCell('A4')->setValue('=DATE(2011,1,10)'); + $sheet->getCell('A5')->setValue('=DATE(2012,2,10)'); + $sheet->getCell('A6')->setValue('=DATE(2012,1,1)'); + $sheet->getCell('A7')->setValue('=DATE(2012,12,31)'); + $sheet->getCell('B1')->setValue('Heading2'); + $sheet->getCell('B2')->setValue(1); + $sheet->getCell('B3')->setValue(2); + $sheet->getCell('B4')->setValue(3); + $sheet->getCell('B5')->setValue(4); + $sheet->getCell('B6')->setValue(5); + $sheet->getCell('B7')->setValue(6); + $this->maxRow = $maxRow = 7; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:B$maxRow"); + + return $sheet; + } + + public function testYearGroup(): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => 2012, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([3, 5, 6, 7], $this->getVisible()); + } + + public function testYearGroupWithInvalidIndex(): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => 2012, + 'xyz' => 5, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([3, 5, 6, 7], $this->getVisible()); + } + + public function testYearGroupNoValidIndexes(): void + { + $this->expectException(SpException::class); + $this->expectExceptionMessage('Invalid rule value for column AutoFilter Rule.'); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'zzyear' => 2012, + 'xyz' => 5, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([3, 5, 6, 7], $this->getVisible()); + } + + public function testYearGroupBadRuleType(): void + { + $this->expectException(SpException::class); + $this->expectExceptionMessage('Invalid rule type for column AutoFilter Rule.'); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => 2012, + ] + ) + ->setRuleType( + 'xyz' + ); + self::assertEquals([3, 5, 6, 7], $this->getVisible()); + } + + public function testYearMonthGroup(): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + [ + 'year' => 2012, + 'month' => 1, + ] + ) + ->setRuleType( + Rule::AUTOFILTER_RULETYPE_DATEGROUP + ); + self::assertEquals([3, 6], $this->getVisible()); + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleTest.php new file mode 100644 index 0000000000..c9eaa4f2e7 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/RuleTest.php @@ -0,0 +1,122 @@ +getSheet(); + $sheet->getCell('A1')->setValue('Heading'); + $sheet->getCell('A2')->setValue(2); + $sheet->getCell('A3')->setValue(3); + $sheet->getCell('A4')->setValue(4); + $sheet->getCell('B1')->setValue('Heading2'); + $sheet->getCell('B2')->setValue(1); + $sheet->getCell('B3')->setValue(2); + $sheet->getCell('B4')->setValue(3); + $this->maxRow = $maxRow = 4; + $autoFilter = $sheet->getAutoFilter(); + $autoFilter->setRange("A1:B$maxRow"); + + return $sheet; + } + + public function testRule(): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $autoFilterRuleObject = new Rule($columnFilter); + self::assertEquals(Rule::AUTOFILTER_RULETYPE_FILTER, $autoFilterRuleObject->getRuleType()); + self::assertEquals([3], $this->getVisible()); + $ruleParent = $autoFilterRuleObject->getParent(); + if ($ruleParent === null) { + self::fail('Unexpected null parent'); + } else { + self::assertEquals('A', $ruleParent->getColumnIndex()); + self::assertSame($columnFilter, $ruleParent); + } + } + + public function testSetParent(): void + { + $sheet = $this->initSheet(); + $autoFilterRuleObject = new Rule(); + $autoFilterRuleObject->setParent($sheet->getAutoFilter()->getColumn('B')); + $columnFilter = $autoFilterRuleObject->getParent(); + if ($columnFilter === null) { + self::fail('Unexpected null parent'); + } else { + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + self::assertEquals(Rule::AUTOFILTER_RULETYPE_FILTER, $autoFilterRuleObject->getRuleType()); + self::assertEquals([4], $this->getVisible()); + } + } + + public function testBadSetRule(): void + { + $this->expectException(SpException::class); + $this->expectExceptionMessage('Invalid operator for column AutoFilter Rule.'); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + 'xyz', + 3 + ); + } + + public function testBadSetGrouping(): void + { + $this->expectException(SpException::class); + $this->expectExceptionMessage('Invalid grouping for column AutoFilter Rule.'); + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + '', + 3 + ); + $autoFilterRuleObject = new Rule($columnFilter); + $autoFilterRuleObject->setGrouping('xyz'); + } + + public function testClone(): void + { + $sheet = $this->initSheet(); + $columnFilter = $sheet->getAutoFilter()->getColumn('A'); + $columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER); + $columnFilter->createRule() + ->setRule( + Rule::AUTOFILTER_COLUMN_RULE_EQUAL, + 3 + ); + $autoFilterRuleObject = new Rule($columnFilter); + $result = clone $autoFilterRuleObject; + self::assertSame($autoFilterRuleObject->getRuleType(), $result->getRuleType()); + self::assertSame($autoFilterRuleObject->getValue(), $result->getValue()); + self::assertSame($autoFilterRuleObject->getRuleType(), $result->getRuleType()); + self::assertSame($autoFilterRuleObject->getOperator(), $result->getOperator()); + self::assertSame($autoFilterRuleObject->getGrouping(), $result->getGrouping()); + self::assertNotNull($autoFilterRuleObject->getParent()); + self::assertNull($result->getParent()); + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/SetupTeardown.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/SetupTeardown.php new file mode 100644 index 0000000000..95d7801268 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/SetupTeardown.php @@ -0,0 +1,68 @@ +sheet = null; + if ($this->spreadsheet !== null) { + $this->spreadsheet->disconnectWorksheets(); + $this->spreadsheet = null; + } + } + + protected function getSpreadsheet(): Spreadsheet + { + if ($this->spreadsheet !== null) { + return $this->spreadsheet; + } + $this->spreadsheet = new Spreadsheet(); + + return $this->spreadsheet; + } + + protected function getSheet(): Worksheet + { + if ($this->sheet !== null) { + return $this->sheet; + } + $this->sheet = $this->getSpreadsheet()->getActiveSheet(); + + return $this->sheet; + } + + public function getVisible(): array + { + $sheet = $this->getSheet(); + $sheet->getAutoFilter()->showHideRows(); + $actualVisible = []; + for ($row = 2; $row <= $this->maxRow; ++$row) { + if ($sheet->getRowDimension($row)->getVisible()) { + $actualVisible[] = $row; + } + } + + return $actualVisible; + } +} diff --git a/tests/data/Calculation/LookupRef/MATCH.php b/tests/data/Calculation/LookupRef/MATCH.php index 03d9bfff14..47b925285f 100644 --- a/tests/data/Calculation/LookupRef/MATCH.php +++ b/tests/data/Calculation/LookupRef/MATCH.php @@ -346,4 +346,10 @@ ['Obtuse', 'Amuse', 'Obverse', 'Inverse', 'Assurance', 'Amplitude', 'Adverse', 'Apartment'], 0, ], + [ + 3, // Expected + '*~~*', // contains a tilde + ['aAAAAA', 'a123456*c', 'abc~xyz', 'alembic'], + 0, + ], ];