mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-10-31 11:24:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			339 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			339 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
| <?php
 | |
| // {{{ICINGA_LICENSE_HEADER}}}
 | |
| // {{{ICINGA_LICENSE_HEADER}}}
 | |
| 
 | |
| namespace Icinga\Protocol\Statusdat\Query;
 | |
| 
 | |
| class Expression implements IQueryPart
 | |
| {
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const ENC_NUMERIC = 0;
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const ENC_SET = 0;
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const ENC_STRING = 0;
 | |
| 
 | |
|     /**
 | |
|      * @var string
 | |
|      */
 | |
|     private $expression;
 | |
| 
 | |
|     /**
 | |
|      * @var null
 | |
|      */
 | |
|     private $field = null;
 | |
| 
 | |
|     /**
 | |
|      * @var array
 | |
|      */
 | |
|     private $basedata = array();
 | |
| 
 | |
|     /**
 | |
|      * @var null
 | |
|      */
 | |
|     private $function = null;
 | |
| 
 | |
|     /**
 | |
|      * @var string
 | |
|      */
 | |
|     private $value = "";
 | |
| 
 | |
|     /**
 | |
|      * @var null
 | |
|      */
 | |
|     private $operator = null;
 | |
| 
 | |
|     /**
 | |
|      * @var null
 | |
|      */
 | |
|     private $name = null;
 | |
| 
 | |
|     /**
 | |
|      * @var null
 | |
|      */
 | |
|     public $CB = null;
 | |
| 
 | |
|     /**
 | |
|      * @param $token
 | |
|      * @throws \Exception
 | |
|      */
 | |
|     private function getOperatorType($token)
 | |
|     {
 | |
|         switch (strtoupper($token)) {
 | |
|             case ">":
 | |
|                 $this->CB = "isGreater";
 | |
|                 break;
 | |
|             case "<":
 | |
|                 $this->CB = "isLess";
 | |
|                 break;
 | |
|             case ">=":
 | |
|                 $this->CB = "isGreaterEq";
 | |
|                 break;
 | |
|             case "<=":
 | |
|                 $this->CB = "isLessEq";
 | |
|                 break;
 | |
|             case "=":
 | |
|                 $this->CB = "isEqual";
 | |
|                 break;
 | |
|             case "LIKE":
 | |
|                 $this->CB = "isLike";
 | |
|                 break;
 | |
|             case "!=":
 | |
|                 $this->CB = "isNotEqual";
 | |
|                 break;
 | |
|             case "IN":
 | |
|                 $this->CB = "isIn";
 | |
|                 break;
 | |
|             default:
 | |
|                 throw new \Exception("Unknown operator $token in expression $this->expression !");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $tokens
 | |
|      * @return mixed
 | |
|      */
 | |
|     private function extractAggregationFunction(&$tokens)
 | |
|     {
 | |
|         $token = $tokens[0];
 | |
|         $value = array();
 | |
|         if (preg_match("/COUNT\{(.*)\}/", $token, $value) == false) {
 | |
|             return $token;
 | |
|         }
 | |
|         $this->function = "count";
 | |
|         $tokens[0] = $value[1];
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $values
 | |
|      */
 | |
|     private function parseExpression(&$values)
 | |
|     {
 | |
|         $tokenized = preg_split("/ +/", trim($this->expression), 3);
 | |
|         $this->extractAggregationFunction($tokenized);
 | |
|         if (count($tokenized) != 3) {
 | |
|             echo(
 | |
|                 "Currently statusdat query expressions must be in "
 | |
|                 . "the format FIELD OPERATOR ? or FIELD OPERATOR :value_name"
 | |
|             );
 | |
|         }
 | |
| 
 | |
|         $this->fields = explode(".", trim($tokenized[0]));
 | |
|         $this->field = $this->fields[count($this->fields) - 1];
 | |
|         $this->getOperatorType(trim($tokenized[1]));
 | |
|         $tokenized[2] = trim($tokenized[2]);
 | |
| 
 | |
|         if ($tokenized[2][0] === ":") {
 | |
|             $this->name = substr($tokenized, 1);
 | |
|             $this->value = $values[$this->name];
 | |
|         } else {
 | |
|             if ($tokenized[2] === "?") {
 | |
|                 $this->value = array_shift($values);
 | |
|             } else {
 | |
|                 $this->value = trim($tokenized[2]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $expression
 | |
|      * @param $values
 | |
|      * @return $this
 | |
|      */
 | |
|     public function fromString($expression, &$values)
 | |
|     {
 | |
|         $this->expression = $expression;
 | |
|         $this->parseExpression($values);
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param null $expression
 | |
|      * @param array $values
 | |
|      */
 | |
|     public function __construct($expression = null, &$values = array())
 | |
|     {
 | |
|         if ($expression) {
 | |
|             $this->fromString($expression, $values);
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param array $base
 | |
|      * @param array $idx
 | |
|      * @return array|mixed
 | |
|      */
 | |
|     public function filter(array &$base, &$idx = array())
 | |
|     {
 | |
|         if (!$idx) {
 | |
|             $idx = array_keys($base);
 | |
|         }
 | |
|         $this->basedata = $base;
 | |
|         return array_filter($idx, array($this, "filterFn"));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     public function getValue()
 | |
|     {
 | |
|         return $this->value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return null
 | |
|      */
 | |
|     public function getField()
 | |
|     {
 | |
|         return $this->field;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $idx
 | |
|      * @return bool
 | |
|      */
 | |
|     protected function filterFn($idx)
 | |
|     {
 | |
|         $values = $this->getFieldValues($idx);
 | |
| 
 | |
|         if ($values === false) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         if ($this->CB == "IS_IN") {
 | |
|             return count(array_intersect($values, $this->value)) > 0;
 | |
|         }
 | |
|         if ($this->CB == "IS_NOT_IN") {
 | |
|             return count(array_intersect($values, $this->value)) == 0;
 | |
|         }
 | |
|         if ($this->function) {
 | |
|             $values = call_user_func($this->function, $values);
 | |
|             if (!is_array($values)) {
 | |
|                 $values = array($values);
 | |
|             }
 | |
|         }
 | |
|         foreach ($values as $val) {
 | |
|             if ($this->{$this->CB}($val)) {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $idx
 | |
|      * @return array
 | |
|      */
 | |
|     private function getFieldValues($idx)
 | |
|     {
 | |
|         $res = $this->basedata[$idx];
 | |
|         foreach ($this->fields as $field) {
 | |
|             if (!is_array($res)) {
 | |
|                 if (!isset($res->$field)) {
 | |
|                     $res = array();
 | |
|                     break;
 | |
|                 }
 | |
|                 $res = $res->$field;
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             // it can be that an element contains more than one value, like it
 | |
|             // happens when using comments, in this case we have to create a new
 | |
|             // array that contains the values/objects we're searching
 | |
|             $swap = array();
 | |
|             foreach ($res as $sub) {
 | |
|                 if (!isset($sub->$field)) {
 | |
|                     continue;
 | |
|                 }
 | |
|                 if (!is_array($sub->$field)) {
 | |
|                     $swap[] = $sub->$field;
 | |
|                 } else {
 | |
|                     $swap = array_merge($swap, $sub->$field);
 | |
|                 }
 | |
|             }
 | |
|             $res = $swap;
 | |
|         }
 | |
|         if (!is_array($res)) {
 | |
|             return array($res);
 | |
|         }
 | |
|         return $res;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isGreater($value)
 | |
|     {
 | |
|         return $value > $this->value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isLess($value)
 | |
|     {
 | |
|         return $value < $this->value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isLike($value)
 | |
|     {
 | |
|         return preg_match("/^" . str_replace("%", ".*", $this->value) . "$/", $value) ? true : false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isEqual($value)
 | |
|     {
 | |
|         if (!is_numeric($value)) {
 | |
|             return strtolower($value) == strtolower($this->value);
 | |
|         }
 | |
|         return $value == $this->value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isNotEqual($value)
 | |
|     {
 | |
|         return $value != $this->value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isGreaterEq($value)
 | |
|     {
 | |
|         return $value >= $this->value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isLessEq($value)
 | |
|     {
 | |
|         return $value <= $this->value;
 | |
|     }
 | |
| }
 |