mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-10-31 11:24:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			398 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			398 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| // {{{ICINGA_LICENSE_HEADER}}}
 | |
| // {{{ICINGA_LICENSE_HEADER}}}
 | |
| 
 | |
| namespace Icinga\Protocol\Statusdat\Query;
 | |
| 
 | |
| use Icinga\Exception\IcingaException;
 | |
| 
 | |
| /**
 | |
|  * Class Group
 | |
|  * @package Icinga\Protocol\Statusdat\Query
 | |
|  */
 | |
| class Group implements IQueryPart
 | |
| {
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const GROUP_BEGIN = "(";
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const GROUP_END = ")";
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const CONJUNCTION_AND = "AND ";
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const CONJUNCTION_OR = "OR ";
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const EXPRESSION = 0;
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const EOF = -1;
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const TYPE_AND = "AND";
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     const TYPE_OR = "OR";
 | |
| 
 | |
|     /**
 | |
|      * @var array
 | |
|      */
 | |
|     private $items = array();
 | |
| 
 | |
|     /**
 | |
|      * @var int
 | |
|      */
 | |
|     private $parsePos = 0;
 | |
| 
 | |
|     /**
 | |
|      * @var string
 | |
|      */
 | |
|     private $expression = "";
 | |
| 
 | |
|     /**
 | |
|      * @var null
 | |
|      */
 | |
|     private $expressionClass = null;
 | |
| 
 | |
|     /**
 | |
|      * @var string
 | |
|      */
 | |
|     private $type = "";
 | |
| 
 | |
|     /**
 | |
|      * @var int
 | |
|      */
 | |
|     private $subExpressionStart = 0;
 | |
| 
 | |
|     /**
 | |
|      * @var int
 | |
|      */
 | |
|     private $subExpressionLength = 0;
 | |
| 
 | |
|     /**
 | |
|      * Optional query to use
 | |
|      *
 | |
|      * @var Query
 | |
|      */
 | |
|     private $query = null;
 | |
| 
 | |
|     /**
 | |
|      * @var
 | |
|      */
 | |
|     private $value;
 | |
| 
 | |
|     /**
 | |
|      * @param $value
 | |
|      */
 | |
|     public function setValue($value)
 | |
|     {
 | |
|         $this->value = $value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return array
 | |
|      */
 | |
|     public function getItems()
 | |
|     {
 | |
|         return $this->items;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     public function getType()
 | |
|     {
 | |
|         return $this->type ? $this->type : self::TYPE_AND;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $type
 | |
|      */
 | |
|     public function setType($type)
 | |
|     {
 | |
|         $this->type = $type;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws IcingaException
 | |
|      */
 | |
|     private function tokenize()
 | |
|     {
 | |
|         $token = 0;
 | |
|         $subgroupCount = 0;
 | |
|         while ($token != self::EOF) {
 | |
| 
 | |
|             $token = $this->getNextToken();
 | |
| 
 | |
|             if ($token === self::GROUP_BEGIN) {
 | |
| 
 | |
|                 /**
 | |
|                  * check if this is a nested group, if so then it's
 | |
|                  * considered part of the subexpression
 | |
|                  */
 | |
|                 if ($subgroupCount == 0) {
 | |
|                     $this->startNewSubExpression();
 | |
|                 }
 | |
|                 $subgroupCount++;
 | |
|                 continue;
 | |
|             }
 | |
|             if ($token === self::GROUP_END) {
 | |
|                 if ($subgroupCount < 1) {
 | |
|                     throw new IcingaException(
 | |
|                         'Invalid Query: unexpected \')\' at pos %s',
 | |
|                         $this->parsePos
 | |
|                     );
 | |
|                 }
 | |
|                 $subgroupCount--;
 | |
|                 /*
 | |
|                  * check if this is a nested group, if so then it's
 | |
|                  * considered part of the subexpression
 | |
|                  */
 | |
|                 if ($subgroupCount == 0) {
 | |
|                     $this->addSubgroupFromExpression();
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if ($token === self::CONJUNCTION_AND && $subgroupCount == 0) {
 | |
|                 $this->startNewSubExpression();
 | |
|                 if ($this->type != self::TYPE_AND && $this->type != "") {
 | |
|                     $this->createImplicitGroup(self::TYPE_AND);
 | |
|                     break;
 | |
|                 } else {
 | |
|                     $this->type = self::TYPE_AND;
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
|             if ($token === self::CONJUNCTION_OR && $subgroupCount == 0) {
 | |
|                 $this->startNewSubExpression();
 | |
|                 if ($this->type != self::TYPE_OR && $this->type != "") {
 | |
|                     $this->createImplicitGroup(self::TYPE_OR);
 | |
|                     break;
 | |
|                 } else {
 | |
| 
 | |
|                     $this->type = self::TYPE_OR;
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             $this->subExpressionLength = $this->parsePos - $this->subExpressionStart;
 | |
|         }
 | |
|         if ($subgroupCount > 0) {
 | |
|             throw new IcingaException('Unexpected end of query, are you missing a parenthesis?');
 | |
|         }
 | |
| 
 | |
|         $this->startNewSubExpression();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $type
 | |
|      */
 | |
|     private function createImplicitGroup($type)
 | |
|     {
 | |
|         $group = new Group();
 | |
|         $group->setType($type);
 | |
|         $group->addItem(array_pop($this->items));
 | |
| 
 | |
|         $group->fromString(substr($this->expression, $this->parsePos), $this->value, $this->expressionClass);
 | |
|         $this->items[] = $group;
 | |
|         $this->parsePos = strlen($this->expression);
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     private function startNewSubExpression()
 | |
|     {
 | |
|         if ($this->getCurrentSubExpression() != "") {
 | |
|             if (!$this->expressionClass) {
 | |
|                 $this->items[] = new Expression($this->getCurrentSubExpression(), $this->value);
 | |
|             } else {
 | |
|                 $this->items[] = new $this->expressionClass($this->getCurrentSubExpression(), $this->value);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         $this->subExpressionStart = $this->parsePos;
 | |
|         $this->subExpressionLength = 0;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     private function getCurrentSubExpression()
 | |
|     {
 | |
| 
 | |
|         return substr($this->expression, $this->subExpressionStart, $this->subExpressionLength);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      *
 | |
|      */
 | |
|     private function addSubgroupFromExpression()
 | |
|     {
 | |
| 
 | |
|         if (!$this->expressionClass) {
 | |
|             $this->items[] = new Group($this->getCurrentSubExpression(), $this->value);
 | |
|         } else {
 | |
|             $group = new Group();
 | |
|             $group->fromString($this->getCurrentSubExpression(), $this->value, $this->expressionClass);
 | |
|             $this->items[] = $group;
 | |
|         }
 | |
|         $this->subExpressionStart = $this->parsePos;
 | |
|         $this->subExpressionLength = 0;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return bool
 | |
|      */
 | |
|     private function isEOF()
 | |
|     {
 | |
|         if ($this->parsePos >= strlen($this->expression)) {
 | |
|             return true;
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return int|string
 | |
|      */
 | |
|     private function getNextToken()
 | |
|     {
 | |
|         if ($this->isEOF()) {
 | |
|             return self::EOF;
 | |
|         }
 | |
| 
 | |
|         // skip whitespaces
 | |
|         while ($this->expression[$this->parsePos] == " ") {
 | |
|             $this->parsePos++;
 | |
|             if ($this->isEOF()) {
 | |
|                 return self::EOF;
 | |
|             }
 | |
|         }
 | |
|         if ($this->expression[$this->parsePos] == self::GROUP_BEGIN) {
 | |
|             $this->parsePos++;
 | |
|             return self::GROUP_BEGIN;
 | |
|         }
 | |
|         if ($this->expression[$this->parsePos] == self::GROUP_END) {
 | |
|             $this->parsePos++;
 | |
|             return self::GROUP_END;
 | |
|         }
 | |
|         if (substr_compare(
 | |
|             $this->expression,
 | |
|             self::CONJUNCTION_AND,
 | |
|             $this->parsePos,
 | |
|             strlen(self::CONJUNCTION_AND),
 | |
|             true
 | |
|         ) === 0) {
 | |
|             $this->parsePos += strlen(self::CONJUNCTION_AND);
 | |
|             return self::CONJUNCTION_AND;
 | |
|         }
 | |
|         if (substr_compare(
 | |
|             $this->expression,
 | |
|             self::CONJUNCTION_OR,
 | |
|             $this->parsePos,
 | |
|             strlen(self::CONJUNCTION_OR),
 | |
|             true
 | |
|         ) === 0) {
 | |
|             $this->parsePos += strlen(self::CONJUNCTION_OR);
 | |
|             return self::CONJUNCTION_OR;
 | |
|         }
 | |
|         $this->parsePos++;
 | |
|         return self::EXPRESSION;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $ex
 | |
|      * @return $this
 | |
|      */
 | |
|     public function addItem($ex)
 | |
|     {
 | |
|         $this->items[] = $ex;
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $expression
 | |
|      * @param array $value
 | |
|      * @param null $expressionClass
 | |
|      * @return $this
 | |
|      */
 | |
|     public function fromString($expression, &$value = array(), $expressionClass = null)
 | |
|     {
 | |
|         $this->expression = $expression;
 | |
|         $this->value = & $value;
 | |
|         $this->expressionClass = $expressionClass;
 | |
| 
 | |
|         $this->tokenize();
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param null $expression
 | |
|      * @param array $value
 | |
|      */
 | |
|     public function __construct($expression = null, &$value = array())
 | |
|     {
 | |
|         if ($expression) {
 | |
|             $this->fromString($expression, $value);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param array $base
 | |
|      * @param null $idx
 | |
|      * @return array|null
 | |
|      */
 | |
|     public function filter(array &$base, &$idx = null)
 | |
|     {
 | |
|         if ($this->type == self::TYPE_OR) {
 | |
|             $idx = array();
 | |
|             foreach ($this->items as &$subFilter) {
 | |
|                 $baseKeys = array_keys($base);
 | |
|                 $subFilter->setQuery($this->query);
 | |
|                 $idx += $subFilter->filter($base, $baseKeys);
 | |
|             }
 | |
|         } else {
 | |
|             if (!$idx) {
 | |
|                 $idx = array_keys($base);
 | |
|             }
 | |
|             foreach ($this->items as $subFilter) {
 | |
|                 $subFilter->setQuery($this->query);
 | |
|                 $idx = array_intersect($idx, $subFilter->filter($base, $idx));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return $idx;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Add additional information about the query this filter belongs to
 | |
|      *
 | |
|      * @param $query
 | |
|      * @return mixed
 | |
|      */
 | |
|     public function setQuery($query)
 | |
|     {
 | |
|         $this->query = $query;
 | |
|     }
 | |
| }
 |