summaryrefslogtreecommitdiffstats
path: root/library/Director/Data/AssignFilterHelper.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Director/Data/AssignFilterHelper.php160
1 files changed, 160 insertions, 0 deletions
diff --git a/library/Director/Data/AssignFilterHelper.php b/library/Director/Data/AssignFilterHelper.php
new file mode 100644
index 0000000..b0253cf
--- /dev/null
+++ b/library/Director/Data/AssignFilterHelper.php
@@ -0,0 +1,160 @@
+<?php
+
+namespace Icinga\Module\Director\Data;
+
+use Icinga\Data\Filter\Filter;
+use Icinga\Data\Filter\FilterAnd;
+use Icinga\Data\Filter\FilterExpression;
+use Icinga\Data\Filter\FilterNot;
+use Icinga\Data\Filter\FilterOr;
+use Icinga\Exception\NotImplementedError;
+
+/**
+ * Class ApplyFilterMatches
+ *
+ * A wrapper for Icinga Filter to evaluate filters against Director's objects
+ */
+class AssignFilterHelper
+{
+ /** @var Filter */
+ protected $filter;
+
+ public function __construct(Filter $filter)
+ {
+ $this->filter = $filter;
+ }
+
+ /**
+ * @param object $object
+ *
+ * @return bool
+ * @throws NotImplementedError
+ */
+ public function matches($object)
+ {
+ return $this->matchesPart($this->filter, $object);
+ }
+
+ /**
+ * @param Filter $filter
+ * @param object $object
+ *
+ * @return bool
+ */
+ public static function matchesFilter(Filter $filter, $object)
+ {
+ $helper = new static($filter);
+ return $helper->matches($object);
+ }
+
+ /**
+ * @param Filter $filter
+ * @param object $object
+ *
+ * @return bool
+ * @throws NotImplementedError
+ */
+ protected function matchesPart(Filter $filter, $object)
+ {
+ if ($filter->isChain()) {
+ return $this->matchesChain($filter, $object);
+ } elseif ($filter->isExpression()) {
+ /** @var FilterExpression $filter */
+ return $this->matchesExpression($filter, $object);
+ } else {
+ return $filter->matches($object);
+ }
+ }
+
+ /**
+ * @param Filter $filter
+ * @param object $object
+ *
+ * @return bool
+ * @throws NotImplementedError
+ */
+ protected function matchesChain(Filter $filter, $object)
+ {
+ if ($filter instanceof FilterAnd) {
+ foreach ($filter->filters() as $f) {
+ if (! $this->matchesPart($f, $object)) {
+ return false;
+ }
+ }
+
+ return true;
+ } elseif ($filter instanceof FilterOr) {
+ foreach ($filter->filters() as $f) {
+ if ($this->matchesPart($f, $object)) {
+ return true;
+ }
+ }
+
+ return false;
+ } elseif ($filter instanceof FilterNot) {
+ foreach ($filter->filters() as $f) {
+ if ($this->matchesPart($f, $object)) {
+ return false;
+ }
+ }
+
+ return true;
+ } else {
+ $class = \get_class($filter);
+ $parts = \preg_split('/\\\/', $class);
+
+ throw new NotImplementedError(
+ 'Matching for Filter of type "%s" is not implemented',
+ \end($parts)
+ );
+ }
+ }
+
+ /**
+ * @param FilterExpression $filter
+ * @param object $object
+ *
+ * @return bool
+ */
+ protected function matchesExpression(FilterExpression $filter, $object)
+ {
+ $column = $filter->getColumn();
+ $sign = $filter->getSign();
+ $expression = $filter->getExpression();
+
+ if ($sign === '=') {
+ if ($expression === true) {
+ return property_exists($object, $column) && ! empty($object->{$column});
+ } elseif ($expression === false) {
+ return ! property_exists($object, $column) || empty($object->{$column});
+ } elseif (is_string($expression) && strpos($expression, '*') !== false) {
+ if (! property_exists($object, $column) || empty($object->{$column})) {
+ return false;
+ }
+ $value = $object->{$column};
+
+ $parts = array();
+ foreach (preg_split('~\*~', $expression) as $part) {
+ $parts[] = preg_quote($part);
+ }
+ // match() is case insensitive
+ $pattern = '/^' . implode('.*', $parts) . '$/i';
+
+ if (is_array($value)) {
+ foreach ($value as $candidate) {
+ if (preg_match($pattern, $candidate)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return (bool) preg_match($pattern, $value);
+ }
+ }
+
+ // fallback to default behavior
+ return $filter->matches($object);
+ }
+}