diff options
Diffstat (limited to 'ui/include/classes/api/services/CCorrelation.php')
-rw-r--r-- | ui/include/classes/api/services/CCorrelation.php | 1630 |
1 files changed, 543 insertions, 1087 deletions
diff --git a/ui/include/classes/api/services/CCorrelation.php b/ui/include/classes/api/services/CCorrelation.php index bac832a83b9..ff6f1cf6aee 100644 --- a/ui/include/classes/api/services/CCorrelation.php +++ b/ui/include/classes/api/services/CCorrelation.php @@ -123,1276 +123,623 @@ class CCorrelation extends CApiService { } /** - * Add correlations. - * - * @param array $correlations An array of correlations. - * @param string $correlations[]['name'] Correlation name. - * @param string $correlations[]['description'] Correlation description (optional). - * @param int $correlations[]['status'] Correlation status (optional). - * Possible values are: - * 0 - ZBX_CORRELATION_ENABLED; - * 1 - ZBX_CORRELATION_DISABLED. - * @param array $correlations[]['filter'] Correlation filter that contains evaluation - * method, formula and conditions. - * @param int $correlations[]['filter']['evaltype'] Correlation condition evaluation method. - * Possible values are: - * 0 - CONDITION_EVAL_TYPE_AND_OR; - * 1 - CONDITION_EVAL_TYPE_AND; - * 2 - CONDITION_EVAL_TYPE_OR; - * 3 - CONDITION_EVAL_TYPE_EXPRESSION. - * @param string $correlations[]['filter']['formula'] User-defined expression to be used for - * evaluating conditions of filters with a - * custom expression. Optional, but required - * when evaluation method is: - * 3 - CONDITION_EVAL_TYPE_EXPRESSION. - * @param array $correlations[]['filter']['conditions'] An array of correlation conditions. - * @param int $correlations[]['filter']['conditions'][]['type'] Condition type. - * Possible values are: - * 0 - ZBX_CORR_CONDITION_OLD_EVENT_TAG; - * 1 - ZBX_CORR_CONDITION_NEW_EVENT_TAG; - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP; - * 3 - ZBX_CORR_CONDITION_EVENT_TAG_PAIR; - * 4 - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE; - * 5 - ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE. - * @param string $correlations[]['filter']['conditions'][]['formulaid'] Condition formula ID. Optional, but required - * when evaluation method is: - * 3 - CONDITION_EVAL_TYPE_EXPRESSION. - * @param string $correlations[]['filter']['conditions'][]['tag'] Correlation condition tag. - * @param int $correlations[]['filter']['conditions'][]['operator'] Correlation condition operator. Optional, - * but required when "type" is one of the following: - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP; - * 4 - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE; - * 5 - ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE. - * Possible values depend on type: - * for type ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: - * 0 - CONDITION_OPERATOR_EQUAL - * 1 - CONDITION_OPERATOR_NOT_EQUAL - * for types ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE - * or ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: - * 0 - CONDITION_OPERATOR_EQUAL; - * 1 - CONDITION_OPERATOR_NOT_EQUAL; - * 2 - CONDITION_OPERATOR_LIKE; - * 3 - CONDITION_OPERATOR_NOT_LIKE. - * @param string $correlations[]['filter']['conditions'][]['groupid'] Correlation host group ID. Optional, but - * required when "type" is: - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP. - * @param string $correlations[]['filter']['conditions'][]['newtag'] Correlation condition new (current) tag. - * @param string $correlations[]['filter']['conditions'][]['oldtag'] Correlation condition old (target/matching) - * tag. - * @param string $correlations[]['filter']['conditions'][]['value'] Correlation condition tag value (optional). - * @param array $correlations[]['operations'] An array of correlation operations. - * @param int $correlations[]['operations'][]['type'] Correlation operation type. - * Possible values are: - * 0 - ZBX_CORR_OPERATION_CLOSE_OLD; - * 1 - ZBX_CORR_OPERATION_CLOSE_NEW. + * @param array $correlations * * @return array */ public function create($correlations) { - $correlations = zbx_toArray($correlations); - - $this->validateCreate($correlations); - - foreach ($correlations as &$correlation) { - $correlation['evaltype'] = $correlation['filter']['evaltype']; - unset($correlation['formula']); + if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) { + self::exception(ZBX_API_ERROR_PERMISSIONS, + _s('No permissions to call "%1$s.%2$s".', 'correlation', __FUNCTION__) + ); } - unset($correlation); - // Insert correlations into DB, get back array with new correlation IDs. - $correlations = DB::save('correlation', $correlations); - $correlations = zbx_toHash($correlations, 'correlationid'); + self::validateCreate($correlations); - $conditions_to_create = []; - $operations_to_create = []; + $ins_correlations = []; - // Collect conditions and operations to be created and set appropriate correlation ID. - foreach ($correlations as $correlationid => &$correlation) { - foreach ($correlation['filter']['conditions'] as $condition) { - $condition['correlationid'] = $correlationid; - $conditions_to_create[] = $condition; - } - - foreach ($correlation['operations'] as $operation) { - $operation['correlationid'] = $correlationid; - $operations_to_create[] = $operation; - } + foreach ($correlations as $correlation) { + $ins_correlations[] = $correlation + ['evaltype' => $correlation['filter']['evaltype']]; } - unset($correlation); - $conditions = $this->addConditions($conditions_to_create); + // Insert correlations into DB, get back array with new correlation IDs. + $correlationids = DB::insert('correlation', $ins_correlations); - // Group back created correlation conditions by correlation ID to be used for updating correlation formula. - $conditions_for_correlations = []; - foreach ($conditions as $condition) { - $conditions_for_correlations[$condition['correlationid']][$condition['corr_conditionid']] = $condition; + foreach ($correlations as $index => &$correlation) { + $correlation['correlationid'] = $correlationids[$index]; } + unset($correlation); - // Update "formula" field if evaluation method is a custom expression. - foreach ($correlations as $correlationid => $correlation) { - if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - $this->updateFormula($correlationid, $correlation['filter']['formula'], - $conditions_for_correlations[$correlationid] - ); - } - } + self::updateConditions($correlations, __FUNCTION__); + self::updateOperations($correlations, __FUNCTION__); - DB::save('corr_operation', $operations_to_create); + self::addAuditLog(CAudit::ACTION_ADD, CAudit::RESOURCE_CORRELATION, $correlations); - return ['correlationids' => array_keys($correlations)]; + return ['correlationids' => $correlationids]; } /** - * Update correlations. + * @static * - * @param array $correlations An array of correlations. - * @param string $correlations[]['name'] Correlation name (optional). - * @param string $correlations[]['description'] Correlation description (optional). - * @param int $correlations[]['status'] Correlation status (optional). - * Possible values are: - * 0 - ZBX_CORRELATION_ENABLED; - * 1 - ZBX_CORRELATION_DISABLED. - * @param array $correlations[]['filter'] Correlation filter that contains evaluation - * method, formula and conditions. - * @param int $correlations[]['filter']['evaltype'] Correlation condition evaluation - * method (optional). - * Possible values are: - * 0 - CONDITION_EVAL_TYPE_AND_OR; - * 1 - CONDITION_EVAL_TYPE_AND; - * 2 - CONDITION_EVAL_TYPE_OR; - * 3 - CONDITION_EVAL_TYPE_EXPRESSION. - * @param string $correlations[]['filter']['formula'] User-defined expression to be used for - * evaluating conditions of filters with a - * custom expression. Optional, but required - * when evaluation method is changed to - * CONDITION_EVAL_TYPE_EXPRESSION (or remains the same) - * and new conditions are set. - * @param array $correlations[]['filter']['conditions'] An array of correlation conditions (optional). - * @param int $correlations[]['filter']['conditions'][]['type'] Condition type. Optional, but required when - * new conditions are set. - * Possible values are: - * 0 - ZBX_CORR_CONDITION_OLD_EVENT_TAG; - * 1 - ZBX_CORR_CONDITION_NEW_EVENT_TAG; - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP; - * 3 - ZBX_CORR_CONDITION_EVENT_TAG_PAIR; - * 4 - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE; - * 5 - ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE. - * @param string $correlations[]['filter']['conditions'][]['formulaid'] Condition formula ID. Optional, but required - * when evaluation method is changed to - * CONDITION_EVAL_TYPE_EXPRESSION (or remains the same) - * and new conditions are set. - * @param string $correlations[]['filter']['conditions'][]['tag'] Correlation condition tag. - * @param int $correlations[]['filter']['conditions'][]['operator'] Correlation condition operator. Optional, - * but required when "type" is changed to one - * of the following: - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP; - * 4 - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE; - * 5 - ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE. - * Possible values depend on type: - * for type ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: - * 0 - CONDITION_OPERATOR_EQUAL - * 1 - CONDITION_OPERATOR_NOT_EQUAL - * for types ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE - * or ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: - * 0 - CONDITION_OPERATOR_EQUAL; - * 1 - CONDITION_OPERATOR_NOT_EQUAL; - * 2 - CONDITION_OPERATOR_LIKE; - * 3 - CONDITION_OPERATOR_NOT_LIKE. - * @param string $correlations[]['filter']['conditions'][]['groupid'] Correlation host group ID. Optional, but - * required when "type" is changed to: - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP. - * @param string $correlations[]['filter']['conditions'][]['newtag'] Correlation condition new (current) tag. - * @param string $correlations[]['filter']['conditions'][]['oldtag'] Correlation condition old (target/matching) - * tag. - * @param string $correlations[]['filter']['conditions'][]['value'] Correlation condition tag value (optional). - * @param array $correlations[]['operations'] An array of correlation operations (optional). - * @param int $correlations[]['operations'][]['type'] Correlation operation type (optional). - * Possible values are: - * 0 - ZBX_CORR_OPERATION_CLOSE_OLD; - * 1 - ZBX_CORR_OPERATION_CLOSE_NEW. + * @param array $db_conditions + * @param array $condition * - * @return array + * @return array|null */ - public function update($correlations) { - $correlations = zbx_toArray($correlations); - $db_correlations = []; - - $this->validateUpdate($correlations, $db_correlations); - - $correlations_to_update = []; - $conditions_to_create = []; - $conditions_to_delete = []; - $operations_to_create = []; - $operations_to_delete = []; - - foreach ($correlations as $correlation) { - $correlationid = $correlation['correlationid']; + private static function getDbCondition(array $db_conditions, array $condition): ?array { + foreach ($db_conditions as $db_condition) { + if ($condition['type'] != $db_condition['type']) { + continue; + } - unset($correlation['evaltype'], $correlation['formula'], $correlation['correlationid']); + switch ($condition['type']) { + case ZBX_CORR_CONDITION_OLD_EVENT_TAG: + case ZBX_CORR_CONDITION_NEW_EVENT_TAG: + if ($condition['tag'] === $db_condition['tag']) { + return $db_condition; + } + break; - $db_correlation = $db_correlations[$correlationid]; + case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: + if ($condition['operator'] == $db_condition['operator'] + && bccomp($condition['groupid'], $db_condition['groupid']) == 0) { + return $db_condition; + } + break; - // Remove fields that have not been changed for correlations. - if (array_key_exists('name', $correlation) && $correlation['name'] === $db_correlation['name']) { - unset($correlation['name']); - } + case ZBX_CORR_CONDITION_EVENT_TAG_PAIR: + if ($condition['oldtag'] === $db_condition['oldtag'] + && $condition['newtag'] === $db_condition['newtag']) { + return $db_condition; + } + break; - if (array_key_exists('description', $correlation) - && $correlation['description'] === $db_correlation['description']) { - unset($correlation['description']); + case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE: + case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: + if ($condition['operator'] == $db_condition['operator'] + && $condition['tag'] === $db_condition['tag'] + && $condition['value'] === $db_condition['value']) { + return $db_condition; + } + break; } + } - if (array_key_exists('status', $correlation) && $correlation['status'] == $db_correlation['status']) { - unset($correlation['status']); - } + return null; + } - $evaltype_changed = false; + /** + * @static + * + * @param array $correlations + * @param string $method + * @param array|null $db_correlations + */ + private static function updateConditions(array &$correlations, string $method, + array $db_correlations = null): void { + $ins_conditions = []; + $del_corr_conditionids = []; - // If the filter is set, something might have changed. - if (array_key_exists('filter', $correlation)) { - // Delete old correlation conditions and create new conditions. - if (array_key_exists('conditions', $correlation['filter'])) { - $conditions_to_delete[$correlationid] = true; + foreach ($correlations as &$correlation) { + if (!array_key_exists('filter', $correlation)) { + continue; + } - foreach ($correlation['filter']['conditions'] as $condition) { - $condition['correlationid'] = $correlationid; - $conditions_to_create[] = $condition; - } - } + $db_conditions = ($method === 'update') + ? $db_correlations[$correlation['correlationid']]['filter']['conditions'] + : []; - // Check if evaltype has changed. - if (array_key_exists('evaltype', $correlation['filter'])) { - if ($correlation['filter']['evaltype'] != $db_correlation['filter']['evaltype']) { - // Clear formula field evaluation method if evaltype has changed. - $correlation['evaltype'] = $correlation['filter']['evaltype']; + foreach ($correlation['filter']['conditions'] as &$condition) { + $db_condition = self::getDbCondition($db_conditions, $condition); - if ($correlation['evaltype'] != CONDITION_EVAL_TYPE_EXPRESSION) { - $correlation['formula'] = ''; - } - } + if ($db_condition !== null) { + $condition['corr_conditionid'] = $db_condition['corr_conditionid']; + unset($db_conditions[$db_condition['corr_conditionid']]); } - } - - // Delete old correlation operations and create new operations. - if (array_key_exists('operations', $correlation)) { - $operations_to_delete[$correlationid] = true; - - foreach ($correlation['operations'] as $operation) { - $operation['correlationid'] = $correlationid; - $operations_to_create[] = $operation; + else { + $ins_conditions[] = ['correlationid' => $correlation['correlationid']] + $condition; } } + unset($condition); - // Add values only if something is set for update. - if (array_key_exists('name', $correlation) - || array_key_exists('description', $correlation) - || array_key_exists('status', $correlation) - || array_key_exists('evaltype', $correlation)) { - $correlations_to_update[] = [ - 'values' => $correlation, - 'where' => ['correlationid' => $correlationid] - ]; - } + $del_corr_conditionids = array_merge($del_corr_conditionids, array_keys($db_conditions)); } + unset($correlation); - // Update correlations. - if ($correlations_to_update) { - DB::update('correlation', $correlations_to_update); + if ($ins_conditions) { + $conditionids = DB::insert('corr_condition', $ins_conditions); } - // Update conditions. Delete the old ones and create new ones. - if ($conditions_to_delete) { - DB::delete('corr_condition', ['correlationid' => array_keys($conditions_to_delete)]); + if ($del_corr_conditionids) { + DB::delete('corr_condition_tag', ['corr_conditionid' => $del_corr_conditionids]); + DB::delete('corr_condition_group', ['corr_conditionid' => $del_corr_conditionids]); + DB::delete('corr_condition_tagpair', ['corr_conditionid' => $del_corr_conditionids]); + DB::delete('corr_condition_tagvalue', ['corr_conditionid' => $del_corr_conditionids]); + DB::delete('corr_condition', ['corr_conditionid' => $del_corr_conditionids]); } - if ($conditions_to_create) { - $conditions = $this->addConditions($conditions_to_create); + $ins_condition_tags = []; + $ins_condition_groups = []; + $ins_condition_tagpairs = []; + $ins_condition_tagvalues = []; + $upd_correlations = []; - // Group back created correlation conditions by correlation ID to be used for updating correlation formula. - $conditions_for_correlations = []; - foreach ($conditions as $condition) { - $conditions_for_correlations[$condition['correlationid']][$condition['corr_conditionid']] = $condition; + foreach ($correlations as &$correlation) { + if (!array_key_exists('filter', $correlation)) { + continue; } - // Update "formula" field if evaluation method is a custom expression. - foreach ($correlations as $correlation) { - if (array_key_exists('filter', $correlation)) { - $db_correlation = $db_correlations[$correlation['correlationid']]; - - // Check if evaluation method has changed. - if (array_key_exists('evaltype', $correlation['filter'])) { - if ($correlation['filter']['evaltype'] != $db_correlation['filter']['evaltype']) { - // The new evaluation method will be saved to DB. - $correlation['evaltype'] = $correlation['filter']['evaltype']; - - if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - // When evaluation method has changed, update the custom formula. - $this->updateFormula($correlation['correlationid'], $correlation['filter']['formula'], - $conditions_for_correlations[$correlation['correlationid']] - ); - } - } - else { - /* - * The evaluation method has not been changed, but it has been set and it's a custom - * expression. The formula needs to be updated in this case. - */ - if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - $this->updateFormula($correlation['correlationid'], $correlation['filter']['formula'], - $conditions_for_correlations[$correlation['correlationid']] - ); - } - } - } - elseif ($db_correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - /* - * The evaluation method has not been changed and was not set. It's read from DB, but it's still - * a custom expression and there are new conditions, so the formula needs to be updated. - */ - $this->updateFormula($correlation['correlationid'], $correlation['filter']['formula'], - $conditions_for_correlations[$correlation['correlationid']] - ); + foreach ($correlation['filter']['conditions'] as &$condition) { + if (!array_key_exists('corr_conditionid', $condition)) { + $condition['corr_conditionid'] = array_shift($conditionids); + + switch ($condition['type']) { + case ZBX_CORR_CONDITION_OLD_EVENT_TAG: + case ZBX_CORR_CONDITION_NEW_EVENT_TAG: + $ins_condition_tags[] = $condition; + break; + + case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: + $ins_condition_groups[] = $condition; + break; + + case ZBX_CORR_CONDITION_EVENT_TAG_PAIR: + $ins_condition_tagpairs[] = $condition; + break; + + case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE: + case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: + $ins_condition_tagvalues[] = $condition; + break; } } } - } - - // Update operations. Delete the old ones and create new ones. - if ($operations_to_delete) { - DB::delete('corr_operation', ['correlationid' => array_keys($operations_to_delete)]); - } + unset($condition); - if ($operations_to_create) { - DB::save('corr_operation', $operations_to_create); - } + if ($method === 'create' || array_key_exists('filter', $correlation)) { + if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { + $correlation['filter']['formula'] = CConditionHelper::replaceLetterIds( + $correlation['filter']['formula'], + array_column($correlation['filter']['conditions'], 'corr_conditionid', 'formulaid') + ); + } + else { + $correlation['filter']['formula'] = ''; + } - return ['correlationids' => zbx_objectValues($correlations, 'correlationid')]; - } + $db_formula = ($method === 'update') + ? $db_correlations[$correlation['correlationid']]['filter']['formula'] + : ''; - /** - * Delete correlations. - * - * @param array $correlationids An array of correlation IDs. - * - * @return array - */ - public function delete(array $correlationids) { - if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) { - self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.')); + if ($correlation['filter']['formula'] !== $db_formula) { + $upd_correlations[] = [ + 'values' => ['formula' => $correlation['filter']['formula']], + 'where' => ['correlationid' => $correlation['correlationid']] + ]; + } + } } + unset($correlation); - $api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true]; - if (!CApiInputValidator::validate($api_input_rules, $correlationids, '/', $error)) { - self::exception(ZBX_API_ERROR_PARAMETERS, $error); + if ($ins_condition_tags) { + DB::insert('corr_condition_tag', $ins_condition_tags, false); } - $db_correlations = $this->get([ - 'output' => ['correlationid', 'name'], - 'correlationids' => $correlationids, - 'preservekeys' => true - ]); - - foreach ($correlationids as $correlationid) { - if (!array_key_exists($correlationid, $db_correlations)) { - self::exception(ZBX_API_ERROR_PERMISSIONS, - _('No permissions to referred object or it does not exist!') - ); - } + if ($ins_condition_groups) { + DB::insert('corr_condition_group', $ins_condition_groups, false); } - DB::delete('correlation', ['correlationid' => $correlationids]); + if ($ins_condition_tagpairs) { + DB::insert('corr_condition_tagpair', $ins_condition_tagpairs, false); + } - $this->addAuditBulk(CAudit::ACTION_DELETE, CAudit::RESOURCE_CORRELATION, $db_correlations); + if ($ins_condition_tagvalues) { + DB::insert('corr_condition_tagvalue', $ins_condition_tagvalues, false); + } - return ['correlationids' => $correlationids]; + if ($upd_correlations) { + DB::update('correlation', $upd_correlations); + } } /** - * Validates the input parameters for the create() method. - * - * @param array $correlations + * @static * - * @throws APIException if the input is invalid. + * @param array $correlations + * @param string $method + * @param array|null $db_correlations */ - protected function validateCreate(array $correlations) { - if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) { - self::exception(ZBX_API_ERROR_PERMISSIONS, _('Only super admins can create correlations.')); - } + private static function updateOperations(array &$correlations, string $method, + array $db_correlations = null): void { + $ins_operations = []; + $del_corr_operationids = []; - if (!$correlations) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Empty input parameter.')); - } - - $required_fields = ['name', 'filter', 'operations']; - - // Validate required fields and check if "name" is not empty. - foreach ($correlations as $correlation) { - if (!is_array($correlation)) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); + foreach ($correlations as &$correlation) { + if (!array_key_exists('operations', $correlation)) { + continue; } - // Check required parameters. - $missing_keys = array_diff($required_fields, array_keys($correlation)); - - if ($missing_keys) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Correlation is missing parameters: %1$s', implode(', ', $missing_keys)) - ); - } + $db_operations = ($method === 'update') + ? array_column($db_correlations[$correlation['correlationid']]['operations'], null, 'type') + : []; - // Validate "name" field. - if (is_array($correlation['name'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - elseif ($correlation['name'] === '' || $correlation['name'] === null || $correlation['name'] === false) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Correlation name cannot be empty.')); + foreach ($correlation['operations'] as &$operation) { + if (array_key_exists($operation['type'], $db_operations)) { + $operation['corr_operationid'] = $db_operations[$operation['type']]['corr_operationid']; + unset($db_operations[$operation['type']]); + } + else { + $ins_operations[] = ['correlationid' => $correlation['correlationid']] + $operation; + } } - } + unset($operation); - // Check for duplicate names. - $duplicate = CArrayHelper::findDuplicate($correlations, 'name'); - if ($duplicate) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Duplicate "%1$s" value "%2$s" for correlation.', 'name', $duplicate['name']) + $del_corr_operationids = array_merge($del_corr_operationids, + array_column($db_operations, 'corr_operationid') ); } + unset($correlation); - // Check if correlation already exists. - $db_correlations = API::getApiService()->select('correlation', [ - 'output' => ['name'], - 'filter' => ['name' => zbx_objectValues($correlations, 'name')], - 'limit' => 1 - ]); - - if ($db_correlations) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Correlation "%1$s" already exists.', $correlations[0]['name']) - ); + if ($ins_operations) { + $corr_operationids = DB::insert('corr_operation', $ins_operations); } - // Set all necessary validators and parser before cycling each correlation. - $status_validator = new CLimitedSetValidator([ - 'values' => [ZBX_CORRELATION_ENABLED, ZBX_CORRELATION_DISABLED] - ]); - - $filter_evaltype_validator = new CLimitedSetValidator([ - 'values' => [CONDITION_EVAL_TYPE_OR, CONDITION_EVAL_TYPE_AND, CONDITION_EVAL_TYPE_AND_OR, - CONDITION_EVAL_TYPE_EXPRESSION - ] - ]); - - $filter_condition_type_validator = new CLimitedSetValidator([ - 'values' => [ZBX_CORR_CONDITION_OLD_EVENT_TAG, ZBX_CORR_CONDITION_NEW_EVENT_TAG, - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP, ZBX_CORR_CONDITION_EVENT_TAG_PAIR, - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE, ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE - ] - ]); - - $filter_condition_hg_operator_validator = new CLimitedSetValidator([ - 'values' => [CONDITION_OPERATOR_EQUAL, CONDITION_OPERATOR_NOT_EQUAL] - ]); - - $filter_condition_tagval_operator_validator = new CLimitedSetValidator([ - 'values' => [CONDITION_OPERATOR_EQUAL, CONDITION_OPERATOR_NOT_EQUAL, CONDITION_OPERATOR_LIKE, - CONDITION_OPERATOR_NOT_LIKE - ] - ]); - - $filter_operations_validator = new CLimitedSetValidator([ - 'values' => [ZBX_CORR_OPERATION_CLOSE_OLD, ZBX_CORR_OPERATION_CLOSE_NEW] - ]); - - $parser = new CConditionFormula(); - - $groupids = []; - - foreach ($correlations as $correlation) { - // Validate "status" field (optional). - if (array_key_exists('status', $correlation) && !$status_validator->validate($correlation['status'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $correlation['status'], - 'status', - $correlation['name'] - )); - } - - // Validate "filter" field. - if (!is_array($correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - - // Validate "evaltype" field. - if (!array_key_exists('evaltype', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect type of calculation for correlation "%1$s".', $correlation['name']) - ); - } - elseif (!$filter_evaltype_validator->validate($correlation['filter']['evaltype'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $correlation['filter']['evaltype'], - 'evaltype', - $correlation['name'] - )); - } + if ($del_corr_operationids) { + DB::delete('corr_operation', ['corr_operationid' => $del_corr_operationids]); + } - // Check if conditions exist and that array is not empty. - if (!array_key_exists('conditions', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'conditions', $correlation['name']) - ); + foreach ($correlations as &$correlation) { + if (!array_key_exists('operations', $correlation)) { + continue; } - // Validate condition operators and other parameters depending on type. - $groupids = $this->validateConditions($correlation, $filter_condition_type_validator, - $filter_condition_hg_operator_validator, $filter_condition_tagval_operator_validator - ); - - // Validate custom expressions and formula. - if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - // Check formula. - if (!array_key_exists('formula', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'formula', $correlation['name']) - ); + foreach ($correlation['operations'] as &$operation) { + if (!array_key_exists('corr_operationid', $operation)) { + $operation['corr_operationid'] = array_shift($corr_operationids); } - - $this->validateFormula($correlation, $parser); - - // Check condition formula IDs. - $this->validateConditionFormulaIDs($correlation, $parser); - } - - // Validate operations. - $this->validateOperations($correlation, $filter_operations_validator); - } - - // Validate collected group IDs if at least one of correlation conditions was "New event host group". - if ($groupids) { - $groups_count = API::HostGroup()->get([ - 'countOutput' => true, - 'groupids' => array_keys($groupids) - ]); - - if ($groups_count != count($groupids)) { - self::exception(ZBX_API_ERROR_PERMISSIONS, - _('No permissions to referred object or it does not exist!') - ); } + unset($operation); } + unset($correlation); } /** - * Validates the input parameters for the update() method. - * * @param array $correlations - * @param array $db_correlations * - * @throws APIException if the input is invalid. + * @return array */ - protected function validateUpdate(array $correlations, array &$db_correlations) { + public function update(array $correlations): array { if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) { - self::exception(ZBX_API_ERROR_PERMISSIONS, _('Only super admins can update correlations.')); - } - - if (!$correlations) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Empty input parameter.')); + self::exception(ZBX_API_ERROR_PERMISSIONS, + _s('No permissions to call "%1$s.%2$s".', 'correlation', __FUNCTION__) + ); } - // Validate given IDs. - $this->checkObjectIds($correlations, 'correlationid', - _('No "%1$s" given for correlation.'), - _('Empty correlation ID.'), - _('Incorrect correlation ID.') - ); - - $db_correlations = $this->get([ - 'output' => ['correlationid', 'name', 'description', 'status'], - 'selectFilter' => ['formula', 'eval_formula', 'evaltype', 'conditions'], - 'selectOperations' => ['type'], - 'correlationids' => zbx_objectValues($correlations, 'correlationid'), - 'preservekeys' => true - ]); + self::validateUpdate($correlations, $db_correlations); - $check_names = []; + $upd_correlations = []; foreach ($correlations as $correlation) { - // Check if this correlation exists. - if (!array_key_exists($correlation['correlationid'], $db_correlations)) { - self::exception(ZBX_API_ERROR_PERMISSIONS, - _('No permissions to referred object or it does not exist!') - ); - } - - // Validate "name" field (optional). - if (array_key_exists('name', $correlation)) { - if (is_array($correlation['name'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - elseif ($correlation['name'] === '' || $correlation['name'] === null || $correlation['name'] === false) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Correlation name cannot be empty.')); - } - - if ($db_correlations[$correlation['correlationid']]['name'] !== $correlation['name']) { - $check_names[] = $correlation; - } - } - } + $db_correlation = $db_correlations[$correlation['correlationid']]; - // Check only if names have changed. - if ($check_names) { - // Check for duplicate names. - $duplicate = CArrayHelper::findDuplicate($check_names, 'name'); - if ($duplicate) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Duplicate "%1$s" value "%2$s" for correlation.', 'name', $duplicate['name']) - ); + if (array_key_exists('filter', $correlation)) { + $correlation['evaltype'] = $correlation['filter']['evaltype']; + $db_correlation['evaltype'] = $db_correlation['filter']['evaltype']; } - // Check if correlation already exists. - $db_correlation_names = API::getApiService()->select('correlation', [ - 'output' => ['correlationid', 'name'], - 'filter' => ['name' => zbx_objectValues($check_names, 'name')] - ]); - $db_correlation_names = zbx_toHash($db_correlation_names, 'name'); + $upd_correlation = DB::getUpdatedValues('correlation', $correlation, $db_correlation); - foreach ($check_names as $correlation) { - if (array_key_exists($correlation['name'], $db_correlation_names) - && bccomp($db_correlation_names[$correlation['name']]['correlationid'], - $correlation['correlationid']) != 0) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Correlation "%1$s" already exists.', $correlation['name']) - ); - } + if ($upd_correlation) { + $upd_correlations[] = [ + 'values' => $upd_correlation, + 'where' => ['correlationid' => $correlation['correlationid']] + ]; } } - // Set all necessary validators and parser before cycling each correlation. - $status_validator = new CLimitedSetValidator([ - 'values' => [ZBX_CORRELATION_ENABLED, ZBX_CORRELATION_DISABLED] - ]); - - $filter_evaltype_validator = new CLimitedSetValidator([ - 'values' => [CONDITION_EVAL_TYPE_OR, CONDITION_EVAL_TYPE_AND, CONDITION_EVAL_TYPE_AND_OR, - CONDITION_EVAL_TYPE_EXPRESSION - ] - ]); - - $filter_condition_type_validator = new CLimitedSetValidator([ - 'values' => [ZBX_CORR_CONDITION_OLD_EVENT_TAG, ZBX_CORR_CONDITION_NEW_EVENT_TAG, - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP, ZBX_CORR_CONDITION_EVENT_TAG_PAIR, - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE, ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE - ] - ]); - - $filter_condition_hg_operator_validator = new CLimitedSetValidator([ - 'values' => [CONDITION_OPERATOR_EQUAL, CONDITION_OPERATOR_NOT_EQUAL] - ]); - - $filter_condition_tagval_operator_validator = new CLimitedSetValidator([ - 'values' => [CONDITION_OPERATOR_EQUAL, CONDITION_OPERATOR_NOT_EQUAL, CONDITION_OPERATOR_LIKE, - CONDITION_OPERATOR_NOT_LIKE - ] - ]); - - $filter_operations_validator = new CLimitedSetValidator([ - 'values' => [ZBX_CORR_OPERATION_CLOSE_OLD, ZBX_CORR_OPERATION_CLOSE_NEW] - ]); - - $parser = new CConditionFormula(); - - $groupids = []; - - // Populate "name" field, if not set. - $correlations = $this->extendFromObjects(zbx_toHash($correlations, 'correlationid'), $db_correlations, - ['name'] - ); - - foreach ($correlations as $correlation) { - $db_correlation = $db_correlations[$correlation['correlationid']]; - - // Validate "status" field (optional). - if (array_key_exists('status', $correlation) && !$status_validator->validate($correlation['status'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $correlation['status'], - 'status', - $correlation['name'] - )); - } - - // Validate "filter" field. If filter is set, then something else must exist. - if (array_key_exists('filter', $correlation)) { - if (!is_array($correlation['filter']) || !$correlation['filter']) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - - $evaltype_changed = false; - - // Validate "evaltype" field. - if (array_key_exists('evaltype', $correlation['filter'])) { - // Check if evaltype has changed. - if ($correlation['filter']['evaltype'] != $db_correlation['filter']['evaltype']) { - if (!$filter_evaltype_validator->validate($correlation['filter']['evaltype'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $correlation['filter']['evaltype'], - 'evaltype', - $correlation['name'] - )); - } - - $evaltype_changed = true; - } - } - else { - // Populate "evaltype" field if not set, so we can later check for custom expressions. - $correlation['filter']['evaltype'] = $db_correlation['filter']['evaltype']; - } - - if ($evaltype_changed) { - if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - if (!array_key_exists('formula', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'formula', $correlation['name']) - ); - } - - $this->validateFormula($correlation, $parser); - - if (!array_key_exists('conditions', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'conditions', $correlation['name']) - ); - } + if ($upd_correlations) { + DB::update('correlation', $upd_correlations); + } - $groupids = $this->validateConditions($correlation, $filter_condition_type_validator, - $filter_condition_hg_operator_validator, $filter_condition_tagval_operator_validator - ); + self::updateConditions($correlations, __FUNCTION__, $db_correlations); + self::updateOperations($correlations, __FUNCTION__, $db_correlations); - $this->validateConditionFormulaIDs($correlation, $parser); - } - else { - if (!array_key_exists('conditions', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'conditions', $correlation['name']) - ); - } + self::addAuditLog(CAudit::ACTION_UPDATE, CAudit::RESOURCE_CORRELATION, $correlations, $db_correlations); - $groupids = $this->validateConditions($correlation, $filter_condition_type_validator, - $filter_condition_hg_operator_validator, $filter_condition_tagval_operator_validator - ); - } - } - else { - if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - if (array_key_exists('formula', $correlation['filter'])) { - $this->validateFormula($correlation, $parser); - - if (!array_key_exists('conditions', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'conditions', $correlation['name']) - ); - } + return ['correlationids' => array_column($correlations, 'correlationid')]; + } - $groupids = $this->validateConditions($correlation, $filter_condition_type_validator, - $filter_condition_hg_operator_validator, $filter_condition_tagval_operator_validator - ); + /** + * @param array $correlationids + * + * @return array + */ + public function delete(array $correlationids): array { + if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) { + self::exception(ZBX_API_ERROR_PERMISSIONS, + _s('No permissions to call "%1$s.%2$s".', 'correlation', __FUNCTION__) + ); + } - $this->validateConditionFormulaIDs($correlation, $parser); - } - elseif (array_key_exists('conditions', $correlation['filter'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'formula', $correlation['name']) - ); - } - } - elseif (array_key_exists('conditions', $correlation['filter'])) { - $groupids = $this->validateConditions($correlation, $filter_condition_type_validator, - $filter_condition_hg_operator_validator, $filter_condition_tagval_operator_validator - ); - } - } - } + self::validateDelete($correlationids, $db_correlations); - // Validate operations (optional). - if (array_key_exists('operations', $correlation)) { - $this->validateOperations($correlation, $filter_operations_validator); - } - } + DB::delete('correlation', ['correlationid' => $correlationids]); - // Validate collected group IDs if at least one of correlation conditions was "New event host group". - if ($groupids) { - $groups_count = API::HostGroup()->get([ - 'countOutput' => true, - 'groupids' => array_keys($groupids) - ]); + self::addAuditLog(CAudit::ACTION_DELETE, CAudit::RESOURCE_CORRELATION, $db_correlations); - if ($groups_count != count($groupids)) { - self::exception(ZBX_API_ERROR_PERMISSIONS, - _('No permissions to referred object or it does not exist!') - ); - } - } + return ['correlationids' => $correlationids]; } /** - * Converts a formula with letters to a formula with IDs and updates it. + * Validates the input parameters for the delete() method. + * + * @static + * + * @param array $correlationids + * @param array|null $db_correlations * - * @param string $correlationid - * @param string $formula_with_letters Formula with letters. - * @param array $conditions + * @throws APIException if the input is invalid. */ - protected function updateFormula($correlationid, $formula_with_letters, array $conditions) { - $formulaid_to_conditionid = []; + private static function validateDelete(array &$correlationids, array &$db_correlations = null): void { + $api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true]; - foreach ($conditions as $condition) { - $formulaid_to_conditionid[$condition['formulaid']] = $condition['corr_conditionid']; + if (!CApiInputValidator::validate($api_input_rules, $correlationids, '/', $error)) { + self::exception(ZBX_API_ERROR_PARAMETERS, $error); } - $formula = CConditionHelper::replaceLetterIds($formula_with_letters, $formulaid_to_conditionid); - DB::updateByPk('correlation', $correlationid, ['formula' => $formula]); + $db_correlations = DB::select('correlation', [ + 'output' => ['correlationid', 'name'], + 'correlationids' => $correlationids, + 'preservekeys' => true + ]); + + if (count($db_correlations) != count($correlationids)) { + self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); + } } /** - * Validate correlation conditions. Check the "conditions" array, check the "type" field and other fields that - * depend on it. As a result return host group IDs that need to be validated afterwards. Otherwise don't return - * anything, just throw an error. + * Check for unique event correlation names. * - * @param array $correlation One correlation containing the conditions. - * @param string $correlation['name'] Correlation name for error messages. - * @param array $correlation['filter'] Correlation filter array containing the conditions. - * @param array $correlation['filter']['conditions'] An array of correlation conditions. - * @param int $correlation['filter']['conditions'][]['type'] Condition type. - * Possible values are: - * 0 - ZBX_CORR_CONDITION_OLD_EVENT_TAG; - * 1 - ZBX_CORR_CONDITION_NEW_EVENT_TAG; - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP; - * 3 - ZBX_CORR_CONDITION_EVENT_TAG_PAIR; - * 4 - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE; - * 5 - ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE. - * @param int $correlation['filter']['conditions'][]['operator'] Correlation condition operator. - * Possible values when "type" - * is one of the following: - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP; - * 4 - ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE; - * 5 - ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE. - * Possible values depend on type: - * for type ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: - * 0 - CONDITION_OPERATOR_EQUAL - * 1 - CONDITION_OPERATOR_NOT_EQUAL - * for types ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE - * or ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: - * 0 - CONDITION_OPERATOR_EQUAL; - * 1 - CONDITION_OPERATOR_NOT_EQUAL; - * 2 - CONDITION_OPERATOR_LIKE; - * 3 - CONDITION_OPERATOR_NOT_LIKE. - * @param string $correlations['filter']['conditions'][]['groupid'] Correlation host group ID. - * Required when "type" is: - * 2 - ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP. - * @param CLimitedSetValidator $filter_condition_type_validator Validator for conditype type. - * @param CLimitedSetValidator $filter_condition_hg_operator_validator Validator for host group operator. - * @param CLimitedSetValidator $filter_condition_tagval_operator_validator Validator for tag value operator. + * @static * - * @throws APIException if the input is invalid. + * @param array $correlations + * @param array|null $db_correlations * - * @return array + * @throws APIException if event correlation names are not unique. */ - protected function validateConditions(array $correlation, CLimitedSetValidator $filter_condition_type_validator, - CLimitedSetValidator $filter_condition_hg_operator_validator, - CLimitedSetValidator $filter_condition_tagval_operator_validator) { - if (!$correlation['filter']['conditions']) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'conditions', $correlation['name']) - ); - } + protected static function checkDuplicates(array $correlations, array $db_correlations = null): void { + $names = []; - if (!is_array($correlation['filter']['conditions'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - - $groupids = []; - $formulaIds = []; - $conditions = []; - - foreach ($correlation['filter']['conditions'] as $condition) { - if (!array_key_exists('type', $condition)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No condition type given for correlation "%1$s".', $correlation['name']) - ); - } - elseif (is_array($condition['type'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - elseif (!$filter_condition_type_validator->validate($condition['type'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $condition['type'], - 'type', - $correlation['name'] - )); - } - - switch ($condition['type']) { - case ZBX_CORR_CONDITION_OLD_EVENT_TAG: - case ZBX_CORR_CONDITION_NEW_EVENT_TAG: - if (!array_key_exists('tag', $condition)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'tag', $correlation['name']) - ); - } - elseif (is_array($condition['tag'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _('Incorrect arguments passed to function.') - ); - } - elseif ($condition['tag'] === '' || $condition['tag'] === null || $condition['tag'] === false) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect value for field "%1$s": %2$s.', 'tag', _('cannot be empty')) - ); - } - break; - - case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: - if (array_key_exists('operator', $condition)) { - if (is_array($condition['operator'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _('Incorrect arguments passed to function.') - ); - } - elseif (!$filter_condition_hg_operator_validator->validate($condition['operator'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $condition['operator'], - 'operator', - $correlation['name'] - )); - } - } - - if (!array_key_exists('groupid', $condition)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'groupid', $correlation['name']) - ); - } - elseif (is_array($condition['groupid'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _('Incorrect arguments passed to function.') - ); - } - elseif ($condition['groupid'] === '' || $condition['groupid'] === null - || $condition['groupid'] === false) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect value for field "%1$s": %2$s.', 'groupid', _('cannot be empty')) - ); - } - - $groupids[$condition['groupid']] = true; - break; - - case ZBX_CORR_CONDITION_EVENT_TAG_PAIR: - if (!array_key_exists('oldtag', $condition)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'oldtag', $correlation['name']) - ); - } - elseif (is_array($condition['oldtag'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _('Incorrect arguments passed to function.') - ); - } - elseif ($condition['oldtag'] === '' || $condition['oldtag'] === null - || $condition['oldtag'] === false) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect value for field "%1$s": %2$s.', 'oldtag', _('cannot be empty')) - ); - } - - if (!array_key_exists('newtag', $condition)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'newtag', $correlation['name']) - ); - } - elseif (is_array($condition['newtag'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _('Incorrect arguments passed to function.') - ); - } - elseif ($condition['newtag'] === '' || $condition['newtag'] === null - || $condition['newtag'] === false) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect value for field "%1$s": %2$s.', 'newtag', _('cannot be empty')) - ); - } - break; - - case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE: - case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: - if (!array_key_exists('tag', $condition)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'tag', $correlation['name']) - ); - } - elseif (is_array($condition['tag'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _('Incorrect arguments passed to function.') - ); - } - elseif ($condition['tag'] === '' || $condition['tag'] === null || $condition['tag'] === false) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect value for field "%1$s": %2$s.', 'tag', _('cannot be empty')) - ); - } - - if (array_key_exists('operator', $condition)) { - if (is_array($condition['operator'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _('Incorrect arguments passed to function.') - ); - } - elseif (($condition['operator'] == CONDITION_OPERATOR_LIKE - || $condition['operator'] == CONDITION_OPERATOR_NOT_LIKE) - && (!array_key_exists('value', $condition) || $condition['value'] === '')) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect value for field "%1$s": %2$s.', 'value', _('cannot be empty')) - ); - } - elseif (!$filter_condition_tagval_operator_validator->validate($condition['operator'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $condition['operator'], - 'operator', - $correlation['name'] - )); - } - } - break; + foreach ($correlations as $correlation) { + if (!array_key_exists('name', $correlation)) { + continue; } - if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { - if (array_key_exists($condition['formulaid'], $formulaIds)) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Duplicate "%1$s" value "%2$s" for correlation "%3$s".', 'formulaid', $condition['formulaid'], - $correlation['name'] - )); - } - else { - $formulaIds[$condition['formulaid']] = true; - } + if ($db_correlations === null + || $correlation['name'] !== $db_correlations[$correlation['correlationid']]['name']) { + $names[] = $correlation['name']; } + } - unset($condition['formulaid']); - $conditions[] = $condition; + if (!$names) { + return; } - if (count($conditions) != count(array_unique($conditions, SORT_REGULAR))) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Duplicate conditions for correlation "%1$s".', $correlation['name']) - ); + $duplicates = DB::select('correlation', [ + 'output' => ['name'], + 'filter' => ['name' => $names], + 'limit' => 1 + ]); + + if ($duplicates) { + self::exception(ZBX_API_ERROR_PARAMETERS, _s('Correlation "%1$s" already exists.', $duplicates[0]['name'])); } + } - return $groupids; + /** + * Returns validation rules for the filter object. + * + * @static + * + * @return array + */ + private static function getFilterValidationRules(): array { + $condition_fields = [ + 'type' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [ZBX_CORR_CONDITION_OLD_EVENT_TAG, ZBX_CORR_CONDITION_NEW_EVENT_TAG, ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP, ZBX_CORR_CONDITION_EVENT_TAG_PAIR, ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE, ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE])], + 'operator' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'type', 'in' => ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP], 'type' => API_INT32, 'in' => implode(',', [CONDITION_OPERATOR_EQUAL, CONDITION_OPERATOR_NOT_EQUAL])], + ['if' => ['field' => 'type', 'in' => implode(',', [ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE, ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE])], 'type' => API_INT32, 'in' => implode(',', [CONDITION_OPERATOR_EQUAL, CONDITION_OPERATOR_NOT_EQUAL, CONDITION_OPERATOR_LIKE, CONDITION_OPERATOR_NOT_LIKE])], + ['else' => true, 'type' => API_INT32, 'in' => CONDITION_OPERATOR_EQUAL] + ]], + 'tag' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'type', 'in' => implode(',', [ZBX_CORR_CONDITION_OLD_EVENT_TAG, ZBX_CORR_CONDITION_NEW_EVENT_TAG, ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE, ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE])], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('corr_condition_tag', 'tag')], + ['else' => true, 'type' => API_UNEXPECTED] + ]], + 'groupid' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'type', 'in' => ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP], 'type' => API_ID, 'flags' => API_REQUIRED], + ['else' => true, 'type' => API_UNEXPECTED] + ]], + 'oldtag' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'type', 'in' => ZBX_CORR_CONDITION_EVENT_TAG_PAIR], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('corr_condition_tagpair', 'oldtag')], + ['else' => true, 'type' => API_UNEXPECTED] + ]], + 'newtag' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'type', 'in' => ZBX_CORR_CONDITION_EVENT_TAG_PAIR], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('corr_condition_tagpair', 'newtag')], + ['else' => true, 'type' => API_UNEXPECTED] + ]], + 'value' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'type', 'in' => implode(',', [ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE, ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE])], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('corr_condition_tagvalue', 'value')], + ['else' => true, 'type' => API_UNEXPECTED] + ]] + ]; + + return ['type' => API_OBJECT, 'fields' => [ + 'evaltype' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [CONDITION_EVAL_TYPE_AND_OR, CONDITION_EVAL_TYPE_AND, CONDITION_EVAL_TYPE_OR, CONDITION_EVAL_TYPE_EXPRESSION])], + 'formula' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'evaltype', 'in' => CONDITION_EVAL_TYPE_EXPRESSION], 'type' => API_COND_FORMULA, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('correlation', 'formula')], + ['else' => true, 'type' => API_UNEXPECTED] + ]], + 'conditions' => ['type' => API_MULTIPLE, 'flags' => API_REQUIRED, 'rules' => [ + ['if' => ['field' => 'evaltype', 'in' => CONDITION_EVAL_TYPE_EXPRESSION], 'type' => API_OBJECTS, 'flags' => API_NOT_EMPTY, 'uniq' => [['formulaid']], 'fields' => [ + 'formulaid' => ['type' => API_COND_FORMULAID, 'flags' => API_REQUIRED] + ] + $condition_fields], + ['else' => true, 'type' => API_OBJECTS, 'flags' => API_NOT_EMPTY, 'fields' => $condition_fields] + ]] + ]]; } /** - * Validate correlation filter "formula" field. + * Validates the input parameters for the create() method. * - * @param array $correlation One correlation containing the filter, formula and name. - * @param string $correlation['name'] Correlation name for error messages. - * @param array $correlation['filter'] Correlation filter array containing the formula. - * @param string $correlation['filter']['formula'] User-defined expression to be used for evaluating - * conditions of filters with a custom expression. - * @param CConditionFormula $parser Condition formula parser. + * @static + * + * @param array $correlations * * @throws APIException if the input is invalid. */ - protected function validateFormula(array $correlation, CConditionFormula $parser) { - if (is_array($correlation['filter']['formula'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); + private static function validateCreate(array &$correlations): void { + $api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['name']], 'fields' => [ + 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('correlation', 'name')], + 'description' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('correlation', 'description')], + 'status' => ['type' => API_INT32, 'in' => implode(',', [ZBX_CORRELATION_ENABLED, ZBX_CORRELATION_DISABLED])], + 'filter' => self::getFilterValidationRules() + ['flags' => API_REQUIRED], + 'operations' => ['type' => API_OBJECTS, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'uniq' => [['type']], 'fields' => [ + 'type' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [ZBX_CORR_OPERATION_CLOSE_OLD, ZBX_CORR_OPERATION_CLOSE_NEW])] + ]] + ]]; + + if (!CApiInputValidator::validate($api_input_rules, $correlations, '/', $error)) { + self::exception(ZBX_API_ERROR_PARAMETERS, $error); } - if (!$parser->parse($correlation['filter']['formula'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect custom expression "%2$s" for correlation "%1$s": %3$s.', - $correlation['name'], $correlation['filter']['formula'], $parser->error - ) - ); - } + self::checkDuplicates($correlations); + self::validateFormula($correlations); + self::checkHostGroups($correlations); } /** - * Validate correlation condition formula IDs. Check the "formulaid" field and that formula matches the conditions. + * Check host group permissions. * - * @param array $correlation One correlation containing array of - * conditions and name. - * @param string $correlation['name'] Correlation name for error messages. - * @param array $correlation['filter'] Correlation filter array containing - * the conditions. - * @param array $correlation['filter']['conditions'] An array of correlation conditions. - * @param string $correlation['filter']['conditions'][]['formulaid'] Condition formula ID. - * @param CConditionFormula $parser Condition formula parser. + * @static * - * @throws APIException if the input is invalid. + * @param array $correlations */ - protected function validateConditionFormulaIDs(array $correlation, CConditionFormula $parser) { - foreach ($correlation['filter']['conditions'] as $condition) { - if (!array_key_exists('formulaid', $condition)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'formulaid', $correlation['name']) - ); - } - elseif (is_array($condition['formulaid'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - elseif (!preg_match('/[A-Z]+/', $condition['formulaid'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Incorrect filter condition formula ID given for correlation "%1$s".', $correlation['name']) - ); - } - } + private static function checkHostGroups(array $correlations): void { + $groupids = []; - $conditions = zbx_toHash($correlation['filter']['conditions'], 'formulaid'); - $constants = array_unique(zbx_objectValues($parser->constants, 'value')); + foreach ($correlations as $correlation) { + if (!array_key_exists('filter', $correlation) || !array_key_exists('conditions', $correlation['filter'])) { + continue; + } - foreach ($constants as $constant) { - if (!array_key_exists($constant, $conditions)) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Condition "%2$s" used in formula "%3$s" for correlation "%1$s" is not defined.', - $correlation['name'], $constant, $correlation['filter']['formula'] - )); + foreach ($correlation['filter']['conditions'] as $condition) { + if ($condition['type'] == ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP) { + $groupids[$condition['groupid']] = true; + } } + } - unset($conditions[$constant]); + if (!$groupids) { + return; } - // Check that the "conditions" array has no unused conditions. - if ($conditions) { - $condition = reset($conditions); - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Condition "%2$s" is not used in formula "%3$s" for correlation "%1$s".', $correlation['name'], - $condition['formulaid'], $correlation['filter']['formula'] - )); + $groups_count = API::HostGroup()->get([ + 'countOutput' => true, + 'groupids' => array_keys($groupids) + ]); + + if ($groups_count != count($groupids)) { + self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); } } /** - * Validate correlation operations. Check if "operations" is valid, if "type" is valid and there are no duplicate - * operations in correlation. + * @static * - * @param array $correlation One correlation containing array of operations and name. - * @param string $correlation['name'] Correlation name for error messages. - * @param array $correlation['operations'] An array of correlation operations. - * @param int $correlation['operations']['type'] Correlation operation type. - * Possible values are: - * 0 - ZBX_CORR_OPERATION_CLOSE_OLD; - * 1 - ZBX_CORR_OPERATION_CLOSE_NEW. - * @param CLimitedSetValidator $filter_operations_validator Operations validator. + * @param array $correlations + * @param array|null $db_correlations * * @throws APIException if the input is invalid. */ - protected function validateOperations(array $correlation, CLimitedSetValidator $filter_operations_validator) { - if (!is_array($correlation['operations'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } - elseif (!$correlation['operations']) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No "%1$s" given for correlation "%2$s".', 'operations', $correlation['name']) - ); + private static function validateUpdate(array &$correlations, array &$db_correlations = null): void { + $api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['correlationid'], ['name']], 'fields' => [ + 'correlationid' => ['type' => API_ID, 'flags' => API_REQUIRED], + 'name' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('correlation', 'name')], + 'description' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('correlation', 'description')], + 'status' => ['type' => API_INT32, 'in' => implode(',', [ZBX_CORRELATION_ENABLED, ZBX_CORRELATION_DISABLED])], + 'filter' => self::getFilterValidationRules(), + 'operations' => ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY, 'uniq' => [['type']], 'fields' => [ + 'type' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [ZBX_CORR_OPERATION_CLOSE_OLD, ZBX_CORR_OPERATION_CLOSE_NEW])] + ]] + ]]; + + if (!CApiInputValidator::validate($api_input_rules, $correlations, '/', $error)) { + self::exception(ZBX_API_ERROR_PARAMETERS, $error); } - foreach ($correlation['operations'] as $operation) { - if (!array_key_exists('type', $operation)) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('No operation type given for correlation "%1$s".', $correlation['name']) - ); - } - elseif (is_array($operation['type'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); - } + $db_correlations = DB::select('correlation', [ + 'output' => ['correlationid', 'name', 'description', 'status'], + 'correlationids' => array_column($correlations, 'correlationid'), + 'preservekeys' => true + ]); - if (!$filter_operations_validator->validate($operation['type'])) { - self::exception(ZBX_API_ERROR_PARAMETERS, _s( - 'Incorrect value "%1$s" in field "%2$s" for correlation "%3$s".', - $operation['type'], - 'type', - $correlation['name'] - )); - } + if (count($correlations) != count($db_correlations)) { + self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); } - // Check that same operation types do not repeat. - $duplicate = CArrayHelper::findDuplicate($correlation['operations'], 'type'); - if ($duplicate) { - self::exception(ZBX_API_ERROR_PARAMETERS, - _s('Duplicate "%1$s" value "%2$s" for correlation "%3$s".', 'type', $duplicate['type'], - $correlation['name'] - ) - ); - } + self::checkDuplicates($correlations, $db_correlations); + + self::addAffectedObjects($correlations, $db_correlations); + self::validateFormula($correlations); + self::checkHostGroups($correlations); } /** - * Insert correlation condition values to their corresponding DB tables. + * Validate correlation condition formula IDs. Check the "formulaid" field and that formula matches the conditions. * - * @param array $conditions An array of conditions to create. + * @static * - * @return array + * @param array $correlations + * + * @throws APIException if the input is invalid. */ - protected function addConditions(array $conditions) { - $conditions = DB::save('corr_condition', $conditions); + protected static function validateFormula(array $correlations): void { + $condition_formula_parser = new CConditionFormula(); - $corr_condition_tags_to_create = []; - $corr_condition_hostgroups_to_create = []; - $corr_condition_tag_pairs_to_create = []; - $corr_condition_tag_values_to_create = []; - - foreach ($conditions as $condition) { - switch ($condition['type']) { - case ZBX_CORR_CONDITION_OLD_EVENT_TAG: - case ZBX_CORR_CONDITION_NEW_EVENT_TAG: - $corr_condition_tags_to_create[] = $condition; - break; - - case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: - $corr_condition_hostgroups_to_create[] = $condition; - break; - - case ZBX_CORR_CONDITION_EVENT_TAG_PAIR: - $corr_condition_tag_pairs_to_create[] = $condition; - break; - - case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE: - case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: - $corr_condition_tag_values_to_create[] = $condition; - break; + foreach ($correlations as $i => $correlation) { + if (!array_key_exists('filter', $correlation)) { + continue; } - } - if ($corr_condition_tags_to_create) { - DB::insert('corr_condition_tag', $corr_condition_tags_to_create, false); - } + if ($correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { + $condition_formula_parser->parse($correlation['filter']['formula']); - if ($corr_condition_hostgroups_to_create) { - DB::insert('corr_condition_group', $corr_condition_hostgroups_to_create, false); - } + $constants = array_column($condition_formula_parser->constants, 'value', 'value'); + $path = '/'.($i + 1).'/filter'; - if ($corr_condition_tag_pairs_to_create) { - DB::insert('corr_condition_tagpair', $corr_condition_tag_pairs_to_create, false); - } + if (count($correlation['filter']['conditions']) != count($constants)) { + self::exception(ZBX_API_ERROR_PARAMETERS, + _s('Invalid parameter "%1$s": %2$s.', $path.'/conditions', _('incorrect number of conditions')) + ); + } - if ($corr_condition_tag_values_to_create) { - DB::insert('corr_condition_tagvalue', $corr_condition_tag_values_to_create, false); + foreach ($correlation['filter']['conditions'] as $j => $condition) { + if (!array_key_exists($condition['formulaid'], $constants)) { + self::exception(ZBX_API_ERROR_PARAMETERS, _s('Invalid parameter "%1$s": %2$s.', + $path.'/conditions/'.($j + 1).'/formulaid', _('an identifier is not defined in the formula') + )); + } + } + } } - - return $conditions; } /** * Apply query output options. * - * @param type $table_name - * @param type $table_alias + * @param string $table_name + * @param string $table_alias * @param array $options * @param array $sql_parts * @@ -1427,7 +774,7 @@ class CCorrelation extends CApiService { * * @return array */ - protected function addRelatedObjects(array $options, array $result) { + protected function addRelatedObjects(array $options, array $result): array { $result = parent::addRelatedObjects($options, $result); $correlationids = array_keys($result); @@ -1569,4 +916,113 @@ class CCorrelation extends CApiService { return $result; } + + /** + * @static + * + * @param array $correlations + * @param array $db_correlations + */ + private static function addAffectedObjects(array $correlations, array &$db_correlations): void { + $correlationids = ['filter' => [], 'operations' => []]; + + foreach ($correlations as $correlation) { + if (array_key_exists('filter', $correlation)) { + $correlationids['filter'][] = $correlation['correlationid']; + $db_correlations[$correlation['correlationid']]['filter']['conditions'] = []; + } + + if (array_key_exists('operations', $correlation)) { + $correlationids['operations'][] = $correlation['correlationid']; + $db_correlations[$correlation['correlationid']]['operations'] = []; + } + } + + if ($correlationids['filter']) { + $options = [ + 'output' => ['correlationid', 'evaltype', 'formula'], + 'filter' => ['correlationid' => $correlationids['filter']] + ]; + $db_filters = DBselect(DB::makeSql('correlation', $options)); + + while ($db_filter = DBfetch($db_filters)) { + $db_correlations[$db_filter['correlationid']]['filter'] = + array_diff_key($db_filter, array_flip(['correlationid'])); + } + + $sql = 'SELECT c.correlationid,c.corr_conditionid,c.type,ct.tag AS ct_tag,'. + 'cg.operator AS cg_operator,cg.groupid,ctp.oldtag,ctp.newtag,ctv.tag AS ctv_tag,'. + 'ctv.operator AS ctv_operator,ctv.value'. + ' FROM corr_condition c'. + ' LEFT JOIN corr_condition_tag ct ON ct.corr_conditionid=c.corr_conditionid'. + ' LEFT JOIN corr_condition_group cg ON cg.corr_conditionid=c.corr_conditionid'. + ' LEFT JOIN corr_condition_tagpair ctp ON ctp.corr_conditionid=c.corr_conditionid'. + ' LEFT JOIN corr_condition_tagvalue ctv ON ctv.corr_conditionid=c.corr_conditionid'. + ' WHERE '.dbConditionId('c.correlationid', $correlationids['filter']); + $db_conditions = DBselect($sql); + + while ($db_condition = DBfetch($db_conditions)) { + $condition = [ + 'corr_conditionid' => $db_condition['corr_conditionid'], + 'type' => $db_condition['type'] + ]; + + switch ($db_condition['type']) { + case ZBX_CORR_CONDITION_OLD_EVENT_TAG: + case ZBX_CORR_CONDITION_NEW_EVENT_TAG: + $condition['tag'] = $db_condition['ct_tag']; + $condition['operator'] = CONDITION_OPERATOR_EQUAL; + break; + + case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP: + $condition['groupid'] = $db_condition['groupid']; + $condition['operator'] = $db_condition['cg_operator']; + break; + + case ZBX_CORR_CONDITION_EVENT_TAG_PAIR: + $condition['oldtag'] = $db_condition['oldtag']; + $condition['newtag'] = $db_condition['newtag']; + $condition['operator'] = CONDITION_OPERATOR_EQUAL; + break; + + case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE: + case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE: + $condition['tag'] = $db_condition['ctv_tag']; + $condition['value'] = $db_condition['value']; + $condition['operator'] = $db_condition['ctv_operator']; + break; + } + + $db_correlations[$db_condition['correlationid']]['filter']['conditions'] + [$db_condition['corr_conditionid']] = $condition; + } + + foreach ($db_correlations as $correlationid => &$db_correlation) { + if ($db_correlation['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { + $formula = $db_correlation['filter']['formula']; + + $formulaids = CConditionHelper::getFormulaIds($formula); + + foreach ($db_correlation['filter']['conditions'] as &$db_condition) { + $db_condition['formulaid'] = $formulaids[$db_condition['corr_conditionid']]; + } + unset($db_condition); + } + } + unset($db_correlation); + } + + if ($correlationids['operations']) { + $options = [ + 'output' => ['corr_operationid', 'correlationid', 'type'], + 'filter' => ['correlationid' => $correlationids['operations']] + ]; + $db_operations = DBselect(DB::makeSql('corr_operation', $options)); + + while ($db_operation = DBfetch($db_operations)) { + $db_correlations[$db_operation['correlationid']]['operations'][$db_operation['corr_operationid']] = + array_diff_key($db_operation, array_flip(['correlationid'])); + } + } + } } |