summaryrefslogtreecommitdiffstats
path: root/library/Icingadb/Model/Behavior
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Icingadb/Model/Behavior/ActionAndNoteUrl.php52
-rw-r--r--library/Icingadb/Model/Behavior/Bitmask.php83
-rw-r--r--library/Icingadb/Model/Behavior/BoolCast.php31
-rw-r--r--library/Icingadb/Model/Behavior/FlattenedObjectVars.php77
-rw-r--r--library/Icingadb/Model/Behavior/ReRoute.php83
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;
+ }
+}