summaryrefslogtreecommitdiffstats
path: root/library/Director/IcingaConfig/AssignRenderer.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Director/IcingaConfig/AssignRenderer.php268
1 files changed, 268 insertions, 0 deletions
diff --git a/library/Director/IcingaConfig/AssignRenderer.php b/library/Director/IcingaConfig/AssignRenderer.php
new file mode 100644
index 0000000..6acbfee
--- /dev/null
+++ b/library/Director/IcingaConfig/AssignRenderer.php
@@ -0,0 +1,268 @@
+<?php
+
+namespace Icinga\Module\Director\IcingaConfig;
+
+use gipfl\Json\JsonString;
+use Icinga\Data\Filter\Filter;
+use Icinga\Data\Filter\FilterAnd;
+use Icinga\Data\Filter\FilterChain;
+use Icinga\Data\Filter\FilterExpression;
+use Icinga\Data\Filter\FilterOr;
+use Icinga\Data\Filter\FilterNot;
+use Icinga\Data\Filter\FilterEqualOrGreaterThan;
+use Icinga\Data\Filter\FilterEqualOrLessThan;
+use Icinga\Data\Filter\FilterEqual;
+use Icinga\Data\Filter\FilterGreaterThan;
+use Icinga\Data\Filter\FilterLessThan;
+use Icinga\Data\Filter\FilterMatch;
+use Icinga\Data\Filter\FilterMatchNot;
+use Icinga\Data\Filter\FilterNotEqual;
+use Icinga\Exception\QueryException;
+use Icinga\Module\Director\Data\Json;
+use InvalidArgumentException;
+
+class AssignRenderer
+{
+ protected $filter;
+
+ public function __construct(Filter $filter)
+ {
+ $this->filter = $filter;
+ }
+
+ public static function forFilter(Filter $filter)
+ {
+ return new static($filter);
+ }
+
+ public function renderAssign()
+ {
+ return $this->render('assign');
+ }
+
+ public function renderIgnore()
+ {
+ return $this->render('ignore');
+ }
+
+ public function render($type)
+ {
+ return $type . ' where ' . $this->renderFilter($this->filter);
+ }
+
+ protected function renderFilter(Filter $filter)
+ {
+ if ($filter instanceof FilterNot) {
+ $parts = [];
+ foreach ($filter->filters() as $sub) {
+ $parts[] = $this->renderFilter($sub);
+ }
+
+ return '!(' . implode(' && ', $parts) . ')';
+ }
+ if ($filter->isChain()) {
+ /** @var FilterChain $filter */
+ return $this->renderFilterChain($filter);
+ } else {
+ /** @var FilterExpression $filter */
+ return $this->renderFilterExpression($filter);
+ }
+ }
+
+ protected function renderEquals($column, $expression)
+ {
+ if (substr($column, -7) === '.groups') {
+ return sprintf(
+ '%s in %s',
+ $expression,
+ $column
+ );
+ } else {
+ return sprintf(
+ '%s == %s',
+ $column,
+ $expression
+ );
+ }
+ }
+
+ protected function renderNotEquals($column, $expression)
+ {
+ if (substr($column, -7) === '.groups') {
+ return sprintf(
+ '!(%s in %s)',
+ $expression,
+ $column
+ );
+ } else {
+ return sprintf(
+ '%s != %s',
+ $column,
+ $expression
+ );
+ }
+ }
+
+ protected function renderInArray($column, $expression)
+ {
+ return sprintf(
+ '%s in %s',
+ $column,
+ $expression
+ );
+ }
+
+ protected function renderContains(FilterExpression $filter)
+ {
+ return sprintf(
+ '%s in %s',
+ $this->renderExpressionValue(json_decode($filter->getColumn())),
+ $filter->getExpression()
+ );
+ }
+
+ protected function renderFilterExpression(FilterExpression $filter)
+ {
+ if ($this->columnIsJson($filter)) {
+ return $this->renderContains($filter);
+ }
+
+ $column = $filter->getColumn();
+ $rawExpression = Json::decode($filter->getExpression());
+ $expression = $this->renderExpressionValue($rawExpression);
+
+ if (is_array($rawExpression) && $filter instanceof FilterMatch) {
+ return $this->renderInArray($column, $expression);
+ }
+
+ if (is_string($rawExpression) && ctype_digit($rawExpression)) {
+ // TODO: doing this for compat reasons, should work for all filters
+ if ($filter instanceof FilterEqualOrGreaterThan
+ || $filter instanceof FilterGreaterThan
+ || $filter instanceof FilterEqualOrLessThan
+ || $filter instanceof FilterLessThan
+ ) {
+ $expression = $rawExpression;
+ }
+ }
+
+ if ($filter instanceof FilterEqual) {
+ if (is_array($rawExpression)) {
+ return sprintf(
+ '%s in %s',
+ $column,
+ $expression
+ );
+ } else {
+ return sprintf(
+ '%s == %s',
+ $column,
+ $expression
+ );
+ }
+ } elseif ($filter instanceof FilterMatch) {
+ if ($rawExpression === true) {
+ return $column;
+ }
+ if ($rawExpression === false) {
+ return sprintf(
+ '! %s',
+ $column
+ );
+ }
+ if (strpos($expression, '*') === false) {
+ return $this->renderEquals($column, $expression);
+ } else {
+ return sprintf(
+ 'match(%s, %s)',
+ $expression,
+ $column
+ );
+ }
+ } elseif ($filter instanceof FilterMatchNot) {
+ if (strpos($expression, '*') === false) {
+ return $this->renderNotEquals($column, $expression);
+ } else {
+ return sprintf(
+ '! match(%s, %s)',
+ $expression,
+ $column
+ );
+ }
+ } elseif ($filter instanceof FilterNotEqual) {
+ return sprintf(
+ '%s != %s',
+ $column,
+ $expression
+ );
+ } elseif ($filter instanceof FilterEqualOrGreaterThan) {
+ return sprintf(
+ '%s >= %s',
+ $column,
+ $expression
+ );
+ } elseif ($filter instanceof FilterEqualOrLessThan) {
+ return sprintf(
+ '%s <= %s',
+ $column,
+ $expression
+ );
+ } elseif ($filter instanceof FilterGreaterThan) {
+ return sprintf(
+ '%s > %s',
+ $column,
+ $expression
+ );
+ } elseif ($filter instanceof FilterLessThan) {
+ return sprintf(
+ '%s < %s',
+ $column,
+ $expression
+ );
+ } else {
+ throw new QueryException(
+ 'Filter expression of type "%s" is not supported',
+ get_class($filter)
+ );
+ }
+ }
+
+ protected function renderExpressionValue($value)
+ {
+ return IcingaConfigHelper::renderPhpValue($value);
+ }
+
+ protected function columnIsJson(FilterExpression $filter)
+ {
+ $col = $filter->getColumn();
+ return strlen($col) && $col[0] === '"';
+ }
+
+ protected function renderFilterChain(FilterChain $filter)
+ {
+ // TODO: brackets if deeper level?
+ if ($filter instanceof FilterAnd) {
+ $op = ' && ';
+ } elseif ($filter instanceof FilterOr) {
+ $op = ' || ';
+ } elseif ($filter instanceof FilterNot) {
+ throw new InvalidArgumentException('renderFilterChain should never get a FilterNot instance');
+ } else {
+ throw new InvalidArgumentException('Cannot render filter: %s', $filter);
+ }
+
+ $parts = array();
+ if (! $filter->isEmpty()) {
+ /** @var Filter $f */
+ foreach ($filter->filters() as $f) {
+ if ($f instanceof FilterChain && $f->count() > 1) {
+ $parts[] = '(' . $this->renderFilter($f) . ')';
+ } else {
+ $parts[] = $this->renderFilter($f);
+ }
+ }
+ }
+
+ return implode($op, $parts);
+ }
+}