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

400 lines
9.4 KiB
PHP
Raw Normal View History

<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
2013-07-15 12:26:10 +02:00
* This file is part of Icinga 2 Web.
*
2013-07-15 12:26:10 +02:00
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* 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.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
2013-07-15 12:26:10 +02:00
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Protocol\Statusdat;
use Icinga\Protocol;
use Icinga\Data\AbstractQuery;
/**
* Class Query
* @package Icinga\Protocol\Statusdat
*/
class Query extends AbstractQuery
{
/**
* @var array
*/
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")
);
/**
* @var IReader|null
*/
private $reader = null;
/**
* @var string
*/
private $source = "";
/**
* @var null
*/
private $limit = null;
/**
* @var int
*/
private $offset = 0;
/**
* @var array
*/
protected $order_columns = array();
/**
* @var array
*/
private $groupColumns = array();
/**
* @var null
*/
private $groupByFn = null;
/**
* @var array
*/
private $filter = array();
/**
*
*/
const FN_SCOPE = 0;
/**
*
*/
const FN_NAME = 1;
/**
* @return bool
*/
public function hasOrder()
{
return !empty($this->order_columns);
}
/**
* @return bool
*/
public function hasColumns()
{
return !empty($this->columns);
}
/**
* @return array
*/
public function getColumns()
{
return $this->columns;
}
/**
* @return bool
*/
public function hasLimit()
{
return $this->limit !== false;
}
/**
* @return bool
*/
public function hasOffset()
{
return $this->offset !== false;
}
/**
* @return null
*/
public function getLimit()
{
return $this->limit;
}
/**
* @return int|null
*/
public function getOffset()
{
return $this->offset;
}
/**
* @param $key
* @param null $val
* @return $this
*/
public function where($key, $val = null)
{
$this->filter[] = array($key, $val);
return $this;
}
/**
* @param $columns
* @param null $dir
* @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;
}
/**
* @param null $count
* @param int $offset
* @return $this
* @throws Exception
*/
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;
}
/**
* @param $table
* @param null $columns
* @return $this
* @throws \Exception
*/
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);
}
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->ds->getObjects();
$result = array();
$source = self::$VALID_TARGETS[$this->source];
foreach ($source as $target) {
2013-07-23 12:18:27 +02:00
$indexes = array_keys($state[$target]);
if ($baseGroup) {
2013-07-23 12:18:27 +02:00
$indexes = $baseGroup->filter($state[$target]);
}
if (!isset($result[$target])) {
$result[$target] = $indexes;
} else {
array_merge($result[$target], $indexes);
}
}
return $result;
}
/**
* @param array $indices
*/
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"));
}
}
}
/**
* @param $a
* @param $b
* @return int
*/
private function orderResult($a, $b)
{
2013-07-23 12:18:27 +02:00
$o1 = $this->ds->getObjectByName($this->currentType, $a);
$o2 = $this->ds->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;
}
/**
* @param array $indices
*/
private function limitIndices(array &$indices)
{
foreach ($indices as $type => $subindices) {
$indices[$type] = array_slice($subindices, $this->offset, $this->limit);
}
}
/**
* @param $fn
* @param null $scope
* @return $this
*/
public function groupByFunction($fn, $scope = null)
{
$this->groupByFn = array($scope ? $scope : $this, $fn);
return $this;
}
/**
* @param $columns
* @return $this
*/
public function groupByColumns($columns)
{
if (!is_array($columns)) {
$columns = array($columns);
}
$this->groupColumns = $columns;
$this->groupByFn = array($this, "columnGroupFn");
return $this;
}
/**
* @param array $indices
* @return array
*/
private function columnGroupFn(array &$indices)
{
$cols = $this->groupColumns;
$result = array();
foreach ($indices as $type => $subindices) {
foreach ($subindices as $objectIndex) {
2013-07-23 12:18:27 +02:00
$r = $this->ds->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);
}
/**
* @return array
*/
public function getResult()
{
2013-07-23 12:18:27 +02:00
$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();
2013-07-23 12:18:27 +02:00
$state = $this->ds->getObjects();
foreach ($indices as $type => $subindices) {
foreach ($subindices as $index) {
$result[] = & $state[$type][$index];
}
}
return $result;
}
}