You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
6.6 KiB
262 lines
6.6 KiB
<?php
|
|
/*
|
|
** Zabbix
|
|
** Copyright (C) 2001-2023 Zabbix SIA
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
**/
|
|
|
|
|
|
/**
|
|
* A class for creating conditions.
|
|
*/
|
|
class CConditionHelper {
|
|
|
|
/**
|
|
* Generate a numeric formula from conditions $conditions with respect to evaluation type $evalType.
|
|
* Each condition must have a condition type, that will be used for grouping.
|
|
*
|
|
* Supported $evalType values:
|
|
* - CONDITION_EVAL_TYPE_AND_OR
|
|
* - CONDITION_EVAL_TYPE_AND
|
|
* - CONDITION_EVAL_TYPE_OR
|
|
*
|
|
* Example:
|
|
* echo CFormulaHelper::getFormula(array(
|
|
* 1 => 'condition1',
|
|
* 2 => 'condition1',
|
|
* 5 => 'condition2'
|
|
* ), CONDITION_EVAL_TYPE_AND_OR);
|
|
*
|
|
* // ({1} or {2}) and {5}
|
|
*
|
|
* Keep in sync with JS getConditionFormula().
|
|
*
|
|
* @param array $conditions conditions with IDs as keys and condition type with values
|
|
* @param int $evalType
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getFormula(array $conditions, $evalType) {
|
|
$groupedConditions = [];
|
|
foreach ($conditions as $id => $condition) {
|
|
$groupedConditions[$condition][] = '{'.$id.'}';
|
|
}
|
|
|
|
// operators
|
|
switch ($evalType) {
|
|
case CONDITION_EVAL_TYPE_AND:
|
|
$conditionOperator = 'and';
|
|
$groupOperator = $conditionOperator;
|
|
break;
|
|
case CONDITION_EVAL_TYPE_OR:
|
|
$conditionOperator = 'or';
|
|
$groupOperator = $conditionOperator;
|
|
break;
|
|
default:
|
|
$conditionOperator = 'or';
|
|
$groupOperator = 'and';
|
|
break;
|
|
}
|
|
|
|
$groupFormulas = [];
|
|
foreach ($groupedConditions as $conditionIds) {
|
|
if (count($conditionIds) > 1) {
|
|
$groupFormulas[] = '('.implode(' '.$conditionOperator.' ', $conditionIds).')';
|
|
}
|
|
else {
|
|
$groupFormulas[] = $conditionIds[0];
|
|
}
|
|
}
|
|
|
|
$formula = implode(' '.$groupOperator.' ', $groupFormulas);
|
|
|
|
// strip parentheses if there's only one condition group
|
|
if (count($groupedConditions) == 1) {
|
|
$formula = trim($formula, '()');
|
|
}
|
|
|
|
return $formula;
|
|
}
|
|
|
|
/**
|
|
* Extract the numeric IDs used in the given formula and generate a set of letter aliases for them.
|
|
* Aliases will be generated in the order they appear in the formula.
|
|
*
|
|
* Example:
|
|
* CFormulaHelper::getFormulaIds('1 or (2 and 3) or 2');
|
|
*
|
|
* // array(1 => 'A', 2 => 'B', 3 => 'C')
|
|
*
|
|
* @param string $formula a formula with numeric IDs
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getFormulaIds($formula) {
|
|
$matches = [];
|
|
preg_match_all('/\d+/', $formula, $matches);
|
|
|
|
$ids = array_keys(array_flip($matches[0]));
|
|
|
|
$i = 0;
|
|
$formulaIds = [];
|
|
foreach ($ids as $id) {
|
|
$formulaIds[$id] = num2letter($i);
|
|
|
|
$i++;
|
|
}
|
|
|
|
return $formulaIds;
|
|
}
|
|
|
|
/**
|
|
* Replace numeric IDs with formula IDs using the pairs given in $ids.
|
|
*
|
|
* @param string $formula
|
|
* @param array $ids array of numeric ID - formula ID pairs
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function replaceNumericIds($formula, array $ids) {
|
|
foreach ($ids as $id => $formulaId) {
|
|
$formula = str_replace('{'.$id.'}', $formulaId, $formula);
|
|
}
|
|
|
|
return $formula;
|
|
}
|
|
|
|
/**
|
|
* Replace formula IDs with numeric IDs using the pairs given in $ids.
|
|
*
|
|
* Notes:
|
|
* - $formula must be valid before the function call
|
|
* - $ids must contain all constants used in the $formula
|
|
*
|
|
* @param string $formula
|
|
* @param array $ids array of formula ID - numeric ID pairs
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function replaceLetterIds($formula, array $ids) {
|
|
$parser = new CConditionFormula();
|
|
$parser->parse($formula);
|
|
|
|
foreach (array_reverse($parser->constants) as $constant) {
|
|
$formula = substr_replace($formula, '{'.$ids[$constant['value']].'}', $constant['pos'],
|
|
strlen($constant['value'])
|
|
);
|
|
}
|
|
|
|
return $formula;
|
|
}
|
|
|
|
/**
|
|
* Sort conditions by formula id as if they were numbers.
|
|
*
|
|
* @param array $conditions conditions
|
|
* @return array
|
|
*/
|
|
public static function sortConditionsByFormulaId($conditions) {
|
|
uasort($conditions, function ($condition1, $condition2) {
|
|
return CConditionHelper::compareFormulaIds($condition1['formulaid'], $condition2['formulaid']);
|
|
});
|
|
|
|
return $conditions;
|
|
}
|
|
|
|
/**
|
|
* Compare formula IDs.
|
|
*
|
|
* @param string $formulaId1
|
|
* @param string $formulaId2
|
|
*
|
|
* @return int
|
|
*/
|
|
public static function compareFormulaIds($formulaId1, $formulaId2) {
|
|
$len1 = strlen($formulaId1);
|
|
$len2 = strlen($formulaId2);
|
|
|
|
if ($len1 == $len2) {
|
|
return strcmp($formulaId1, $formulaId2);
|
|
}
|
|
else {
|
|
return ($len1 < $len2) ? -1 : 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns next formula ID - A => B, B => C, ..., Z => AA, ..., ZZ => AAA, ...
|
|
*
|
|
* @param array $formulaIds
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getNextFormulaId(array $formulaIds) {
|
|
if (!$formulaIds) {
|
|
$nextFormulaId = 'A';
|
|
}
|
|
else {
|
|
usort($formulaIds, ['CConditionHelper', 'compareFormulaIds']);
|
|
|
|
$lastFormulaId = array_pop($formulaIds);
|
|
|
|
$calculateNextFormulaId = function($formulaId) use (&$calculateNextFormulaId) {
|
|
$head = substr($formulaId, 0, -1);
|
|
$tail = substr($formulaId, -1);
|
|
|
|
if ($tail == 'Z') {
|
|
$nextFormulaId = $head ? $calculateNextFormulaId($head).'A' : 'AA';
|
|
}
|
|
else {
|
|
$nextFormulaId = $head.chr(ord($tail) + 1);
|
|
}
|
|
|
|
return $nextFormulaId;
|
|
};
|
|
|
|
$nextFormulaId = $calculateNextFormulaId($lastFormulaId);
|
|
}
|
|
|
|
return $nextFormulaId;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sorts the conditions based on the given formula.
|
|
*
|
|
* @param array $filter Array containing the formula and conditions.
|
|
*
|
|
* $filter = [
|
|
* 'conditions' => (array) Array of conditions.
|
|
* 'formula' => (string) Action condition formula.
|
|
* ]
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function sortConditionsByFormula(array $filter): array {
|
|
$formula = $filter['formula'];
|
|
|
|
usort($filter['conditions'], static function (array $a, array $b) use ($formula) {
|
|
$pattern = '/([A-Z]+)/';
|
|
preg_match_all($pattern, $formula, $matches);
|
|
$upper_letters = $matches[0];
|
|
|
|
return array_search($a['formulaid'], $upper_letters) <=> array_search($b['formulaid'], $upper_letters);
|
|
});
|
|
|
|
return $filter['conditions'];
|
|
}
|
|
}
|