summaryrefslogtreecommitdiffstats
path: root/library/Icingadb/Model
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Icingadb/Model/AcknowledgementHistory.php102
-rw-r--r--library/Icingadb/Model/ActionUrl.php62
-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
-rw-r--r--library/Icingadb/Model/Checkcommand.php86
-rw-r--r--library/Icingadb/Model/CheckcommandArgument.php75
-rw-r--r--library/Icingadb/Model/CheckcommandCustomvar.php52
-rw-r--r--library/Icingadb/Model/CheckcommandEnvvar.php61
-rw-r--r--library/Icingadb/Model/Comment.php114
-rw-r--r--library/Icingadb/Model/CommentHistory.php107
-rw-r--r--library/Icingadb/Model/Customvar.php72
-rw-r--r--library/Icingadb/Model/CustomvarFlat.php167
-rw-r--r--library/Icingadb/Model/Downtime.php144
-rw-r--r--library/Icingadb/Model/DowntimeHistory.php128
-rw-r--r--library/Icingadb/Model/Endpoint.php69
-rw-r--r--library/Icingadb/Model/Environment.php105
-rw-r--r--library/Icingadb/Model/Eventcommand.php86
-rw-r--r--library/Icingadb/Model/EventcommandArgument.php75
-rw-r--r--library/Icingadb/Model/EventcommandCustomvar.php52
-rw-r--r--library/Icingadb/Model/EventcommandEnvvar.php61
-rw-r--r--library/Icingadb/Model/FlappingHistory.php91
-rw-r--r--library/Icingadb/Model/History.php127
-rw-r--r--library/Icingadb/Model/Host.php234
-rw-r--r--library/Icingadb/Model/HostCustomvar.php52
-rw-r--r--library/Icingadb/Model/HostState.php81
-rw-r--r--library/Icingadb/Model/Hostgroup.php92
-rw-r--r--library/Icingadb/Model/HostgroupCustomvar.php52
-rw-r--r--library/Icingadb/Model/HostgroupMember.php53
-rw-r--r--library/Icingadb/Model/Hostgroupsummary.php213
-rw-r--r--library/Icingadb/Model/HoststateSummary.php78
-rw-r--r--library/Icingadb/Model/IconImage.php55
-rw-r--r--library/Icingadb/Model/Instance.php78
-rw-r--r--library/Icingadb/Model/LastHostComment.php19
-rw-r--r--library/Icingadb/Model/LastServiceComment.php19
-rw-r--r--library/Icingadb/Model/NotesUrl.php62
-rw-r--r--library/Icingadb/Model/Notification.php130
-rw-r--r--library/Icingadb/Model/NotificationCustomvar.php52
-rw-r--r--library/Icingadb/Model/NotificationHistory.php115
-rw-r--r--library/Icingadb/Model/NotificationUser.php49
-rw-r--r--library/Icingadb/Model/NotificationUsergroup.php49
-rw-r--r--library/Icingadb/Model/Notificationcommand.php87
-rw-r--r--library/Icingadb/Model/NotificationcommandArgument.php75
-rw-r--r--library/Icingadb/Model/NotificationcommandCustomvar.php52
-rw-r--r--library/Icingadb/Model/NotificationcommandEnvvar.php61
-rw-r--r--library/Icingadb/Model/Service.php225
-rw-r--r--library/Icingadb/Model/ServiceCustomvar.php52
-rw-r--r--library/Icingadb/Model/ServiceState.php76
-rw-r--r--library/Icingadb/Model/Servicegroup.php91
-rw-r--r--library/Icingadb/Model/ServicegroupCustomvar.php52
-rw-r--r--library/Icingadb/Model/ServicegroupMember.php49
-rw-r--r--library/Icingadb/Model/ServicegroupSummary.php167
-rw-r--r--library/Icingadb/Model/ServicestateSummary.php99
-rw-r--r--library/Icingadb/Model/State.php177
-rw-r--r--library/Icingadb/Model/StateHistory.php101
-rw-r--r--library/Icingadb/Model/Timeperiod.php91
-rw-r--r--library/Icingadb/Model/TimeperiodCustomvar.php52
-rw-r--r--library/Icingadb/Model/TimeperiodOverrideExclude.php51
-rw-r--r--library/Icingadb/Model/TimeperiodOverrideInclude.php51
-rw-r--r--library/Icingadb/Model/TimeperiodRange.php58
-rw-r--r--library/Icingadb/Model/User.php134
-rw-r--r--library/Icingadb/Model/UserCustomvar.php52
-rw-r--r--library/Icingadb/Model/Usergroup.php95
-rw-r--r--library/Icingadb/Model/UsergroupCustomvar.php52
-rw-r--r--library/Icingadb/Model/UsergroupMember.php49
-rw-r--r--library/Icingadb/Model/Vars.php28
-rw-r--r--library/Icingadb/Model/Zone.php82
69 files changed, 5804 insertions, 0 deletions
diff --git a/library/Icingadb/Model/AcknowledgementHistory.php b/library/Icingadb/Model/AcknowledgementHistory.php
new file mode 100644
index 0000000..549d2ff
--- /dev/null
+++ b/library/Icingadb/Model/AcknowledgementHistory.php
@@ -0,0 +1,102 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+/**
+ * Model for table `acknowledgement_history`
+ *
+ * Please note that using this model will fetch history entries for decommissioned services. To avoid this, the query
+ * needs a `acknowledgement_history.service_id IS NULL OR acknowledgement_history_service.id IS NOT NULL` where.
+ */
+class AcknowledgementHistory extends Model
+{
+ public function getTableName()
+ {
+ return 'acknowledgement_history';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'set_time',
+ 'clear_time',
+ 'author',
+ 'cleared_by',
+ 'comment',
+ 'expire_time',
+ 'is_sticky',
+ 'is_persistent'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'endpoint_id' => t('Endpoint Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'set_time' => t('Acknowledgement Set Time'),
+ 'clear_time' => t('Acknowledgement Clear Time'),
+ 'author' => t('Acknowledgement Author'),
+ 'cleared_by' => t('Acknowledgement Cleared By'),
+ 'comment' => t('Acknowledgement Comment'),
+ 'expire_time' => t('Acknowledgement Expire Time'),
+ 'is_sticky' => t('Acknowledgement Is Sticky'),
+ 'is_persistent' => t('Acknowledgement Is Persistent')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'is_sticky',
+ 'is_persistent'
+ ]));
+
+ $behaviors->add(new MillisecondTimestamp([
+ 'set_time',
+ 'clear_time',
+ 'expire_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'endpoint_id',
+ 'host_id',
+ 'service_id',
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('endpoint', Endpoint::class);
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('history', History::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('acknowledgement_history_id');
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/ActionUrl.php b/library/Icingadb/Model/ActionUrl.php
new file mode 100644
index 0000000..e0b092e
--- /dev/null
+++ b/library/Icingadb/Model/ActionUrl.php
@@ -0,0 +1,62 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ActionAndNoteUrl;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class ActionUrl extends Model
+{
+ public function getTableName()
+ {
+ return 'action_url';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'action_url',
+ 'environment_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'action_url' => t('Action Url'),
+ 'environment_id' => t('Environment Id')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ActionAndNoteUrl(['action_url']));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+
+ $relations->hasMany('host', Host::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('action_url_id');
+ $relations->hasMany('service', Service::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('action_url_id');
+ }
+}
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;
+ }
+}
diff --git a/library/Icingadb/Model/Checkcommand.php b/library/Icingadb/Model/Checkcommand.php
new file mode 100644
index 0000000..400a24b
--- /dev/null
+++ b/library/Icingadb/Model/Checkcommand.php
@@ -0,0 +1,86 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Checkcommand extends Model
+{
+ public function getTableName()
+ {
+ return 'checkcommand';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'zone_id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'command',
+ 'timeout'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'zone_id' => t('Zone Id'),
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Checkcommand Name Checksum'),
+ 'properties_checksum' => t('Checkcommand Properties Checksum'),
+ 'name' => t('Checkcommand Name'),
+ 'name_ci' => t('Checkcommand Name (CI)'),
+ 'command' => t('Checkcommand'),
+ 'timeout' => t('Checkcommand Timeout')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'zone_id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(CheckcommandCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(CheckcommandCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(CheckcommandCustomvar::class);
+
+ $relations->hasMany('argument', CheckcommandArgument::class);
+ $relations->hasMany('envvar', CheckcommandEnvvar::class);
+ $relations->hasMany('host', Host::class);
+ $relations->hasMany('service', Service::class);
+ }
+}
diff --git a/library/Icingadb/Model/CheckcommandArgument.php b/library/Icingadb/Model/CheckcommandArgument.php
new file mode 100644
index 0000000..3fb4ad5
--- /dev/null
+++ b/library/Icingadb/Model/CheckcommandArgument.php
@@ -0,0 +1,75 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class CheckcommandArgument extends Model
+{
+ public function getTableName()
+ {
+ return 'checkcommand_argument';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'checkcommand_id',
+ 'argument_key',
+ 'environment_id',
+ 'properties_checksum',
+ 'argument_value',
+ 'argument_order',
+ 'description',
+ 'argument_key_override',
+ 'repeat_key',
+ 'required',
+ 'set_if',
+ 'skip_key'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'checkcommand_id' => t('Checkcommand Id'),
+ 'argument_key' => t('Checkcommand Argument Name'),
+ 'environment_id' => t('Environment Id'),
+ 'properties_checksum' => t('Checkcommand Argument Properties Checksum'),
+ 'argument_value' => t('Checkcommand Argument Value'),
+ 'argument_order' => t('Checkcommand Argument Position'),
+ 'description' => t('Checkcommand Argument Description'),
+ 'argument_key_override' => t('Checkcommand Argument Actual Name'),
+ 'repeat_key' => t('Checkcommand Argument Repeated'),
+ 'required' => t('Checkcommand Argument Required'),
+ 'set_if' => t('Checkcommand Argument Condition'),
+ 'skip_key' => t('Checkcommand Argument Without Name')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'checkcommand_id',
+ 'environment_id',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('checkcommand', Checkcommand::class);
+ }
+}
diff --git a/library/Icingadb/Model/CheckcommandCustomvar.php b/library/Icingadb/Model/CheckcommandCustomvar.php
new file mode 100644
index 0000000..0a834b5
--- /dev/null
+++ b/library/Icingadb/Model/CheckcommandCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class CheckcommandCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'checkcommand_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'checkcommand_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'checkcommand_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('checkcommand', Checkcommand::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/CheckcommandEnvvar.php b/library/Icingadb/Model/CheckcommandEnvvar.php
new file mode 100644
index 0000000..517a45f
--- /dev/null
+++ b/library/Icingadb/Model/CheckcommandEnvvar.php
@@ -0,0 +1,61 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class CheckcommandEnvvar extends Model
+{
+ public function getTableName()
+ {
+ return 'checkcommand_envvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'checkcommand_id',
+ 'envvar_key',
+ 'environment_id',
+ 'properties_checksum',
+ 'envvar_value'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'checkcommand_id' => t('Checkcommand Id'),
+ 'envvar_key' => t('Checkcommand Envvar Name'),
+ 'environment_id' => t('Environment Id'),
+ 'properties_checksum' => t('Checkcommand Properties Checksum'),
+ 'envvar_value' => t('Checkcommand Envvar Value')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'checkcommand_id',
+ 'environment_id',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('checkcommand', Checkcommand::class);
+ }
+}
diff --git a/library/Icingadb/Model/Comment.php b/library/Icingadb/Model/Comment.php
new file mode 100644
index 0000000..bcdd5e0
--- /dev/null
+++ b/library/Icingadb/Model/Comment.php
@@ -0,0 +1,114 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Comment extends Model
+{
+ public function getTableName()
+ {
+ return 'comment';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'author',
+ 'text',
+ 'entry_type',
+ 'entry_time',
+ 'is_persistent',
+ 'is_sticky',
+ 'expire_time',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'name_checksum' => t('Comment Name Checksum'),
+ 'properties_checksum' => t('Comment Properties Checksum'),
+ 'name' => t('Comment Name'),
+ 'author' => t('Comment Author'),
+ 'text' => t('Comment Text'),
+ 'entry_type' => t('Comment Type'),
+ 'entry_time' => t('Comment Entry Time'),
+ 'is_persistent' => t('Comment Is Persistent'),
+ 'is_sticky' => t('Comment Is Sticky'),
+ 'expire_time' => t('Comment Expire Time'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['text'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'comment.entry_time desc';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'is_persistent',
+ 'is_sticky'
+ ]));
+
+ $behaviors->add(new MillisecondTimestamp([
+ 'entry_time',
+ 'expire_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'host_id',
+ 'service_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'zone_id'
+ ]));
+
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('host', Host::class)->setJoinType('LEFT');
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ $relations->belongsTo('zone', Zone::class);
+ }
+}
diff --git a/library/Icingadb/Model/CommentHistory.php b/library/Icingadb/Model/CommentHistory.php
new file mode 100644
index 0000000..5f03e68
--- /dev/null
+++ b/library/Icingadb/Model/CommentHistory.php
@@ -0,0 +1,107 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+/**
+ * Model for table `comment_history`
+ *
+ * Please note that using this model will fetch history entries for decommissioned services. To avoid this,
+ * the query needs a `comment_history.service_id IS NULL OR comment_history_service.id IS NOT NULL` where.
+ */
+class CommentHistory extends Model
+{
+ public function getTableName()
+ {
+ return 'comment_history';
+ }
+
+ public function getKeyName()
+ {
+ return 'comment_id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'entry_time',
+ 'author',
+ 'removed_by',
+ 'comment',
+ 'entry_type',
+ 'is_persistent',
+ 'is_sticky',
+ 'expire_time',
+ 'remove_time',
+ 'has_been_removed'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'endpoint_id' => t('Endpoint Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'entry_time' => t('Comment Entry Time'),
+ 'author' => t('Comment Author'),
+ 'removed_by' => t('Comment Removed By'),
+ 'comment' => t('Comment Text'),
+ 'entry_type' => t('Comment Entry Type'),
+ 'is_persistent' => t('Comment Is Persistent'),
+ 'is_sticky' => t('Comment Is Sticky'),
+ 'expire_time' => t('Comment Expire Time'),
+ 'remove_time' => t('Comment Remove Time'),
+ 'has_been_removed' => t('Comment Has Been Removed')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'is_persistent',
+ 'is_sticky',
+ 'has_been_removed'
+ ]));
+
+ $behaviors->add(new MillisecondTimestamp([
+ 'entry_time',
+ 'expire_time',
+ 'remove_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'comment_id',
+ 'environment_id',
+ 'endpoint_id',
+ 'host_id',
+ 'service_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('endpoint', Endpoint::class);
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('history', History::class)
+ ->setCandidateKey('comment_id')
+ ->setForeignKey('comment_history_id');
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/Customvar.php b/library/Icingadb/Model/Customvar.php
new file mode 100644
index 0000000..e043229
--- /dev/null
+++ b/library/Icingadb/Model/Customvar.php
@@ -0,0 +1,72 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Customvar extends Model
+{
+ public function getTableName()
+ {
+ return 'customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'name',
+ 'value'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+
+ $relations->belongsToMany('checkcommand', Checkcommand::class)
+ ->through(CheckcommandCustomvar::class);
+ $relations->belongsToMany('eventcommand', Eventcommand::class)
+ ->through(EventcommandCustomvar::class);
+ $relations->belongsToMany('host', Host::class)
+ ->through(HostCustomvar::class);
+ $relations->belongsToMany('hostgroup', Hostgroup::class)
+ ->through(HostgroupCustomvar::class);
+ $relations->belongsToMany('notification', Notification::class)
+ ->through(NotificationCustomvar::class);
+ $relations->belongsToMany('notificationcommand', Notificationcommand::class)
+ ->through(NotificationcommandCustomvar::class);
+ $relations->belongsToMany('service', Service::class)
+ ->through(ServiceCustomvar::class);
+ $relations->belongsToMany('servicegroup', Servicegroup::class)
+ ->through(ServicegroupCustomvar::class);
+ $relations->belongsToMany('timeperiod', Timeperiod::class)
+ ->through(TimeperiodCustomvar::class);
+ $relations->belongsToMany('user', User::class)
+ ->through(UserCustomvar::class);
+ $relations->belongsToMany('usergroup', Usergroup::class)
+ ->through(UsergroupCustomvar::class);
+
+ $relations->hasMany('customvar_flat', CustomvarFlat::class);
+ }
+}
diff --git a/library/Icingadb/Model/CustomvarFlat.php b/library/Icingadb/Model/CustomvarFlat.php
new file mode 100644
index 0000000..99d8aca
--- /dev/null
+++ b/library/Icingadb/Model/CustomvarFlat.php
@@ -0,0 +1,167 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Query;
+use ipl\Orm\Relations;
+use Traversable;
+
+class CustomvarFlat extends Model
+{
+ public function getTableName()
+ {
+ return 'customvar_flat';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'customvar_id',
+ 'flatname_checksum',
+ 'flatname',
+ 'flatvalue'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'customvar_id',
+ 'flatname_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('customvar', Customvar::class);
+
+ $relations->belongsToMany('checkcommand', Checkcommand::class)
+ ->through(CheckcommandCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('eventcommand', Eventcommand::class)
+ ->through(EventcommandCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('host', Host::class)
+ ->through(HostCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('hostgroup', Hostgroup::class)
+ ->through(HostgroupCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('notification', Notification::class)
+ ->through(NotificationCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('notificationcommand', Notificationcommand::class)
+ ->through(NotificationcommandCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('service', Service::class)
+ ->through(ServiceCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('servicegroup', Servicegroup::class)
+ ->through(ServicegroupCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('timeperiod', Timeperiod::class)
+ ->through(TimeperiodCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('user', User::class)
+ ->through(UserCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ $relations->belongsToMany('usergroup', Usergroup::class)
+ ->through(UsergroupCustomvar::class)
+ ->setCandidateKey('customvar_id');
+ }
+
+ /**
+ * Restore flattened custom variables to their previous structure
+ *
+ * @param Traversable $flattenedVars
+ *
+ * @return array
+ */
+ public function unFlattenVars(Traversable $flattenedVars): array
+ {
+ $registerValue = function (&$data, $source, $path, $value) use (&$registerValue) {
+ $step = array_shift($path);
+
+ $isIndex = (bool) preg_match('/^\[(\d+)]$/', $step, $m);
+ if ($isIndex) {
+ $step = $m[1];
+ }
+
+ if ($source !== null) {
+ while (! isset($source[$step])) {
+ if ($isIndex) {
+ $step = sprintf('[%d]', $step);
+ $isIndex = false;
+ } else {
+ if (empty($path)) {
+ break;
+ }
+
+ $step = implode('.', [$step, array_shift($path)]);
+ }
+ }
+ }
+
+ if (! empty($path)) {
+ if (! isset($data[$step])) {
+ $data[$step] = [];
+ }
+
+ $registerValue($data[$step], $source[$step] ?? null, $path, $value);
+ } else {
+ // Since empty custom vars of type dictionaries and arrays have null values in customvar_flat table,
+ // we won't be able to render them as such. Therefore, we have to use the value of the `customvar`
+ // table if it's not null, otherwise the current value, which is a "null" string.
+ $data[$step] = $value === null && ($source[$step] ?? null) === [] ? $source[$step] : $value;
+ }
+ };
+
+ if ($flattenedVars instanceof Query) {
+ $flattenedVars->withColumns(['customvar.name', 'customvar.value']);
+ }
+
+ $vars = [];
+ foreach ($flattenedVars as $var) {
+ if (isset($var->customvar->name)) {
+ $var->customvar->value = json_decode($var->customvar->value, true);
+
+ $realName = $var->customvar->name;
+ $source = [$realName => $var->customvar->value];
+
+ $sourcePath = ltrim(substr($var->flatname, strlen($realName)), '.');
+ $path = array_merge(
+ [$realName],
+ $sourcePath
+ ? preg_split('/(?<=\w|])\.|(?<!^|\.)(?=\[)/', $sourcePath)
+ : []
+ );
+ } else {
+ $path = explode('.', $var->flatname);
+ $source = null;
+ }
+
+ $registerValue($vars, $source, $path, $var->flatvalue);
+
+ if (isset($var->customvar->name)) {
+ $var->customvar->name = null;
+ $var->customvar->value = null;
+ }
+ }
+
+ return $vars;
+ }
+}
diff --git a/library/Icingadb/Model/Downtime.php b/library/Icingadb/Model/Downtime.php
new file mode 100644
index 0000000..7f600e9
--- /dev/null
+++ b/library/Icingadb/Model/Downtime.php
@@ -0,0 +1,144 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Downtime extends Model
+{
+ public function getTableName()
+ {
+ return 'downtime';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'triggered_by_id',
+ 'parent_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'author',
+ 'comment',
+ 'entry_time',
+ 'scheduled_start_time',
+ 'scheduled_end_time',
+ 'scheduled_duration',
+ 'is_flexible',
+ 'flexible_duration',
+ 'is_in_effect',
+ 'start_time',
+ 'end_time',
+ 'duration',
+ 'scheduled_by',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'triggered_by_id' => t('Triggered By Downtime Id'),
+ 'parent_id' => t('Parent Downtime Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'name_checksum' => t('Downtime Name Checksum'),
+ 'properties_checksum' => t('Downtime Properties Checksum'),
+ 'name' => t('Downtime Name'),
+ 'author' => t('Downtime Author'),
+ 'comment' => t('Downtime Comment'),
+ 'entry_time' => t('Downtime Entry Time'),
+ 'scheduled_start_time' => t('Downtime Scheduled Start'),
+ 'scheduled_end_time' => t('Downtime Scheduled End'),
+ 'scheduled_duration' => t('Downtime Scheduled Duration'),
+ 'is_flexible' => t('Downtime Is Flexible'),
+ 'flexible_duration' => t('Downtime Flexible Duration'),
+ 'is_in_effect' => t('Downtime Is In Effect'),
+ 'start_time' => t('Downtime Actual Start'),
+ 'end_time' => t('Downtime Actual End'),
+ 'duration' => t('Downtime Duration'),
+ 'scheduled_by' => t('Scheduled By Downtime'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['comment'];
+ }
+
+ public function getDefaultSort()
+ {
+ return ['downtime.is_in_effect desc', 'downtime.start_time desc'];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'is_flexible',
+ 'is_in_effect'
+ ]));
+
+ $behaviors->add(new MillisecondTimestamp([
+ 'entry_time',
+ 'scheduled_start_time',
+ 'scheduled_end_time',
+ 'start_time',
+ 'end_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'triggered_by_id',
+ 'parent_id',
+ 'host_id',
+ 'service_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'zone_id'
+ ]));
+
+ // As long as the rewriteCondition() expects only Filter\Condition as a first argument
+ // We have to add this reroute behavior after the binary because the filter condition might
+ // be transformed into a filter chain!
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('triggered_by', self::class)
+ ->setCandidateKey('triggered_by_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('parent', self::class)
+ ->setCandidateKey('parent_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('host', Host::class)->setJoinType('LEFT');
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ $relations->belongsTo('zone', Zone::class);
+ }
+}
diff --git a/library/Icingadb/Model/DowntimeHistory.php b/library/Icingadb/Model/DowntimeHistory.php
new file mode 100644
index 0000000..7ba992f
--- /dev/null
+++ b/library/Icingadb/Model/DowntimeHistory.php
@@ -0,0 +1,128 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+/**
+ * Model for table `downtime_history`
+ *
+ * Please note that using this model will fetch history entries for decommissioned services. To avoid this,
+ * the query needs a `downtime_history.service_id IS NULL OR downtime_history_service.id IS NOT NULL` where.
+ */
+class DowntimeHistory extends Model
+{
+ public function getTableName()
+ {
+ return 'downtime_history';
+ }
+
+ public function getKeyName()
+ {
+ return 'downtime_id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'triggered_by_id',
+ 'parent_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'entry_time',
+ 'author',
+ 'cancelled_by',
+ 'comment',
+ 'is_flexible',
+ 'flexible_duration',
+ 'scheduled_start_time',
+ 'scheduled_end_time',
+ 'start_time',
+ 'end_time',
+ 'has_been_cancelled',
+ 'trigger_time',
+ 'cancel_time'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'endpoint_id' => t('Endpoint Id'),
+ 'triggered_by_id' => t('Triggered By Downtime Id'),
+ 'parent_id' => t('Parent Downtime Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'entry_time' => t('Downtime Entry Time'),
+ 'author' => t('Downtime Author'),
+ 'cancelled_by' => t('Downtime Cancelled By'),
+ 'comment' => t('Downtime Comment'),
+ 'is_flexible' => t('Downtime Is Flexible'),
+ 'flexible_duration' => t('Downtime Flexible Duration'),
+ 'scheduled_start_time' => t('Downtime Scheduled Start'),
+ 'scheduled_end_time' => t('Downtime Scheduled End'),
+ 'start_time' => t('Downtime Actual Start'),
+ 'end_time' => t('Downtime Actual End'),
+ 'has_been_cancelled' => t('Downtime Has Been Cancelled'),
+ 'trigger_time' => t('Downtime Trigger Time'),
+ 'cancel_time' => t('Downtime Cancel Time')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'is_flexible',
+ 'has_been_cancelled'
+ ]));
+
+ $behaviors->add(new MillisecondTimestamp([
+ 'entry_time',
+ 'scheduled_start_time',
+ 'scheduled_end_time',
+ 'start_time',
+ 'end_time',
+ 'trigger_time',
+ 'cancel_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'downtime_id',
+ 'environment_id',
+ 'endpoint_id',
+ 'triggered_by_id',
+ 'parent_id',
+ 'host_id',
+ 'service_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('triggered_by', self::class)
+ ->setCandidateKey('triggered_by_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('parent', self::class)
+ ->setCandidateKey('parent_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('endpoint', Endpoint::class);
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('history', History::class)
+ ->setCandidateKey('downtime_id')
+ ->setForeignKey('downtime_history_id');
+ $relations->belongsTo('host', Host::class)->setJoinType('LEFT');
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/Endpoint.php b/library/Icingadb/Model/Endpoint.php
new file mode 100644
index 0000000..257001b
--- /dev/null
+++ b/library/Icingadb/Model/Endpoint.php
@@ -0,0 +1,69 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Endpoint extends Model
+{
+ public function getTableName()
+ {
+ return 'endpoint';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Endpoint Name Checksum'),
+ 'properties_checksum' => t('Endpoint Properties Checksum'),
+ 'name' => t('Endpoint Name'),
+ 'name_ci' => t('Endpoint Name (CI)'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'zone_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->hasMany('host', Host::class)
+ ->setForeignKey('command_endpoint_id');
+ $relations->hasMany('service', Service::class)
+ ->setForeignKey('command_endpoint_id');
+ }
+}
diff --git a/library/Icingadb/Model/Environment.php b/library/Icingadb/Model/Environment.php
new file mode 100644
index 0000000..919ca1c
--- /dev/null
+++ b/library/Icingadb/Model/Environment.php
@@ -0,0 +1,105 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Environment extends Model
+{
+ public function getTableName()
+ {
+ return 'environment';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'name'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'name' => t('Environment Name')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->hasMany('acknowledgement_history', AcknowledgementHistory::class);
+ $relations->hasMany('action_url', ActionUrl::class);
+ $relations->hasMany('checkcommand', Checkcommand::class);
+ $relations->hasMany('checkcommand_argument', CheckcommandArgument::class);
+ $relations->hasMany('checkcommand_customvar', CheckcommandCustomvar::class);
+ $relations->hasMany('checkcommand_envvar', CheckcommandEnvvar::class);
+ $relations->hasMany('comment', Comment::class);
+ $relations->hasMany('comment_history', CommentHistory::class);
+ $relations->hasMany('customvar', Customvar::class);
+ $relations->hasMany('customvar_flat', CustomvarFlat::class);
+ $relations->hasMany('downtime', Downtime::class);
+ $relations->hasMany('downtime_history', DowntimeHistory::class);
+ $relations->hasMany('endpoint', Endpoint::class);
+ $relations->hasMany('eventcommand', Eventcommand::class);
+ $relations->hasMany('eventcommand_argument', EventcommandArgument::class);
+ $relations->hasMany('eventcommand_customvar', EventcommandCustomvar::class);
+ $relations->hasMany('eventcommand_envvar', EventcommandEnvvar::class);
+ $relations->hasMany('flapping_history', FlappingHistory::class);
+ $relations->hasMany('history', History::class);
+ $relations->hasMany('host', Host::class);
+ $relations->hasMany('host_customvar', HostCustomvar::class);
+ $relations->hasMany('host_state', HostState::class);
+ $relations->hasMany('hostgroup', Hostgroup::class);
+ $relations->hasMany('hostgroup_customvar', HostgroupCustomvar::class);
+ $relations->hasMany('hostgroup_member', HostgroupMember::class);
+ $relations->hasMany('instance', Instance::class);
+ $relations->hasMany('icon_image', IconImage::class);
+ $relations->hasMany('notes_url', NotesUrl::class);
+ $relations->hasMany('notification', Notification::class);
+ $relations->hasMany('notification_customvar', NotificationCustomvar::class);
+ $relations->hasMany('notification_history', NotificationHistory::class);
+ //$relations->hasMany('notification_recipient', NotificationRecipient::class);
+ $relations->hasMany('notification_user', NotificationUser::class);
+ $relations->hasMany('notification_usergroup', NotificationUsergroup::class);
+ $relations->hasMany('notificationcommand', Notificationcommand::class);
+ $relations->hasMany('notificationcommand_argument', NotificationcommandArgument::class);
+ $relations->hasMany('notificationcommand_customvar', NotificationcommandCustomvar::class);
+ $relations->hasMany('notificationcommand_envvar', NotificationcommandEnvvar::class);
+ $relations->hasMany('service', Service::class);
+ $relations->hasMany('service_customvar', ServiceCustomvar::class);
+ $relations->hasMany('service_state', ServiceState::class);
+ $relations->hasMany('servicegroup', Servicegroup::class);
+ $relations->hasMany('servicegroup_customvar', ServicegroupCustomvar::class);
+ $relations->hasMany('servicegroup_member', ServicegroupMember::class);
+ $relations->hasMany('state_history', StateHistory::class);
+ $relations->hasMany('timeperiod', Timeperiod::class);
+ $relations->hasMany('timeperiod_customvar', TimeperiodCustomvar::class);
+ $relations->hasMany('timeperiod_override_exclude', TimeperiodOverrideExclude::class);
+ $relations->hasMany('timeperiod_override_include', TimeperiodOverrideInclude::class);
+ $relations->hasMany('timeperiod_range', TimeperiodRange::class);
+ $relations->hasMany('user', User::class);
+ $relations->hasMany('user_customvar', UserCustomvar::class);
+ //$relations->hasMany('user_notification_history', UserNotificationHistory::class);
+ $relations->hasMany('usergroup', Usergroup::class);
+ $relations->hasMany('usergroup_customvar', UsergroupCustomvar::class);
+ $relations->hasMany('usergroup_member', UsergroupMember::class);
+ $relations->hasMany('zone', Zone::class);
+ }
+}
diff --git a/library/Icingadb/Model/Eventcommand.php b/library/Icingadb/Model/Eventcommand.php
new file mode 100644
index 0000000..ad18e22
--- /dev/null
+++ b/library/Icingadb/Model/Eventcommand.php
@@ -0,0 +1,86 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Eventcommand extends Model
+{
+ public function getTableName()
+ {
+ return 'eventcommand';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'zone_id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'command',
+ 'timeout'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'zone_id' => t('Zone Id'),
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Eventcommand Name Checksum'),
+ 'properties_checksum' => t('Eventcommand Properties Checksum'),
+ 'name' => t('Eventcommand Name'),
+ 'name_ci' => t('Eventcommand Name (CI)'),
+ 'command' => t('Eventcommand'),
+ 'timeout' => t('Eventcommand Timeout')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'zone_id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(EventcommandCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(EventcommandCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(EventcommandCustomvar::class);
+
+ $relations->hasMany('argument', EventcommandArgument::class);
+ $relations->hasMany('envvar', EventcommandEnvvar::class);
+ $relations->hasMany('host', Host::class);
+ $relations->hasMany('service', Service::class);
+ }
+}
diff --git a/library/Icingadb/Model/EventcommandArgument.php b/library/Icingadb/Model/EventcommandArgument.php
new file mode 100644
index 0000000..485e5d3
--- /dev/null
+++ b/library/Icingadb/Model/EventcommandArgument.php
@@ -0,0 +1,75 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class EventcommandArgument extends Model
+{
+ public function getTableName()
+ {
+ return 'eventcommand_argument';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'eventcommand_id',
+ 'argument_key',
+ 'environment_id',
+ 'properties_checksum',
+ 'argument_value',
+ 'argument_order',
+ 'description',
+ 'argument_key_override',
+ 'repeat_key',
+ 'required',
+ 'set_if',
+ 'skip_key'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'eventcommand_id' => t('Eventcommand Id'),
+ 'argument_key' => t('Eventcommand Argument Name'),
+ 'environment_id' => t('Environment Id'),
+ 'properties_checksum' => t('Eventcommand Argument Properties Checksum'),
+ 'argument_value' => t('Eventcommand Argument Value'),
+ 'argument_order' => t('Eventcommand Argument Position'),
+ 'description' => t('Eventcommand Argument Description'),
+ 'argument_key_override' => t('Eventcommand Argument Actual Name'),
+ 'repeat_key' => t('Eventcommand Argument Repeated'),
+ 'required' => t('Eventcommand Argument Required'),
+ 'set_if' => t('Eventcommand Argument Condition'),
+ 'skip_key' => t('Eventcommand Argument Without Name')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'eventcommand_id',
+ 'environment_id',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('eventcommand', Eventcommand::class);
+ }
+}
diff --git a/library/Icingadb/Model/EventcommandCustomvar.php b/library/Icingadb/Model/EventcommandCustomvar.php
new file mode 100644
index 0000000..3d1fa48
--- /dev/null
+++ b/library/Icingadb/Model/EventcommandCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class EventcommandCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'eventcommand_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'eventcommand_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'eventcommand_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('eventcommand', Eventcommand::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/EventcommandEnvvar.php b/library/Icingadb/Model/EventcommandEnvvar.php
new file mode 100644
index 0000000..3883bef
--- /dev/null
+++ b/library/Icingadb/Model/EventcommandEnvvar.php
@@ -0,0 +1,61 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class EventcommandEnvvar extends Model
+{
+ public function getTableName()
+ {
+ return 'eventcommand_envvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'eventcommand_id',
+ 'envvar_key',
+ 'environment_id',
+ 'properties_checksum',
+ 'envvar_value'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'eventcommand_id' => t('Eventcommand Id'),
+ 'envvar_key' => t('Eventcommand Envvar Name'),
+ 'environment_id' => t('Environment Id'),
+ 'properties_checksum' => t('Eventcommand Envvar Properties Checksum'),
+ 'envvar_value' => t('Eventcommand Envvar Value')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'eventcommand_id',
+ 'environment_id',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('eventcommand', Eventcommand::class);
+ }
+}
diff --git a/library/Icingadb/Model/FlappingHistory.php b/library/Icingadb/Model/FlappingHistory.php
new file mode 100644
index 0000000..69711eb
--- /dev/null
+++ b/library/Icingadb/Model/FlappingHistory.php
@@ -0,0 +1,91 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+/**
+ * Model for table `flapping_history`
+ *
+ * Please note that using this model will fetch history entries for decommissioned services. To avoid this,
+ * the query needs a `flapping_history.service_id IS NULL OR flapping_history_service.id IS NOT NULL` where.
+ */
+class FlappingHistory extends Model
+{
+ public function getTableName()
+ {
+ return 'flapping_history';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'start_time',
+ 'end_time',
+ 'percent_state_change_start',
+ 'percent_state_change_end',
+ 'flapping_threshold_low',
+ 'flapping_threshold_high'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'endpoint_id' => t('Endpoint Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'start_time' => t('Flapping Start Time'),
+ 'end_time' => t('Flapping End Time'),
+ 'percent_state_change_start' => t('Flapping Percent State Change Start'),
+ 'percent_state_change_end' => t('Flapping Percent State Change End'),
+ 'flapping_threshold_low' => t('Flapping Threshold Low'),
+ 'flapping_threshold_high' => t('Flapping Threshold High')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new MillisecondTimestamp([
+ 'start_time',
+ 'end_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'endpoint_id',
+ 'host_id',
+ 'service_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('endpoint', Endpoint::class);
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('history', History::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('flapping_history_id');
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/History.php b/library/Icingadb/Model/History.php
new file mode 100644
index 0000000..a34b3bd
--- /dev/null
+++ b/library/Icingadb/Model/History.php
@@ -0,0 +1,127 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+/**
+ * Model for table `history`
+ *
+ * Please note that using this model will fetch history entries for decommissioned services. To avoid
+ * this, the query needs a `history.service_id IS NULL OR history_service.id IS NOT NULL` where.
+ */
+class History extends Model
+{
+ public function getTableName()
+ {
+ return 'history';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'comment_history_id',
+ 'downtime_history_id',
+ 'flapping_history_id',
+ 'notification_history_id',
+ 'acknowledgement_history_id',
+ 'state_history_id',
+ 'event_type',
+ 'event_time'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'endpoint_id' => t('Endpoint Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'event_type' => t('Event Type'),
+ 'event_time' => t('Event Time')
+ ];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'history.event_time desc, history.event_type desc';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new MillisecondTimestamp([
+ 'event_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'endpoint_id',
+ 'host_id',
+ 'service_id',
+ 'comment_history_id',
+ 'downtime_history_id',
+ 'flapping_history_id',
+ 'notification_history_id',
+ 'acknowledgement_history_id',
+ 'state_history_id'
+ ]));
+
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('endpoint', Endpoint::class);
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+
+ $relations->hasOne('comment', CommentHistory::class)
+ ->setCandidateKey('comment_history_id')
+ ->setForeignKey('comment_id')
+ ->setJoinType('LEFT');
+ $relations->hasOne('downtime', DowntimeHistory::class)
+ ->setCandidateKey('downtime_history_id')
+ ->setForeignKey('downtime_id')
+ ->setJoinType('LEFT');
+ $relations->hasOne('flapping', FlappingHistory::class)
+ ->setCandidateKey('flapping_history_id')
+ ->setForeignKey('id')
+ ->setJoinType('LEFT');
+ $relations->hasOne('notification', NotificationHistory::class)
+ ->setCandidateKey('notification_history_id')
+ ->setForeignKey('id')
+ ->setJoinType('LEFT');
+ $relations->hasOne('acknowledgement', AcknowledgementHistory::class)
+ ->setCandidateKey('acknowledgement_history_id')
+ ->setForeignKey('id')
+ ->setJoinType('LEFT');
+ $relations->hasOne('state', StateHistory::class)
+ ->setCandidateKey('state_history_id')
+ ->setForeignKey('id')
+ ->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/Host.php b/library/Icingadb/Model/Host.php
new file mode 100644
index 0000000..e1296c8
--- /dev/null
+++ b/library/Icingadb/Model/Host.php
@@ -0,0 +1,234 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Common\Auth;
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Defaults;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+use ipl\Orm\ResultSet;
+
+/**
+ * Host model.
+ */
+class Host extends Model
+{
+ use Auth;
+
+ public function getTableName()
+ {
+ return 'host';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'display_name',
+ 'address',
+ 'address6',
+ 'address_bin',
+ 'address6_bin',
+ 'checkcommand_name',
+ 'checkcommand_id',
+ 'max_check_attempts',
+ 'check_timeperiod_name',
+ 'check_timeperiod_id',
+ 'check_timeout',
+ 'check_interval',
+ 'check_retry_interval',
+ 'active_checks_enabled',
+ 'passive_checks_enabled',
+ 'event_handler_enabled',
+ 'notifications_enabled',
+ 'flapping_enabled',
+ 'flapping_threshold_low',
+ 'flapping_threshold_high',
+ 'perfdata_enabled',
+ 'eventcommand_name',
+ 'eventcommand_id',
+ 'is_volatile',
+ 'action_url_id',
+ 'notes_url_id',
+ 'notes',
+ 'icon_image_id',
+ 'icon_image_alt',
+ 'zone_name',
+ 'zone_id',
+ 'command_endpoint_name',
+ 'command_endpoint_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Host Name Checksum'),
+ 'properties_checksum' => t('Host Properties Checksum'),
+ 'name' => t('Host Name'),
+ 'name_ci' => t('Host Name (CI)'),
+ 'display_name' => t('Host Display Name'),
+ 'address' => t('Host Address (IPv4)'),
+ 'address6' => t('Host Address (IPv6)'),
+ 'address_bin' => t('Host Address (IPv4, Binary)'),
+ 'address6_bin' => t('Host Address (IPv6, Binary)'),
+ 'checkcommand_name' => t('Checkcommand Name'),
+ 'checkcommand_id' => t('Checkcommand Id'),
+ 'max_check_attempts' => t('Host Max Check Attempts'),
+ 'check_timeperiod_name' => t('Check Timeperiod Name'),
+ 'check_timeperiod_id' => t('Check Timeperiod Id'),
+ 'check_timeout' => t('Host Check Timeout'),
+ 'check_interval' => t('Host Check Interval'),
+ 'check_retry_interval' => t('Host Check Retry Inverval'),
+ 'active_checks_enabled' => t('Host Active Checks Enabled'),
+ 'passive_checks_enabled' => t('Host Passive Checks Enabled'),
+ 'event_handler_enabled' => t('Host Event Handler Enabled'),
+ 'notifications_enabled' => t('Host Notifications Enabled'),
+ 'flapping_enabled' => t('Host Flapping Enabled'),
+ 'flapping_threshold_low' => t('Host Flapping Threshold Low'),
+ 'flapping_threshold_high' => t('Host Flapping Threshold High'),
+ 'perfdata_enabled' => t('Host Performance Data Enabled'),
+ 'eventcommand_name' => t('Eventcommand Name'),
+ 'eventcommand_id' => t('Eventcommand Id'),
+ 'is_volatile' => t('Host Is Volatile'),
+ 'action_url_id' => t('Action Url Id'),
+ 'notes_url_id' => t('Notes Url Id'),
+ 'notes' => t('Host Notes'),
+ 'icon_image_id' => t('Icon Image Id'),
+ 'icon_image_alt' => t('Icon Image Alt'),
+ 'zone_name' => t('Zone Name'),
+ 'zone_id' => t('Zone Id'),
+ 'command_endpoint_name' => t('Endpoint Name'),
+ 'command_endpoint_id' => t('Endpoint Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['name_ci', 'display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'host.display_name';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'active_checks_enabled',
+ 'passive_checks_enabled',
+ 'event_handler_enabled',
+ 'notifications_enabled',
+ 'flapping_enabled',
+ 'is_volatile'
+ ]));
+
+ $behaviors->add(new ReRoute([
+ 'servicegroup' => 'service.servicegroup',
+ 'user' => 'notification.user',
+ 'usergroup' => 'notification.usergroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'address_bin',
+ 'address6_bin',
+ 'checkcommand_id',
+ 'check_timeperiod_id',
+ 'eventcommand_id',
+ 'action_url_id',
+ 'notes_url_id',
+ 'icon_image_id',
+ 'zone_id',
+ 'command_endpoint_id'
+ ]));
+ }
+
+ public function createDefaults(Defaults $defaults)
+ {
+ $defaults->add('vars', function (self $subject) {
+ if (! $subject->customvar_flat instanceof ResultSet) {
+ $this->applyRestrictions($subject->customvar_flat);
+ }
+
+ $vars = [];
+ foreach ($subject->customvar_flat as $customVar) {
+ $vars[$customVar->flatname] = $customVar->flatvalue;
+ }
+
+ return $vars;
+ });
+
+ $defaults->add('customvars', function (self $subject) {
+ if (! $subject->customvar instanceof ResultSet) {
+ $this->applyRestrictions($subject->customvar);
+ }
+
+ $vars = [];
+ foreach ($subject->customvar as $customVar) {
+ $vars[$customVar->name] = json_decode($customVar->value, true);
+ }
+
+ return $vars;
+ });
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('eventcommand', Eventcommand::class);
+ $relations->belongsTo('checkcommand', Checkcommand::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class)
+ ->setCandidateKey('check_timeperiod_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('action_url', ActionUrl::class)
+ ->setCandidateKey('action_url_id')
+ ->setForeignKey('id');
+ $relations->belongsTo('notes_url', NotesUrl::class)
+ ->setCandidateKey('notes_url_id')
+ ->setForeignKey('id');
+ $relations->belongsTo('icon_image', IconImage::class)
+ ->setCandidateKey('icon_image_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('zone', Zone::class);
+ $relations->belongsTo('endpoint', Endpoint::class)
+ ->setCandidateKey('command_endpoint_id');
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(HostCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(HostCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(HostCustomvar::class);
+ $relations->belongsToMany('hostgroup', Hostgroup::class)
+ ->through(HostgroupMember::class);
+
+ $relations->hasOne('state', HostState::class)->setJoinType('LEFT');
+ $relations->hasMany('comment', Comment::class)->setJoinType('LEFT');
+ $relations->hasMany('downtime', Downtime::class)->setJoinType('LEFT');
+ $relations->hasMany('history', History::class);
+ $relations->hasMany('notification', Notification::class)->setJoinType('LEFT');
+ $relations->hasMany('notification_history', NotificationHistory::class);
+ $relations->hasMany('service', Service::class)->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/HostCustomvar.php b/library/Icingadb/Model/HostCustomvar.php
new file mode 100644
index 0000000..9f7df26
--- /dev/null
+++ b/library/Icingadb/Model/HostCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class HostCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'host_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'host_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'host_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setForeignKey('customvar_id')
+ ->setCandidateKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/HostState.php b/library/Icingadb/Model/HostState.php
new file mode 100644
index 0000000..efa2752
--- /dev/null
+++ b/library/Icingadb/Model/HostState.php
@@ -0,0 +1,81 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Common\HostStates;
+use ipl\Orm\Relations;
+
+/**
+ * Host state model.
+ */
+class HostState extends State
+{
+ public function getTableName()
+ {
+ return 'host_state';
+ }
+
+ public function getKeyName()
+ {
+ return 'host_id';
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'state_type' => t('Host State Type'),
+ 'soft_state' => t('Host Soft State'),
+ 'hard_state' => t('Host Hard State'),
+ 'previous_soft_state' => t('Host Previous Soft State'),
+ 'previous_hard_state' => t('Host Previous Hard State'),
+ 'check_attempt' => t('Host Check Attempt No.'),
+ 'severity' => t('Host State Severity'),
+ 'output' => t('Host Output'),
+ 'long_output' => t('Host Long Output'),
+ 'performance_data' => t('Host Performance Data'),
+ 'normalized_performance_data' => t('Host Normalized Performance Data'),
+ 'check_commandline' => t('Host Check Commandline'),
+ 'is_problem' => t('Host Has Problem'),
+ 'is_handled' => t('Host Is Handled'),
+ 'is_reachable' => t('Host Is Reachable'),
+ 'is_flapping' => t('Host Is Flapping'),
+ 'is_overdue' => t('Host Check Is Overdue'),
+ 'is_acknowledged' => t('Host Is Acknowledged'),
+ 'acknowledgement_comment_id' => t('Acknowledgement Comment Id'),
+ 'in_downtime' => t('Host In Downtime'),
+ 'execution_time' => t('Host Check Execution Time'),
+ 'latency' => t('Host Check Latency'),
+ 'check_timeout' => t('Host Check Timeout'),
+ 'check_source' => t('Host Check Source'),
+ 'last_update' => t('Host Last Update'),
+ 'last_state_change' => t('Host Last State Change'),
+ 'next_check' => t('Host Next Check'),
+ 'next_update' => t('Host Next Update')
+ ];
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('host', Host::class);
+ $relations->hasOne('last_comment', LastHostComment::class)
+ ->setCandidateKey('last_comment_id')
+ ->setForeignKey('id')
+ ->setJoinType('LEFT');
+ }
+
+
+ public function getStateText(): string
+ {
+ return HostStates::text($this->soft_state);
+ }
+
+
+ public function getStateTextTranslated(): string
+ {
+ return HostStates::text($this->soft_state);
+ }
+}
diff --git a/library/Icingadb/Model/Hostgroup.php b/library/Icingadb/Model/Hostgroup.php
new file mode 100644
index 0000000..97930fa
--- /dev/null
+++ b/library/Icingadb/Model/Hostgroup.php
@@ -0,0 +1,92 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Hostgroup extends Model
+{
+ public function getTableName()
+ {
+ return 'hostgroup';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'display_name',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Hostgroup Name Checksum'),
+ 'properties_checksum' => t('Hostgroup Properties Checksum'),
+ 'name' => t('Hostgroup Name'),
+ 'name_ci' => t('Hostgroup Name (CI)'),
+ 'display_name' => t('Hostgroup Display Name'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['name_ci', 'display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'display_name';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'zone_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(HostgroupCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(HostgroupCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(HostgroupCustomvar::class);
+ $relations->belongsToMany('host', Host::class)
+ ->through(HostgroupMember::class);
+ $relations->belongsToMany('service', Service::class)
+ ->through(HostgroupMember::class);
+ }
+}
diff --git a/library/Icingadb/Model/HostgroupCustomvar.php b/library/Icingadb/Model/HostgroupCustomvar.php
new file mode 100644
index 0000000..41272d1
--- /dev/null
+++ b/library/Icingadb/Model/HostgroupCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class HostgroupCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'hostgroup_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'hostgroup_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'hostgroup_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('hostgroup', Hostgroup::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/HostgroupMember.php b/library/Icingadb/Model/HostgroupMember.php
new file mode 100644
index 0000000..3660e71
--- /dev/null
+++ b/library/Icingadb/Model/HostgroupMember.php
@@ -0,0 +1,53 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class HostgroupMember extends Model
+{
+ public function getTableName()
+ {
+ return 'hostgroup_member';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'host_id',
+ 'hostgroup_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'host_id',
+ 'hostgroup_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('hostgroup', Hostgroup::class);
+ $relations->belongsTo('host', Host::class);
+
+ $relations->hasMany('service', Service::class)
+ ->setForeignKey('host_id')
+ ->setCandidateKey('host_id');
+ }
+}
diff --git a/library/Icingadb/Model/Hostgroupsummary.php b/library/Icingadb/Model/Hostgroupsummary.php
new file mode 100644
index 0000000..a9295bb
--- /dev/null
+++ b/library/Icingadb/Model/Hostgroupsummary.php
@@ -0,0 +1,213 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Relations;
+use ipl\Orm\UnionModel;
+use ipl\Sql\Adapter\Pgsql;
+use ipl\Sql\Connection;
+use ipl\Sql\Expression;
+use ipl\Sql\Select;
+
+class Hostgroupsummary extends UnionModel
+{
+ public static function on(Connection $db)
+ {
+ $q = parent::on($db);
+
+ $q->on($q::ON_SELECT_ASSEMBLED, function (Select $select) use ($q) {
+ $model = $q->getModel();
+
+ $groupBy = $q->getResolver()->qualifyColumnsAndAliases((array) $model->getKeyName(), $model, false);
+
+ // For PostgreSQL, ALL non-aggregate SELECT columns must appear in the GROUP BY clause:
+ if ($q->getDb()->getAdapter() instanceof Pgsql) {
+ /**
+ * Ignore Expressions, i.e. aggregate functions {@see getColumns()},
+ * which do not need to be added to the GROUP BY.
+ */
+ $candidates = array_filter($select->getColumns(), 'is_string');
+ // Remove already considered columns for the GROUP BY, i.e. the primary key.
+ $candidates = array_diff_assoc($candidates, $groupBy);
+ $groupBy = array_merge($groupBy, $candidates);
+ }
+
+ $select->groupBy($groupBy);
+ });
+
+ return $q;
+ }
+
+ public function getTableName()
+ {
+ return 'hostgroup';
+ }
+
+ public function getKeyName()
+ {
+ return ['id' => 'hostgroup_id'];
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'display_name' => 'hostgroup_display_name',
+ 'hosts_down_handled' => new Expression(
+ 'SUM(CASE WHEN host_state = 1'
+ . ' AND (host_handled = \'y\' OR host_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_down_unhandled' => new Expression(
+ 'SUM(CASE WHEN host_state = 1'
+ . ' AND host_handled = \'n\' AND host_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_pending' => new Expression(
+ 'SUM(CASE WHEN host_state = 99 THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_total' => new Expression(
+ 'SUM(CASE WHEN host_id IS NOT NULL THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_up' => new Expression(
+ 'SUM(CASE WHEN host_state = 0 THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_severity' => new Expression('MAX(host_severity)'),
+ 'name' => 'hostgroup_name',
+ 'services_critical_handled' => new Expression(
+ 'SUM(CASE WHEN service_state = 2'
+ . ' AND (service_handled = \'y\' OR service_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_critical_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state = 2'
+ . ' AND service_handled = \'n\' AND service_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_ok' => new Expression(
+ 'SUM(CASE WHEN service_state = 0 THEN 1 ELSE 0 END)'
+ ),
+ 'services_pending' => new Expression(
+ 'SUM(CASE WHEN service_state = 99 THEN 1 ELSE 0 END)'
+ ),
+ 'services_total' => new Expression(
+ 'SUM(CASE WHEN service_id IS NOT NULL THEN 1 ELSE 0 END)'
+ ),
+ 'services_unknown_handled' => new Expression(
+ 'SUM(CASE WHEN service_state = 3'
+ . ' AND (service_handled = \'y\' OR service_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_unknown_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state = 3'
+ . ' AND service_handled = \'n\' AND service_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_warning_handled' => new Expression(
+ 'SUM(CASE WHEN service_state = 1'
+ . ' AND (service_handled = \'y\' OR service_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_warning_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state = 1'
+ . ' AND service_handled = \'n\' AND service_reachable = \'y\' THEN 1 ELSE 0 END)'
+ )
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'display_name';
+ }
+
+ public function getUnions()
+ {
+ $unions = [
+ [
+ Host::class,
+ [
+ 'hostgroup',
+ 'state'
+ ],
+ [
+ 'hostgroup_id' => 'hostgroup.id',
+ 'hostgroup_name' => 'hostgroup.name',
+ 'hostgroup_display_name' => 'hostgroup.display_name',
+ 'host_id' => 'host.id',
+ 'host_state' => 'state.soft_state',
+ 'host_handled' => 'state.is_handled',
+ 'host_reachable' => 'state.is_reachable',
+ 'host_severity' => 'state.severity',
+ 'service_id' => new Expression('NULL'),
+ 'service_state' => new Expression('NULL'),
+ 'service_handled' => new Expression('NULL'),
+ 'service_reachable' => new Expression('NULL')
+ ]
+ ],
+ [
+ Service::class,
+ [
+ 'hostgroup',
+ 'state'
+ ],
+ [
+ 'hostgroup_id' => 'hostgroup.id',
+ 'hostgroup_name' => 'hostgroup.name',
+ 'hostgroup_display_name' => 'hostgroup.display_name',
+ 'host_id' => new Expression('NULL'),
+ 'host_state' => new Expression('NULL'),
+ 'host_handled' => new Expression('NULL'),
+ 'host_reachable' => new Expression('NULL'),
+ 'host_severity' => new Expression('0'),
+ 'service_id' => 'service.id',
+ 'service_state' => 'state.soft_state',
+ 'service_handled' => 'state.is_handled',
+ 'service_reachable' => 'state.is_reachable'
+ ]
+ ],
+ [
+ Hostgroup::class,
+ [],
+ [
+ 'hostgroup_id' => 'hostgroup.id',
+ 'hostgroup_name' => 'hostgroup.name',
+ 'hostgroup_display_name' => 'hostgroup.display_name',
+ 'host_id' => new Expression('NULL'),
+ 'host_state' => new Expression('NULL'),
+ 'host_handled' => new Expression('NULL'),
+ 'host_reachable' => new Expression('NULL'),
+ 'host_severity' => new Expression('0'),
+ 'service_id' => new Expression('NULL'),
+ 'service_state' => new Expression('NULL'),
+ 'service_handled' => new Expression('NULL'),
+ 'service_reachable' => new Expression('NULL')
+ ]
+ ]
+ ];
+
+ return $unions;
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id'
+ ]));
+
+ // This is because there is no better way
+ (new Hostgroup())->createBehaviors($behaviors);
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ // This is because there is no better way
+ (new Hostgroup())->createRelations($relations);
+ }
+
+ public function getColumnDefinitions()
+ {
+ // This is because there is no better way
+ return (new Hostgroup())->getColumnDefinitions();
+ }
+}
diff --git a/library/Icingadb/Model/HoststateSummary.php b/library/Icingadb/Model/HoststateSummary.php
new file mode 100644
index 0000000..93268f3
--- /dev/null
+++ b/library/Icingadb/Model/HoststateSummary.php
@@ -0,0 +1,78 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Sql\Connection;
+use ipl\Sql\Expression;
+
+class HoststateSummary extends Host
+{
+ public function getSummaryColumns()
+ {
+ return [
+ 'hosts_acknowledged' => new Expression(
+ 'SUM(CASE WHEN host_state.is_acknowledged = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_active_checks_enabled' => new Expression(
+ 'SUM(CASE WHEN host.active_checks_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_passive_checks_enabled' => new Expression(
+ 'SUM(CASE WHEN host.passive_checks_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_down_handled' => new Expression(
+ 'SUM(CASE WHEN host_state.soft_state = 1'
+ . ' AND (host_state.is_handled = \'y\' OR host_state.is_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_down_unhandled' => new Expression(
+ 'SUM(CASE WHEN host_state.soft_state = 1'
+ . ' AND host_state.is_handled = \'n\' AND host_state.is_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_event_handler_enabled' => new Expression(
+ 'SUM(CASE WHEN host.event_handler_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_flapping_enabled' => new Expression(
+ 'SUM(CASE WHEN host.flapping_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_notifications_enabled' => new Expression(
+ 'SUM(CASE WHEN host.notifications_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_pending' => new Expression(
+ 'SUM(CASE WHEN host_state.soft_state = 99 THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_problems_unacknowledged' => new Expression(
+ 'SUM(CASE WHEN host_state.is_problem = \'y\''
+ . ' AND host_state.is_acknowledged = \'n\' THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_total' => new Expression(
+ 'SUM(CASE WHEN host.id IS NOT NULL THEN 1 ELSE 0 END)'
+ ),
+ 'hosts_up' => new Expression(
+ 'SUM(CASE WHEN host_state.soft_state = 0 THEN 1 ELSE 0 END)'
+ )
+ ];
+ }
+
+ public static function on(Connection $db)
+ {
+ $q = parent::on($db);
+ $q->utilize('state');
+
+ /** @var static $m */
+ $m = $q->getModel();
+ $q->columns($m->getSummaryColumns());
+
+ return $q;
+ }
+
+ public function getColumns()
+ {
+ return array_merge(parent::getColumns(), $this->getSummaryColumns());
+ }
+
+ public function getDefaultSort()
+ {
+ return null;
+ }
+}
diff --git a/library/Icingadb/Model/IconImage.php b/library/Icingadb/Model/IconImage.php
new file mode 100644
index 0000000..212234a
--- /dev/null
+++ b/library/Icingadb/Model/IconImage.php
@@ -0,0 +1,55 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class IconImage extends Model
+{
+ public function getTableName()
+ {
+ return 'icon_image';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'icon_image',
+ 'environment_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'icon_image' => t('Icon Image'),
+ 'environment_id' => t('Environment Id')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+
+ $relations->hasMany('host', Host::class);
+ $relations->hasMany('service', Service::class);
+ }
+}
diff --git a/library/Icingadb/Model/Instance.php b/library/Icingadb/Model/Instance.php
new file mode 100644
index 0000000..73db565
--- /dev/null
+++ b/library/Icingadb/Model/Instance.php
@@ -0,0 +1,78 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Instance extends Model
+{
+ public function getTableName()
+ {
+ return 'icingadb_instance';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'heartbeat',
+ 'responsible',
+ 'icinga2_active_host_checks_enabled',
+ 'icinga2_active_service_checks_enabled',
+ 'icinga2_event_handlers_enabled',
+ 'icinga2_flap_detection_enabled',
+ 'icinga2_notifications_enabled',
+ 'icinga2_performance_data_enabled',
+ 'icinga2_start_time',
+ 'icinga2_version'
+ ];
+ }
+
+ public function getDefaultSort()
+ {
+ return ['responsible desc', 'heartbeat desc'];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new MillisecondTimestamp([
+ 'heartbeat',
+ 'icinga2_start_time'
+ ]));
+
+ $behaviors->add(new BoolCast([
+ 'responsible',
+ 'icinga2_active_host_checks_enabled',
+ 'icinga2_active_service_checks_enabled',
+ 'icinga2_event_handlers_enabled',
+ 'icinga2_flap_detection_enabled',
+ 'icinga2_notifications_enabled',
+ 'icinga2_performance_data_enabled'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'endpoint_id',
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('endpoint', Endpoint::class)->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/LastHostComment.php b/library/Icingadb/Model/LastHostComment.php
new file mode 100644
index 0000000..621b204
--- /dev/null
+++ b/library/Icingadb/Model/LastHostComment.php
@@ -0,0 +1,19 @@
+<?php
+
+/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Relations;
+
+class LastHostComment extends Comment
+{
+ public function createRelations(Relations $relations): void
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+ $relations->belongsTo('state', HostState::class)
+ ->setForeignKey('last_comment_id')
+ ->setCandidateKey('id');
+ }
+}
diff --git a/library/Icingadb/Model/LastServiceComment.php b/library/Icingadb/Model/LastServiceComment.php
new file mode 100644
index 0000000..4d44f11
--- /dev/null
+++ b/library/Icingadb/Model/LastServiceComment.php
@@ -0,0 +1,19 @@
+<?php
+
+/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Relations;
+
+class LastServiceComment extends Comment
+{
+ public function createRelations(Relations $relations): void
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+ $relations->belongsTo('state', ServiceState::class)
+ ->setForeignKey('last_comment_id')
+ ->setCandidateKey('id');
+ }
+}
diff --git a/library/Icingadb/Model/NotesUrl.php b/library/Icingadb/Model/NotesUrl.php
new file mode 100644
index 0000000..5865c52
--- /dev/null
+++ b/library/Icingadb/Model/NotesUrl.php
@@ -0,0 +1,62 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ActionAndNoteUrl;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class NotesUrl extends Model
+{
+ public function getTableName()
+ {
+ return 'notes_url';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'notes_url',
+ 'environment_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'notes_url' => t('Notes Url'),
+ 'environment_id' => t('Environment Id')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ActionAndNoteUrl(['notes_url']));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+
+ $relations->hasMany('host', Host::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('notes_url_id');
+ $relations->hasMany('service', Service::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('notes_url_id');
+ }
+}
diff --git a/library/Icingadb/Model/Notification.php b/library/Icingadb/Model/Notification.php
new file mode 100644
index 0000000..8d42301
--- /dev/null
+++ b/library/Icingadb/Model/Notification.php
@@ -0,0 +1,130 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\Bitmask;
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Notification extends Model
+{
+ public function getTableName()
+ {
+ return 'notification';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'host_id',
+ 'service_id',
+ 'notificationcommand_id',
+ 'times_begin',
+ 'times_end',
+ 'notification_interval',
+ 'timeperiod_id',
+ 'states',
+ 'types',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Notification Name Checksum'),
+ 'properties_checksum' => t('Notification Properties Checksum'),
+ 'name' => t('Notification Name'),
+ 'name_ci' => t('Notification Name (CI)'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'notificationcommand_id' => t('Notificationcommand Id'),
+ 'times_begin' => t('Notification Escalate After'),
+ 'times_end' => t('Notification Escalate Until'),
+ 'notification_interval' => t('Notification Interval'),
+ 'timeperiod_id' => t('Timeperiod Id'),
+ 'states' => t('Notification State Filter'),
+ 'types' => t('Notification Type Filter'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+
+ $behaviors->add(new Bitmask([
+ 'states' => [
+ 'ok' => 1,
+ 'warning' => 2,
+ 'critical' => 4,
+ 'unknown' => 8,
+ 'up' => 16,
+ 'down' => 32
+ ],
+ 'types' => [
+ 'downtime_start' => 1,
+ 'downtime_end' => 2,
+ 'downtime_removed' => 4,
+ 'custom' => 8,
+ 'ack' => 16,
+ 'problem' => 32,
+ 'recovery' => 64,
+ 'flapping_start' => 128,
+ 'flapping_end' => 256
+ ]
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'host_id',
+ 'service_id',
+ 'notificationcommand_id',
+ 'timeperiod_id',
+ 'zone_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('service', Service::class);
+ $relations->belongsTo('notificationcommand', Notificationcommand::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(NotificationCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(NotificationCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(NotificationCustomvar::class);
+ $relations->belongsToMany('user', User::class)
+ ->through('notification_recipient');
+ $relations->belongsToMany('usergroup', Usergroup::class)
+ ->through('notification_recipient');
+ }
+}
diff --git a/library/Icingadb/Model/NotificationCustomvar.php b/library/Icingadb/Model/NotificationCustomvar.php
new file mode 100644
index 0000000..620ae5c
--- /dev/null
+++ b/library/Icingadb/Model/NotificationCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class NotificationCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'notification_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'notification_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'notification_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('notification', Notification::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/NotificationHistory.php b/library/Icingadb/Model/NotificationHistory.php
new file mode 100644
index 0000000..c635dbb
--- /dev/null
+++ b/library/Icingadb/Model/NotificationHistory.php
@@ -0,0 +1,115 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+/**
+ * Model for table `notification_history`
+ *
+ * Please note that using this model will fetch history entries for decommissioned services. To avoid this, the
+ * query needs a `notification_history.service_id IS NULL OR notification_history_service.id IS NOT NULL` where.
+ */
+class NotificationHistory extends Model
+{
+ public function getTableName()
+ {
+ return 'notification_history';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'notification_id',
+ 'type',
+ 'send_time',
+ 'state',
+ 'previous_hard_state',
+ 'author',
+ 'text',
+ 'users_notified'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'id' => t('History Id'),
+ 'environment_id' => t('Environment Id'),
+ 'endpoint_id' => t('Endpoint Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'notification_id' => t('Notification Id'),
+ 'type' => t('Notification Type'),
+ 'send_time' => t('Notification Sent On'),
+ 'state' => t('Hard State'),
+ 'previous_hard_state' => t('Previous Hard State'),
+ 'author' => t('Notification Author'),
+ 'text' => t('Notification Text'),
+ 'users_notified' => t('Users Notified')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['text'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'notification_history.send_time desc';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new MillisecondTimestamp([
+ 'send_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'endpoint_id',
+ 'host_id',
+ 'service_id',
+ 'notification_id'
+ ]));
+
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('history', History::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('notification_history_id');
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ $relations->belongsTo('notification', Notification::class)->setJoinType('LEFT');
+
+ $relations->belongsToMany('user', User::class)
+ ->through('user_notification_history');
+ }
+}
diff --git a/library/Icingadb/Model/NotificationUser.php b/library/Icingadb/Model/NotificationUser.php
new file mode 100644
index 0000000..ab23ad4
--- /dev/null
+++ b/library/Icingadb/Model/NotificationUser.php
@@ -0,0 +1,49 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class NotificationUser extends Model
+{
+ public function getTableName()
+ {
+ return 'notification_user';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'notification_id',
+ 'user_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'notification_id',
+ 'user_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('notification', Notification::class);
+ $relations->belongsTo('user', User::class);
+ }
+}
diff --git a/library/Icingadb/Model/NotificationUsergroup.php b/library/Icingadb/Model/NotificationUsergroup.php
new file mode 100644
index 0000000..bd60fae
--- /dev/null
+++ b/library/Icingadb/Model/NotificationUsergroup.php
@@ -0,0 +1,49 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class NotificationUsergroup extends Model
+{
+ public function getTableName()
+ {
+ return 'notification_usergroup';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'notification_id',
+ 'usergroup_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'notification_id',
+ 'usergroup_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('notification', Notification::class);
+ $relations->belongsTo('usergroup', Usergroup::class);
+ }
+}
diff --git a/library/Icingadb/Model/Notificationcommand.php b/library/Icingadb/Model/Notificationcommand.php
new file mode 100644
index 0000000..6ee2a21
--- /dev/null
+++ b/library/Icingadb/Model/Notificationcommand.php
@@ -0,0 +1,87 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Notificationcommand extends Model
+{
+ public function getTableName()
+ {
+ return 'notificationcommand';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'zone_id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'command',
+ 'timeout'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'zone_id' => t('Zone Id'),
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Notificationcommand Name Checksum'),
+ 'properties_checksum' => t('Notificationcommand Properties Checksum'),
+ 'name' => t('Notificationcommand Name'),
+ 'name_ci' => t('Notificationcommand Name (CI)'),
+ 'command' => t('Notificationcommand'),
+ 'timeout' => t('Notificationcommand Timeout')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'host' => 'notification.host',
+ 'hostgroup' => 'notification.host.hostgroup',
+ 'service' => 'notification.service',
+ 'servicegroup' => 'notification.service.servicegroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'zone_id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(NotificationcommandCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(NotificationcommandCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(NotificationcommandCustomvar::class);
+
+ $relations->hasMany('notification', Notification::class);
+ $relations->hasMany('argument', NotificationcommandArgument::class);
+ $relations->hasMany('envvar', NotificationcommandEnvvar::class);
+ }
+}
diff --git a/library/Icingadb/Model/NotificationcommandArgument.php b/library/Icingadb/Model/NotificationcommandArgument.php
new file mode 100644
index 0000000..e855022
--- /dev/null
+++ b/library/Icingadb/Model/NotificationcommandArgument.php
@@ -0,0 +1,75 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class NotificationcommandArgument extends Model
+{
+ public function getTableName()
+ {
+ return 'notificationcommand_argument';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'notificationcommand_id',
+ 'argument_key',
+ 'environment_id',
+ 'properties_checksum',
+ 'argument_value',
+ 'argument_order',
+ 'description',
+ 'argument_key_override',
+ 'repeat_key',
+ 'required',
+ 'set_if',
+ 'skip_key'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'notificationcommand_id' => t('Notificationcommand Id'),
+ 'argument_key' => t('Notificationcommand Argument Name'),
+ 'environment_id' => t('Environment Id'),
+ 'properties_checksum' => t('Notificationcommand Argument Properties Checksum'),
+ 'argument_value' => t('Notificationcommand Argument Value'),
+ 'argument_order' => t('Notificationcommand Argument Position'),
+ 'description' => t('Notificationcommand Argument Description'),
+ 'argument_key_override' => t('Notificationcommand Argument Actual Name'),
+ 'repeat_key' => t('Notificationcommand Argument Repeated'),
+ 'required' => t('Notificationcommand Argument Required'),
+ 'set_if' => t('Notificationcommand Argument Condition'),
+ 'skip_key' => t('Notificationcommand Argument Without Name')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'notificationcommand_id',
+ 'environment_id',
+ 'properties_checksum'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('notificationcommand', Notificationcommand::class);
+ }
+}
diff --git a/library/Icingadb/Model/NotificationcommandCustomvar.php b/library/Icingadb/Model/NotificationcommandCustomvar.php
new file mode 100644
index 0000000..bd103f7
--- /dev/null
+++ b/library/Icingadb/Model/NotificationcommandCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class NotificationcommandCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'notificationcommand_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'notificationcommand_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'notificationcommand_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('notificationcommand', Notificationcommand::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/NotificationcommandEnvvar.php b/library/Icingadb/Model/NotificationcommandEnvvar.php
new file mode 100644
index 0000000..09f77b0
--- /dev/null
+++ b/library/Icingadb/Model/NotificationcommandEnvvar.php
@@ -0,0 +1,61 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class NotificationcommandEnvvar extends Model
+{
+ public function getTableName()
+ {
+ return 'notificationcommand_envvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'notificationcommand_id',
+ 'envvar_key',
+ 'environment_id',
+ 'properties_checksum',
+ 'envvar_value'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'notificationcommand_id' => t('Notificationcommand Id'),
+ 'envvar_key' => t('Notificationcommand Envvar Key'),
+ 'environment_id' => t('Environment Id'),
+ 'properties_checksum' => t('Notificationcommand Envvar Properties Checksum'),
+ 'envvar_value' => t('Notificationcommand Envvar Value')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'notificationcommand_id',
+ 'environment_id',
+ 'properties_checksum',
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('notificationcommand', Notificationcommand::class);
+ }
+}
diff --git a/library/Icingadb/Model/Service.php b/library/Icingadb/Model/Service.php
new file mode 100644
index 0000000..c57b6ba
--- /dev/null
+++ b/library/Icingadb/Model/Service.php
@@ -0,0 +1,225 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Common\Auth;
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Defaults;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+use ipl\Orm\ResultSet;
+
+class Service extends Model
+{
+ use Auth;
+
+ public function getTableName()
+ {
+ return 'service';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'host_id',
+ 'name',
+ 'name_ci',
+ 'display_name',
+ 'checkcommand_name',
+ 'checkcommand_id',
+ 'max_check_attempts',
+ 'check_timeperiod_name',
+ 'check_timeperiod_id',
+ 'check_timeout',
+ 'check_interval',
+ 'check_retry_interval',
+ 'active_checks_enabled',
+ 'passive_checks_enabled',
+ 'event_handler_enabled',
+ 'notifications_enabled',
+ 'flapping_enabled',
+ 'flapping_threshold_low',
+ 'flapping_threshold_high',
+ 'perfdata_enabled',
+ 'eventcommand_name',
+ 'eventcommand_id',
+ 'is_volatile',
+ 'action_url_id',
+ 'notes_url_id',
+ 'notes',
+ 'icon_image_id',
+ 'icon_image_alt',
+ 'zone_name',
+ 'zone_id',
+ 'command_endpoint_name',
+ 'command_endpoint_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Service Name Checksum'),
+ 'properties_checksum' => t('Service Properties Checksum'),
+ 'host_id' => t('Host Id'),
+ 'name' => t('Service Name'),
+ 'name_ci' => t('Service Name (CI)'),
+ 'display_name' => t('Service Display Name'),
+ 'checkcommand_name' => t('Checkcommand Name'),
+ 'checkcommand_id' => t('Checkcommand Id'),
+ 'max_check_attempts' => t('Service Max Check Attempts'),
+ 'check_timeperiod_name' => t('Check Timeperiod Name'),
+ 'check_timeperiod_id' => t('Check Timeperiod Id'),
+ 'check_timeout' => t('Service Check Timeout'),
+ 'check_interval' => t('Service Check Interval'),
+ 'check_retry_interval' => t('Service Check Retry Inverval'),
+ 'active_checks_enabled' => t('Service Active Checks Enabled'),
+ 'passive_checks_enabled' => t('Service Passive Checks Enabled'),
+ 'event_handler_enabled' => t('Service Event Handler Enabled'),
+ 'notifications_enabled' => t('Service Notifications Enabled'),
+ 'flapping_enabled' => t('Service Flapping Enabled'),
+ 'flapping_threshold_low' => t('Service Flapping Threshold Low'),
+ 'flapping_threshold_high' => t('Service Flapping Threshold High'),
+ 'perfdata_enabled' => t('Service Performance Data Enabled'),
+ 'eventcommand_name' => t('Eventcommand Name'),
+ 'eventcommand_id' => t('Eventcommand Id'),
+ 'is_volatile' => t('Service Is Volatile'),
+ 'action_url_id' => t('Action Url Id'),
+ 'notes_url_id' => t('Notes Url Id'),
+ 'notes' => t('Service Notes'),
+ 'icon_image_id' => t('Icon Image Id'),
+ 'icon_image_alt' => t('Icon Image Alt'),
+ 'zone_name' => t('Zone Name'),
+ 'zone_id' => t('Zone Id'),
+ 'command_endpoint_name' => t('Endpoint Name'),
+ 'command_endpoint_id' => t('Endpoint Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['name_ci', 'display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'service.display_name';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'active_checks_enabled',
+ 'passive_checks_enabled',
+ 'event_handler_enabled',
+ 'notifications_enabled',
+ 'flapping_enabled',
+ 'is_volatile'
+ ]));
+
+ $behaviors->add(new ReRoute([
+ 'user' => 'notification.user',
+ 'usergroup' => 'notification.usergroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'host_id',
+ 'checkcommand_id',
+ 'check_timeperiod_id',
+ 'eventcommand_id',
+ 'action_url_id',
+ 'notes_url_id',
+ 'icon_image_id',
+ 'zone_id',
+ 'command_endpoint_id'
+ ]));
+ }
+
+ public function createDefaults(Defaults $defaults)
+ {
+ $defaults->add('vars', function (self $subject) {
+ if (! $subject->customvar_flat instanceof ResultSet) {
+ $this->applyRestrictions($subject->customvar_flat);
+ }
+
+ $vars = [];
+ foreach ($subject->customvar_flat as $customVar) {
+ $vars[$customVar->flatname] = $customVar->flatvalue;
+ }
+
+ return $vars;
+ });
+
+ $defaults->add('customvars', function (self $subject) {
+ if (! $subject->customvar instanceof ResultSet) {
+ $this->applyRestrictions($subject->customvar);
+ }
+
+ $vars = [];
+ foreach ($subject->customvar as $customVar) {
+ $vars[$customVar->name] = json_decode($customVar->value, true);
+ }
+
+ return $vars;
+ });
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('host', Host::class)->setJoinType('LEFT');
+ $relations->belongsTo('checkcommand', Checkcommand::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class)
+ ->setCandidateKey('check_timeperiod_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('eventcommand', Eventcommand::class);
+ $relations->belongsTo('action_url', ActionUrl::class)
+ ->setCandidateKey('action_url_id')
+ ->setForeignKey('id');
+ $relations->belongsTo('notes_url', NotesUrl::class)
+ ->setCandidateKey('notes_url_id')
+ ->setForeignKey('id');
+ $relations->belongsTo('icon_image', IconImage::class)
+ ->setCandidateKey('icon_image_id')
+ ->setJoinType('LEFT');
+ $relations->belongsTo('zone', Zone::class);
+ $relations->belongsTo('endpoint', Endpoint::class)
+ ->setCandidateKey('command_endpoint_id');
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(ServiceCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(ServiceCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(ServiceCustomvar::class);
+ $relations->belongsToMany('servicegroup', Servicegroup::class)
+ ->through(ServicegroupMember::class);
+ $relations->belongsToMany('hostgroup', Hostgroup::class)
+ ->through(HostgroupMember::class);
+
+ $relations->hasOne('state', ServiceState::class)->setJoinType('LEFT');
+ $relations->hasMany('comment', Comment::class)->setJoinType('LEFT');
+ $relations->hasMany('downtime', Downtime::class)->setJoinType('LEFT');
+ $relations->hasMany('history', History::class);
+ $relations->hasMany('notification', Notification::class)->setJoinType('LEFT');
+ $relations->hasMany('notification_history', NotificationHistory::class);
+ }
+}
diff --git a/library/Icingadb/Model/ServiceCustomvar.php b/library/Icingadb/Model/ServiceCustomvar.php
new file mode 100644
index 0000000..07ee84c
--- /dev/null
+++ b/library/Icingadb/Model/ServiceCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class ServiceCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'service_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'service_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'service_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('service', Service::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setForeignKey('customvar_id')
+ ->setCandidateKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/ServiceState.php b/library/Icingadb/Model/ServiceState.php
new file mode 100644
index 0000000..c5daa08
--- /dev/null
+++ b/library/Icingadb/Model/ServiceState.php
@@ -0,0 +1,76 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Common\ServiceStates;
+use ipl\Orm\Relations;
+
+class ServiceState extends State
+{
+ public function getTableName()
+ {
+ return 'service_state';
+ }
+
+ public function getKeyName()
+ {
+ return 'service_id';
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'state_type' => t('Service State Type'),
+ 'soft_state' => t('Service Soft State'),
+ 'hard_state' => t('Service Hard State'),
+ 'previous_soft_state' => t('Service Previous Soft State'),
+ 'previous_hard_state' => t('Service Previous Hard State'),
+ 'check_attempt' => t('Service Check Attempt No.'),
+ 'severity' => t('Service State Severity'),
+ 'output' => t('Service Output'),
+ 'long_output' => t('Service Long Output'),
+ 'performance_data' => t('Service Performance Data'),
+ 'normalized_performance_data' => t('Service Normalized Performance Data'),
+ 'check_commandline' => t('Service Check Commandline'),
+ 'is_problem' => t('Service Has Problem'),
+ 'is_handled' => t('Service Is Handled'),
+ 'is_reachable' => t('Service Is Reachable'),
+ 'is_flapping' => t('Service Is Flapping'),
+ 'is_overdue' => t('Service Check Is Overdue'),
+ 'is_acknowledged' => t('Service Is Acknowledged'),
+ 'acknowledgement_comment_id' => t('Acknowledgement Comment Id'),
+ 'in_downtime' => t('Service In Downtime'),
+ 'execution_time' => t('Service Check Execution Time'),
+ 'latency' => t('Service Check Latency'),
+ 'check_timeout' => t('Service Check Timeout'),
+ 'check_source' => t('Service Check Source'),
+ 'last_update' => t('Service Last Update'),
+ 'last_state_change' => t('Service Last State Change'),
+ 'next_check' => t('Service Next Check'),
+ 'next_update' => t('Service Next Update')
+ ];
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('service', Service::class);
+ $relations->hasOne('last_comment', LastServiceComment::class)
+ ->setCandidateKey('last_comment_id')
+ ->setForeignKey('id')
+ ->setJoinType('LEFT');
+ }
+
+ public function getStateText(): string
+ {
+ return ServiceStates::text($this->soft_state);
+ }
+
+ public function getStateTextTranslated(): string
+ {
+ return ServiceStates::text($this->soft_state);
+ }
+}
diff --git a/library/Icingadb/Model/Servicegroup.php b/library/Icingadb/Model/Servicegroup.php
new file mode 100644
index 0000000..0da92fb
--- /dev/null
+++ b/library/Icingadb/Model/Servicegroup.php
@@ -0,0 +1,91 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Servicegroup extends Model
+{
+ public function getTableName()
+ {
+ return 'servicegroup';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'display_name',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Servicegroup Name Checksum'),
+ 'properties_checksum' => t('Servicegroup Properties Checksum'),
+ 'name' => t('Servicegroup Name'),
+ 'name_ci' => t('Servicegroup Name (CI)'),
+ 'display_name' => t('Servicegroup Display Name'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['name_ci', 'display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'display_name';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'host' => 'service.host',
+ 'hostgroup' => 'service.hostgroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'zone_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(ServicegroupCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(ServicegroupCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(ServicegroupCustomvar::class);
+ $relations->belongsToMany('service', Service::class)
+ ->through(ServicegroupMember::class);
+ }
+}
diff --git a/library/Icingadb/Model/ServicegroupCustomvar.php b/library/Icingadb/Model/ServicegroupCustomvar.php
new file mode 100644
index 0000000..23e536b
--- /dev/null
+++ b/library/Icingadb/Model/ServicegroupCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class ServicegroupCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'servicegroup_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'servicegroup_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'servicegroup_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('servicegroup', Servicegroup::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/ServicegroupMember.php b/library/Icingadb/Model/ServicegroupMember.php
new file mode 100644
index 0000000..5da537a
--- /dev/null
+++ b/library/Icingadb/Model/ServicegroupMember.php
@@ -0,0 +1,49 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class ServicegroupMember extends Model
+{
+ public function getTableName()
+ {
+ return 'servicegroup_member';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'service_id',
+ 'servicegroup_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'service_id',
+ 'servicegroup_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('servicegroup', Servicegroup::class);
+ $relations->belongsTo('service', Service::class);
+ }
+}
diff --git a/library/Icingadb/Model/ServicegroupSummary.php b/library/Icingadb/Model/ServicegroupSummary.php
new file mode 100644
index 0000000..89a0953
--- /dev/null
+++ b/library/Icingadb/Model/ServicegroupSummary.php
@@ -0,0 +1,167 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Relations;
+use ipl\Orm\UnionModel;
+use ipl\Sql\Adapter\Pgsql;
+use ipl\Sql\Connection;
+use ipl\Sql\Expression;
+use ipl\Sql\Select;
+
+class ServicegroupSummary extends UnionModel
+{
+ public static function on(Connection $db)
+ {
+ $q = parent::on($db);
+
+ $q->on($q::ON_SELECT_ASSEMBLED, function (Select $select) use ($q) {
+ $model = $q->getModel();
+
+ $groupBy = $q->getResolver()->qualifyColumnsAndAliases((array) $model->getKeyName(), $model, false);
+
+ // For PostgreSQL, ALL non-aggregate SELECT columns must appear in the GROUP BY clause:
+ if ($q->getDb()->getAdapter() instanceof Pgsql) {
+ /**
+ * Ignore Expressions, i.e. aggregate functions {@see getColumns()},
+ * which do not need to be added to the GROUP BY.
+ */
+ $candidates = array_filter($select->getColumns(), 'is_string');
+ // Remove already considered columns for the GROUP BY, i.e. the primary key.
+ $candidates = array_diff_assoc($candidates, $groupBy);
+ $groupBy = array_merge($groupBy, $candidates);
+ }
+
+ $select->groupBy($groupBy);
+ });
+
+ return $q;
+ }
+
+ public function getTableName()
+ {
+ return 'servicegroup';
+ }
+
+ public function getKeyName()
+ {
+ return ['id' => 'servicegroup_id'];
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'display_name' => 'servicegroup_display_name',
+ 'name' => 'servicegroup_name',
+ 'services_critical_handled' => new Expression(
+ 'SUM(CASE WHEN service_state = 2'
+ . ' AND (service_handled = \'y\' OR service_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_critical_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state = 2'
+ . ' AND service_handled = \'n\' AND service_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_ok' => new Expression(
+ 'SUM(CASE WHEN service_state = 0 THEN 1 ELSE 0 END)'
+ ),
+ 'services_pending' => new Expression(
+ 'SUM(CASE WHEN service_state = 99 THEN 1 ELSE 0 END)'
+ ),
+ 'services_total' => new Expression(
+ 'SUM(CASE WHEN service_id IS NOT NULL THEN 1 ELSE 0 END)'
+ ),
+ 'services_unknown_handled' => new Expression(
+ 'SUM(CASE WHEN service_state = 3'
+ . ' AND (service_handled = \'y\' OR service_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_unknown_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state = 3'
+ . ' AND service_handled = \'n\' AND service_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_warning_handled' => new Expression(
+ 'SUM(CASE WHEN service_state = 1'
+ . ' AND (service_handled = \'y\' OR service_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_warning_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state = 1'
+ . ' AND service_handled = \'n\' AND service_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_severity' => new Expression('MAX(service_severity)')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'display_name';
+ }
+
+ public function getUnions()
+ {
+ $unions = [
+ [
+ Service::class,
+ [
+ 'servicegroup',
+ 'state'
+ ],
+ [
+ 'servicegroup_id' => 'servicegroup.id',
+ 'servicegroup_name' => 'servicegroup.name',
+ 'servicegroup_display_name' => 'servicegroup.display_name',
+ 'service_id' => 'service.id',
+ 'service_state' => 'state.soft_state',
+ 'service_handled' => 'state.is_handled',
+ 'service_reachable' => 'state.is_reachable',
+ 'service_severity' => 'state.severity'
+ ]
+ ],
+ [
+ Servicegroup::class,
+ [],
+ [
+ 'servicegroup_id' => 'servicegroup.id',
+ 'servicegroup_name' => 'servicegroup.name',
+ 'servicegroup_display_name' => 'servicegroup.display_name',
+ 'service_id' => new Expression('NULL'),
+ 'service_state' => new Expression('NULL'),
+ 'service_handled' => new Expression('NULL'),
+ 'service_reachable' => new Expression('NULL'),
+ 'service_severity' => new Expression('0')
+ ]
+ ]
+ ];
+
+ return $unions;
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id'
+ ]));
+
+ // This is because there is no better way
+ (new Servicegroup())->createBehaviors($behaviors);
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ // This is because there is no better way
+ (new Servicegroup())->createRelations($relations);
+ }
+
+ public function getColumnDefinitions()
+ {
+ // This is because there is no better way
+ return (new Servicegroup())->getColumnDefinitions();
+ }
+}
diff --git a/library/Icingadb/Model/ServicestateSummary.php b/library/Icingadb/Model/ServicestateSummary.php
new file mode 100644
index 0000000..b1364f7
--- /dev/null
+++ b/library/Icingadb/Model/ServicestateSummary.php
@@ -0,0 +1,99 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Sql\Connection;
+use ipl\Sql\Expression;
+
+class ServicestateSummary extends Service
+{
+ public function getSummaryColumns()
+ {
+ return [
+ 'services_acknowledged' => new Expression(
+ 'SUM(CASE WHEN service_state.is_acknowledged = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_active_checks_enabled' => new Expression(
+ 'SUM(CASE WHEN service.active_checks_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_passive_checks_enabled' => new Expression(
+ 'SUM(CASE WHEN service.passive_checks_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_critical_handled' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 2'
+ . ' AND (service_state.is_handled = \'y\' OR service_state.is_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_critical_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 2'
+ . ' AND service_state.is_handled = \'n\' AND service_state.is_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_event_handler_enabled' => new Expression(
+ 'SUM(CASE WHEN service.event_handler_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_flapping_enabled' => new Expression(
+ 'SUM(CASE WHEN service.flapping_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_notifications_enabled' => new Expression(
+ 'SUM(CASE WHEN service.notifications_enabled = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_ok' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 0 THEN 1 ELSE 0 END)'
+ ),
+ 'services_pending' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 99 THEN 1 ELSE 0 END)'
+ ),
+ 'services_problems_unacknowledged' => new Expression(
+ 'SUM(CASE WHEN service_state.is_problem = \'y\''
+ . ' AND service_state.is_acknowledged = \'n\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_total' => new Expression(
+ 'SUM(CASE WHEN service.id IS NOT NULL THEN 1 ELSE 0 END)'
+ ),
+ 'services_unknown_handled' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 3'
+ . ' AND (service_state.is_handled = \'y\' OR service_state.is_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_unknown_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 3'
+ . ' AND service_state.is_handled = \'n\' AND service_state.is_reachable = \'y\' THEN 1 ELSE 0 END)'
+ ),
+ 'services_warning_handled' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 1'
+ . ' AND (service_state.is_handled = \'y\' OR service_state.is_reachable = \'n\') THEN 1 ELSE 0 END)'
+ ),
+ 'services_warning_unhandled' => new Expression(
+ 'SUM(CASE WHEN service_state.soft_state = 1'
+ . ' AND service_state.is_handled = \'n\' AND service_state.is_reachable = \'y\' THEN 1 ELSE 0 END)'
+ )
+ ];
+ }
+
+ public static function on(Connection $db)
+ {
+ $q = parent::on($db);
+ $q->utilize('state');
+
+ /** @var static $m */
+ $m = $q->getModel();
+ $q->columns($m->getSummaryColumns());
+
+ return $q;
+ }
+
+ public function getColumns()
+ {
+ return array_merge(parent::getColumns(), $this->getSummaryColumns());
+ }
+
+ public function getDefaultSort()
+ {
+ return null;
+ }
+
+ public function getSearchColumns()
+ {
+ return ['name_ci', 'host.name_ci'];
+ }
+}
diff --git a/library/Icingadb/Model/State.php b/library/Icingadb/Model/State.php
new file mode 100644
index 0000000..2d242a8
--- /dev/null
+++ b/library/Icingadb/Model/State.php
@@ -0,0 +1,177 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use DateTime;
+use Icinga\Module\Icingadb\Common\Icons;
+use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Web\Widget\Icon;
+
+/**
+ * Base class for the {@link HostState} and {@link ServiceState} models providing common columns.
+ *
+ * @property string $environment_id The environment id
+ * @property string $state_type The state type (hard or soft)
+ * @property int $soft_state The current soft state code (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN)
+ * @property int $hard_state The current hard state code (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN)
+ * @property int $previous_soft_state The previous soft state code (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN)
+ * @property int $previous_hard_state The previous hard state code (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN)
+ * @property int $check_attempt The check attempt count
+ * @property int $severity The calculated severity
+ * @property ?string $output The check output
+ * @property ?string $long_output The long check output
+ * @property ?string $performance_data The performance data
+ * @property ?string $normalized_performance_data The normalized performance data (converted ms to s, GiB to byte etc.)
+ * @property ?string $check_commandline The executed check command
+ * @property bool $is_problem Whether in non-OK state
+ * @property bool $is_handled Whether the state is handled
+ * @property bool $is_reachable Whether the node is reachable
+ * @property bool $is_flapping Whether the state is flapping
+ * @property bool $is_overdue Whether the check is overdue
+ * @property bool|string $is_acknowledged Whether the state is acknowledged (bool), can also be `sticky` (string)
+ * @property ?string $acknowledgement_comment_id The id of acknowledgement comment
+ * @property ?string $last_comment_id The id of last comment
+ * @property bool $in_downtime Whether the node is in downtime
+ * @property ?int $execution_time The check execution time
+ * @property ?int $latency The check latency
+ * @property ?int $check_timeout The check timeout
+ * @property ?string $check_source The name of the node that executes the check
+ * @property ?string $scheduling_source The name of the node that schedules the check
+ * @property ?DateTime $last_update The time when the node was last updated
+ * @property ?DateTime $last_state_change The time when the node last got a status change
+ * @property ?DateTime $next_check The time when the node will execute the next check
+ * @property ?DateTime $next_update The time when the next check of the node is expected to end
+ */
+abstract class State extends Model
+{
+ /**
+ * Get the state as the textual representation
+ *
+ * @return string
+ */
+ abstract public function getStateText(): string;
+
+ /**
+ * Get the state as the translated textual representation
+ *
+ * @return string
+ */
+ abstract public function getStateTextTranslated(): string;
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'state_type',
+ 'soft_state',
+ 'hard_state',
+ 'previous_soft_state',
+ 'previous_hard_state',
+ 'check_attempt',
+ 'severity',
+ 'output',
+ 'long_output',
+ 'performance_data',
+ 'normalized_performance_data',
+ 'check_commandline',
+ 'is_problem',
+ 'is_handled',
+ 'is_reachable',
+ 'is_flapping',
+ 'is_overdue',
+ 'is_acknowledged',
+ 'acknowledgement_comment_id',
+ 'last_comment_id',
+ 'in_downtime',
+ 'execution_time',
+ 'latency',
+ 'check_timeout',
+ 'check_source',
+ 'scheduling_source',
+ 'last_update',
+ 'last_state_change',
+ 'next_check',
+ 'next_update'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new BoolCast([
+ 'is_problem',
+ 'is_handled',
+ 'is_reachable',
+ 'is_flapping',
+ 'is_overdue',
+ 'is_acknowledged',
+ 'in_downtime'
+ ]));
+
+ $behaviors->add(new MillisecondTimestamp([
+ 'last_update',
+ 'last_state_change',
+ 'next_check',
+ 'next_update'
+ ]));
+
+ $behaviors->add(new Binary([
+ $this->getKeyName(),
+ 'environment_id',
+ 'acknowledgement_comment_id',
+ 'last_comment_id'
+ ]));
+ }
+
+ /**
+ * Get the state icon
+ *
+ * @return Icon|null
+ */
+ public function getIcon(): ?Icon
+ {
+ $icon = null;
+ switch (true) {
+ case $this->is_acknowledged:
+ $icon = new Icon(Icons::IS_ACKNOWLEDGED);
+
+ break;
+ case $this->in_downtime:
+ $icon = new Icon(
+ Icons::IN_DOWNTIME,
+ ['title' => sprintf(
+ '%s (%s)',
+ strtoupper($this->getStateTextTranslated()),
+ $this->is_handled ? t('handled by Downtime') : t('in Downtime')
+ )]
+ );
+
+ break;
+ case $this->is_flapping:
+ $icon = new Icon(Icons::IS_FLAPPING);
+
+ break;
+ case ! $this->is_reachable:
+ $icon = new Icon(Icons::HOST_DOWN, [
+ 'title' => sprintf(
+ '%s (%s)',
+ strtoupper($this->getStateTextTranslated()),
+ t('is unreachable')
+ )
+ ]);
+
+ break;
+ case $this->is_handled:
+ $icon = new Icon(Icons::HOST_DOWN);
+
+ break;
+ }
+
+ return $icon;
+ }
+}
diff --git a/library/Icingadb/Model/StateHistory.php b/library/Icingadb/Model/StateHistory.php
new file mode 100644
index 0000000..9d80cb2
--- /dev/null
+++ b/library/Icingadb/Model/StateHistory.php
@@ -0,0 +1,101 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behavior\MillisecondTimestamp;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+/**
+ * Model for table `state_history`
+ *
+ * Please note that using this model will fetch history entries for decommissioned services. To avoid this,
+ * the query needs a `state_history.service_id IS NULL OR state_history_service.id IS NOT NULL` where.
+ */
+class StateHistory extends Model
+{
+ public function getTableName()
+ {
+ return 'state_history';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'endpoint_id',
+ 'object_type',
+ 'host_id',
+ 'service_id',
+ 'event_time',
+ 'state_type',
+ 'soft_state',
+ 'hard_state',
+ 'check_attempt',
+ 'previous_soft_state',
+ 'previous_hard_state',
+ 'output',
+ 'long_output',
+ 'max_check_attempts',
+ 'check_source',
+ 'scheduling_source'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'endpoint_id' => t('Endpoint Id'),
+ 'object_type' => t('Object Type'),
+ 'host_id' => t('Host Id'),
+ 'service_id' => t('Service Id'),
+ 'event_time' => t('Event Time'),
+ 'state_type' => t('Event State Type'),
+ 'soft_state' => t('Event Soft State'),
+ 'hard_state' => t('Event Hard State'),
+ 'check_attempt' => t('Event Check Attempt No.'),
+ 'previous_soft_state' => t('Event Previous Soft State'),
+ 'previous_hard_state' => t('Event Previous Hard State'),
+ 'output' => t('Event Output'),
+ 'long_output' => t('Event Long Output'),
+ 'max_check_attempts' => t('Event Max Check Attempts'),
+ 'check_source' => t('Event Check Source')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new MillisecondTimestamp([
+ 'event_time'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'endpoint_id',
+ 'host_id',
+ 'service_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('endpoint', Endpoint::class);
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('history', History::class)
+ ->setCandidateKey('id')
+ ->setForeignKey('state_history_id');
+ $relations->belongsTo('host', Host::class);
+ $relations->belongsTo('service', Service::class)->setJoinType('LEFT');
+ }
+}
diff --git a/library/Icingadb/Model/Timeperiod.php b/library/Icingadb/Model/Timeperiod.php
new file mode 100644
index 0000000..26dd722
--- /dev/null
+++ b/library/Icingadb/Model/Timeperiod.php
@@ -0,0 +1,91 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Timeperiod extends Model
+{
+ public function getTableName()
+ {
+ return 'timeperiod';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'display_name',
+ 'prefer_includes',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Timeperiod Name Checksum'),
+ 'properties_checksum' => t('Timeperiod Properties Checksum'),
+ 'name' => t('Timeperiod Name'),
+ 'name_ci' => t('Timeperiod Name (CI)'),
+ 'display_name' => t('Timeperiod Display Name'),
+ 'prefer_includes' => t('Timeperiod Prefer Includes'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'hostgroup' => 'host.hostgroup',
+ 'servicegroup' => 'service.servicegroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'zone_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(TimeperiodCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(TimeperiodCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(TimeperiodCustomvar::class);
+
+ // TODO: Decide how to establish the override relations
+
+ $relations->hasMany('range', TimeperiodRange::class);
+ $relations->hasMany('host', Host::class)
+ ->setForeignKey('check_timeperiod_id');
+ $relations->hasMany('Notification', Notification::class);
+ $relations->hasMany('service', Service::class)
+ ->setForeignKey('check_timeperiod_id');
+ $relations->hasMany('user', User::class);
+ }
+}
diff --git a/library/Icingadb/Model/TimeperiodCustomvar.php b/library/Icingadb/Model/TimeperiodCustomvar.php
new file mode 100644
index 0000000..614a312
--- /dev/null
+++ b/library/Icingadb/Model/TimeperiodCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class TimeperiodCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'timeperiod_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'timeperiod_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'timeperiod_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/TimeperiodOverrideExclude.php b/library/Icingadb/Model/TimeperiodOverrideExclude.php
new file mode 100644
index 0000000..c33df77
--- /dev/null
+++ b/library/Icingadb/Model/TimeperiodOverrideExclude.php
@@ -0,0 +1,51 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class TimeperiodOverrideExclude extends Model
+{
+ public function getTableName()
+ {
+ return 'timeperiod_override_exclude';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'timeperiod_id',
+ 'override_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'timeperiod_id',
+ 'override_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class);
+ // TODO: `timeperiod` cannot be used again, find a better name
+ $relations->belongsTo('timeperiod', Timeperiod::class)
+ ->setCandidateKey('override_id');
+ }
+}
diff --git a/library/Icingadb/Model/TimeperiodOverrideInclude.php b/library/Icingadb/Model/TimeperiodOverrideInclude.php
new file mode 100644
index 0000000..5418596
--- /dev/null
+++ b/library/Icingadb/Model/TimeperiodOverrideInclude.php
@@ -0,0 +1,51 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class TimeperiodOverrideInclude extends Model
+{
+ public function getTableName()
+ {
+ return 'timeperiod_override_include';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'timeperiod_id',
+ 'override_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'timeperiod_id',
+ 'override_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class);
+ // TODO: `timeperiod` cannot be used again, find a better name
+ $relations->belongsTo('timeperiod', Timeperiod::class)
+ ->setCandidateKey('override_id');
+ }
+}
diff --git a/library/Icingadb/Model/TimeperiodRange.php b/library/Icingadb/Model/TimeperiodRange.php
new file mode 100644
index 0000000..62e87f8
--- /dev/null
+++ b/library/Icingadb/Model/TimeperiodRange.php
@@ -0,0 +1,58 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class TimeperiodRange extends Model
+{
+ public function getTableName()
+ {
+ return 'timeperiod_range';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'timeperiod_id',
+ 'range_key',
+ 'environment_id',
+ 'range_value'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'timeperiod_id' => t('Timeperiod Id'),
+ 'range_key' => t('Timeperiod Range Date(s)/Day'),
+ 'environment_id' => t('Environment Id'),
+ 'range_value' => t('Timeperiod Range Time')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'timeperiod_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class);
+ }
+}
diff --git a/library/Icingadb/Model/User.php b/library/Icingadb/Model/User.php
new file mode 100644
index 0000000..91d0d71
--- /dev/null
+++ b/library/Icingadb/Model/User.php
@@ -0,0 +1,134 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\Bitmask;
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class User extends Model
+{
+ public function getTableName()
+ {
+ return 'user';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'display_name',
+ 'email',
+ 'pager',
+ 'notifications_enabled',
+ 'timeperiod_id',
+ 'states',
+ 'types',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('User Name Checksum'),
+ 'properties_checksum' => t('User Properties Checksum'),
+ 'name' => t('User Name'),
+ 'name_ci' => t('User Name (CI)'),
+ 'display_name' => t('User Display Name'),
+ 'email' => t('User Email'),
+ 'pager' => t('User Pager'),
+ 'notifications_enabled' => t('User Receives Notifications'),
+ 'timeperiod_id' => t('Timeperiod Id'),
+ 'states' => t('Notification State Filter'),
+ 'types' => t('Notification Type Filter'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['name_ci', 'display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'user.display_name';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'host' => 'notification.host',
+ 'service' => 'notification.service',
+ 'hostgroup' => 'notification.host.hostgroup',
+ 'servicegroup' => 'notification.service.servicegroup'
+ ]));
+
+ $behaviors->add(new Bitmask([
+ 'states' => [
+ 'ok' => 1,
+ 'warning' => 2,
+ 'critical' => 4,
+ 'unknown' => 8,
+ 'up' => 16,
+ 'down' => 32
+ ],
+ 'types' => [
+ 'downtime_start' => 1,
+ 'downtime_end' => 2,
+ 'downtime_removed' => 4,
+ 'custom' => 8,
+ 'ack' => 16,
+ 'problem' => 32,
+ 'recovery' => 64,
+ 'flapping_start' => 128,
+ 'flapping_end' => 256
+ ]
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'timeperiod_id',
+ 'zone_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('timeperiod', Timeperiod::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(UserCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(UserCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(UserCustomvar::class);
+ $relations->belongsToMany('notification', Notification::class)
+ ->through('notification_recipient');
+ $relations->belongsToMany('notification_history', NotificationHistory::class)
+ ->through('user_notification_history');
+ $relations->belongsToMany('usergroup', Usergroup::class)
+ ->through(UsergroupMember::class);
+ }
+}
diff --git a/library/Icingadb/Model/UserCustomvar.php b/library/Icingadb/Model/UserCustomvar.php
new file mode 100644
index 0000000..a702b68
--- /dev/null
+++ b/library/Icingadb/Model/UserCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class UserCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'user_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'user_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'user_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('user', User::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/Usergroup.php b/library/Icingadb/Model/Usergroup.php
new file mode 100644
index 0000000..34b0647
--- /dev/null
+++ b/library/Icingadb/Model/Usergroup.php
@@ -0,0 +1,95 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Usergroup extends Model
+{
+ public function getTableName()
+ {
+ return 'usergroup';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'display_name',
+ 'zone_id'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Usergroup Name Checksum'),
+ 'properties_checksum' => t('Usergroup Properties Checksum'),
+ 'name' => t('Usergroup Name'),
+ 'name_ci' => t('Usergroup Name (CI)'),
+ 'display_name' => t('Usergroup Display Name'),
+ 'zone_id' => t('Zone Id')
+ ];
+ }
+
+ public function getSearchColumns()
+ {
+ return ['name_ci', 'display_name'];
+ }
+
+ public function getDefaultSort()
+ {
+ return 'usergroup.display_name';
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new ReRoute([
+ 'host' => 'notification.host',
+ 'service' => 'notification.service',
+ 'hostgroup' => 'notification.host.hostgroup',
+ 'servicegroup' => 'notification.service.servicegroup'
+ ]));
+
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'zone_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('zone', Zone::class);
+
+ $relations->belongsToMany('customvar', Customvar::class)
+ ->through(UsergroupCustomvar::class);
+ $relations->belongsToMany('customvar_flat', CustomvarFlat::class)
+ ->through(UsergroupCustomvar::class);
+ $relations->belongsToMany('vars', Vars::class)
+ ->through(UsergroupCustomvar::class);
+ $relations->belongsToMany('user', User::class)
+ ->through(UsergroupMember::class);
+ $relations->belongsToMany('notification', Notification::class)
+ ->through('notification_recipient');
+ }
+}
diff --git a/library/Icingadb/Model/UsergroupCustomvar.php b/library/Icingadb/Model/UsergroupCustomvar.php
new file mode 100644
index 0000000..ab97273
--- /dev/null
+++ b/library/Icingadb/Model/UsergroupCustomvar.php
@@ -0,0 +1,52 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class UsergroupCustomvar extends Model
+{
+ public function getTableName()
+ {
+ return 'usergroup_customvar';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'usergroup_id',
+ 'customvar_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'usergroup_id',
+ 'customvar_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('usergroup', Usergroup::class);
+ $relations->belongsTo('customvar', Customvar::class);
+ $relations->belongsTo('customvar_flat', CustomvarFlat::class)
+ ->setCandidateKey('customvar_id')
+ ->setForeignKey('customvar_id');
+ }
+}
diff --git a/library/Icingadb/Model/UsergroupMember.php b/library/Icingadb/Model/UsergroupMember.php
new file mode 100644
index 0000000..7c61d67
--- /dev/null
+++ b/library/Icingadb/Model/UsergroupMember.php
@@ -0,0 +1,49 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class UsergroupMember extends Model
+{
+ public function getTableName()
+ {
+ return 'usergroup_member';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'user_id',
+ 'usergroup_id',
+ 'environment_id'
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'user_id',
+ 'usergroup_id',
+ 'environment_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+ $relations->belongsTo('usergroup', Usergroup::class);
+ $relations->belongsTo('user', User::class);
+ }
+}
diff --git a/library/Icingadb/Model/Vars.php b/library/Icingadb/Model/Vars.php
new file mode 100644
index 0000000..304d526
--- /dev/null
+++ b/library/Icingadb/Model/Vars.php
@@ -0,0 +1,28 @@
+<?php
+
+/* Icinga DB Web | (c) 2022 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use Icinga\Module\Icingadb\Model\Behavior\FlattenedObjectVars;
+use ipl\Orm\Behaviors;
+use ipl\Sql\Connection;
+
+class Vars extends CustomvarFlat
+{
+ /**
+ * @internal Don't use. This model acts only as relation target and is not supposed to be directly used as query
+ * target. Use {@see CustomvarFlat} instead.
+ */
+ public static function on(Connection $_)
+ {
+ throw new \LogicException('Documentation says: DO NOT USE. Can\'t you read?');
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ parent::createBehaviors($behaviors);
+
+ $behaviors->add(new FlattenedObjectVars());
+ }
+}
diff --git a/library/Icingadb/Model/Zone.php b/library/Icingadb/Model/Zone.php
new file mode 100644
index 0000000..aaf3bbf
--- /dev/null
+++ b/library/Icingadb/Model/Zone.php
@@ -0,0 +1,82 @@
+<?php
+
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+namespace Icinga\Module\Icingadb\Model;
+
+use ipl\Orm\Behavior\Binary;
+use ipl\Orm\Behaviors;
+use ipl\Orm\Model;
+use ipl\Orm\Relations;
+
+class Zone extends Model
+{
+ public function getTableName()
+ {
+ return 'zone';
+ }
+
+ public function getKeyName()
+ {
+ return 'id';
+ }
+
+ public function getColumns()
+ {
+ return [
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'name',
+ 'name_ci',
+ 'is_global',
+ 'parent_id',
+ 'depth'
+ ];
+ }
+
+ public function getColumnDefinitions()
+ {
+ return [
+ 'environment_id' => t('Environment Id'),
+ 'name_checksum' => t('Zone Name Checksum'),
+ 'properties_checksum' => t('Zone Properties Checksum'),
+ 'name' => t('Zone Name'),
+ 'name_ci' => t('Zone Name (CI)'),
+ 'is_global' => t('Zone Is Global'),
+ 'parent_id' => t('Parent Zone Id'),
+ 'depth' => t('Zone Depth')
+ ];
+ }
+
+ public function createBehaviors(Behaviors $behaviors)
+ {
+ $behaviors->add(new Binary([
+ 'id',
+ 'environment_id',
+ 'name_checksum',
+ 'properties_checksum',
+ 'parent_id'
+ ]));
+ }
+
+ public function createRelations(Relations $relations)
+ {
+ $relations->belongsTo('environment', Environment::class);
+
+ $relations->hasMany('comment', Comment::class);
+ $relations->hasMany('downtime', Downtime::class);
+ $relations->hasMany('endpoint', Endpoint::class);
+ $relations->hasMany('eventcommand', Eventcommand::class);
+ $relations->hasMany('host', Host::class);
+ $relations->hasMany('hostgroup', Hostgroup::class);
+ $relations->hasMany('notification', Notification::class);
+ $relations->hasMany('service', Service::class);
+ $relations->hasMany('servicegroup', Servicegroup::class);
+ $relations->hasMany('timeperiod', Timeperiod::class);
+ $relations->hasMany('user', User::class);
+ $relations->hasMany('usergroup', Usergroup::class);
+
+ // TODO: Decide how to establish recursive relations
+ }
+}