You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1115 lines
33 KiB

<?php
/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/**
* Common class for dashboards API and template dashboards API.
*/
abstract class CDashboardGeneral extends CApiService {
protected const WIDGET_FIELD_TYPE_COLUMNS_FK = [
ZBX_WIDGET_FIELD_TYPE_GROUP => 'value_groupid',
ZBX_WIDGET_FIELD_TYPE_HOST => 'value_hostid',
ZBX_WIDGET_FIELD_TYPE_ITEM => 'value_itemid',
ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE => 'value_itemid',
ZBX_WIDGET_FIELD_TYPE_GRAPH => 'value_graphid',
ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE => 'value_graphid',
ZBX_WIDGET_FIELD_TYPE_MAP => 'value_sysmapid',
ZBX_WIDGET_FIELD_TYPE_SERVICE => 'value_serviceid',
ZBX_WIDGET_FIELD_TYPE_SLA => 'value_slaid',
ZBX_WIDGET_FIELD_TYPE_USER => 'value_userid',
ZBX_WIDGET_FIELD_TYPE_ACTION => 'value_actionid',
ZBX_WIDGET_FIELD_TYPE_MEDIA_TYPE => 'value_mediatypeid'
];
protected const WIDGET_FIELD_TYPE_COLUMNS = [
ZBX_WIDGET_FIELD_TYPE_INT32 => 'value_int',
ZBX_WIDGET_FIELD_TYPE_STR => 'value_str'
] + self::WIDGET_FIELD_TYPE_COLUMNS_FK;
protected $tableName = 'dashboard';
protected $tableAlias = 'd';
protected $sortColumns = ['dashboardid', 'name'];
/**
* @param array $options
*
* @throws APIException if the input is invalid.
*
* @return array|int
*/
abstract public function get(array $options = []);
/**
* @param array $dashboardids
*
* @throws APIException if the input is invalid.
*
* @return array
*/
public function delete(array $dashboardids): array {
$api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true];
if (!CApiInputValidator::validate($api_input_rules, $dashboardids, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
$db_dashboards = $this->get([
'output' => ['dashboardid', 'name'],
'dashboardids' => $dashboardids,
'editable' => true,
'preservekeys' => true
]);
if (count($db_dashboards) != count($dashboardids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
}
// Check if dashboards are used in scheduled reports.
if ($this instanceof CDashboard) {
$db_reports = DB::select('report', [
'output' => ['name', 'dashboardid'],
'filter' => ['dashboardid' => $dashboardids],
'limit' => 1
]);
if ($db_reports) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Dashboard "%1$s" is used in report "%2$s".',
$db_dashboards[$db_reports[0]['dashboardid']]['name'], $db_reports[0]['name']
));
}
}
$db_dashboard_pages = DB::select('dashboard_page', [
'output' => [],
'filter' => ['dashboardid' => $dashboardids],
'preservekeys' => true
]);
if ($db_dashboard_pages) {
$db_widgets = DB::select('widget', [
'output' => [],
'filter' => ['dashboard_pageid' => array_keys($db_dashboard_pages)],
'preservekeys' => true
]);
if ($db_widgets) {
self::deleteWidgets(array_keys($db_widgets));
}
DB::delete('dashboard_page', ['dashboard_pageid' => array_keys($db_dashboard_pages)]);
}
DB::delete('dashboard', ['dashboardid' => $dashboardids]);
$resource = ($this instanceof CDashboard) ? CAudit::RESOURCE_DASHBOARD : CAudit::RESOURCE_TEMPLATE_DASHBOARD;
self::addAuditLog(CAudit::ACTION_DELETE, $resource, $db_dashboards);
return ['dashboardids' => $dashboardids];
}
/**
* Add the existing users, user groups, pages, widgets and widget fields to $db_dashboards whether
* these are affected by the update.
*
* @param array $dashboards
* @param array $db_dashboards
*/
protected function addAffectedObjects(array $dashboards, array &$db_dashboards): void {
// Select pages, users and user groups of these dashboards.
$dashboardids = ['pages' => [], 'users' => [], 'userGroups' => []];
// Select widgets of these pages.
$dashboard_pageids = [];
// Select fields of these widgets.
$widgetids = [];
foreach ($dashboards as $dashboard) {
if (array_key_exists('users', $dashboard)) {
$dashboardids['users'][] = $dashboard['dashboardid'];
$db_dashboards[$dashboard['dashboardid']]['users'] = [];
}
if (array_key_exists('userGroups', $dashboard)) {
$dashboardids['userGroups'][] = $dashboard['dashboardid'];
$db_dashboards[$dashboard['dashboardid']]['userGroups'] = [];
}
if (array_key_exists('pages', $dashboard)) {
$dashboardids['pages'][] = $dashboard['dashboardid'];
$db_dashboards[$dashboard['dashboardid']]['pages'] = [];
foreach ($dashboard['pages'] as $dashboard_page) {
if (array_key_exists('dashboard_pageid', $dashboard_page)
&& array_key_exists('widgets', $dashboard_page)) {
$dashboard_pageids[] = $dashboard_page['dashboard_pageid'];
foreach ($dashboard_page['widgets'] as $widget) {
if (array_key_exists('widgetid', $widget) && array_key_exists('fields', $widget)) {
$widgetids[] = $widget['widgetid'];
}
}
}
}
}
}
if ($dashboardids['users']) {
$options = [
'output' => ['dashboard_userid', 'dashboardid', 'userid', 'permission'],
'filter' => ['dashboardid' => $dashboardids['users']]
];
$db_users = DBselect(DB::makeSql('dashboard_user', $options));
while ($db_user = DBfetch($db_users)) {
$db_dashboards[$db_user['dashboardid']]['users'][$db_user['dashboard_userid']] =
array_diff_key($db_user, array_flip(['dashboardid']));
}
}
if ($dashboardids['userGroups']) {
$options = [
'output' => ['dashboard_usrgrpid', 'dashboardid', 'usrgrpid', 'permission'],
'filter' => ['dashboardid' => $dashboardids['userGroups']]
];
$db_groups = DBselect(DB::makeSql('dashboard_usrgrp', $options));
while ($db_group = DBfetch($db_groups)) {
$db_dashboards[$db_group['dashboardid']]['userGroups'][$db_group['dashboard_usrgrpid']] =
array_diff_key($db_group, array_flip(['dashboardid']));
}
}
if ($dashboardids['pages']) {
$db_dashboard_pages = DB::select('dashboard_page', [
'output' => ['dashboard_pageid', 'dashboardid', 'name', 'display_period', 'sortorder'],
'filter' => ['dashboardid' => $dashboardids['pages']],
'preservekeys' => true
]);
foreach ($db_dashboard_pages as &$db_dashboard_page) {
$db_dashboard_page['widgets'] = [];
}
unset($db_dashboard_page);
if ($dashboard_pageids) {
$db_widgets = DB::select('widget', [
'output' => ['widgetid', 'dashboard_pageid', 'type', 'name', 'x', 'y', 'width', 'height',
'view_mode'
],
'filter' => ['dashboard_pageid' => $dashboard_pageids],
'preservekeys' => true
]);
foreach ($db_widgets as &$db_widget) {
$db_widget['fields'] = [];
}
unset($db_widget);
if ($widgetids) {
$options = [
'output' => ['widget_fieldid', 'widgetid', 'type', 'name', 'value_int', 'value_str',
'value_groupid', 'value_hostid', 'value_itemid', 'value_graphid', 'value_serviceid',
'value_slaid', 'value_userid', 'value_actionid', 'value_mediatypeid', 'value_sysmapid'
],
'filter' => ['widgetid' => $widgetids]
];
$db_widget_fields = DBselect(DB::makeSql('widget_field', $options));
while ($db_widget_field = DBfetch($db_widget_fields)) {
$db_widgets[$db_widget_field['widgetid']]['fields'][$db_widget_field['widget_fieldid']] = [
'widget_fieldid' => $db_widget_field['widget_fieldid'],
'type' => $db_widget_field['type'],
'name' => $db_widget_field['name'],
'value' => $db_widget_field[self::WIDGET_FIELD_TYPE_COLUMNS[$db_widget_field['type']]]
];
}
}
foreach ($db_widgets as $widgetid => $db_widget) {
$db_dashboard_pages[$db_widget['dashboard_pageid']]['widgets'][$widgetid] =
array_diff_key($db_widget, array_flip(['dashboard_pageid']));
}
}
foreach ($db_dashboard_pages as $dashboard_pageid => $db_dashboard_page) {
$db_dashboards[$db_dashboard_page['dashboardid']]['pages'][$dashboard_pageid] =
array_diff_key($db_dashboard_page, array_flip(['dashboardid']));
}
}
}
/**
* Check ownership of the referenced pages and widgets.
*
* @param array $dashboards
* @param array $db_dashboards
*
* @throws APIException.
*/
protected function checkReferences(array $dashboards, array $db_dashboards): void {
foreach ($dashboards as $dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
$db_dashboard_pages = $db_dashboards[$dashboard['dashboardid']]['pages'];
foreach ($dashboard['pages'] as $dashboard_page) {
if (array_key_exists('dashboard_pageid', $dashboard_page)
&& !array_key_exists($dashboard_page['dashboard_pageid'], $db_dashboard_pages)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('No permissions to referred object or it does not exist!')
);
}
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
$db_widgets = array_key_exists('dashboard_pageid', $dashboard_page)
? $db_dashboard_pages[$dashboard_page['dashboard_pageid']]['widgets']
: [];
foreach ($dashboard_page['widgets'] as $widget) {
if (array_key_exists('widgetid', $widget) && !array_key_exists($widget['widgetid'], $db_widgets)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('No permissions to referred object or it does not exist!')
);
}
}
}
}
}
/**
* Check widgets.
*
* Note: For any object with ID in $dashboards a corresponding object in $db_dashboards must exist.
*
* @param array $dashboards
* @param array|null $db_dashboards
*
* @throws APIException if the input is invalid.
*/
protected function checkWidgets(array $dashboards, array $db_dashboards = null): void {
$widget_defaults = DB::getDefaults('widget');
foreach ($dashboards as $dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
$db_dashboard_pages = ($db_dashboards !== null) ? $db_dashboards[$dashboard['dashboardid']]['pages'] : null;
foreach ($dashboard['pages'] as $index => $dashboard_page) {
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
$filled = [];
foreach ($dashboard_page['widgets'] as $widget) {
$widget += array_key_exists('widgetid', $widget)
? $db_dashboard_pages[$dashboard_page['dashboard_pageid']]['widgets'][$widget['widgetid']]
: $widget_defaults;
for ($x = $widget['x']; $x < $widget['x'] + $widget['width']; $x++) {
for ($y = $widget['y']; $y < $widget['y'] + $widget['height']; $y++) {
if (array_key_exists($x, $filled) && array_key_exists($y, $filled[$x])) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Overlapping widgets at X:%3$d, Y:%4$d on page #%2$d of dashboard "%1$s".',
$dashboard['name'], $index + 1, $widget['x'], $widget['y']
)
);
}
$filled[$x][$y] = true;
}
}
if ($widget['x'] + $widget['width'] > DASHBOARD_MAX_COLUMNS
|| $widget['y'] + $widget['height'] > DASHBOARD_MAX_ROWS) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Widget at X:%3$d, Y:%4$d on page #%2$d of dashboard "%1$s" is out of bounds.',
$dashboard['name'], $index + 1, $widget['x'], $widget['y']
)
);
}
}
}
}
}
/**
* Check widget fields.
*
* Note: For any object with ID in $dashboards a corresponding object in $db_dashboards must exist.
*
* @param array $dashboards
* @param array|null $db_dashboards
*
* @throws APIException if the input is invalid.
*/
protected function checkWidgetFields(array $dashboards, array $db_dashboards = null): void {
$ids = [
ZBX_WIDGET_FIELD_TYPE_ITEM => [],
ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE => [],
ZBX_WIDGET_FIELD_TYPE_GRAPH => [],
ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE => [],
ZBX_WIDGET_FIELD_TYPE_GROUP => [],
ZBX_WIDGET_FIELD_TYPE_HOST => [],
ZBX_WIDGET_FIELD_TYPE_MAP => [],
ZBX_WIDGET_FIELD_TYPE_SERVICE => [],
ZBX_WIDGET_FIELD_TYPE_SLA => [],
ZBX_WIDGET_FIELD_TYPE_USER => [],
ZBX_WIDGET_FIELD_TYPE_ACTION => [],
ZBX_WIDGET_FIELD_TYPE_MEDIA_TYPE => []
];
foreach ($dashboards as $dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
$db_dashboard_pages = ($db_dashboards !== null) ? $db_dashboards[$dashboard['dashboardid']]['pages'] : null;
foreach ($dashboard['pages'] as $dashboard_page) {
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
foreach ($dashboard_page['widgets'] as $widget) {
if (!array_key_exists('fields', $widget)) {
continue;
}
$widgetid = array_key_exists('widgetid', $widget) ? $widget['widgetid'] : null;
// Skip testing linked object availability of already stored widget fields.
$stored_widget_fields = [];
if ($widgetid !== null) {
$db_widget = $db_dashboard_pages[$dashboard_page['dashboard_pageid']]['widgets'][$widgetid];
foreach ($db_widget['fields'] as $db_widget_field) {
if (array_key_exists($db_widget_field['type'], $ids)) {
$stored_widget_fields[$db_widget_field['type']][$db_widget_field['value']] = true;
}
}
}
foreach ($widget['fields'] as $widget_field) {
if (array_key_exists($widget_field['type'], $ids)) {
if ($widgetid === null
|| !array_key_exists($widget_field['type'], $stored_widget_fields)
|| !array_key_exists($widget_field['value'],
$stored_widget_fields[$widget_field['type']]
)) {
if ($this instanceof CTemplateDashboard) {
$ids[$widget_field['type']][$widget_field['value']][$dashboard['templateid']] =
true;
}
else {
$ids[$widget_field['type']][$widget_field['value']] = true;
}
}
}
}
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_ITEM]) {
$itemids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_ITEM]);
$db_items = API::Item()->get([
'output' => ($this instanceof CTemplateDashboard) ? ['hostid'] : [],
'itemids' => $itemids,
'webitems' => true,
'preservekeys' => true
]);
foreach ($itemids as $itemid) {
if (!array_key_exists($itemid, $db_items)) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Item with ID "%1$s" is not available.', $itemid));
}
if ($this instanceof CTemplateDashboard) {
foreach (array_keys($ids[ZBX_WIDGET_FIELD_TYPE_ITEM][$itemid]) as $templateid) {
if ($db_items[$itemid]['hostid'] != $templateid) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Item with ID "%1$s" is not available.', $itemid)
);
}
}
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE]) {
$item_prototypeids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE]);
$db_item_prototypes = API::ItemPrototype()->get([
'output' => ($this instanceof CTemplateDashboard) ? ['hostid'] : [],
'itemids' => $item_prototypeids,
'preservekeys' => true
]);
foreach ($item_prototypeids as $item_prototypeid) {
if (!array_key_exists($item_prototypeid, $db_item_prototypes)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Item prototype with ID "%1$s" is not available.', $item_prototypeid)
);
}
if ($this instanceof CTemplateDashboard) {
foreach (array_keys($ids[ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE][$item_prototypeid]) as $templateid) {
if ($db_item_prototypes[$item_prototypeid]['hostid'] != $templateid) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Item prototype with ID "%1$s" is not available.', $item_prototypeid)
);
}
}
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_GRAPH]) {
$graphids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_GRAPH]);
$db_graphs = API::Graph()->get([
'output' => [],
'selectHosts' => ($this instanceof CTemplateDashboard) ? ['hostid'] : null,
'graphids' => $graphids,
'preservekeys' => true
]);
foreach ($graphids as $graphid) {
if (!array_key_exists($graphid, $db_graphs)) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Graph with ID "%1$s" is not available.', $graphid));
}
if ($this instanceof CTemplateDashboard) {
foreach (array_keys($ids[ZBX_WIDGET_FIELD_TYPE_GRAPH][$graphid]) as $templateid) {
if (!in_array($templateid, array_column($db_graphs[$graphid]['hosts'], 'hostid'))) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Graph with ID "%1$s" is not available.', $graphid)
);
}
}
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE]) {
$graph_prototypeids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE]);
$db_graph_prototypes = API::GraphPrototype()->get([
'output' => [],
'selectHosts' => ($this instanceof CTemplateDashboard) ? ['hostid'] : null,
'graphids' => $graph_prototypeids,
'preservekeys' => true
]);
foreach ($graph_prototypeids as $graph_prototypeid) {
if (!array_key_exists($graph_prototypeid, $db_graph_prototypes)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Graph prototype with ID "%1$s" is not available.', $graph_prototypeid)
);
}
if ($this instanceof CTemplateDashboard) {
$templateids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE][$graph_prototypeid]);
foreach ($templateids as $templateid) {
$hostids = array_column($db_graph_prototypes[$graph_prototypeid]['hosts'], 'hostid');
if (!in_array($templateid, $hostids)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Graph prototype with ID "%1$s" is not available.', $graph_prototypeid)
);
}
}
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_GROUP]) {
$groupids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_GROUP]);
$db_groups = API::HostGroup()->get([
'output' => [],
'groupids' => $groupids,
'preservekeys' => true
]);
foreach ($groupids as $groupid) {
if (!array_key_exists($groupid, $db_groups)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Host group with ID "%1$s" is not available.', $groupid)
);
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_HOST]) {
$hostids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_HOST]);
$db_hosts = API::Host()->get([
'output' => [],
'hostids' => $hostids,
'preservekeys' => true
]);
foreach ($hostids as $hostid) {
if (!array_key_exists($hostid, $db_hosts)) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Host with ID "%1$s" is not available.', $hostid));
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_MAP]) {
$sysmapids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_MAP]);
$db_sysmaps = API::Map()->get([
'output' => [],
'sysmapids' => $sysmapids,
'preservekeys' => true
]);
foreach ($sysmapids as $sysmapid) {
if (!array_key_exists($sysmapid, $db_sysmaps)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Map with ID "%1$s" is not available.', $sysmapid)
);
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_SERVICE]) {
$serviceids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_SERVICE]);
$db_services = API::Service()->get([
'output' => [],
'serviceids' => $serviceids,
'preservekeys' => true
]);
foreach ($serviceids as $serviceid) {
if (!array_key_exists($serviceid, $db_services)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Service with ID "%1$s" is not available.', $serviceid)
);
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_SLA]) {
$slaids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_SLA]);
$db_slas = API::Sla()->get([
'output' => [],
'slaids' => $slaids,
'preservekeys' => true
]);
foreach ($slaids as $slaid) {
if (!array_key_exists($slaid, $db_slas)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('SLA with ID "%1$s" is not available.', $slaid)
);
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_USER]) {
$userids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_USER]);
$db_users = API::User()->get([
'output' => [],
'userids' => $userids,
'preservekeys' => true
]);
foreach ($userids as $userid) {
if (!array_key_exists($userid, $db_users)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('User with ID "%1$s" is not available.', $userid)
);
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_ACTION]) {
$actionids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_ACTION]);
$db_actions = API::Action()->get([
'output' => [],
'actionids' => $actionids,
'preservekeys' => true
]);
foreach ($actionids as $actionid) {
if (!array_key_exists($actionid, $db_actions)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Action with ID "%1$s" is not available.', $actionid)
);
}
}
}
if ($ids[ZBX_WIDGET_FIELD_TYPE_MEDIA_TYPE]) {
$mediatypeids = array_keys($ids[ZBX_WIDGET_FIELD_TYPE_MEDIA_TYPE]);
$db_media_types = API::MediaType()->get([
'output' => [],
'mediatypeids' => $mediatypeids,
'preservekeys' => true
]);
foreach ($mediatypeids as $mediatypeid) {
if (!array_key_exists($mediatypeid, $db_media_types)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Media type with ID "%1$s" is not available.', $mediatypeid)
);
}
}
}
}
/**
* Update table "dashboard_page".
*
* Note: For any object with ID in $dashboards a corresponding object in $db_dashboards must exist.
*
* @param array $dashboards
* @param array|null $db_dashboards
*/
protected function updatePages(array &$dashboards, array $db_dashboards = null): void {
$db_dashboard_pages = [];
if ($db_dashboards !== null) {
foreach ($dashboards as $dashboard) {
if (array_key_exists('pages', $dashboard)) {
$db_dashboard_pages += $db_dashboards[$dashboard['dashboardid']]['pages'];
}
}
}
$ins_dashboard_pages = [];
$upd_dashboard_pages = [];
foreach ($dashboards as $dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
foreach ($dashboard['pages'] as $index => $dashboard_page) {
$dashboard_page['sortorder'] = $index;
if (array_key_exists('dashboard_pageid', $dashboard_page)) {
$upd_dashboard_page = DB::getUpdatedValues('dashboard_page', $dashboard_page,
$db_dashboard_pages[$dashboard_page['dashboard_pageid']]
);
if ($upd_dashboard_page) {
$upd_dashboard_pages[] = [
'values' => $upd_dashboard_page,
'where' => ['dashboard_pageid' => $dashboard_page['dashboard_pageid']]
];
}
unset($db_dashboard_pages[$dashboard_page['dashboard_pageid']]);
}
else {
unset($dashboard_page['widgets']);
$ins_dashboard_pages[] = ['dashboardid' => $dashboard['dashboardid']] + $dashboard_page;
}
}
}
if ($ins_dashboard_pages) {
$dashboard_pageids = DB::insert('dashboard_page', $ins_dashboard_pages);
}
if ($upd_dashboard_pages) {
DB::update('dashboard_page', $upd_dashboard_pages);
}
foreach ($dashboards as &$dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
foreach ($dashboard['pages'] as &$dashboard_page) {
if (!array_key_exists('dashboard_pageid', $dashboard_page)) {
$dashboard_page['dashboard_pageid'] = array_shift($dashboard_pageids);
}
}
unset($dashboard_page);
}
unset($dashboard);
$this->updateWidgets($dashboards, $db_dashboards);
if ($db_dashboard_pages) {
DB::delete('dashboard_page', ['dashboard_pageid' => array_keys($db_dashboard_pages)]);
}
}
/**
* Update table "widget".
*
* Note: For any object with ID in $dashboards a corresponding object in $db_dashboards must exist.
*
* @param array $dashboards
* @param array|null $db_dashboards
*/
protected function updateWidgets(array &$dashboards, array $db_dashboards = null): void {
$db_widgets = [];
if ($db_dashboards !== null) {
foreach ($dashboards as $dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
$db_dashboard_pages = $db_dashboards[$dashboard['dashboardid']]['pages'];
foreach ($dashboard['pages'] as $dashboard_page) {
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
if (array_key_exists($dashboard_page['dashboard_pageid'], $db_dashboard_pages)) {
$db_widgets += $db_dashboard_pages[$dashboard_page['dashboard_pageid']]['widgets'];
}
}
}
}
$ins_widgets = [];
$upd_widgets = [];
foreach ($dashboards as $dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
foreach ($dashboard['pages'] as $dashboard_page) {
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
foreach ($dashboard_page['widgets'] as $widget) {
if (array_key_exists('widgetid', $widget)) {
$upd_widget = DB::getUpdatedValues('widget', $widget, $db_widgets[$widget['widgetid']]);
if ($upd_widget) {
$upd_widgets[] = [
'values' => $upd_widget,
'where' => ['widgetid' => $widget['widgetid']]
];
}
unset($db_widgets[$widget['widgetid']]);
}
else {
unset($widget['fields']);
$ins_widgets[] = ['dashboard_pageid' => $dashboard_page['dashboard_pageid']] + $widget;
}
}
}
}
if ($ins_widgets) {
$widgetids = DB::insert('widget', $ins_widgets);
}
if ($upd_widgets) {
DB::update('widget', $upd_widgets);
}
foreach ($dashboards as &$dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
foreach ($dashboard['pages'] as &$dashboard_page) {
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
foreach ($dashboard_page['widgets'] as &$widget) {
if (!array_key_exists('widgetid', $widget)) {
$widget['widgetid'] = array_shift($widgetids);
}
}
unset($widget);
}
unset($dashboard_page);
}
unset($dashboard);
$this->updateWidgetFields($dashboards, $db_dashboards);
if ($db_widgets) {
self::deleteWidgets(array_keys($db_widgets));
}
}
/**
* Update table "widget_field".
*
* Note: For any object with ID in $dashboards a corresponding object in $db_dashboards must exist.
*
* @param array $dashboards
* @param array|null $db_dashboards
*/
protected function updateWidgetFields(array &$dashboards, array $db_dashboards = null): void {
$ins_widget_fields = [];
$upd_widget_fields = [];
$del_widget_fieldids = [];
foreach ($dashboards as &$dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
$db_dashboard_pages = ($db_dashboards !== null) ? $db_dashboards[$dashboard['dashboardid']]['pages'] : [];
foreach ($dashboard['pages'] as &$dashboard_page) {
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
$db_widgets = array_key_exists($dashboard_page['dashboard_pageid'], $db_dashboard_pages)
? $db_dashboard_pages[$dashboard_page['dashboard_pageid']]['widgets']
: [];
foreach ($dashboard_page['widgets'] as &$widget) {
if (!array_key_exists('fields', $widget)) {
continue;
}
$db_widget_fields = array_key_exists($widget['widgetid'], $db_widgets)
? $db_widgets[$widget['widgetid']]['fields']
: [];
foreach ($widget['fields'] as &$widget_field) {
$db_widget_field = current(
array_filter($db_widget_fields,
static function (array $db_widget_field) use ($widget_field): bool {
return ($widget_field['type'] == $db_widget_field['type']
&& $widget_field['name'] === $db_widget_field['name']);
}
)
);
if ($db_widget_field) {
$widget_field['widget_fieldid'] = $db_widget_field['widget_fieldid'];
$upd_widget_field = DB::getUpdatedValues('widget_field',
CArrayHelper::renameKeys($widget_field, [
'value' => self::WIDGET_FIELD_TYPE_COLUMNS[$widget_field['type']]
]),
CArrayHelper::renameKeys($db_widget_field, [
'value' => self::WIDGET_FIELD_TYPE_COLUMNS[$db_widget_field['type']]
])
);
if ($upd_widget_field) {
$upd_widget_fields[] = [
'values' => $upd_widget_field,
'where' => ['widget_fieldid' => $db_widget_field['widget_fieldid']]
];
}
unset($db_widget_fields[$db_widget_field['widget_fieldid']]);
}
else {
$ins_widget_fields[] = ['widgetid' => $widget['widgetid']] +
CArrayHelper::renameKeys($widget_field, [
'value' => self::WIDGET_FIELD_TYPE_COLUMNS[$widget_field['type']]
]);
}
}
unset($widget_field);
$del_widget_fieldids += $db_widget_fields;
}
unset($widget);
}
unset($dashboard_page);
}
unset($dashboard);
if ($ins_widget_fields) {
$widget_fieldids = DB::insert('widget_field', $ins_widget_fields);
}
if ($upd_widget_fields) {
DB::update('widget_field', $upd_widget_fields);
}
if ($del_widget_fieldids) {
DB::delete('widget_field', ['widget_fieldid' => array_keys($del_widget_fieldids)]);
}
foreach ($dashboards as &$dashboard) {
if (!array_key_exists('pages', $dashboard)) {
continue;
}
foreach ($dashboard['pages'] as &$dashboard_page) {
if (!array_key_exists('widgets', $dashboard_page)) {
continue;
}
foreach ($dashboard_page['widgets'] as &$widget) {
if (!array_key_exists('fields', $widget)) {
continue;
}
foreach ($widget['fields'] as &$widget_field) {
if (!array_key_exists('widget_fieldid', $widget_field)) {
$widget_field['widget_fieldid'] = array_shift($widget_fieldids);
}
}
unset($widget_field);
}
unset($widget);
}
unset($dashboard_page);
}
unset($dashboard);
}
/**
* Delete widgets.
*
* This will also delete profile keys related to the specified widgets, including the standard ones:
* - web.dashboard.widget.rf_rate
* - web.dashboard.widget.navtree.item.selected
* - web.dashboard.widget.navtree.item-*.toggle
*
* @static
*
* @param array $widgetids
*/
protected static function deleteWidgets(array $widgetids): void {
DBexecute(
'DELETE FROM profiles'.
' WHERE idx LIKE '.zbx_dbstr('web.dashboard.widget.%').
' AND '.dbConditionId('idx2', $widgetids)
);
DB::delete('widget', ['widgetid' => $widgetids]);
}
protected function addRelatedObjects(array $options, array $result) {
$result = parent::addRelatedObjects($options, $result);
if ($options['selectPages'] !== null) {
foreach ($result as &$row) {
$row['pages'] = [];
}
unset($row);
$widgets_requested = $this->outputIsRequested('widgets', $options['selectPages']);
if ($widgets_requested && is_array($options['selectPages'])) {
$options['selectPages'] = array_diff($options['selectPages'], ['widgets']);
}
$db_dashboard_pages = API::getApiService()->select('dashboard_page', [
'output' => $this->outputExtend($options['selectPages'], ['dashboardid', 'sortorder']),
'filter' => ['dashboardid' => array_keys($result)],
'preservekeys' => true
]);
if ($db_dashboard_pages) {
uasort($db_dashboard_pages, function (array $db_dashboard_page_1, array $db_dashboard_page_2): int {
return $db_dashboard_page_1['sortorder'] <=> $db_dashboard_page_2['sortorder'];
});
if ($widgets_requested) {
foreach ($db_dashboard_pages as &$db_dashboard_page) {
$db_dashboard_page['widgets'] = [];
}
unset($db_dashboard_page);
$db_widgets = DB::select('widget', [
'output' => ['widgetid', 'type', 'name', 'x', 'y', 'width', 'height', 'view_mode',
'dashboard_pageid'
],
'filter' => ['dashboard_pageid' => array_keys($db_dashboard_pages)],
'preservekeys' => true
]);
if ($db_widgets) {
foreach ($db_widgets as &$db_widget) {
$db_widget['fields'] = [];
}
unset($db_widget);
$db_widget_fields = DB::select('widget_field', [
'output' => ['widget_fieldid', 'widgetid', 'type', 'name', 'value_int', 'value_str',
'value_groupid', 'value_hostid', 'value_itemid', 'value_graphid', 'value_serviceid',
'value_slaid', 'value_userid', 'value_actionid', 'value_mediatypeid', 'value_sysmapid'
],
'filter' => [
'widgetid' => array_keys($db_widgets),
'type' => array_keys(self::WIDGET_FIELD_TYPE_COLUMNS)
]
]);
foreach ($db_widget_fields as $db_widget_field) {
$db_widgets[$db_widget_field['widgetid']]['fields'][] = [
'type' => $db_widget_field['type'],
'name' => $db_widget_field['name'],
'value' => $db_widget_field[self::WIDGET_FIELD_TYPE_COLUMNS[$db_widget_field['type']]]
];
}
}
foreach ($db_widgets as $db_widget) {
$dashboard_pageid = $db_widget['dashboard_pageid'];
unset($db_widget['dashboard_pageid']);
$db_dashboard_pages[$dashboard_pageid]['widgets'][] = $db_widget;
}
}
$db_dashboard_pages = $this->unsetExtraFields($db_dashboard_pages, ['dashboard_pageid'],
$options['selectPages']
);
foreach ($db_dashboard_pages as $db_dashboard_page) {
$dashboardid = $db_dashboard_page['dashboardid'];
unset($db_dashboard_page['dashboardid'], $db_dashboard_page['sortorder']);
$result[$dashboardid]['pages'][] = $db_dashboard_page;
}
}
}
return $result;
}
}