diff options
Diffstat (limited to 'library/Icingadb/Model/Behavior')
-rw-r--r-- | library/Icingadb/Model/Behavior/ActionAndNoteUrl.php | 52 | ||||
-rw-r--r-- | library/Icingadb/Model/Behavior/Bitmask.php | 83 | ||||
-rw-r--r-- | library/Icingadb/Model/Behavior/BoolCast.php | 31 | ||||
-rw-r--r-- | library/Icingadb/Model/Behavior/FlattenedObjectVars.php | 77 | ||||
-rw-r--r-- | library/Icingadb/Model/Behavior/ReRoute.php | 83 |
5 files changed, 326 insertions, 0 deletions
diff --git a/library/Icingadb/Model/Behavior/ActionAndNoteUrl.php b/library/Icingadb/Model/Behavior/ActionAndNoteUrl.php new file mode 100644 index 0000000..e8f6799 --- /dev/null +++ b/library/Icingadb/Model/Behavior/ActionAndNoteUrl.php @@ -0,0 +1,52 @@ +<?php + +/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Model\Behavior; + +use ipl\Orm\Contract\PropertyBehavior; + +class ActionAndNoteUrl extends PropertyBehavior +{ + public function fromDb($value, $key, $_) + { + if (empty($value)) { + return []; + } + + $links = []; + if (strpos($value, "' ") === false) { + $links[] = $value; + } else { + foreach (explode("' ", $value) as $url) { + $url = strpos($url, "'") === 0 ? substr($url, 1) : $url; + $url = strpos($url, "'") === strlen($url) - 1 ? substr($url, 0, strlen($url) - 1) : $url; + $links[] = $url; + } + } + + return $links; + } + + public function toDb($value, $key, $_) + { + if (empty($value) || ! is_array($value)) { + return $value; + } + + if (count($value) === 1) { + return $value[0]; + } + + $links = ''; + foreach ($value as $url) { + if (! empty($links)) { + $links .= ' '; + } + + $links .= "'$url'"; + } + + return $links; + } +} diff --git a/library/Icingadb/Model/Behavior/Bitmask.php b/library/Icingadb/Model/Behavior/Bitmask.php new file mode 100644 index 0000000..f8d91f6 --- /dev/null +++ b/library/Icingadb/Model/Behavior/Bitmask.php @@ -0,0 +1,83 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Model\Behavior; + +use ipl\Orm\Contract\PropertyBehavior; +use ipl\Orm\Contract\RewriteFilterBehavior; +use ipl\Stdlib\Filter\Condition; + +/** + * Class Bitmask + * + * @method void __construct(array $properties) Pass property names as keys and their bitmap ([value => bit]) as value + */ +class Bitmask extends PropertyBehavior implements RewriteFilterBehavior +{ + public function fromDb($bits, $key, $context) + { + $values = []; + foreach ($context as $value => $bit) { + if ($bits & $bit) { + $values[] = $value; + } + } + + return $values; + } + + public function toDb($value, $key, $context) + { + if (! is_array($value)) { + if (is_int($value) || ctype_digit($value)) { + return $value; + } + + return isset($context[$value]) ? $context[$value] : -1; + } + + $bits = []; + $allBits = 0; + foreach ($value as $v) { + if (isset($context[$v])) { + $bits[] = $context[$v]; + $allBits |= $context[$v]; + } elseif (is_int($v) || ctype_digit($v)) { + $bits[] = $v; + $allBits |= $v; + } + } + + $bits[] = $allBits; + return $bits; + } + + public function rewriteCondition(Condition $condition, $relation = null) + { + $column = $condition->metaData()->get('columnName'); + if (! isset($this->properties[$column])) { + return; + } + + $values = $condition->getValue(); + if (! is_array($values)) { + if (is_int($values) || ctype_digit($values)) { + return; + } + + $values = [$values]; + } + + $bits = 0; + foreach ($values as $value) { + if (isset($this->properties[$column][$value])) { + $bits |= $this->properties[$column][$value]; + } elseif (is_int($value) || ctype_digit($value)) { + $bits |= $value; + } + } + + $condition->setColumn(sprintf('%s & %s', $condition->getColumn(), $bits)); + } +} diff --git a/library/Icingadb/Model/Behavior/BoolCast.php b/library/Icingadb/Model/Behavior/BoolCast.php new file mode 100644 index 0000000..8ab01ae --- /dev/null +++ b/library/Icingadb/Model/Behavior/BoolCast.php @@ -0,0 +1,31 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Model\Behavior; + +use ipl\Orm\Contract\PropertyBehavior; + +class BoolCast extends PropertyBehavior +{ + public function fromDb($value, $key, $_) + { + switch ((string) $value) { + case 'y': + return true; + case 'n': + return false; + default: + return $value; + } + } + + public function toDb($value, $key, $_) + { + if (is_string($value)) { + return $value; + } + + return $value ? 'y' : 'n'; + } +} diff --git a/library/Icingadb/Model/Behavior/FlattenedObjectVars.php b/library/Icingadb/Model/Behavior/FlattenedObjectVars.php new file mode 100644 index 0000000..b1c308a --- /dev/null +++ b/library/Icingadb/Model/Behavior/FlattenedObjectVars.php @@ -0,0 +1,77 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Model\Behavior; + +use Icinga\Module\Icingadb\Common\Auth; +use Icinga\Module\Icingadb\Model\CustomvarFlat; +use ipl\Orm\AliasedExpression; +use ipl\Orm\ColumnDefinition; +use ipl\Orm\Contract\QueryAwareBehavior; +use ipl\Orm\Contract\RewriteColumnBehavior; +use ipl\Orm\Query; +use ipl\Stdlib\Filter; + +class FlattenedObjectVars implements RewriteColumnBehavior, QueryAwareBehavior +{ + use Auth; + + /** @var Query */ + protected $query; + + public function setQuery(Query $query) + { + $this->query = $query; + + return $this; + } + + public function rewriteCondition(Filter\Condition $condition, $relation = null) + { + $column = $condition->metaData()->get('columnName'); + if ($column !== null) { + $relation = substr($relation, 0, -5) . 'customvar_flat.'; + $nameFilter = Filter::like($relation . 'flatname', $column); + $class = get_class($condition); + $valueFilter = new $class($relation . 'flatvalue', $condition->getValue()); + + return Filter::all($nameFilter, $valueFilter); + } + } + + public function rewriteColumn($column, $relation = null) + { + $subQuery = $this->query->createSubQuery(new CustomvarFlat(), $relation) + ->limit(1) + ->columns('flatvalue') + ->filter(Filter::equal('flatname', $column)); + + $this->applyRestrictions($subQuery); + + $alias = $this->query->getDb()->quoteIdentifier([str_replace('.', '_', $relation) . "_$column"]); + + list($select, $values) = $this->query->getDb()->getQueryBuilder()->assembleSelect($subQuery->assembleSelect()); + return new AliasedExpression($alias, "($select)", null, ...$values); + } + + public function rewriteColumnDefinition(ColumnDefinition $def, string $relation): void + { + $parts = explode('.', substr($relation, 0, -5)); + $objectType = array_pop($parts); + + $name = $def->getName(); + if (substr($name, -3) === '[*]') { + // The suggestions also hide this from the label, so should this + $name = substr($name, 0, -3); + } + + // Programmatically translated since the full definition is available in class ObjectSuggestions + $def->setLabel(sprintf(t(ucfirst($objectType) . ' %s', '..<customvar-name>'), $name)); + } + + public function isSelectableColumn(string $name): bool + { + return true; + } +} diff --git a/library/Icingadb/Model/Behavior/ReRoute.php b/library/Icingadb/Model/Behavior/ReRoute.php new file mode 100644 index 0000000..d054f00 --- /dev/null +++ b/library/Icingadb/Model/Behavior/ReRoute.php @@ -0,0 +1,83 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Model\Behavior; + +use ipl\Orm\Contract\RewriteFilterBehavior; +use ipl\Orm\Contract\RewritePathBehavior; +use ipl\Stdlib\Filter; + +class ReRoute implements RewriteFilterBehavior, RewritePathBehavior +{ + protected $routes; + + /** + * Tables with mixed object type entries for which servicegroup filters need to be resolved in multiple steps + * + * @var string[] + */ + const MIXED_TYPE_RELATIONS = ['downtime', 'comment', 'history', 'notification_history']; + + public function __construct(array $routes) + { + $this->routes = $routes; + } + + public function getRoutes(): array + { + return $this->routes; + } + + public function rewriteCondition(Filter\Condition $condition, $relation = null) + { + $remainingPath = $condition->metaData()->get('columnName', ''); + if (strpos($remainingPath, '.') === false) { + return; + } + + if (($path = $this->rewritePath($remainingPath, $relation)) !== null) { + $class = get_class($condition); + $filter = new $class($relation . $path, $condition->getValue()); + if ($condition->metaData()->has('forceOptimization')) { + $filter->metaData()->set( + 'forceOptimization', + $condition->metaData()->get('forceOptimization') + ); + } + + if ( + in_array(substr($relation, 0, -1), self::MIXED_TYPE_RELATIONS) + && substr($remainingPath, 0, 13) === 'servicegroup.' + ) { + $applyAll = Filter::all(); + $applyAll->add(Filter::equal($relation . 'object_type', 'host')); + + $orgFilter = clone $filter; + $orgFilter->setColumn($relation . 'host.' . $path); + + $applyAll->add($orgFilter); + + $filter = Filter::any($filter, $applyAll); + } + + return $filter; + } + } + + public function rewritePath(string $path, ?string $relation = null): ?string + { + $dot = strpos($path, '.'); + if ($dot !== false) { + $routeName = substr($path, 0, $dot); + } else { + $routeName = $path; + } + + if (isset($this->routes[$routeName])) { + return $this->routes[$routeName] . ($dot !== false ? substr($path, $dot) : ''); + } + + return null; + } +} |