Merge pull request #2141 from oleibman/moredatefilter

Autofilter Part 1
This commit is contained in:
oleibman 2021-06-14 20:28:03 -07:00 committed by GitHub
commit 55b95201ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 801 additions and 190 deletions

View File

@ -327,14 +327,14 @@ $columnFilter->setFilterType(
```
When defining the rule for a dynamic filter, we don't define a value (we
can simply set that to NULL) but we do specify the dynamic filter
can simply set that to null string) but we do specify the dynamic filter
category.
```php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
NULL,
'',
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE
)
->setRuleType(

View File

@ -5392,7 +5392,7 @@ parameters:
-
message: "#^Parameter \\#1 \\$excelTimestamp of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:excelToTimestamp\\(\\) expects float\\|int, float\\|int\\|string given\\.$#"
count: 2
count: 1
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
@ -5405,36 +5405,6 @@ parameters:
count: 1
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
message: "#^Parameter \\#2 \\$now of function strtotime expects int, int\\|false given\\.$#"
count: 6
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
message: "#^Parameter \\#5 \\$day of function gmmktime expects int, string given\\.$#"
count: 8
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
message: "#^Parameter \\#6 \\$year of function gmmktime expects int, string given\\.$#"
count: 13
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
message: "#^Parameter \\#4 \\$mon of function gmmktime expects int, string given\\.$#"
count: 2
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
message: "#^Parameter \\#5 \\$day of function gmmktime expects int, float given\\.$#"
count: 2
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
message: "#^Parameter \\#1 \\$attributes of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\:\\:setAttributes\\(\\) expects array\\<string\\>, array\\<string, float\\|int\\|null\\> given\\.$#"
count: 1
path: src/PhpSpreadsheet/Worksheet/AutoFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has no return typehint specified\\.$#"
count: 1
@ -7415,21 +7385,11 @@ parameters:
count: 1
path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php
-
message: "#^Parameter \\#1 \\$attributes of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\:\\:setAttributes\\(\\) expects array\\<string\\>, array\\<string, int\\> given\\.$#"
count: 3
path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php
-
message: "#^Parameter \\#2 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\:\\:setAttribute\\(\\) expects string, int given\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php
-
message: "#^Parameter \\#1 \\$pColumn of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:setColumn\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\|string, float given\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php
-
message: "#^Parameter \\#1 \\$im of function imagecolorallocate expects resource, resource\\|false given\\.$#"
count: 1

View File

@ -0,0 +1,100 @@
<?php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
require __DIR__ . '/../Header.php';
// Sample can be slightly off if processing begins just before midnight
// and does not complete till after midnight.
// This possibility is accounted for in unit tests,
// but seems unneccesarily complicated for the sample.
function createSheet(Spreadsheet $spreadsheet, string $rule): void
{
$sheet = $spreadsheet->createSheet();
$sheet->setTitle($rule);
$sheet->getCell('A1')->setValue('Date');
$row = 1;
$date = new DateTime();
$year = (int) $date->format('Y');
$month = (int) $date->format('m');
$day = (int) $date->format('d');
$yearMinus2 = $year - 2;
$sheet->getCell('B1')->setValue("=DATE($year, $month, $day)");
// Each day for two weeks before today through 2 weeks after
for ($dayOffset = -14; $dayOffset < 14; ++$dayOffset) {
++$row;
$sheet->getCell("A$row")->setValue("=B1+($dayOffset)");
}
// First and last day of each month, starting with January 2 years before,
// through December 2 years after.
for ($monthOffset = 0; $monthOffset < 48; ++$monthOffset) {
++$row;
$sheet->getCell("A$row")->setValue("=DATE($yearMinus2, $monthOffset, 1)");
++$row;
$sheet->getCell("A$row")->setValue("=DATE($yearMinus2, $monthOffset + 1, 0)");
}
$sheet->getStyle("A2:A$row")->getNumberFormat()->setFormatCode('yyyy-mm-dd');
$sheet->getStyle('B1')->getNumberFormat()->setFormatCode('yyyy-mm-dd');
$sheet->getColumnDimension('A')->setAutoSize(true);
$sheet->getColumnDimension('B')->setAutoSize(true);
$autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter();
$autoFilter->setRange("A1:A$row");
$columnFilter = $autoFilter->getColumn('A');
$columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
$columnFilter->createRule()
->setRule(
Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
'',
$rule
)
->setRuleType(Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
$sheet->setSelectedCell('B1');
}
// Create new Spreadsheet object
$helper->log('Create new Spreadsheet object');
$spreadsheet = new Spreadsheet();
// Set document properties
$helper->log('Set document properties');
$spreadsheet->getProperties()->setCreator('Owen Leibman')
->setLastModifiedBy('Owen Leibman')
->setTitle('PhpSpreadsheet Test Document')
->setSubject('PhpSpreadsheet Test Document')
->setDescription('Test document for PhpSpreadsheet, generated using PHP classes.')
->setKeywords('office PhpSpreadsheet php')
->setCategory('Test result file');
$ruleNames = [
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_TODAY,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2,
Rule::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_3,
];
// Create the worksheets
foreach ($ruleNames as $ruleName) {
$helper->log("Add data and filter for $ruleName");
createSheet($spreadsheet, $ruleName);
}
$spreadsheet->removeSheetByIndex(0);
$spreadsheet->setActiveSheetIndex(0);
// Save
$helper->write($spreadsheet, __FILE__);

View File

@ -2,12 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use DateTime;
use DateTimeZone;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
class AutoFilter
{
@ -358,38 +360,38 @@ class AutoFilter
if (is_numeric($rule['value'])) {
// Numeric values are tested using the appropriate operator
switch ($rule['operator']) {
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL:
case Rule::AUTOFILTER_COLUMN_RULE_EQUAL:
$retVal = ($cellValue == $rule['value']);
break;
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL:
case Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL:
$retVal = ($cellValue != $rule['value']);
break;
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN:
case Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN:
$retVal = ($cellValue > $rule['value']);
break;
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL:
case Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL:
$retVal = ($cellValue >= $rule['value']);
break;
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN:
case Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN:
$retVal = ($cellValue < $rule['value']);
break;
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL:
case Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL:
$retVal = ($cellValue <= $rule['value']);
break;
}
} elseif ($rule['value'] == '') {
switch ($rule['operator']) {
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL:
case Rule::AUTOFILTER_COLUMN_RULE_EQUAL:
$retVal = (($cellValue == '') || ($cellValue === null));
break;
case AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL:
case Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL:
$retVal = (($cellValue != '') && ($cellValue !== null));
break;
@ -439,7 +441,8 @@ class AutoFilter
}
if (is_numeric($cellValue)) {
$dateValue = date('m', Date::excelToTimestamp($cellValue));
$dateObject = Date::excelToDateTimeObject((float) $cellValue, new DateTimeZone('UTC'));
$dateValue = (int) $dateObject->format('m');
if (in_array($dateValue, $monthSet)) {
return true;
}
@ -457,6 +460,224 @@ class AutoFilter
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();
$baseDate->setDate($year, $month, $day);
$baseDate->setTime($hour, $minute, $second);
return $baseDate;
}
private const DATE_FUNCTIONS = [
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH => 'dynamicLastMonth',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER => 'dynamicLastQuarter',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK => 'dynamicLastWeek',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR => 'dynamicLastYear',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH => 'dynamicNextMonth',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER => 'dynamicNextQuarter',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK => 'dynamicNextWeek',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR => 'dynamicNextYear',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH => 'dynamicThisMonth',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER => 'dynamicThisQuarter',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK => 'dynamicThisWeek',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR => 'dynamicThisYear',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_TODAY => 'dynamicToday',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW => 'dynamicTomorrow',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE => 'dynamicYearToDate',
Rule::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY => 'dynamicYesterday',
];
private static function dynamicLastMonth(): array
{
$maxval = new DateTime();
$year = (int) $maxval->format('Y');
$month = (int) $maxval->format('m');
$maxval->setDate($year, $month, 1);
$maxval->setTime(0, 0, 0);
$val = clone $maxval;
$val->modify('-1 month');
return [$val, $maxval];
}
private static function firstDayOfQuarter(): DateTime
{
$val = new DateTime();
$year = (int) $val->format('Y');
$month = (int) $val->format('m');
$month = 3 * intdiv($month - 1, 3) + 1;
$val->setDate($year, $month, 1);
$val->setTime(0, 0, 0);
return $val;
}
private static function dynamicLastQuarter(): array
{
$maxval = self::firstDayOfQuarter();
$val = clone $maxval;
$val->modify('-3 months');
return [$val, $maxval];
}
private static function dynamicLastWeek(): array
{
$val = new DateTime();
$val->setTime(0, 0, 0);
$dayOfWeek = (int) $val->format('w'); // Sunday is 0
$subtract = $dayOfWeek + 7; // revert to prior Sunday
$val->modify("-$subtract days");
$maxval = clone $val;
$maxval->modify('+7 days');
return [$val, $maxval];
}
private static function dynamicLastYear(): array
{
$val = new DateTime();
$year = (int) $val->format('Y');
$val = self::makeDateObject($year - 1, 1, 1);
$maxval = self::makeDateObject($year, 1, 1);
return [$val, $maxval];
}
private static function dynamicNextMonth(): array
{
$val = new DateTime();
$year = (int) $val->format('Y');
$month = (int) $val->format('m');
$val->setDate($year, $month, 1);
$val->setTime(0, 0, 0);
$val->modify('+1 month');
$maxval = clone $val;
$maxval->modify('+1 month');
return [$val, $maxval];
}
private static function dynamicNextQuarter(): array
{
$val = self::firstDayOfQuarter();
$val->modify('+3 months');
$maxval = clone $val;
$maxval->modify('+3 months');
return [$val, $maxval];
}
private static function dynamicNextWeek(): array
{
$val = new DateTime();
$val->setTime(0, 0, 0);
$dayOfWeek = (int) $val->format('w'); // Sunday is 0
$add = 7 - $dayOfWeek; // move to next Sunday
$val->modify("+$add days");
$maxval = clone $val;
$maxval->modify('+7 days');
return [$val, $maxval];
}
private static function dynamicNextYear(): array
{
$val = new DateTime();
$year = (int) $val->format('Y');
$val = self::makeDateObject($year + 1, 1, 1);
$maxval = self::makeDateObject($year + 2, 1, 1);
return [$val, $maxval];
}
private static function dynamicThisMonth(): array
{
$baseDate = new DateTime();
$baseDate->setTime(0, 0, 0);
$year = (int) $baseDate->format('Y');
$month = (int) $baseDate->format('m');
$val = self::makeDateObject($year, $month, 1);
$maxval = clone $val;
$maxval->modify('+1 month');
return [$val, $maxval];
}
private static function dynamicThisQuarter(): array
{
$val = self::firstDayOfQuarter();
$maxval = clone $val;
$maxval->modify('+3 months');
return [$val, $maxval];
}
private static function dynamicThisWeek(): array
{
$val = new DateTime();
$val->setTime(0, 0, 0);
$dayOfWeek = (int) $val->format('w'); // Sunday is 0
$subtract = $dayOfWeek; // revert to Sunday
$val->modify("-$subtract days");
$maxval = clone $val;
$maxval->modify('+7 days');
return [$val, $maxval];
}
private static function dynamicThisYear(): array
{
$val = new DateTime();
$year = (int) $val->format('Y');
$val = self::makeDateObject($year, 1, 1);
$maxval = self::makeDateObject($year + 1, 1, 1);
return [$val, $maxval];
}
private static function dynamicToday(): array
{
$val = new DateTime();
$val->setTime(0, 0, 0);
$maxval = clone $val;
$maxval->modify('+1 day');
return [$val, $maxval];
}
private static function dynamicTomorrow(): array
{
$val = new DateTime();
$val->setTime(0, 0, 0);
$val->modify('+1 day');
$maxval = clone $val;
$maxval->modify('+1 day');
return [$val, $maxval];
}
private static function dynamicYearToDate(): array
{
$maxval = new DateTime();
$maxval->setTime(0, 0, 0);
$val = self::makeDateObject((int) $maxval->format('Y'), 1, 1);
$maxval->modify('+1 day');
return [$val, $maxval];
}
private static function dynamicYesterday(): array
{
$maxval = new DateTime();
$maxval->setTime(0, 0, 0);
$val = clone $maxval;
$val->modify('-1 day');
return [$val, $maxval];
}
/**
* Convert a dynamic rule daterange to a custom filter range expression for ease of calculation.
*
@ -467,118 +688,24 @@ class AutoFilter
*/
private function dynamicFilterDateRange($dynamicRuleType, &$filterColumn)
{
$rDateType = Functions::getReturnDateType();
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
$val = $maxVal = null;
$ruleValues = [];
$baseDate = DateTimeExcel\Current::now();
$callBack = [__CLASS__, self::DATE_FUNCTIONS[$dynamicRuleType]]; // What if not found?
// Calculate start/end dates for the required date range based on current date
switch ($dynamicRuleType) {
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK:
$baseDate = strtotime('-7 days', $baseDate);
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK:
$baseDate = strtotime('-7 days', $baseDate);
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH:
$baseDate = strtotime('-1 month', gmmktime(0, 0, 0, 1, date('m', $baseDate), date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH:
$baseDate = strtotime('+1 month', gmmktime(0, 0, 0, 1, date('m', $baseDate), date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER:
$baseDate = strtotime('-3 month', gmmktime(0, 0, 0, 1, date('m', $baseDate), date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER:
$baseDate = strtotime('+3 month', gmmktime(0, 0, 0, 1, date('m', $baseDate), date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR:
$baseDate = strtotime('-1 year', gmmktime(0, 0, 0, 1, date('m', $baseDate), date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR:
$baseDate = strtotime('+1 year', gmmktime(0, 0, 0, 1, date('m', $baseDate), date('Y', $baseDate)));
break;
}
switch ($dynamicRuleType) {
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_TODAY:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW:
$maxVal = (int) Date::PHPtoExcel(strtotime('+1 day', $baseDate));
$val = (int) Date::PHPToExcel($baseDate);
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE:
$maxVal = (int) Date::PHPtoExcel(strtotime('+1 day', $baseDate));
$val = (int) Date::PHPToExcel(gmmktime(0, 0, 0, 1, 1, date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR:
$maxVal = (int) Date::PHPToExcel(gmmktime(0, 0, 0, 31, 12, date('Y', $baseDate)));
++$maxVal;
$val = (int) Date::PHPToExcel(gmmktime(0, 0, 0, 1, 1, date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER:
$thisMonth = date('m', $baseDate);
$thisQuarter = floor(--$thisMonth / 3);
$maxVal = (int) Date::PHPtoExcel(gmmktime(0, 0, 0, date('t', $baseDate), (1 + $thisQuarter) * 3, date('Y', $baseDate)));
++$maxVal;
$val = (int) Date::PHPToExcel(gmmktime(0, 0, 0, 1, 1 + $thisQuarter * 3, date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH:
$maxVal = (int) Date::PHPtoExcel(gmmktime(0, 0, 0, date('t', $baseDate), date('m', $baseDate), date('Y', $baseDate)));
++$maxVal;
$val = (int) Date::PHPToExcel(gmmktime(0, 0, 0, 1, date('m', $baseDate), date('Y', $baseDate)));
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK:
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK:
$dayOfWeek = date('w', $baseDate);
$val = (int) Date::PHPToExcel($baseDate) - $dayOfWeek;
$maxVal = $val + 7;
break;
}
switch ($dynamicRuleType) {
// Adjust Today dates for Yesterday and Tomorrow
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY:
--$maxVal;
--$val;
break;
case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW:
++$maxVal;
++$val;
break;
// Val is lowest permitted value.
// Maxval is greater than highest permitted value
$val = $maxval = 0;
if (is_callable($callBack)) {
[$val, $maxval] = $callBack();
}
$val = Date::dateTimeToExcel($val);
$maxval = Date::dateTimeToExcel($maxval);
// Set the filter column rule attributes ready for writing
$filterColumn->setAttributes(['val' => $val, 'maxVal' => $maxVal]);
$filterColumn->setAttributes(['val' => $val, 'maxVal' => $maxval]);
// Set the rules for identifying rows for hide/show
$ruleValues[] = ['operator' => AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL, 'value' => $val];
$ruleValues[] = ['operator' => AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN, 'value' => $maxVal];
Functions::setReturnDateType($rDateType);
$ruleValues[] = ['operator' => Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL, 'value' => $val];
$ruleValues[] = ['operator' => Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN, 'value' => $maxval];
return ['method' => 'filterTestInCustomDataSet', 'arguments' => ['filterRules' => $ruleValues, 'join' => AutoFilter\Column::AUTOFILTER_COLUMN_JOIN_AND]];
}
@ -589,7 +716,7 @@ class AutoFilter
$dataValues = Functions::flattenArray($this->workSheet->rangeToArray($range, null, true, false));
$dataValues = array_filter($dataValues);
if ($ruleType == AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) {
if ($ruleType == Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) {
rsort($dataValues);
} else {
sort($dataValues);
@ -630,7 +757,7 @@ class AutoFilter
if (count($ruleValues) != count($ruleDataSet)) {
$blanks = true;
}
if ($ruleType == AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_FILTER) {
if ($ruleType == Rule::AUTOFILTER_RULETYPE_FILTER) {
// Filter on absolute values
$columnFilterTests[$columnID] = [
'method' => 'filterTestInSimpleDataSet',
@ -646,40 +773,40 @@ class AutoFilter
foreach ($ruleDataSet as $ruleValue) {
$date = $time = '';
if (
(isset($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_YEAR])) &&
($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_YEAR] !== '')
(isset($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_YEAR])) &&
($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_YEAR] !== '')
) {
$date .= sprintf('%04d', $ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_YEAR]);
$date .= sprintf('%04d', $ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_YEAR]);
}
if (
(isset($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH])) &&
($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH] != '')
(isset($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH])) &&
($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH] != '')
) {
$date .= sprintf('%02d', $ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH]);
$date .= sprintf('%02d', $ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH]);
}
if (
(isset($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_DAY])) &&
($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_DAY] !== '')
(isset($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_DAY])) &&
($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_DAY] !== '')
) {
$date .= sprintf('%02d', $ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_DAY]);
$date .= sprintf('%02d', $ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_DAY]);
}
if (
(isset($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_HOUR])) &&
($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_HOUR] !== '')
(isset($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_HOUR])) &&
($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_HOUR] !== '')
) {
$time .= sprintf('%02d', $ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_HOUR]);
$time .= sprintf('%02d', $ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_HOUR]);
}
if (
(isset($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE])) &&
($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE] !== '')
(isset($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE])) &&
($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE] !== '')
) {
$time .= sprintf('%02d', $ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE]);
$time .= sprintf('%02d', $ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE]);
}
if (
(isset($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_SECOND])) &&
($ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_SECOND] !== '')
(isset($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_SECOND])) &&
($ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_SECOND] !== '')
) {
$time .= sprintf('%02d', $ruleValue[AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_SECOND]);
$time .= sprintf('%02d', $ruleValue[Rule::AUTOFILTER_RULETYPE_DATEGROUP_SECOND]);
}
$dateTime = $date . $time;
$arguments['date'][] = $date;
@ -727,17 +854,17 @@ class AutoFilter
// We should only ever have one Dynamic Filter Rule anyway
$dynamicRuleType = $rule->getGrouping();
if (
($dynamicRuleType == AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE) ||
($dynamicRuleType == AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE)
($dynamicRuleType == Rule::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE) ||
($dynamicRuleType == Rule::AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE)
) {
// 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'));
// Set above/below rule based on greaterThan or LessTan
$operator = ($dynamicRuleType === AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE)
? AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN
: AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN;
$operator = ($dynamicRuleType === Rule::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE)
? Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN
: Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN;
$ruleValues[] = [
'operator' => $operator,
'value' => $average,
@ -788,7 +915,7 @@ class AutoFilter
$ruleValue = $rule->getValue();
$ruleOperator = $rule->getOperator();
}
if ($ruleOperator === AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) {
if ($ruleOperator === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) {
$ruleValue = floor($ruleValue * ($dataRowCount / 100));
}
if (!is_array($ruleValue) && $ruleValue < 1) {
@ -800,9 +927,9 @@ class AutoFilter
$maxVal = $this->calculateTopTenValue($columnID, $rangeStart[1] + 1, $rangeEnd[1], $toptenRuleType, $ruleValue);
$operator = ($toptenRuleType == AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP)
? AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL
: AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL;
$operator = ($toptenRuleType == Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP)
? Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL
: Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL;
$ruleValues[] = ['operator' => $operator, 'value' => $maxVal];
$columnFilterTests[$columnID] = [
'method' => 'filterTestInCustomDataSet',

View File

@ -215,11 +215,11 @@ class Column
/**
* Set AutoFilter Attributes.
*
* @param string[] $attributes
* @param mixed[] $attributes
*
* @return $this
*/
public function setAttributes(array $attributes)
public function setAttributes($attributes)
{
$this->attributes = $attributes;

View File

@ -0,0 +1,91 @@
<?php
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
{
public function providerMonth(): array
{
return [
[[2, 3], Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH],
[[4], Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH],
[[6], Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH],
];
}
private static function setCells(Worksheet $sheet, int $startMonth): void
{
$sheet->getCell('A1')->setValue('Date');
$sheet->getCell('A2')->setValue('=TODAY()');
$sheet->getCell('A3')->setValue('=DATE(YEAR(A2), MONTH(A2), 1)');
if ($startMonth === 12) {
$sheet->getCell('A4')->setValue('=DATE(YEAR(A2) + 1, 1, 1)');
$sheet->getCell('A5')->setValue('=DATE(YEAR(A2) + 1, 2, 1)');
} elseif ($startMonth === 11) {
$sheet->getCell('A4')->setValue('=DATE(YEAR(A2), MONTH(A2) + 1, 1)');
$sheet->getCell('A5')->setValue('=DATE(YEAR(A2) + 1, 1, 1)');
} else {
$sheet->getCell('A4')->setValue('=DATE(YEAR(A2), MONTH(A2) + 1, 1)');
$sheet->getCell('A5')->setValue('=DATE(YEAR(A2), MONTH(A2) + 2, 1)');
}
if ($startMonth === 1) {
$sheet->getCell('A6')->setValue('=DATE(YEAR(A2) - 1, 12, 1)');
$sheet->getCell('A7')->setValue('=DATE(YEAR(A2) - 1, 10, 1)');
} elseif ($startMonth === 2) {
$sheet->getCell('A6')->setValue('=DATE(YEAR(A2), 1, 1)');
$sheet->getCell('A7')->setValue('=DATE(YEAR(A2) - 1, 12, 1)');
} else {
$sheet->getCell('A6')->setValue('=DATE(YEAR(A2), MONTH(A2) - 1, 1)');
$sheet->getCell('A7')->setValue('=DATE(YEAR(A2), MONTH(A2) - 2, 1)');
}
$sheet->getCell('A8')->setValue('=DATE(YEAR(A2) + 1, MONTH(A2), 1)');
$sheet->getCell('A9')->setValue('=DATE(YEAR(A2) - 1, MONTH(A2), 1)');
}
/**
* @dataProvider providerMonth
*/
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();
$dtStart = new DateTimeImmutable();
$startDay = (int) $dtStart->format('d');
$startMonth = (int) $dtStart->format('m');
self::setCells($sheet, $startMonth);
$maxRow = 9;
$autoFilter = $spreadsheet->getActiveSheet()->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);
$autoFilter->showHideRows();
$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);
}
}

View File

@ -0,0 +1,74 @@
<?php
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
{
public function providerQuarter(): array
{
return [
[[2, 3], Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER],
[[4], Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER],
[[6], Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER],
];
}
private static function setCells(Worksheet $sheet): void
{
$sheet->getCell('A1')->setValue('Date');
$sheet->getCell('A2')->setValue('=TODAY()');
$sheet->getCell('A3')->setValue('=DATE(YEAR(A2), MONTH(A2), 1)');
$sheet->getCell('A4')->setValue('=DATE(YEAR(A2), MONTH(A2) + 3, 1)');
$sheet->getCell('A5')->setValue('=DATE(YEAR(A2), MONTH(A2) + 6, 1)');
$sheet->getCell('A6')->setValue('=DATE(YEAR(A2), MONTH(A2) - 3, 1)');
$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)');
}
/**
* @dataProvider providerQuarter
*/
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();
$dtStart = new DateTimeImmutable();
$startDay = (int) $dtStart->format('d');
self::setCells($sheet);
$maxRow = 9;
$autoFilter = $spreadsheet->getActiveSheet()->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);
$autoFilter->showHideRows();
$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);
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter;
use PhpOffice\PhpSpreadsheet\Collection\Cells;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter;
@ -207,6 +207,7 @@ class AutoFilterTest extends TestCase
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
$invalidColumn = 123.456;
// @phpstan-ignore-next-line
$this->testAutoFilterObject->setColumn($invalidColumn);
}

View File

@ -0,0 +1,65 @@
<?php
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
{
public function providerYesterdayTodayTomorrow(): array
{
return [
[[2, 5], Rule::AUTOFILTER_RULETYPE_DYNAMIC_TODAY],
[[3, 6], Rule::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW],
[[4, 7], Rule::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY],
];
}
/**
* @dataProvider providerYesterdayTodayTomorrow
*/
public function testYesterdayTodayTomorrow(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();
$dtStart = new DateTimeImmutable();
$startDay = $dtStart->format('d');
$sheet->getCell('A1')->setValue('Date');
$sheet->getCell('A2')->setValue('=NOW()');
$sheet->getCell('A3')->setValue('=A2+1');
$sheet->getCell('A4')->setValue('=A2-1');
$sheet->getCell('A5')->setValue('=TODAY()');
$sheet->getCell('A6')->setValue('=A5+1');
$sheet->getCell('A7')->setValue('=A5-1');
$maxRow = 7;
$autoFilter = $spreadsheet->getActiveSheet()->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);
$autoFilter->showHideRows();
$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);
}
}

View File

@ -0,0 +1,75 @@
<?php
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
{
public function providerWeek(): array
{
return [
[[2, 3], Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK],
[[4], Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK],
[[6], Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK],
];
}
private static function setCells(Worksheet $sheet): void
{
$sheet->getCell('A1')->setValue('Date');
$sheet->getCell('A2')->setValue('=TODAY()');
$sheet->getCell('B2')->setValue('=WEEKDAY(A2) - 1'); // subtract to get to Sunday
$sheet->getCell('A3')->setValue('=DATE(YEAR(A2), MONTH(A2), DAY(A2) - B2)');
$sheet->getCell('A4')->setValue('=DATE(YEAR(A3), MONTH(A3), DAY(A3) + 8)');
$sheet->getCell('A5')->setValue('=DATE(YEAR(A3), MONTH(A3), DAY(A3) + 19)');
$sheet->getCell('A6')->setValue('=DATE(YEAR(A3), MONTH(A3), DAY(A3) - 6)');
$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)');
}
/**
* @dataProvider providerWeek
*/
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();
$dtStart = new DateTimeImmutable();
$startDay = (int) $dtStart->format('d');
self::setCells($sheet);
$maxRow = 9;
$autoFilter = $spreadsheet->getActiveSheet()->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);
$autoFilter->showHideRows();
$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);
}
}

View File

@ -0,0 +1,118 @@
<?php
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
{
public function providerYear(): array
{
return [
[[5, 6, 7], Rule::AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR],
[[2, 3, 4], Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR],
[[8, 9, 10], Rule::AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR],
[[], Rule::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_2],
[[2, 5, 8, 11], Rule::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_1],
[[4, 7, 10], Rule::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11],
];
}
/**
* @dataProvider providerYear
*/
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();
$dtStart = new DateTimeImmutable();
$startDay = (int) $dtStart->format('d');
$sheet->getCell('A1')->setValue('Date');
$year = (int) $dtStart->format('Y') - 1;
$row = 1;
$iteration = 0;
while ($iteration < 3) {
for ($month = 3; $month < 13; $month += 4) {
++$row;
$sheet->getCell("A$row")->setValue("=DATE($year, $month, 1)");
}
++$year;
++$iteration;
}
++$row;
$sheet->getCell("A$row")->setValue('=DATE(2041, 1, 1)'); // beyond epoch
$maxRow = $row;
$autoFilter = $spreadsheet->getActiveSheet()->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);
$autoFilter->showHideRows();
$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);
}
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();
$dtStart = new DateTimeImmutable();
$startDay = (int) $dtStart->format('d');
$startMonth = (int) $dtStart->format('m');
$sheet->getCell('A1')->setValue('Date');
$sheet->getCell('A2')->setValue('=TODAY()');
$sheet->getCell('A3')->setValue('=DATE(YEAR(A2), 12, 31)');
$sheet->getCell('A4')->setValue('=A3 + 1');
$sheet->getCell('A5')->setValue('=DATE(YEAR(A2), 1, 1)');
$sheet->getCell('A6')->setValue('=A5 - 1');
$maxRow = 6;
$autoFilter = $spreadsheet->getActiveSheet()->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::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE
)
->setRuleType(Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
$autoFilter->showHideRows();
$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);
}
}