summaryrefslogtreecommitdiffstats
path: root/library/Icinga/Data/Filter/Filter.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/Icinga/Data/Filter/Filter.php')
-rw-r--r--library/Icinga/Data/Filter/Filter.php255
1 files changed, 255 insertions, 0 deletions
diff --git a/library/Icinga/Data/Filter/Filter.php b/library/Icinga/Data/Filter/Filter.php
new file mode 100644
index 0000000..f5d8bdf
--- /dev/null
+++ b/library/Icinga/Data/Filter/Filter.php
@@ -0,0 +1,255 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Data\Filter;
+
+use Icinga\Web\UrlParams;
+use Icinga\Exception\ProgrammingError;
+
+/**
+ * Filter
+ *
+ * Base class for filters (why?) and factory for the different FilterOperators
+ */
+abstract class Filter
+{
+ protected $id = '1';
+
+ public function setId($id)
+ {
+ $this->id = (string) $id;
+ return $this;
+ }
+
+ abstract public function isExpression();
+
+ abstract public function isChain();
+
+ abstract public function isEmpty();
+
+ abstract public function toQueryString();
+
+ abstract public function andFilter(Filter $filter);
+
+ abstract public function orFilter(Filter $filter);
+
+ /**
+ * Whether the give row matches this Filter
+ *
+ * @param mixed $row Preferrably an stdClass instance
+ * @return bool
+ */
+ abstract public function matches($row);
+
+ public function getUrlParams()
+ {
+ return UrlParams::fromQueryString($this->toQueryString());
+ }
+
+ public function getById($id)
+ {
+ if ((string) $id === $this->getId()) {
+ return $this;
+ }
+ throw new ProgrammingError(
+ 'Trying to get invalid filter index "%s" from "%s" ("%s")',
+ $id,
+ $this,
+ $this->id
+ );
+ }
+
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ public function isRootNode()
+ {
+ return false === strpos($this->id, '-');
+ }
+
+ abstract public function listFilteredColumns();
+
+ public function applyChanges($changes)
+ {
+ $filter = $this;
+ $pairs = array();
+ foreach ($changes as $k => $v) {
+ if (preg_match('/^(column|value|sign|operator)_([\d-]+)$/', $k, $m)) {
+ $pairs[$m[2]][$m[1]] = $v;
+ }
+ }
+ $operators = array();
+ foreach ($pairs as $id => $fs) {
+ if (array_key_exists('operator', $fs)) {
+ $operators[$id] = $fs['operator'];
+ } else {
+ $f = $filter->getById($id);
+ $f->setColumn($fs['column']);
+ if ($f->getSign() !== $fs['sign']) {
+ if ($f->isRootNode()) {
+ $filter = $f->setSign($fs['sign']);
+ } else {
+ $filter->replaceById($id, $f->setSign($fs['sign']));
+ }
+ }
+ $f->setExpression($fs['value']);
+ }
+ }
+
+ krsort($operators, SORT_NATURAL);
+ foreach ($operators as $id => $operator) {
+ $f = $filter->getById($id);
+ if ($f->getOperatorName() !== $operator) {
+ if ($f->isRootNode()) {
+ $filter = $f->setOperatorName($operator);
+ } else {
+ $filter->replaceById($id, $f->setOperatorName($operator));
+ }
+ }
+ }
+
+ return $filter;
+ }
+
+ public function getParentId()
+ {
+ if ($this->isRootNode()) {
+ throw new ProgrammingError('Filter root nodes have no parent');
+ }
+ return substr($this->id, 0, strrpos($this->id, '-'));
+ }
+
+ public function getParent()
+ {
+ return $this->getById($this->getParentId());
+ }
+
+ public function hasId($id)
+ {
+ if ($id === $this->getId()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Where Filter factory
+ *
+ * @param string $col Column to be filtered
+ * @param string $filter Filter expression
+ *
+ * @throws FilterException
+ * @return FilterExpression
+ */
+ public static function where($col, $filter)
+ {
+ return new FilterExpression($col, '=', $filter);
+ }
+
+ public static function expression($col, $op, $expression)
+ {
+ switch ($op) {
+ case '=':
+ return new FilterMatch($col, $op, $expression);
+ case '<':
+ return new FilterLessThan($col, $op, $expression);
+ case '>':
+ return new FilterGreaterThan($col, $op, $expression);
+ case '>=':
+ return new FilterEqualOrGreaterThan($col, $op, $expression);
+ case '<=':
+ return new FilterEqualOrLessThan($col, $op, $expression);
+ case '!=':
+ return new FilterMatchNot($col, $op, $expression);
+ default:
+ throw new ProgrammingError(
+ 'There is no such filter sign: %s',
+ $op
+ );
+ }
+ }
+
+ /**
+ * Or FilterOperator factory
+ *
+ * @param Filter $filter,... Unlimited optional list of Filters
+ *
+ * @return FilterOr
+ */
+ public static function matchAny()
+ {
+ $args = func_get_args();
+ if (count($args) === 1 && is_array($args[0])) {
+ $args = $args[0];
+ }
+ return new FilterOr($args);
+ }
+
+ /**
+ * Or FilterOperator factory
+ *
+ * @param Filter $filter,... Unlimited optional list of Filters
+ *
+ * @return FilterAnd
+ */
+ public static function matchAll()
+ {
+ $args = func_get_args();
+ if (count($args) === 1 && is_array($args[0])) {
+ $args = $args[0];
+ }
+ return new FilterAnd($args);
+ }
+
+ /**
+ * FilterNot factory, negates the given filter
+ *
+ * @param Filter $filter Filter to be negated
+ *
+ * @return FilterNot
+ */
+ public static function not()
+ {
+ $args = func_get_args();
+ if (count($args) === 1) {
+ if (is_array($args[0])) {
+ $args = $args[0];
+ }
+ }
+ if (count($args) > 1) {
+ return new FilterNot(array(new FilterAnd($args)));
+ } else {
+ return new FilterNot($args);
+ }
+ }
+
+ public static function chain($operator, $filters = array())
+ {
+ switch ($operator) {
+ case 'AND':
+ return self::matchAll($filters);
+ case 'OR':
+ return self::matchAny($filters);
+ case 'NOT':
+ return self::not($filters);
+ }
+ throw new ProgrammingError(
+ '"%s" is not a valid filter chain operator',
+ $operator
+ );
+ }
+
+ /**
+ * Create filter from queryString
+ *
+ * This is still pretty basic, need improvement
+ *
+ * @return static
+ */
+ public static function fromQueryString($query)
+ {
+ return FilterQueryString::parse($query);
+ }
+}