array("host"), "services" => array("service"), "downtimes" => array("hostdowntime", "servicedowntime"), "hostdowntimes" => array("hostdowntime"), "servicedowntimes" => array("servicedowntime"), "hostgroups" => array("hostgroup"), "servicegroups" => array("servicegroup"), "comments" => array("servicecomment", "hostcomment"), "hostcomments" => array("hostcomment"), "servicecomments" => array("servicecomment") ); private $reader = null; private $source = ""; private $columns = array(); private $limit = null; private $offset = 0; private $order_columns = array(); private $groupColumns = array(); private $groupByFn = null; private $filter = array(); // Magic indexes const FN_SCOPE = 0; const FN_NAME = 1; public function hasOrder() { return !empty($this->order_columns); } public function hasColumns() { return !empty($this->columns); } public function getColumns() { return $this->columns; } public function hasLimit() { return $this->limit !== false; } public function hasOffset() { return $this->offset !== false; } public function getLimit() { return $this->limit; } public function getOffset() { return $this->offset; } public function __construct(IReader $reader) { $this->reader = $reader; } public function where($key, $val = null) { $this->filter[] = array($key, $val); return $this; } public function order($columns, $dir = null) { if($dir && strtolower($dir) == "desc") $dir = self::SORT_DESC; else $dir = self::SORT_ASC; if(!is_array($columns)) $columns = array($columns); foreach($columns as $col) { if (($pos = strpos($col, ' ')) !== false) { $dir = strtoupper(substr($col, $pos + 1)); if ($dir === 'DESC') { $dir = self::SORT_DESC; } else { $dir = self::SORT_ASC; } $col = substr($col, 0, $pos); } else { $col = $col; } $this->order_columns[] = array($col, $dir); } return $this; } public function limit($count = null, $offset = 0) { if ((is_null($count) || is_integer($count)) && (is_null($offset) || is_integer($offset))) { $this->offset = $offset; $this->limit = $count; } else { throw new Exception("Got invalid limit $count, $offset"); } return $this; } public function from($table, $columns = null) { if (isset(self::$VALID_TARGETS[$table])) $this->source = $table; else throw new \Exception("Unknown from target for status.dat :". $table); $this->columns = $columns; return $this; } /** * * @throws Exception */ private function getFilteredIndices($classType = "\Icinga\Protocol\Statusdat\Query\Group") { $baseGroup = null; if (!empty($this->filter)) { $baseGroup = new $classType(); foreach ($this->filter as $values) { $baseGroup->addItem(new $classType($values[0], $values[1])); } } $state = $this->reader->getObjects(); $result = array(); foreach (self::$VALID_TARGETS[$this->source] as $target) { $indexes = & array_keys($state[$target]); if ($baseGroup) { $indexes = & $baseGroup->filter($state[$target]); } if (!isset($result[$target])) { $result[$target] = $indexes; } else { array_merge($result[$target], $indexes); } } return $result; } private function orderIndices(array &$indices) { if(!empty($this->order_columns)) { foreach($indices as $type=>&$subindices) { $this->currentType = $type; // we're singlethreaded, so let's do it a bit dirty usort($subindices,array($this,"orderResult")); } } } private function orderResult($a,$b) { $o1 = &$this->reader->getObjectByName($this->currentType,$a); $o2 = &$this->reader->getObjectByName($this->currentType,$b); $result = 0; foreach($this->order_columns as $col) { $result += $col[1]*strnatcasecmp($o1->{$col[0]},$o2->{$col[0]}); } if($result > 0) return 1; if($result < 0) return -1; return 0; } private function limitIndices(array &$indices) { foreach($indices as $type=>$subindices){ $indices[$type] = array_slice($subindices,$this->offset,$this->limit); } } public function groupByFunction($fn,$scope=null) { $this->groupByFn = array($scope ? $scope : $this,$fn); return $this; } public function groupByColumns($columns) { if(!is_array($columns)) $columns = array($columns); $this->groupColumns = $columns; $this->groupByFn = array($this,"columnGroupFn"); return $this; } private function columnGroupFn(array &$indices) { $cols = $this->groupColumns; $result = array(); foreach($indices as $type=>$subindices) { foreach($subindices as $objectIndex) { $r = &$this->reader->getObjectByName($type,$objectIndex); $hash = ""; $cols = array(); foreach($this->groupColumns as $col) { $hash = md5($hash.$r->$col); $cols[$col] = $r->$col; } if(!isset($result[$hash])) $result[$hash] = (object) array( "columns" => (object) $cols, "count" => 0 ); $result[$hash]->count++; } } return array_values($result); } public function getResult() { $indices = &$this->getFilteredIndices(); $this->orderIndices($indices); if($this->groupByFn) { $scope = $this->groupByFn[self::FN_SCOPE]; $fn = $this->groupByFn[self::FN_NAME]; return $scope->$fn($indices); } $this->limitIndices($indices); $result = array(); $state = &$this->reader->getObjects(); foreach ($indices as $type=>$subindices) { foreach($subindices as $index) { $result[] = &$state[$type][$index]; } } return $result; } }