mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-04 06:33:33 +00:00
More AutoFilter Tweaks
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
||||
|
||||
use Composer\Pcre\Preg;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
@@ -146,7 +147,7 @@ class AutoFilter implements Stringable
|
||||
$this->evaluated = false;
|
||||
if ($this->workSheet !== null) {
|
||||
$thisrange = $this->range;
|
||||
$range = (string) preg_replace('/\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
$range = Preg::replace('/\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
if ($range !== $thisrange) {
|
||||
$this->setRange($range);
|
||||
}
|
||||
@@ -239,12 +240,10 @@ class AutoFilter implements Stringable
|
||||
public function setColumn(AutoFilter\Column|string $columnObjectOrString): static
|
||||
{
|
||||
$this->evaluated = false;
|
||||
if ((is_string($columnObjectOrString)) && (!empty($columnObjectOrString))) {
|
||||
if (is_string($columnObjectOrString)) {
|
||||
$column = $columnObjectOrString;
|
||||
} elseif ($columnObjectOrString instanceof AutoFilter\Column) {
|
||||
$column = $columnObjectOrString->getColumnIndex();
|
||||
} else {
|
||||
throw new Exception('Column is not within the autofilter range.');
|
||||
$column = $columnObjectOrString->getColumnIndex();
|
||||
}
|
||||
$this->testColumnInRange($column);
|
||||
|
||||
@@ -434,32 +433,15 @@ class AutoFilter implements Stringable
|
||||
};
|
||||
} else {
|
||||
// String values are always tested for equality, factoring in for wildcards (hence a regexp test)
|
||||
switch ($ruleOperator) {
|
||||
case Rule::AUTOFILTER_COLUMN_RULE_EQUAL:
|
||||
$retVal = (bool) preg_match('/^' . $ruleValue . '$/i', $cellValueString);
|
||||
|
||||
break;
|
||||
case Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL:
|
||||
$retVal = !((bool) preg_match('/^' . $ruleValue . '$/i', $cellValueString));
|
||||
|
||||
break;
|
||||
case Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN:
|
||||
$retVal = strcasecmp($cellValueString, $ruleValue) > 0;
|
||||
|
||||
break;
|
||||
case Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL:
|
||||
$retVal = strcasecmp($cellValueString, $ruleValue) >= 0;
|
||||
|
||||
break;
|
||||
case Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN:
|
||||
$retVal = strcasecmp($cellValueString, $ruleValue) < 0;
|
||||
|
||||
break;
|
||||
case Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL:
|
||||
$retVal = strcasecmp($cellValueString, $ruleValue) <= 0;
|
||||
|
||||
break;
|
||||
}
|
||||
$retVal = match ($ruleOperator) {
|
||||
Rule::AUTOFILTER_COLUMN_RULE_EQUAL => Preg::isMatch('/^' . $ruleValue . '$/i', $cellValueString),
|
||||
Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL => !(Preg::isMatch('/^' . $ruleValue . '$/i', $cellValueString)),
|
||||
Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN => strcasecmp($cellValueString, $ruleValue) > 0,
|
||||
Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL => strcasecmp($cellValueString, $ruleValue) >= 0,
|
||||
Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN => strcasecmp($cellValueString, $ruleValue) < 0,
|
||||
// Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL
|
||||
default => strcasecmp($cellValueString, $ruleValue) <= 0,
|
||||
};
|
||||
}
|
||||
// If there are multiple conditions, then we need to test both using the appropriate join operator
|
||||
switch ($join) {
|
||||
@@ -1084,26 +1066,16 @@ class AutoFilter implements Stringable
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$vars = get_object_vars($this);
|
||||
foreach ($vars as $key => $value) {
|
||||
if (is_object($value)) {
|
||||
if ($key === 'workSheet') {
|
||||
// Detach from worksheet
|
||||
$this->{$key} = null;
|
||||
} else {
|
||||
$this->{$key} = clone $value;
|
||||
}
|
||||
} elseif ((is_array($value)) && ($key == 'columns')) {
|
||||
// The columns array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter objects
|
||||
$this->{$key} = [];
|
||||
foreach ($value as $k => $v) {
|
||||
$this->{$key}[$k] = clone $v; //* @phpstan-ignore-line
|
||||
// attach the new cloned Column to this new cloned Autofilter object
|
||||
$this->{$key}[$k]->setParent($this); //* @phpstan-ignore-line
|
||||
}
|
||||
} else {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
// workSheet is only property which is an object
|
||||
// detach from worksheet
|
||||
$this->workSheet = null;
|
||||
// columns is the only property which is an array
|
||||
$columns = $this->columns;
|
||||
$this->columns = [];
|
||||
foreach ($columns as $k => $v) {
|
||||
$this->columns[$k] = clone $v;
|
||||
// attach the new cloned Column to this new cloned Autofilter object
|
||||
$this->columns[$k]->setParent($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,14 @@ class ColumnTest extends SetupTeardown
|
||||
$sheet->getAutoFilter()->getColumn('B');
|
||||
}
|
||||
|
||||
public function testSetBadColumnIndex(): void
|
||||
{
|
||||
$this->expectException(PhpSpreadsheetException::class);
|
||||
$this->expectExceptionMessage('Column string index can not be empty');
|
||||
$sheet = $this->initSheet();
|
||||
$sheet->getAutoFilter()->setColumn('');
|
||||
}
|
||||
|
||||
public function testSetColumnIndex(): void
|
||||
{
|
||||
$sheet = $this->initSheet();
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class RuleCustom2Test extends SetupTeardown
|
||||
{
|
||||
protected function initSheet(): Worksheet
|
||||
{
|
||||
$sheet = $this->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;
|
||||
}
|
||||
|
||||
/** @param int[] $expectedResult */
|
||||
#[DataProvider('providerCondition')]
|
||||
public function testComparisonToNullString(array $expectedResult, string $condition): void
|
||||
{
|
||||
$sheet = $this->initSheet();
|
||||
$columnFilter = $sheet->getAutoFilter()->getColumn('A');
|
||||
$columnFilter->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
|
||||
$columnFilter->createRule()
|
||||
->setRule(
|
||||
$condition,
|
||||
''
|
||||
)
|
||||
->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
|
||||
self::assertEquals($expectedResult, $this->getVisible());
|
||||
}
|
||||
|
||||
/** @return array<array{int[], string}> */
|
||||
public static function providerCondition(): array
|
||||
{
|
||||
// Comparing to null-string, equal and notequal work as expected.
|
||||
// Other conditions filter everything.
|
||||
return [
|
||||
[[3], Rule::AUTOFILTER_COLUMN_RULE_EQUAL],
|
||||
[[2, 4], Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL],
|
||||
[[2, 3, 4], Rule::AUTOFILTER_COLUMN_RULE_GREATERTHAN],
|
||||
[[2, 3, 4], Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL],
|
||||
[[2, 3, 4], Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN],
|
||||
[[2, 3, 4], Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user