diff --git a/src/Filter.php b/src/Filter.php index 9b60f8e..afffed8 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -181,17 +181,7 @@ protected function matchEqual($rule, $row) $value = $rule->getValue(); $this->normalizeTypes($rowValue, $value); - if (! is_array($rowValue)) { - $rowValue = [$rowValue]; - } - - foreach ($rowValue as $rowVal) { - if ($this->performEqualityMatch($value, $rowVal, $rule->ignoresCase())) { - return true; - } - } - - return false; + return $this->performEqualityMatch($value, $rowValue, $rule->ignoresCase()); } /** @@ -228,21 +218,17 @@ protected function matchSimilar($rule, $row) )); } - $rowValue = $this->extractValue($rule->getColumn(), $row); $value = $rule->getValue(); - $this->normalizeTypes($rowValue, $value); - - if (! is_array($rowValue)) { - $rowValue = [$rowValue]; + if (is_array($value)) { + throw new InvalidArgumentException( + 'Cannot perform a similarity match if the expression is an array' + ); } - foreach ($rowValue as $rowVal) { - if ($this->performSimilarityMatch($value, $rowVal, $rule->ignoresCase())) { - return true; - } - } + $rowValue = $this->extractValue($rule->getColumn(), $row); + $this->normalizeTypes($rowValue, $value); - return false; + return $this->performSimilarityMatch((string) $value, (string) $rowValue, $rule->ignoresCase()); } /** @@ -256,14 +242,16 @@ protected function matchSimilar($rule, $row) */ protected function performEqualityMatch($value, $rowValue, $ignoreCase = false) { - if ($ignoreCase && is_string($rowValue)) { - $rowValue = strtolower($rowValue); + if ($ignoreCase) { + $rowValue = is_array($rowValue) + ? array_map('strtolower', $rowValue) + : strtolower($rowValue); $value = is_array($value) ? array_map('strtolower', $value) : strtolower($value); } - if (is_array($value)) { + if (is_array($value) && ! is_array($rowValue)) { return in_array($rowValue, $value, true); } elseif (! is_string($value)) { if (is_string($rowValue)) { @@ -277,23 +265,17 @@ protected function performEqualityMatch($value, $rowValue, $ignoreCase = false) /** * Apply similarity matching rules on the given row value * - * @param string|string[] $value + * @param string $value * @param string $rowValue * @param bool $ignoreCase * * @return bool */ - protected function performSimilarityMatch($value, $rowValue, $ignoreCase = false) + protected function performSimilarityMatch(string $value, string $rowValue, bool $ignoreCase = false): bool { if ($ignoreCase) { $rowValue = strtolower($rowValue); - $value = is_array($value) - ? array_map('strtolower', $value) - : strtolower($value); - } - - if (is_array($value)) { - return in_array($rowValue, $value, true); + $value = strtolower($value); } $wildcardSubSegments = preg_split('~\*~', $value); @@ -530,6 +512,15 @@ protected function performMatch(Rule $rule, $row) */ protected function extractValue($column, $row) { + if (is_array($column)) { + $value = []; + foreach ($column as $name) { + $value[] = $this->extractValue($name, $row); + } + + return $value; + } + try { return $row->{$column}; } catch (Exception $_) { diff --git a/tests/FilterTest.php b/tests/FilterTest.php index f7fc277..269af78 100644 --- a/tests/FilterTest.php +++ b/tests/FilterTest.php @@ -27,6 +27,13 @@ class FilterTest extends TestCase 'service' => 'www.icinga.com', 'state' => 1, 'handled' => '0' + ], + [ + 'host' => 'LocalHost', + 'problem' => '1', + 'service' => 'Ping', + 'state' => 3, + 'handled' => '1' ] ]; @@ -139,45 +146,10 @@ public function testLikeMismatches() public function testLikeIgnoresCase() { - // single string $like = Filter::like('host', '*LOCAL*') ->ignoreCase(); $this->assertTrue(Filter::match($like, $this->row(0))); - - // string array - $like->setValue(['LoCaLhOsT', '127.0.0.1']); - - $this->assertTrue(Filter::match($like, $this->row(0))); - } - - public function testEqualMatchesMultiValuedColumns() - { - $this->assertTrue(Filter::match(Filter::equal('foo', 'bar'), [ - 'foo' => ['foo', 'bar'] - ])); - $this->assertTrue(Filter::match(Filter::equal('foo', 'BAR')->ignoreCase(), [ - 'foo' => ['FoO', 'bAr'] - ])); - $this->assertTrue(Filter::match(Filter::equal('foo', ['bar', 'boar']), [ - 'foo' => ['foo', 'bar'] - ])); - } - - public function testLikeMatchesMultiValuedColumns() - { - $this->assertTrue(Filter::match(Filter::like('foo', 'bar'), [ - 'foo' => ['foo', 'bar'] - ])); - $this->assertTrue(Filter::match(Filter::like('foo', 'ba*'), [ - 'foo' => ['foo', 'bar'] - ])); - $this->assertTrue(Filter::match(Filter::like('foo', 'BAR')->ignoreCase(), [ - 'foo' => ['FoO', 'bAr'] - ])); - $this->assertTrue(Filter::match(Filter::like('foo', ['bar', 'boar']), [ - 'foo' => ['foo', 'bar'] - ])); } public function testUnequalMatches() @@ -224,45 +196,10 @@ public function testUnlikeMismatches() public function testUnlikeIgnoresCase() { - // single string $unlike = Filter::unlike('host', '*LOCAL*') ->ignoreCase(); $this->assertFalse(Filter::match($unlike, $this->row(0))); - - // string array - $unlike->setValue(['LoCaLhOsT', '127.0.0.1']); - - $this->assertFalse(Filter::match($unlike, $this->row(0))); - } - - public function testUnequalMatchesMultiValuedColumns() - { - $this->assertFalse(Filter::match(Filter::unequal('foo', 'bar'), [ - 'foo' => ['foo', 'bar'] - ])); - $this->assertFalse(Filter::match(Filter::unequal('foo', 'BAR')->ignoreCase(), [ - 'foo' => ['FoO', 'bAr'] - ])); - $this->assertFalse(Filter::match(Filter::unequal('foo', ['bar', 'boar']), [ - 'foo' => ['foo', 'bar'] - ])); - } - - public function testUnlikeMatchesMultiValuedColumns() - { - $this->assertFalse(Filter::match(Filter::unlike('foo', 'bar'), [ - 'foo' => ['foo', 'bar'] - ])); - $this->assertFalse(Filter::match(Filter::unlike('foo', 'ba*'), [ - 'foo' => ['foo', 'bar'] - ])); - $this->assertFalse(Filter::match(Filter::unlike('foo', 'BAR')->ignoreCase(), [ - 'foo' => ['FoO', 'bAr'] - ])); - $this->assertFalse(Filter::match(Filter::unlike('foo', ['bar', 'boar']), [ - 'foo' => ['foo', 'bar'] - ])); } public function testGreaterThanMatches() @@ -381,32 +318,49 @@ public function testEqualWithArrayMismatches() $this->assertFalse(Filter::match($equal, $this->row(0))); } - public function testLikeWithArrayMatches() + public function testEqualWithArrayComparisonMatches() { - $like = Filter::like('host', ['127.0.0.1', 'localhost']); + $equal = Filter::equal(['host', 'service'], ['localhost', 'ping']); - $this->assertTrue(Filter::match($like, $this->row(0))); + $this->assertTrue(Filter::match($equal, $this->row(0))); } - public function testLikeWithArrayMismatches() + public function testEqualWithCaseInsensitiveArrayComparisonMatches() { - $like = Filter::like('host', ['10.0.10.20', '10.0.10.21']); + $equal = Filter::equal(['host', 'service'], ['lOcAlHost', 'PiNg'])->ignoreCase(); - $this->assertFalse(Filter::match($like, $this->row(0))); + $this->assertTrue(Filter::match($equal, $this->row(3))); } - public function testUnequalWithArrayMatches() + public function testUnequalWithArrayComparisonMatches() { - $unequal = Filter::unequal('host', ['10.0.20.10', '10.0.20.11']); + $unequal = Filter::unequal(['host', 'service'], ['ping', 'localhost']); $this->assertTrue(Filter::match($unequal, $this->row(0))); } - public function testUnlikeWithArrayMatches() + public function testUnequalWithCaseInsensitiveArrayComparisonMatches() + { + $unequal = Filter::unequal(['host', 'service'], ['PiNg', 'lOcAlHost'])->ignoreCase(); + + $this->assertTrue(Filter::match($unequal, $this->row(3))); + } + + public function testLikeWithArrayThrows() { - $unlike = Filter::unlike('host', ['10.0.20.10', '10.0.20.11']); + $like = Filter::like('host', ['127.0.0.*', 'local*']); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot perform a similarity match if the expression is an array'); - $this->assertTrue(Filter::match($unlike, $this->row(0))); + Filter::match($like, $this->row(0)); + } + + public function testUnequalWithArrayMatches() + { + $unequal = Filter::unequal('host', ['10.0.20.10', '10.0.20.11']); + + $this->assertTrue(Filter::match($unequal, $this->row(0))); } public function testUnequalWithArrayMismatches() @@ -416,11 +370,14 @@ public function testUnequalWithArrayMismatches() $this->assertFalse(Filter::match($unequal, $this->row(0))); } - public function testUnlikeWithArrayMismatches() + public function testUnlikeWithArrayThrows() { - $unlike = Filter::unlike('host', ['127.0.0.1', 'localhost']); + $unlike = Filter::unlike('host', ['127.0.0.*', 'local*']); - $this->assertFalse(Filter::match($unlike, $this->row(0))); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot perform a similarity match if the expression is an array'); + + Filter::match($unlike, $this->row(0)); } public function testConditionsAreValueTypeAgnostic()