['min_user_type' => USER_TYPE_ZABBIX_USER], 'create' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN], 'update' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN], 'delete' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN], 'massadd' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN], 'massupdate' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN], 'massremove' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN] ]; /** * Check for valid host groups and template groups. * * @param array $hosts * @param array|null $db_hosts * * @throws APIException if groups are not valid. */ protected function checkGroups(array $hosts, array $db_hosts = null): void { $id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid'; $edit_groupids = []; foreach ($hosts as $host) { if (!array_key_exists('groups', $host)) { continue; } $groupids = array_column($host['groups'], 'groupid'); if ($db_hosts === null) { $edit_groupids += array_flip($groupids); } else { $db_groupids = array_column($db_hosts[$host[$id_field_name]]['groups'], 'groupid'); $ins_groupids = array_flip(array_diff($groupids, $db_groupids)); $del_groupids = array_flip(array_diff($db_groupids, $groupids)); $edit_groupids += $ins_groupids + $del_groupids; } } if (!$edit_groupids) { return; } $entity = $this instanceof CTemplate ? API::TemplateGroup() : API::HostGroup(); $count = $entity->get([ 'countOutput' => true, 'groupids' => array_keys($edit_groupids), 'editable' => true ]); if ($count != count($edit_groupids)) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); } } /** * Check for unique host names. * * @param array $hosts * @param array|null $db_hosts * * @throws APIException if host names are not unique. */ protected function checkDuplicates(array $hosts, array $db_hosts = null): void { $id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid'; $h_names = []; $v_names = []; foreach ($hosts as $host) { if (array_key_exists('host', $host)) { if ($db_hosts === null || $host['host'] !== $db_hosts[$host[$id_field_name]]['host']) { $h_names[] = $host['host']; } } if (array_key_exists('name', $host)) { if ($db_hosts === null || $host['name'] !== $db_hosts[$host[$id_field_name]]['name']) { $v_names[] = $host['name']; } } } if ($h_names) { $duplicates = DB::select('hosts', [ 'output' => ['host', 'status'], 'filter' => [ 'flags' => [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_CREATED], 'status' => [HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE], 'host' => $h_names ], 'limit' => 1 ]); if ($duplicates) { $error = ($duplicates[0]['status'] == HOST_STATUS_TEMPLATE) ? _s('Template with host name "%1$s" already exists.', $duplicates[0]['host']) : _s('Host with host name "%1$s" already exists.', $duplicates[0]['host']); self::exception(ZBX_API_ERROR_PARAMETERS, $error); } } if ($v_names) { $duplicates = DB::select('hosts', [ 'output' => ['name', 'status'], 'filter' => [ 'flags' => [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_CREATED], 'status' => [HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE], 'name' => $v_names ], 'limit' => 1 ]); if ($duplicates) { $error = ($duplicates[0]['status'] == HOST_STATUS_TEMPLATE) ? _s('Template with visible name "%1$s" already exists.', $duplicates[0]['name']) : _s('Host with visible name "%1$s" already exists.', $duplicates[0]['name']); self::exception(ZBX_API_ERROR_PARAMETERS, $error); } } } /** * Check templates links for given data of mass API methods. * * @param string $method * @param array $templateids * @param array $db_hosts */ protected function massCheckTemplatesLinks(string $method, array $templateids, array $db_hosts, array $templateids_clear = []): void { $ins_templates = []; $del_links = []; $check_double_linkage = false; $del_templates = []; $del_links_clear = []; foreach ($db_hosts as $hostid => $db_host) { $db_templateids = array_column($db_host['templates'], 'templateid'); if ($method === 'massadd') { $_templateids = array_diff($templateids, $db_templateids); } elseif ($method === 'massremove') { $_templateids = array_diff($db_templateids, $templateids); } else { $_templateids = $templateids; } $permitted_templateids = $_templateids; $templates_count = count($permitted_templateids); $upd_templateids = []; if (array_key_exists('nopermissions_templates', $db_host)) { foreach ($db_host['nopermissions_templates'] as $db_template) { $_templateids[] = $db_template['templateid']; $templates_count++; $upd_templateids[] = $db_template['templateid']; } } foreach ($permitted_templateids as $templateid) { $index = array_search($templateid, $db_templateids); if ($index !== false) { $upd_templateids[] = $templateid; unset($db_templateids[$index]); } else { $ins_templates[$templateid][$hostid] = $_templateids; if ($this instanceof CTemplate || $templates_count > 1) { $check_double_linkage = true; } } } foreach ($db_templateids as $db_templateid) { $del_links[$db_templateid][$hostid] = true; if ($upd_templateids) { $del_templates[$db_templateid][$hostid] = $upd_templateids; } if (array_key_exists($db_templateid, $templateids_clear)) { $del_links_clear[$db_templateid][$hostid] = true; } } } if ($del_templates) { $this->checkTriggerExpressionsOfDelTemplates($del_templates); } if ($del_links_clear) { $this->checkTriggerDependenciesOfHostTriggers($del_links_clear); } if ($ins_templates) { if ($this instanceof CTemplate) { self::checkCircularLinkageNew($ins_templates, $del_links); } if ($check_double_linkage) { $this->checkDoubleLinkageNew($ins_templates, $del_links, null); } $this->checkTriggerDependenciesOfInsTemplates($ins_templates); $this->checkTriggerExpressionsOfInsTemplates($ins_templates); } } /** * Update table "hosts_groups" and populate hosts.groups by "hostgroupid" property. * * @param array $hosts * @param array|null $db_hosts */ protected function updateGroups(array &$hosts, array $db_hosts = null): void { $id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid'; $ins_hosts_groups = []; $del_hostgroupids = []; foreach ($hosts as &$host) { if (!array_key_exists('groups', $host)) { continue; } $db_groups = ($db_hosts !== null) ? array_column($db_hosts[$host[$id_field_name]]['groups'], null, 'groupid') : []; foreach ($host['groups'] as &$group) { if (array_key_exists($group['groupid'], $db_groups)) { $group['hostgroupid'] = $db_groups[$group['groupid']]['hostgroupid']; unset($db_groups[$group['groupid']]); } else { $ins_hosts_groups[] = [ 'hostid' => $host[$id_field_name], 'groupid' => $group['groupid'] ]; } } unset($group); $del_hostgroupids = array_merge($del_hostgroupids, array_column($db_groups, 'hostgroupid')); } unset($host); if ($del_hostgroupids) { DB::delete('hosts_groups', ['hostgroupid' => $del_hostgroupids]); } if ($ins_hosts_groups) { $hostgroupids = DB::insertBatch('hosts_groups', $ins_hosts_groups); } foreach ($hosts as &$host) { if (!array_key_exists('groups', $host)) { continue; } foreach ($host['groups'] as &$group) { if (!array_key_exists('hostgroupid', $group)) { $group['hostgroupid'] = array_shift($hostgroupids); } } unset($group); } unset($host); } /** * Update table "hosts_templates" and change objects of linked or unliked templates on target hosts or templates. * * @param array $hosts * @param array|null $db_hosts * @param array|null $upd_hostids */ protected function updateTemplates(array &$hosts, array &$db_hosts = null, array &$upd_hostids = null): void { $id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid'; parent::updateTemplates($hosts, $db_hosts); $ins_links = []; $del_links = []; $del_links_clear = []; foreach ($hosts as $host) { if (!array_key_exists('templates', $host) && !array_key_exists('templates_clear', $host)) { continue; } $db_templates = ($db_hosts !== null) ? array_column($db_hosts[$host[$id_field_name]]['templates'], null, 'templateid') : []; if (array_key_exists('templates', $host)) { foreach ($host['templates'] as $template) { if (array_key_exists($template['templateid'], $db_templates)) { unset($db_templates[$template['templateid']]); } else { $ins_links[$template['templateid']][] = $host[$id_field_name]; } } $templates_clear = array_key_exists('templates_clear', $host) ? array_column($host['templates_clear'], null, 'templateid') : []; foreach ($db_templates as $del_template) { if (array_key_exists($del_template['templateid'], $templates_clear)) { $del_links_clear[$del_template['templateid']][] = $host[$id_field_name]; } else { $del_links[$del_template['templateid']][] = $host[$id_field_name]; } } } elseif (array_key_exists('templates_clear', $host)) { foreach ($host['templates_clear'] as $template) { $del_links_clear[$template['templateid']][] = $host[$id_field_name]; } } } while ($del_links_clear) { $templateid = key($del_links_clear); $hostids = reset($del_links_clear); $templateids = [$templateid]; unset($del_links_clear[$templateid]); foreach ($del_links_clear as $templateid => $_hostids) { if ($_hostids === $hostids) { $templateids[] = $templateid; unset($del_links_clear[$templateid]); } } self::unlinkTemplatesObjects($templateids, $hostids, true); } while ($del_links) { $templateid = key($del_links); $hostids = reset($del_links); $templateids = [$templateid]; unset($del_links[$templateid]); foreach ($del_links as $templateid => $_hostids) { if ($_hostids === $hostids) { $templateids[] = $templateid; unset($del_links[$templateid]); } } self::unlinkTemplatesObjects($templateids, $hostids); } while ($ins_links) { $templateid = key($ins_links); $hostids = reset($ins_links); $templateids = [$templateid]; unset($ins_links[$templateid]); foreach ($ins_links as $templateid => $_hostids) { if ($_hostids === $hostids) { $templateids[] = $templateid; unset($ins_links[$templateid]); } } self::linkTemplatesObjects($templateids, $hostids); } } /** * Unlink or clear objects of given templates from given hosts or templates. * * @param array $templateids * @param array|null $hostids * @param bool $clear */ protected static function unlinkTemplatesObjects(array $templateids, array $hostids = null, bool $clear = false): void { $flags = ($clear) ? [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE] : [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE, ZBX_FLAG_DISCOVERY_PROTOTYPE]; // triggers $db_triggers = DBselect( 'SELECT DISTINCT f.triggerid'. ' FROM functions f,items i'. ' WHERE f.itemid=i.itemid'. ' AND '.dbConditionInt('i.hostid', $templateids) ); $tpl_triggerids = DBfetchColumn($db_triggers, 'triggerid'); $upd_triggers = [ ZBX_FLAG_DISCOVERY_NORMAL => [], ZBX_FLAG_DISCOVERY_PROTOTYPE => [] ]; if ($tpl_triggerids) { $sql_distinct = ($hostids !== null) ? ' DISTINCT' : ''; $sql_from = ($hostids !== null) ? ',functions f,items i' : ''; $sql_where = ($hostids !== null) ? ' AND t.triggerid=f.triggerid'. ' AND f.itemid=i.itemid'. ' AND '.dbConditionInt('i.hostid', $hostids) : ''; $db_triggers = DBSelect( 'SELECT'.$sql_distinct.' t.triggerid,t.flags'. ' FROM triggers t'.$sql_from. ' WHERE '.dbConditionInt('t.templateid', $tpl_triggerids). ' AND '.dbConditionInt('t.flags', $flags). $sql_where ); while ($db_trigger = DBfetch($db_triggers)) { if ($clear) { $upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = true; } else { $upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = [ 'values' => ['templateid' => 0], 'where' => ['triggerid' => $db_trigger['triggerid']] ]; } } if (!$clear && ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])) { $db_triggers = DBselect( 'SELECT DISTINCT t.triggerid,t.flags'. ' FROM triggers t,functions f,items i,hosts h'. ' WHERE t.triggerid=f.triggerid'. ' AND f.itemid=i.itemid'. ' AND i.hostid=h.hostid'. ' AND h.status='.HOST_STATUS_TEMPLATE. ' AND '.dbConditionInt('t.triggerid', array_keys( $upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE] )) ); while ($db_trigger = DBfetch($db_triggers)) { $upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']]['values']['uuid'] = generateUuidV4(); } } } if ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]) { if ($clear) { CTriggerManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL])); } else { DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]); } } if ($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]) { if ($clear) { CTriggerPrototypeManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])); } else { DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]); } } // graphs $db_tpl_graphs = DBselect( 'SELECT DISTINCT g.graphid'. ' FROM graphs g,graphs_items gi,items i'. ' WHERE g.graphid=gi.graphid'. ' AND gi.itemid=i.itemid'. ' AND '.dbConditionInt('i.hostid', $templateids). ' AND '.dbConditionInt('g.flags', $flags) ); $tpl_graphids = []; while ($db_tpl_graph = DBfetch($db_tpl_graphs)) { $tpl_graphids[] = $db_tpl_graph['graphid']; } if ($tpl_graphids) { $upd_graphs = [ ZBX_FLAG_DISCOVERY_NORMAL => [], ZBX_FLAG_DISCOVERY_PROTOTYPE => [] ]; $sql = ($hostids !== null) ? 'SELECT DISTINCT g.graphid,g.flags'. ' FROM graphs g,graphs_items gi,items i'. ' WHERE g.graphid=gi.graphid'. ' AND gi.itemid=i.itemid'. ' AND '.dbConditionInt('g.templateid', $tpl_graphids). ' AND '.dbConditionInt('i.hostid', $hostids) : 'SELECT g.graphid,g.flags'. ' FROM graphs g'. ' WHERE '.dbConditionInt('g.templateid', $tpl_graphids); $db_graphs = DBSelect($sql); while ($db_graph = DBfetch($db_graphs)) { if ($clear) { $upd_graphs[$db_graph['flags']][$db_graph['graphid']] = true; } else { $upd_graphs[$db_graph['flags']][$db_graph['graphid']] = [ 'values' => ['templateid' => 0], 'where' => ['graphid' => $db_graph['graphid']] ]; } } if (!$clear && ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])) { $db_graphs = DBselect( 'SELECT DISTINCT g.graphid,g.flags'. ' FROM graphs g,graphs_items gi,items i,hosts h'. ' WHERE g.graphid=gi.graphid'. ' AND gi.itemid=i.itemid'. ' AND i.hostid=h.hostid'. ' AND h.status='.HOST_STATUS_TEMPLATE. ' AND '.dbConditionInt('g.graphid', array_keys( $upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE] )) ); while ($db_graph = DBfetch($db_graphs)) { $upd_graphs[$db_graph['flags']][$db_graph['graphid']]['values']['uuid'] = generateUuidV4(); } } if ($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]) { if ($clear) { CGraphPrototypeManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])); } else { DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]); } } if ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]) { if ($clear) { CGraphManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL])); } else { DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]); } } } if ($clear) { CDiscoveryRule::clearTemplateObjects($templateids, $hostids); CItem::clearTemplateObjects($templateids, $hostids); CHttpTest::clearTemplateObjects($templateids, $hostids); } else { CDiscoveryRule::unlinkTemplateObjects($templateids, $hostids); CItem::unlinkTemplateObjects($templateids, $hostids); CHttpTest::unlinkTemplateObjects($templateids, $hostids); } } /** * Add objects of given templates to given hosts or templates. * * @param array $templateids * @param array $hostids */ private static function linkTemplatesObjects(array $templateids, array $hostids): void { // TODO: Modify parameters of syncTemplates methods when complete audit log will be implementing for hosts. $link_request = [ 'templateids' => $templateids, 'hostids' => $hostids ]; foreach ($templateids as $templateid) { // Fist link web items, so that later regular items can use web item as their master item. Manager::HttpTest()->link($templateid, $hostids); } CItem::linkTemplateObjects($templateids, $hostids); API::Trigger()->syncTemplates($link_request); API::Graph()->syncTemplates($link_request); CDiscoveryRule::linkTemplateObjects($templateids, $hostids); CTriggerGeneral::syncTemplateDependencies($link_request['templateids'], $link_request['hostids']); } /** * Checks if the current user has access to the given hosts and templates. Assumes the "hostid" field is valid. * * @param array $hostids an array of host or template IDs * * @throws APIException if the user doesn't have write permissions for the given hosts. */ protected function checkHostPermissions(array $hostids) { if ($hostids) { $hostids = array_unique($hostids); $count = API::Host()->get([ 'countOutput' => true, 'hostids' => $hostids, 'editable' => true ]); if ($count == count($hostids)) { return; } $count += API::Template()->get([ 'countOutput' => true, 'templateids' => $hostids, 'editable' => true ]); if ($count != count($hostids)) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!') ); } } } /** * Allows to: * - add hosts to groups; * - link templates to hosts; * - add new macros to hosts. * * Supported $data parameters are: * - hosts - an array of hosts to be updated * - templates - an array of templates to be updated * - groups - an array of host groups to add the host to * - templates_link - an array of templates to link to the hosts * - macros - an array of macros to create on the host * * @param array $data * * @return array */ public function massAdd(array $data) { $hostIds = zbx_objectValues($data['hosts'], 'hostid'); $templateIds = zbx_objectValues($data['templates'], 'templateid'); $allHostIds = array_merge($hostIds, $templateIds); // add groups if (array_key_exists('groups', $data) && $data['groups']) { $options = ['groups' => $data['groups']]; if ($data['hosts']) { $options += [ 'hosts' => array_map( static function($host) { return array_intersect_key($host, array_flip(['hostid'])); }, $data['hosts'] ) ]; } if ($data['templates']) { $options += [ 'templates' => array_map( static function($template) { return array_intersect_key($template, array_flip(['templateid'])); }, $data['templates'] ) ]; } API::HostGroup()->massAdd($options); } // link templates if (!empty($data['templates_link'])) { $this->checkHostPermissions($allHostIds); $this->link(zbx_objectValues(zbx_toArray($data['templates_link']), 'templateid'), $allHostIds); } // create macros if (!empty($data['macros'])) { $data['macros'] = zbx_toArray($data['macros']); $hostMacrosToAdd = []; foreach ($data['macros'] as $hostMacro) { foreach ($allHostIds as $hostid) { $hostMacro['hostid'] = $hostid; $hostMacrosToAdd[] = $hostMacro; } } API::UserMacro()->create($hostMacrosToAdd); } $ids = ['hostids' => $hostIds, 'templateids' => $templateIds]; return [$this->pkOption() => $ids[$this->pkOption()]]; } /** * Allows to: * - remove hosts from groups; * - unlink and clear templates from hosts; * - remove macros from hosts. * * Supported $data parameters are: * - hostids - an array of host IDs to be updated * - templateids - an array of template IDs to be updated * - groupids - an array of host group IDs the hosts should be removed from * - templateids_link - an array of template IDs to unlink from the hosts * - templateids_clear - an array of template IDs to unlink and clear from the hosts * - macros - an array of macros to delete from the hosts * * @param array $data * * @return array */ public function massRemove(array $data) { $allHostIds = array_merge($data['hostids'], $data['templateids']); $this->checkHostPermissions($allHostIds); if (!empty($data['templateids_link'])) { $this->unlink(zbx_toArray($data['templateids_link']), $allHostIds); } if (isset($data['templateids_clear'])) { $this->unlink(zbx_toArray($data['templateids_clear']), $allHostIds, true); } if (array_key_exists('macros', $data)) { if (!$data['macros']) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Empty input parameter.')); } $hostMacros = API::UserMacro()->get([ 'output' => ['hostmacroid'], 'hostids' => $allHostIds, 'filter' => [ 'macro' => $data['macros'] ] ]); $hostMacroIds = zbx_objectValues($hostMacros, 'hostmacroid'); if ($hostMacroIds) { API::UserMacro()->delete($hostMacroIds); } } if (isset($data['groupids'])) { $options = ['groupids' => $data['groupids']]; if ($data['hostids']) { $options['hostids'] = $data['hostids']; } if ($data['templateids']) { $options['templateids'] = $data['templateids']; } API::HostGroup()->massRemove($options); } return [$this->pkOption() => $data[$this->pkOption()]]; } protected function link(array $templateIds, array $targetIds) { $hosts_linkage_inserts = parent::link($templateIds, $targetIds); $templates_hostids = []; $link_requests = []; foreach ($hosts_linkage_inserts as $host_tpl_ids) { $templates_hostids[$host_tpl_ids['templateid']][] = $host_tpl_ids['hostid']; } foreach ($templates_hostids as $templateid => $hostids) { // Fist link web items, so that later regular items can use web item as their master item. Manager::HttpTest()->link($templateid, $hostids); } while ($templates_hostids) { $templateid = key($templates_hostids); $link_request = [ 'hostids' => reset($templates_hostids), 'templateids' => [$templateid] ]; unset($templates_hostids[$templateid]); foreach ($templates_hostids as $templateid => $hostids) { if ($link_request['hostids'] === $hostids) { $link_request['templateids'][] = $templateid; unset($templates_hostids[$templateid]); } } $link_requests[] = $link_request; } foreach ($link_requests as $link_request) { CItem::linkTemplateObjects($link_request['templateids'], $link_request['hostids']); } foreach ($link_requests as $link_request) { API::Trigger()->syncTemplates($link_request); API::Graph()->syncTemplates($link_request); } foreach ($link_requests as $link_request){ CDiscoveryRule::linkTemplateObjects($link_request['templateids'], $link_request['hostids']); CTriggerGeneral::syncTemplateDependencies($link_request['templateids'], $link_request['hostids']); } return $hosts_linkage_inserts; } /** * Unlinks the templates from the given hosts. If $targetids is set to null, the templates will be unlinked from * all hosts. * * @param array $templateids * @param null|array $targetids the IDs of the hosts to unlink the templates from * @param bool $clear delete all of the inherited objects from the hosts */ protected function unlink($templateids, $targetids = null, $clear = false) { $flags = ($clear) ? [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE] : [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE, ZBX_FLAG_DISCOVERY_PROTOTYPE]; // check that all triggers on templates that we unlink, don't have items from another templates $sql = 'SELECT DISTINCT t.description'. ' FROM triggers t,functions f,items i'. ' WHERE t.triggerid=f.triggerid'. ' AND f.itemid=i.itemid'. ' AND '.dbConditionInt('i.hostid', $templateids). ' AND EXISTS ('. 'SELECT ff.triggerid'. ' FROM functions ff,items ii'. ' WHERE ff.itemid=ii.itemid'. ' AND ff.triggerid=t.triggerid'. ' AND '.dbConditionInt('ii.hostid', $templateids, true). ')'. ' AND t.flags='.ZBX_FLAG_DISCOVERY_NORMAL; if ($dbTrigger = DBfetch(DBSelect($sql, 1))) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot unlink trigger "%1$s", it has items from template that is left linked to host.', $dbTrigger['description'] ) ); } $templ_triggerids = []; $db_triggers = DBselect( 'SELECT DISTINCT f.triggerid'. ' FROM functions f,items i'. ' WHERE f.itemid=i.itemid'. ' AND '.dbConditionInt('i.hostid', $templateids) ); while ($db_trigger = DBfetch($db_triggers)) { $templ_triggerids[] = $db_trigger['triggerid']; } $upd_triggers = [ ZBX_FLAG_DISCOVERY_NORMAL => [], ZBX_FLAG_DISCOVERY_PROTOTYPE => [] ]; if ($templ_triggerids) { $sql_distinct = ($targetids !== null) ? ' DISTINCT' : ''; $sql_from = ($targetids !== null) ? ',functions f,items i' : ''; $sql_where = ($targetids !== null) ? ' AND t.triggerid=f.triggerid'. ' AND f.itemid=i.itemid'. ' AND '.dbConditionInt('i.hostid', $targetids) : ''; $db_triggers = DBSelect( 'SELECT'.$sql_distinct.' t.triggerid,t.flags'. ' FROM triggers t'.$sql_from. ' WHERE '.dbConditionInt('t.templateid', $templ_triggerids). ' AND '.dbConditionInt('t.flags', $flags). $sql_where ); while ($db_trigger = DBfetch($db_triggers)) { if ($clear) { $upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = true; } else { $upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = [ 'values' => ['templateid' => 0], 'where' => ['triggerid' => $db_trigger['triggerid']] ]; } } if (!$clear && ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])) { $db_triggers = DBselect( 'SELECT DISTINCT t.triggerid,t.flags'. ' FROM triggers t,functions f,items i,hosts h'. ' WHERE t.triggerid=f.triggerid'. ' AND f.itemid=i.itemid'. ' AND i.hostid=h.hostid'. ' AND h.status='.HOST_STATUS_TEMPLATE. ' AND '.dbConditionInt('t.triggerid', array_keys( $upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE] )) ); while ($db_trigger = DBfetch($db_triggers)) { $upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']]['values']['uuid'] = generateUuidV4(); } } } if ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]) { if ($clear) { CTriggerManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL])); } else { DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]); } } if ($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]) { if ($clear) { CTriggerPrototypeManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])); } else { DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]); } } /* GRAPHS {{{ */ $db_tpl_graphs = DBselect( 'SELECT DISTINCT g.graphid'. ' FROM graphs g,graphs_items gi,items i'. ' WHERE g.graphid=gi.graphid'. ' AND gi.itemid=i.itemid'. ' AND '.dbConditionInt('i.hostid', $templateids). ' AND '.dbConditionInt('g.flags', $flags) ); $tpl_graphids = []; while ($db_tpl_graph = DBfetch($db_tpl_graphs)) { $tpl_graphids[] = $db_tpl_graph['graphid']; } if ($tpl_graphids) { $upd_graphs = [ ZBX_FLAG_DISCOVERY_NORMAL => [], ZBX_FLAG_DISCOVERY_PROTOTYPE => [] ]; $sql = ($targetids !== null) ? 'SELECT DISTINCT g.graphid,g.flags'. ' FROM graphs g,graphs_items gi,items i'. ' WHERE g.graphid=gi.graphid'. ' AND gi.itemid=i.itemid'. ' AND '.dbConditionInt('g.templateid', $tpl_graphids). ' AND '.dbConditionInt('i.hostid', $targetids) : 'SELECT g.graphid,g.flags'. ' FROM graphs g'. ' WHERE '.dbConditionInt('g.templateid', $tpl_graphids); $db_graphs = DBSelect($sql); while ($db_graph = DBfetch($db_graphs)) { if ($clear) { $upd_graphs[$db_graph['flags']][$db_graph['graphid']] = true; } else { $upd_graphs[$db_graph['flags']][$db_graph['graphid']] = [ 'values' => ['templateid' => 0], 'where' => ['graphid' => $db_graph['graphid']] ]; } } if (!$clear && ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])) { $db_graphs = DBselect( 'SELECT DISTINCT g.graphid,g.flags'. ' FROM graphs g,graphs_items gi,items i,hosts h'. ' WHERE g.graphid=gi.graphid'. ' AND gi.itemid=i.itemid'. ' AND i.hostid=h.hostid'. ' AND h.status='.HOST_STATUS_TEMPLATE. ' AND '.dbConditionInt('g.graphid', array_keys( $upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE] )) ); while ($db_graph = DBfetch($db_graphs)) { $upd_graphs[$db_graph['flags']][$db_graph['graphid']]['values']['uuid'] = generateUuidV4(); } } if ($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]) { if ($clear) { CGraphPrototypeManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])); } else { DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]); } } if ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]) { if ($clear) { CGraphManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL])); } else { DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]); } } } /* }}} GRAPHS */ if ($clear) { CDiscoveryRule::clearTemplateObjects($templateids, $targetids); CItem::clearTemplateObjects($templateids, $targetids); CHttpTest::clearTemplateObjects($templateids, $targetids); } else { CDiscoveryRule::unlinkTemplateObjects($templateids, $targetids); CItem::unlinkTemplateObjects($templateids, $targetids); CHttpTest::unlinkTemplateObjects($templateids, $targetids); } parent::unlink($templateids, $targetids); } protected function addRelatedObjects(array $options, array $result) { $result = parent::addRelatedObjects($options, $result); $hostids = array_keys($result); // Add templates. if ($options['selectParentTemplates'] !== null) { if ($options['selectParentTemplates'] != API_OUTPUT_COUNT) { $templates = []; // Get template IDs for each host and additional field from relation table if necessary. $hosts_templates = DBfetchArray(DBselect( 'SELECT ht.hostid,ht.templateid'. ($this->outputIsRequested('link_type', $options['selectParentTemplates']) ? ',ht.link_type' : '' ). ' FROM hosts_templates ht'. ' WHERE '.dbConditionId('ht.hostid', array_keys($result)) )); if ($hosts_templates) { // Select also template ID if not selected. It can be removed from results if not requested. $template_options = $this->outputIsRequested('templateid', $options['selectParentTemplates']) ? $options['selectParentTemplates'] : array_merge($options['selectParentTemplates'], ['templateid']); /* * Since templates API does not have "link_type" field, remove it from request, so that template.get * validation may pass successfully. */ if ($this->outputIsRequested('link_type', $template_options) && is_array($template_options) && ($key = array_search('link_type', $template_options)) !== false) { unset($template_options[$key]); } $templates = API::Template()->get([ 'output' => $template_options, 'templateids' => array_column($hosts_templates, 'templateid'), 'nopermissions' => $options['nopermissions'], 'preservekeys' => true ]); if ($options['limitSelects'] !== null) { order_result($templates, 'host'); } } /* * In order to correctly slice the ordered templates in case of "limitSelects", first they must be * mapped for each host. Otherwise incorrect results may appear. $relation_map key is the host ID, and * values are template ID and, if selected, "link_type". */ $relation_map = []; foreach ($hosts_templates as $host_template) { if (!array_key_exists($host_template['hostid'], $relation_map)) { $relation_map[$host_template['hostid']] = []; } $related_fields = ['templateid' => $host_template['templateid']]; if ($this->outputIsRequested('link_type', $options['selectParentTemplates'])) { $related_fields['link_type'] = $host_template['link_type']; } $relation_map[$host_template['hostid']][] = $related_fields; } foreach ($result as $hostid => &$host) { $host['parentTemplates'] = []; if (array_key_exists($hostid, $relation_map)) { $templateids = array_column($relation_map[$hostid], 'templateid'); $templateids = array_combine($templateids, $templateids); // Find the matching templates and limit the results if necessary. $host['parentTemplates'] = array_values(array_intersect_key($templates, $templateids)); if ($options['limitSelects'] !== null && $options['limitSelects'] != 0) { $host['parentTemplates'] = array_slice($host['parentTemplates'], 0, $options['limitSelects'] ); } // Append the additional field from relation table. if ($this->outputIsRequested('link_type', $options['selectParentTemplates'])) { foreach ($host['parentTemplates'] as &$template) { foreach ($relation_map[$hostid] as $rel_template) { if (bccomp($template['templateid'], $rel_template['templateid']) == 0) { $template['link_type'] = $rel_template['link_type']; } } } } // Unset fields if they were not requested. $host['parentTemplates'] = $this->unsetExtraFields($host['parentTemplates'], ['templateid'], $options['selectParentTemplates'] ); } } unset($host); } else { $templates = API::Template()->get([ 'hostids' => $hostids, 'countOutput' => true, 'groupCount' => true ]); $templates = zbx_toHash($templates, 'hostid'); foreach ($result as $hostid => $host) { $result[$hostid]['parentTemplates'] = array_key_exists($hostid, $templates) ? $templates[$hostid]['rowscount'] : '0'; } } } if ($options['selectItems'] !== null) { if ($options['selectItems'] != API_OUTPUT_COUNT) { $items = API::Item()->get([ 'output' => $this->outputExtend($options['selectItems'], ['hostid', 'itemid']), 'hostids' => $hostids, 'nopermissions' => true, 'preservekeys' => true ]); if (!is_null($options['limitSelects'])) { order_result($items, 'name'); } $relationMap = $this->createRelationMap($items, 'hostid', 'itemid'); $items = $this->unsetExtraFields($items, ['hostid', 'itemid'], $options['selectItems']); $result = $relationMap->mapMany($result, $items, 'items', $options['limitSelects']); } else { $items = API::Item()->get([ 'hostids' => $hostids, 'nopermissions' => true, 'countOutput' => true, 'groupCount' => true ]); $items = zbx_toHash($items, 'hostid'); foreach ($result as $hostid => $host) { $result[$hostid]['items'] = array_key_exists($hostid, $items) ? $items[$hostid]['rowscount'] : '0'; } } } if ($options['selectDiscoveries'] !== null) { if ($options['selectDiscoveries'] != API_OUTPUT_COUNT) { $items = API::DiscoveryRule()->get([ 'output' => $this->outputExtend($options['selectDiscoveries'], ['hostid', 'itemid']), 'hostids' => $hostids, 'nopermissions' => true, 'preservekeys' => true ]); if (!is_null($options['limitSelects'])) { order_result($items, 'name'); } $relationMap = $this->createRelationMap($items, 'hostid', 'itemid'); $items = $this->unsetExtraFields($items, ['hostid', 'itemid'], $options['selectDiscoveries']); $result = $relationMap->mapMany($result, $items, 'discoveries', $options['limitSelects']); } else { $items = API::DiscoveryRule()->get([ 'hostids' => $hostids, 'nopermissions' => true, 'countOutput' => true, 'groupCount' => true ]); $items = zbx_toHash($items, 'hostid'); foreach ($result as $hostid => $host) { $result[$hostid]['discoveries'] = array_key_exists($hostid, $items) ? $items[$hostid]['rowscount'] : '0'; } } } if ($options['selectTriggers'] !== null) { if ($options['selectTriggers'] != API_OUTPUT_COUNT) { $triggers = []; $relationMap = new CRelationMap(); // discovered items $res = DBselect( 'SELECT i.hostid,f.triggerid'. ' FROM items i,functions f'. ' WHERE '.dbConditionInt('i.hostid', $hostids). ' AND i.itemid=f.itemid' ); while ($relation = DBfetch($res)) { $relationMap->addRelation($relation['hostid'], $relation['triggerid']); } $related_ids = $relationMap->getRelatedIds(); if ($related_ids) { $triggers = API::Trigger()->get([ 'output' => $options['selectTriggers'], 'triggerids' => $related_ids, 'preservekeys' => true ]); if (!is_null($options['limitSelects'])) { order_result($triggers, 'description'); } } $result = $relationMap->mapMany($result, $triggers, 'triggers', $options['limitSelects']); } else { $triggers = API::Trigger()->get([ 'hostids' => $hostids, 'countOutput' => true, 'groupCount' => true ]); $triggers = zbx_toHash($triggers, 'hostid'); foreach ($result as $hostid => $host) { $result[$hostid]['triggers'] = array_key_exists($hostid, $triggers) ? $triggers[$hostid]['rowscount'] : '0'; } } } if ($options['selectGraphs'] !== null) { if ($options['selectGraphs'] != API_OUTPUT_COUNT) { $graphs = []; $relationMap = new CRelationMap(); // discovered items $res = DBselect( 'SELECT i.hostid,gi.graphid'. ' FROM items i,graphs_items gi'. ' WHERE '.dbConditionInt('i.hostid', $hostids). ' AND i.itemid=gi.itemid' ); while ($relation = DBfetch($res)) { $relationMap->addRelation($relation['hostid'], $relation['graphid']); } $related_ids = $relationMap->getRelatedIds(); if ($related_ids) { $graphs = API::Graph()->get([ 'output' => $options['selectGraphs'], 'graphids' => $related_ids, 'preservekeys' => true ]); if (!is_null($options['limitSelects'])) { order_result($graphs, 'name'); } } $result = $relationMap->mapMany($result, $graphs, 'graphs', $options['limitSelects']); } else { $graphs = API::Graph()->get([ 'hostids' => $hostids, 'countOutput' => true, 'groupCount' => true ]); $graphs = zbx_toHash($graphs, 'hostid'); foreach ($result as $hostid => $host) { $result[$hostid]['graphs'] = array_key_exists($hostid, $graphs) ? $graphs[$hostid]['rowscount'] : '0'; } } } if ($options['selectHttpTests'] !== null) { if ($options['selectHttpTests'] != API_OUTPUT_COUNT) { $httpTests = API::HttpTest()->get([ 'output' => $this->outputExtend($options['selectHttpTests'], ['hostid', 'httptestid']), 'hostids' => $hostids, 'nopermissions' => true, 'preservekeys' => true ]); if (!is_null($options['limitSelects'])) { order_result($httpTests, 'name'); } $relationMap = $this->createRelationMap($httpTests, 'hostid', 'httptestid'); $httpTests = $this->unsetExtraFields($httpTests, ['hostid', 'httptestid'], $options['selectHttpTests']); $result = $relationMap->mapMany($result, $httpTests, 'httpTests', $options['limitSelects']); } else { $httpTests = API::HttpTest()->get([ 'hostids' => $hostids, 'nopermissions' => true, 'countOutput' => true, 'groupCount' => true ]); $httpTests = zbx_toHash($httpTests, 'hostid'); foreach ($result as $hostid => $host) { $result[$hostid]['httpTests'] = array_key_exists($hostid, $httpTests) ? $httpTests[$hostid]['rowscount'] : '0'; } } } if ($options['selectValueMaps'] !== null) { if ($options['selectValueMaps'] === API_OUTPUT_EXTEND) { $options['selectValueMaps'] = ['valuemapid', 'name', 'mappings']; } foreach ($result as &$host) { $host['valuemaps'] = []; } unset($host); $valuemaps = DB::select('valuemap', [ 'output' => array_diff($this->outputExtend($options['selectValueMaps'], ['valuemapid', 'hostid']), ['mappings'] ), 'filter' => ['hostid' => $hostids], 'preservekeys' => true ]); if ($this->outputIsRequested('mappings', $options['selectValueMaps']) && $valuemaps) { $params = [ 'output' => ['valuemapid', 'type', 'value', 'newvalue'], 'filter' => ['valuemapid' => array_keys($valuemaps)], 'sortfield' => ['sortorder'] ]; $query = DBselect(DB::makeSql('valuemap_mapping', $params)); while ($mapping = DBfetch($query)) { $valuemaps[$mapping['valuemapid']]['mappings'][] = [ 'type' => $mapping['type'], 'value' => $mapping['value'], 'newvalue' => $mapping['newvalue'] ]; } } foreach ($valuemaps as $valuemap) { $result[$valuemap['hostid']]['valuemaps'][] = array_intersect_key($valuemap, array_flip($options['selectValueMaps']) ); } } return $result; } /** * Add the existing host or template groups, templates, tags, macros. * * @param array $hosts * @param array $db_hosts */ protected function addAffectedObjects(array $hosts, array &$db_hosts): void { $this->addAffectedGroups($hosts, $db_hosts); parent::addAffectedObjects($hosts, $db_hosts); } /** * @param array $hosts * @param array $db_hosts */ protected function addAffectedGroups(array $hosts, array &$db_hosts): void { $id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid'; $hostids = []; foreach ($hosts as $host) { if (array_key_exists('groups', $host)) { $hostids[] = $host[$id_field_name]; $db_hosts[$host[$id_field_name]]['groups'] = []; } } if (!$hostids) { return; } $filter = ['hostid' => $hostids]; if (self::$userData['type'] == USER_TYPE_ZABBIX_ADMIN) { if ($this instanceof CTemplate) { $db_groups = API::TemplateGroup()->get([ 'output' => [], 'templateids' => $hostids, 'preservekeys' => true ]); } else { $db_groups = API::HostGroup()->get([ 'output' => [], 'hostids' => $hostids, 'preservekeys' => true ]); } $filter += ['groupid' => array_keys($db_groups)]; } $options = [ 'output' => ['hostgroupid', 'hostid', 'groupid'], 'filter' => $filter ]; $db_groups = DBselect(DB::makeSql('hosts_groups', $options)); while ($db_group = DBfetch($db_groups)) { $db_hosts[$db_group['hostid']]['groups'][$db_group['hostgroupid']] = array_diff_key($db_group, array_flip(['hostid'])); } } /** * Add the existing groups, macros or templates whether these are affected by the mass methods. * * @param string $objects * @param array $objectids * @param array $db_hosts */ protected function massAddAffectedObjects(string $objects, array $objectids, array &$db_hosts): void { $id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid'; foreach ($db_hosts as &$db_host) { $db_host[$objects] = []; } unset($db_host); if ($objects === 'groups') { $filter = ['hostid' => array_keys($db_hosts)]; if ($objectids) { $filter += ['groupid' => $objectids]; } elseif (self::$userData['type'] == USER_TYPE_ZABBIX_ADMIN) { if ($this instanceof CTemplate) { $db_groups = API::TemplateGroup()->get([ 'output' => [], 'templateids' => array_keys($db_hosts), 'preservekeys' => true ]); } else { $db_groups = API::HostGroup()->get([ 'output' => [], 'hostids' => array_keys($db_hosts), 'preservekeys' => true ]); } $filter += ['groupid' => array_keys($db_groups)]; } $options = [ 'output' => ['hostgroupid', 'hostid', 'groupid'], 'filter' => $filter ]; $db_hosts_groups = DBselect(DB::makeSql('hosts_groups', $options)); while ($link = DBfetch($db_hosts_groups)) { $db_hosts[$link['hostid']]['groups'][$link['hostgroupid']] = array_diff_key($link, array_flip(['hostid'])); } } if ($objects === 'macros') { $options = [ 'output' => ['hostmacroid', 'hostid', 'macro', 'value', 'description', 'type'], 'filter' => ['hostid' => array_keys($db_hosts)] ]; if ($objectids) { $macro_patterns = []; $trimmed_macros = []; foreach ($objectids as $macro) { $trimmed_macro = CApiInputValidator::trimMacro($macro); $context_pos = strpos($trimmed_macro, ':'); $macro_patterns[] = ($context_pos === false) ? '{$'.$trimmed_macro : '{$'.substr($trimmed_macro, 0, $context_pos); $trimmed_macros[] = $trimmed_macro; } $options += [ 'search' => ['macro' => $macro_patterns], 'startSearch' => true, 'searchByAny' => true ]; } $db_macros = DBselect(DB::makeSql('hostmacro', $options)); while ($db_macro = DBfetch($db_macros)) { if (!$objectids || in_array(CApiInputValidator::trimMacro($db_macro['macro']), $trimmed_macros)) { $db_hosts[$db_macro['hostid']]['macros'][$db_macro['hostmacroid']] = array_diff_key($db_macro, array_flip(['hostid'])); } } } if ($objects === 'templates') { $permitted_templates = []; if (!$objectids && self::$userData['type'] == USER_TYPE_ZABBIX_ADMIN) { $permitted_templates = API::Template()->get([ 'output' => [], 'hostids' => array_keys($db_hosts), 'preservekeys' => true ]); } $options = [ 'output' => ['hosttemplateid', 'hostid', 'templateid'], 'filter' => [ 'hostid' => array_keys($db_hosts) ] ]; $db_hosts_templates = DBselect(DB::makeSql('hosts_templates', $options)); while ($link = DBfetch($db_hosts_templates)) { if ($objectids) { if (in_array($link['templateid'], $objectids)) { $db_hosts[$link['hostid']]['templates'][$link['hosttemplateid']] = array_diff_key($link, array_flip(['hostid'])); } else { $db_hosts[$link['hostid']]['nopermissions_templates'][$link['hosttemplateid']] = array_diff_key($link, array_flip(['hostid'])); } } else { if (self::$userData['type'] == USER_TYPE_SUPER_ADMIN || array_key_exists($link['templateid'], $permitted_templates)) { $db_hosts[$link['hostid']]['templates'][$link['hosttemplateid']] = array_diff_key($link, array_flip(['hostid'])); } else { $db_hosts[$link['hostid']]['nopermissions_templates'][$link['hosttemplateid']] = array_diff_key($link, array_flip(['hostid'])); } } } } } /** * Get templates or hosts input array based on requested data and database data. * * @param array $data * @param array $db_objects * * @return array */ protected function getObjectsByData(array $data, array $db_objects): array { $id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid'; $objects = []; foreach ($db_objects as $db_object) { $object = [$id_field_name => $db_object[$id_field_name]]; if (array_key_exists('groups', $db_object)) { $object['groups'] = []; if (array_key_exists('groups', $data)) { foreach ($data['groups'] as $group) { $object['groups'][] = ['groupid' => $group['groupid']]; } } } if (array_key_exists('macros', $db_object)) { $object['macros'] = []; if (array_key_exists('macros', $data) && is_array(reset($data['macros']))) { $db_macros = []; foreach ($db_object['macros'] as $db_macro) { $db_macros[CApiInputValidator::trimMacro($db_macro['macro'])] = $db_macro; } foreach ($data['macros'] as $macro) { $trimmed_macro = CApiInputValidator::trimMacro($macro['macro']); if (array_key_exists($trimmed_macro, $db_macros)) { $object['macros'][] = ['hostmacroid' => $db_macros[$trimmed_macro]['hostmacroid']] + $macro + ['description' => DB::getDefault('hostmacro', 'description')]; } else { $object['macros'][] = $macro; } } } } if (array_key_exists('templates', $db_object)) { $templates = $this instanceof CTemplate ? 'templates_link' : 'templates'; $templateids = $this instanceof CTemplate ? 'templateids_link' : 'templateids'; if (array_key_exists($templates, $data) || array_key_exists($templateids, $data)) { $object['templates'] = []; if (array_key_exists($templates, $data)) { foreach ($data[$templates] as $template) { $object['templates'][] = ['templateid' => $template['templateid']]; } } } if (array_key_exists('templates_clear', $data) || array_key_exists('templateids_clear', $data)) { $object['templates_clear'] = []; $db_templateids = array_column($db_object['templates'], 'templateid'); if (array_key_exists('templates_clear', $data)) { foreach ($data['templates_clear'] as $template) { if (in_array($template['templateid'], $db_templateids)) { $object['templates_clear'][] = ['templateid' => $template['templateid']]; } } } else { foreach ($data['templateids_clear'] as $templateid) { if (in_array($templateid, $db_templateids)) { $object['templates_clear'][] = ['templateid' => $templateid]; } } } } } $objects[] = $object; } return $objects; } }