icingaweb2/library/Icinga/Protocol/Statusdat/Query.php

257 lines
6.9 KiB
PHP
Raw Normal View History

<?php
namespace Icinga\Protocol\Statusdat;
use Icinga\Protocol;
class Query extends Protocol\AbstractQuery
{
public static $VALID_TARGETS = array(
"hosts" => 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;
}
}