Refactoring and Query and IDO code,

the Monitoring/View code was completly dropped in favor of
the DataView implementations, as new Backends otherwise
would require to implement two seperate query logics

refs #3801
This commit is contained in:
Jannis Moßhammer 2013-10-15 19:56:33 +02:00
parent df81c85090
commit 44be5e85da
77 changed files with 1843 additions and 2921 deletions

View File

@ -1,400 +0,0 @@
<?php
namespace Icinga\Data;
use Icinga\Exception;
abstract class AbstractQuery implements QueryInterface
{
/**
* Sort ascending
*/
const SORT_ASC = 1;
/**
* Sort descending
*/
const SORT_DESC = -1;
/**
* Query data source
*
* @var DatasourceInterface
*/
protected $ds;
/**
* The table you are going to query
*/
protected $table;
/**
* The columns you are interested in. All columns if empty
*/
protected $columns = array();
/**
* A list of filters
*/
protected $filters = array();
/**
* The columns you're using to sort the query result
*/
protected $order_columns = array();
/**
* Return not more than that many rows
*/
protected $limit_count;
/**
* Result starts with this row
*/
protected $limit_offset;
/**
* Constructor
*
* @param DatasourceInterface $ds Your data source
*/
public function __construct(DatasourceInterface $ds, $columns = null)
{
$this->ds = $ds;
if ($columns === null) {
$columns = $this->getDefaultColumns();
}
if ($columns !== null) {
$this->columns($columns);
}
$this->init();
}
public function addColumn($name, $alias = null)
{
// TODO: Fail if adding column twice, but allow same col with new alias
if ($alias === null) {
$this->columns[] = $name;
} else {
$this->columns[$alias] = $name;
}
return $this;
}
public function getDatasource()
{
return $this->ds;
}
protected function getDefaultColumns()
{
return null;
}
/**
* Choose a table and the colums you are interested in
*
* Query will return all available columns if none are given here
*
* @return self
*/
public function from($table, $columns = null)
{
$this->table = $table;
if ($columns !== null) {
$this->columns($columns);
} else {
// TODO: Really?
$this->columns = $this->getDefaultColumns();
}
return $this;
}
public function columns($columns)
{
if (is_array($columns)) {
$this->columns = $columns;
} else {
$this->columns = array($columns);
}
return $this;
}
/**
* Use once or multiple times to filter result set
*
* Multiple where calls will be combined by a logical AND operation
*
* @param string $key Column or backend-specific search expression
* @param string $val Search value, must be escaped automagically
*
* @return self
*/
public function where($key, $val = null)
{
$this->filters[] = array($key, $val);
return $this;
}
/**
* Sort query result by the given column name
*
* Sort direction can be ascending (self::SORT_ASC, being the default)
* or descending (self::SORT_DESC).
*
* Preferred usage:
* <code>
* $query->sort('column_name ASC')
* </code>
*
* @param string $col Column, may contain direction separated by space
* @param int $dir Sort direction
*
* @return self
*/
public function order($col, $dir = null)
{
if ($dir === null) {
if (($pos = strpos($col, ' ')) === false) {
$dir = $this->getDefaultSortDir($col);
} else {
$dir = strtoupper(substr($col, $pos + 1));
if ($dir === 'DESC') {
$dir = self::SORT_DESC;
} else {
$dir = self::SORT_ASC;
}
$col = substr($col, 0, $pos);
}
} else {
if ($dir === self::SORT_DESC || strtoupper($dir) === 'DESC') {
$dir = self::SORT_DESC;
} else {
$dir = self::SORT_ASC;
}
}
$this->order_columns[] = array($col, $dir);
return $this;
}
protected function getDefaultSortDir($col)
{
return self::SORT_ASC;
}
/**
* Limit the result set
*
* @param int $count Return not more than that many rows
* @param int $offset Result starts with this row
*
* @return self
*/
// Nur wenn keine stats, sonst im RAM!!
// Offset gibt es nicht, muss simuliert werden
public function limit($count = null, $offset = null)
{
if (! preg_match('~^\d+~', $count . $offset)) {
throw new Exception\ProgrammingError(
sprintf(
'Got invalid limit: %s, %s',
$count,
$offset
)
);
}
$this->limit_count = (int) $count;
$this->limit_offset = (int) $offset;
return $this;
}
/**
* Wheter at least one order column has been applied to this Query
*
* @return bool
*/
public function hasOrder()
{
return ! empty($this->order_columns);
}
/**
* Wheter a limit has been applied to this Query
*
* @return bool
*/
public function hasLimit()
{
return $this->limit_count !== null;
}
/**
* Wheter a starting offset been applied to this Query
*
* @return bool
*/
public function hasOffset()
{
return $this->limit_offset > 0;
}
/**
* Get the query limit
*
* @return int|null
*/
public function getLimit()
{
return $this->limit_count;
}
/**
* Get the query starting offset
*
* @return int|null
*/
public function getOffset()
{
return $this->limit_offset;
}
/**
* Get the columns that have been asked for with this query
*
* @return array
*/
public function listColumns()
{
return $this->columns;
}
/**
* Get the filters that have been applied to this query
*
* @return array
*/
public function listFilters()
{
return $this->filters;
}
/**
* Extend this function for things that should happen at construction time
*/
protected function init()
{
}
/**
* Extend this function for things that should happen before query execution
*/
protected function finish()
{
}
/**
* Total result size regardless of limit and offset
*
* @return int
*/
public function count()
{
return $this->ds->count($this);
}
/**
* Fetch result as an array of objects
*
* @return array
*/
public function fetchAll()
{
return $this->ds->fetchAll($this);
}
/**
* Fetch first result row
*
* @return object
*/
public function fetchRow()
{
return $this->ds->fetchRow($this);
}
/**
* Fetch first result column
*
* @return array
*/
public function fetchColumn()
{
return $this->ds->fetchColumn($this);
}
/**
* Fetch first column value from first result row
*
* @return mixed
*/
public function fetchOne()
{
return $this->ds->fetchOne($this);
}
/**
* Fetch result as a key/value pair array
*
* @return array
*/
public function fetchPairs()
{
return $this->ds->fetchPairs($this);
}
/**
* Return a pagination adapter for this query
*
* @return \Zend_Paginator
*/
public function paginate($limit = null, $page = null)
{
$this->finish();
if ($page === null && $limit === null) {
$request = \Zend_Controller_Front::getInstance()->getRequest();
if ($page === null) {
$page = $request->getParam('page', 0);
}
if ($limit === null) {
$limit = $request->getParam('limit', 20);
}
}
$this->limit($limit, $page * $limit);
$paginator = new \Zend_Paginator(
new \Icinga\Web\Paginator\Adapter\QueryAdapter($this)
);
$paginator->setItemCountPerPage($limit);
$paginator->setCurrentPageNumber($page);
return $paginator;
}
public function getColumns()
{
return $this->columns;
}
/**
* Destructor. Remove $ds, just to be on the safe side
*/
public function __destruct()
{
unset($this->ds);
}
}

View File

@ -0,0 +1,486 @@
<?php
namespace Icinga\Data;
use Icinga\Application\Logger;
use Icinga\Exception;
use Icinga\Filter\Filterable;
use Icinga\Filter\Query\Node;
use Icinga\Filter\Query\Tree;
use Zend_Paginator;
use Icinga\Web\Paginator\Adapter\QueryAdapter;
abstract class BaseQuery implements Filterable
{
/**
* Sort ascending
*/
const SORT_ASC = 1;
/**
* Sort descending
*/
const SORT_DESC = -1;
/**
* Query data source
*
* @var DatasourceInterface
*/
protected $ds;
/**
* The target of this query
* @var string
*/
protected $table;
/**
* The columns of the target that should be returned
* @var array
*/
private $columns;
/**
* The columns you're using to sort the query result
* @var array
*/
private $orderColumns = array();
/**
* Return not more than that many rows
* @var int
*/
private $limitCount;
/**
* Result starts with this row
* @var int
*/
private $limitOffset;
/**
* The backend independent filter to use for this query
*
* @var Tree
*/
private $filter;
/**
* Constructor
*
* @param DatasourceInterface $ds Your data source
*/
public function __construct(DatasourceInterface $ds, array $columns = null)
{
$this->ds = $ds;
$this->columns = $columns;
$this->clearFilter();
$this->init();
}
public function getDatasource()
{
return $this->ds;
}
public function setColumns(array $columns)
{
$this->columns = $columns;
}
/**
* Define the target and attributes for this query
*
* The Query will return the default attribute the attributes parameter is omitted
*
* @param String $target The target of this query (tablename, objectname, depends on the concrete implementation)
* @param array $columns An optional array of columns to select, if none are given the default
* columnset is returned
*
* @return self Fluent interface
*/
public function from($target, array $attributes = null)
{
$this->table = $target;
if ($attributes !== null) {
$this->columns = $attributes;
}
return $this;
}
/**
* Add a filter expression to be applied on this query.
*
* This is an alias to andWhere()
* The syntax of the expression and valid parameters are to be defined by the concrete
* backend-specific query implementation.
*
* @param string $expression Implementation specific search expression
* @param mixed $parameters Implementation specific search value to use for query placeholders
*
* @return self Fluent Interface
* @see BaseQuery::andWhere() This is an alias to andWhere()
*/
public function where($expression, $parameters = null)
{
return $this->andWhere($expression, $parameters);
}
/**
* Add an mandatory filter expression to be applied on this query
*
* The syntax of the expression and valid parameters are to be defined by the concrete
* backend-specific query implementation.
*
* @param string $expression Implementation specific search expression
* @param mixed $parameters Implementation specific search value to use for query placeholders
* @return self Fluent interface
*/
public function andWhere($expression, $parameters = null)
{
$node = $this->parseFilterExpression($expression, $parameters);
if ($node === null) {
Logger::debug('Ignoring invalid filter expression: %s (params: %s)', $expression, $parameters);
return $this;
}
$this->filter->insert(Node::createAndNode());
$this->filter->insert($node);
return $this;
}
/**
* Add an lower priority filter expression to be applied on this query
*
* The syntax of the expression and valid parameters are to be defined by the concrete
* backend-specific query implementation.
*
* @param string $expression Implementation specific search expression
* @param mixed $parameters Implementation specific search value to use for query placeholders
* @return self Fluent interface
*/
public function orWhere($expression, $parameters = null)
{
$node = $this->parseFilterExpression($expression, $parameters);
if ($node === null) {
Logger::debug('Ignoring invalid filter expression: %s (params: %s)', $expression, $parameters);
return $this;
}
$this->filter->insert(Node::createOrNode());
$this->filter->insert($node);
return $this;
}
/**
* Determine whether the given field is a valid filter target
*
* The base implementation always returns true, overwrite it in concrete backend-specific
* implementations
*
* @param String $field The field to test for being filterable
* @return bool True if the field can be filtered, otherwise false
*/
public function isValidFilterTarget($field)
{
return true;
}
/**
* Return the internally used field name for the given alias
*
* The base implementation just returns the given field, overwrite it in concrete backend-specific
* implementations
*
* @param String $field The field to test for being filterable
* @return bool True if the field can be filtered, otherwise false
*/
public function getMappedField($field)
{
return $field;
}
/**
* Add a filter to this query
*
* This is the implementation for the Filterable, use where instead
*
* @param $filter
*/
public function addFilter($filter)
{
if (is_string($filter)) {
$this->addFilter(call_user_func_array(array($this, 'parseFilterExpression'), func_get_args()));
} elseif ($filter instanceof Node) {
$this->filter->insert($filter);
}
}
public function setFilter(Tree $filter)
{
$this->filter = $filter;
}
/**
* Parse a backend specific filter expression and return a Query\Node object
*
* @param $expression The expression to parse
* @param $parameters Optional parameters for the expression
* @return Node A query node or null if it's an invalid expression
*/
abstract protected function parseFilterExpression($expression, $parameters = null);
/**
* Return all default columns
*
* @return array An array of default columns to use when none are selected
*/
public function getDefaultColumns()
{
return array();
}
/**
* Sort query result by the given column name
*
* Sort direction can be ascending (self::SORT_ASC, being the default)
* or descending (self::SORT_DESC).
*
* Preferred usage:
* <code>
* $query->sort('column_name ASC')
* </code>
*
* @param string $columnOrAlias Column, may contain direction separated by space
* @param int $dir Sort direction
*
* @return BaseQuery
*/
public function order($columnOrAlias, $dir = null)
{
if ($dir === null) {
$colDirPair = explode(' ', $columnOrAlias, 2);
if (count($colDirPair) === 1) {
$dir = $this->getDefaultSortDir($columnOrAlias);
} else {
$dir = $colDirPair[1];
$columnOrAlias = $colDirPair[0];
}
}
$dir = (strtoupper(trim($dir)) === 'DESC') ? self::SORT_DESC : self::SORT_ASC;
$this->orderColumns[] = array($columnOrAlias, $dir);
return $this;
}
/**
* Determine the default sort direction constant for the given column
*
* @param String $col The column to get the sort direction for
* @return int Either SORT_ASC or SORT_DESC
*/
protected function getDefaultSortDir($col)
{
return self::SORT_ASC;
}
/**
* Limit the result set
*
* @param int $count The numeric maximum limit to apply on the query result
* @param int $offset The offset to use for the result set
*
* @return BaseQuery
*/
public function limit($count = null, $offset = null)
{
$this->limitCount = $count !== null ? intval($count) : null;
$this->limitOffset = intval($offset);
return $this;
}
/**
* Determine whether this query will be ordered explicitly
*
* @return bool True when an order column has been set
*/
public function hasOrder()
{
return !empty($this->orderColumns);
}
/**
* Determine whether this query will be limited explicitly
*
* @return bool True when an limit count has been set, otherwise false
*/
public function hasLimit()
{
return $this->limitCount !== null;
}
/**
* Determine whether an offset is set or not
*
* @return bool True when an offset > 0 is set
*/
public function hasOffset()
{
return $this->limitOffset > 0;
}
/**
* Get the query limit
*
* @return int The query limit or null if none is set
*/
public function getLimit()
{
return $this->limitCount;
}
/**
* Get the query starting offset
*
* @return int The query offset or null if none is set
*/
public function getOffset()
{
return $this->limitOffset;
}
/**
* Implementation specific initialization
*
* Overwrite this instead of __construct (it's called at the end of the construct) to
* implement custom initialization logic on construction time
*/
protected function init()
{
}
/**
* Return all columns set in this query or the default columns if none are set
*
* @return array An array of columns
*/
public function getColumns()
{
return ($this->columns !== null) ? $this->columns : $this->getDefaultColumns();
}
/**
* Return all columns used for ordering
*
* @return array
*/
public function getOrderColumns()
{
return $this->orderColumns;
}
public function getFilter()
{
return $this->filter;
}
public function clearFilter()
{
$this->filter = new Tree();
}
/**
* Return a pagination adapter for this query
*
* @return \Zend_Paginator
*/
public function paginate($limit = null, $page = null)
{
if ($page === null && $limit === null) {
$request = \Zend_Controller_Front::getInstance()->getRequest();
if ($page === null) {
$page = $request->getParam('page', 0);
}
if ($limit === null) {
$limit = $request->getParam('limit', 20);
}
}
$this->limit($limit, $page * $limit);
$paginator = new Zend_Paginator(new QueryAdapter($this));
$paginator->setItemCountPerPage($limit);
$paginator->setCurrentPageNumber($page);
return $paginator;
}
/**
* Total result size regardless of limit and offset
*
* @return int
*/
public function count()
{
return $this->ds->count($this);
}
/**
* Fetch result as an array of objects
*
* @return array
*/
public function fetchAll()
{
return $this->ds->fetchAll($this);
}
/**
* Fetch first result row
*
* @return object
*/
public function fetchRow()
{
return $this->ds->fetchRow($this);
}
/**
* Fetch first result column
*
* @return array
*/
public function fetchColumn()
{
return $this->ds->fetchColumn($this);
}
/**
* Fetch first column value from first result row
*
* @return mixed
*/
public function fetchOne()
{
return $this->ds->fetchOne($this);
}
/**
* Fetch result as a key/value pair array
*
* @return array
*/
public function fetchPairs()
{
return $this->ds->fetchPairs($this);
}
}

View File

@ -73,7 +73,7 @@ class Datasource implements DatasourceInterface
}
$result = array();
$filters = $query->listFilters();
$columns = $query->listColumns();
$columns = $query->getColumns();
foreach ($this->data as & $row) {
// Skip rows that do not match applied filters

View File

@ -2,9 +2,9 @@
namespace Icinga\Data\DataArray;
use Icinga\Data\AbstractQuery;
use Icinga\Data\BaseQuery;
class Query extends AbstractQuery
class Query extends BaseQuery
{
/**
* Remember the last count
@ -63,16 +63,18 @@ class Query extends AbstractQuery
*/
public function compare(& $a, & $b, $col_num = 0)
{
if (! array_key_exists($col_num, $this->order_columns)) {
$orderColumns = $this->getOrderColumns();
if (! array_key_exists($col_num, $orderColumns)) {
return 0;
}
$col = $this->order_columns[$col_num][0];
$dir = $this->order_columns[$col_num][1];
$col = $orderColumns[$col_num][0];
$dir = $orderColumns[$col_num][1];
//$res = strnatcmp(strtolower($a->$col), strtolower($b->$col));
$res = strcmp(strtolower($a->$col), strtolower($b->$col));
if ($res === 0) {
if (array_key_exists(++$col_num, $this->order_columns)) {
if (array_key_exists(++$col_num, $orderColumns)) {
return $this->compare($a, $b, $col_num);
} else {
return 0;
@ -84,4 +86,16 @@ class Query extends AbstractQuery
return $res * -1;
}
}
public function parseFilterExpression($expression, $parameters = null)
{
return null;
}
public function applyFilter()
{
return null;
}
}

View File

@ -8,7 +8,8 @@ interface DatasourceInterface
/**
* Instantiate a Query object
*
* @return AbstractQuery
* @return BaseQuery
*/
public function select();
}

View File

@ -2,12 +2,22 @@
namespace Icinga\Data\Db;
use Icinga\Data\AbstractQuery;
use Icinga\Data\Optional;
use Icinga\Data\The;
use Icinga\Filter\Query\Node;
use Icinga\Filter\Query\Tree;
use Zend_Db_Select;
use Icinga\Data\BaseQuery;
class Query extends AbstractQuery
/**
* Db/Query class for implementing database queries
*/
class Query extends BaseQuery
{
/**
* Zend_Db_Adapter_Abstract
*
*
*/
protected $db;
@ -20,19 +30,19 @@ class Query extends AbstractQuery
/**
* Select object
*/
protected $selectQuery;
private $selectQuery;
/**
* Select object used for count query
*/
protected $countQuery;
private $countQuery;
/**
* Allow to override COUNT(*)
*/
protected $countColumns;
protected $uglySlowConservativeCount = false;
protected $useSubqueryCount = false;
protected $countCache;
@ -44,7 +54,36 @@ class Query extends AbstractQuery
$this->baseQuery = $this->db->select();
}
protected function getSelectQuery()
/**
* Return the raw base query
*
* Modifications on this requires a call to Query::refreshQueryObjects()
*
* @return Zend_Db_Select
*
*/
public function getRawBaseQuery()
{
return $this->baseQuery;
}
/**
* Recreate the select and count queries
*
* Required when external modifications are made in the baseQuery
*/
public function refreshQueryObjects()
{
$this->createQueryObjects();
}
/**
* Return the select query and initialize it if not done yet
*
* @return Zend_Db_Select
*/
public function getSelectQuery()
{
if ($this->selectQuery === null) {
$this->createQueryObjects();
@ -56,7 +95,12 @@ class Query extends AbstractQuery
return $this->selectQuery;
}
protected function getCountQuery()
/**
* Return the current count query and initialize it if not done yet
*
* @return Zend_Db_Select
*/
public function getCountQuery()
{
if ($this->countQuery === null) {
$this->createQueryObjects();
@ -64,54 +108,99 @@ class Query extends AbstractQuery
return $this->countQuery;
}
protected function createQueryObjects()
/**
* Create the Zend_Db select query for this query
*/
private function createSelectQuery()
{
$this->beforeCreatingCountQuery();
$this->beforeCreatingSelectQuery();
$this->selectQuery = clone($this->baseQuery);
$this->selectQuery->columns($this->columns);
$this->selectQuery->columns($this->getColumns());
if ($this->hasOrder()) {
foreach ($this->order_columns as $col) {
foreach ($this->getOrderColumns() as $col) {
$this->selectQuery->order(
$col[0]
. ' '
. ( $col[1] === self::SORT_DESC ? 'DESC' : 'ASC')
$col[0] . ' ' . (($col[1] === self::SORT_DESC) ? 'DESC' : 'ASC')
);
}
}
}
if ($this->uglySlowConservativeCount) {
$query = clone($this->selectQuery);
if ($this->maxCount === null) {
$this->countQuery = $this->db->select()->from(
$query,
'COUNT(*)'
);
} else {
$this->countQuery = $this->db->select()->from(
$query->reset('order')->limit($this->maxCount),
'COUNT(*)'
);
}
/**
* Create a countquery by using the select query as a subselect and count it's result
*
* This is a rather naive approach and not suitable for complex queries or queries with many results
*
* @return Zend_Db_Select The query object representing the count
*/
private function createCountAsSubQuery()
{
$query = clone($this->selectQuery);
if ($this->maxCount === null) {
return $this->db->select()->from($query, 'COUNT(*)');
} else {
$this->countQuery = clone($this->baseQuery);
if ($this->countColumns === null) {
$this->countColumns = array('cnt' => 'COUNT(*)');
}
$this->countQuery->columns($this->countColumns);
return $this->db->select()->from(
$query->reset('order')->limit($this->maxCount),
'COUNT(*)'
);
}
}
protected function beforeCreatingCountQuery()
/**
* Create a custom count query based on the columns set in countColumns
*
* @return Zend_Db_Select The query object representing the count
*/
private function createCustomCountQuery()
{
$query = clone($this->baseQuery);
if ($this->countColumns === null) {
$this->countColumns = array('cnt' => 'COUNT(*)');
}
$query->columns($this->countColumns);
return $query;
}
protected function beforeCreatingSelectQuery()
/**
* Create a query using the selected operation
*
* @see Query::createCountAsSubQuery() Used when useSubqueryCount is true
* @see Query::createCustomCountQuery() Called when useSubqueryCount is false
*/
private function createCountQuery()
{
if ($this->useSubqueryCount) {
$this->countQuery = $this->createCountAsSubquery();
} else {
$this->countQuery =$this->createCustomCountQuery();
}
}
protected function beforeQueryCreation()
{
}
protected function afterQueryCreation()
{
}
/**
* Create the Zend_Db select and count query objects for this instance
*/
private function createQueryObjects()
{
$this->beforeQueryCreation();
$this->applyFilter();
$this->createSelectQuery();
$this->createCountQuery();
$this->afterQueryCreation();
}
/**
* Query the database and fetch the result count of this query
*
* @return int The result count of this query as returned by the database
*/
public function count()
{
if ($this->countCache === null) {
@ -120,31 +209,62 @@ class Query extends AbstractQuery
return $this->countCache;
}
/**
* Query the database and return all results
*
* @return array An array containing subarrays with all results contained in the database
*/
public function fetchAll()
{
return $this->db->fetchAll($this->getSelectQuery());
}
/**
* Query the database and return the next result row
*
* @return array An array containing the next row of the database result
*/
public function fetchRow()
{
return $this->db->fetchRow($this->getSelectQuery());
}
/**
* Query the database and return a single column of the result
*
* @return array An array containing the first column of the result
*/
public function fetchColumn()
{
return $this->db->fetchCol($this->getSelectQuery());
}
/**
* Query the database and return a single result
*
* @return array An associative array containing the first result
*/
public function fetchOne()
{
return $this->db->fetchOne($this->getSelectQuery());
}
/**
* Query the database and return key=>value pairs using hte first two columns
*
* @return array An array containing key=>value pairs
*/
public function fetchPairs()
{
return $this->db->fetchPairs($this->getSelectQuery());
}
/**
* Return the select and count query as a textual representation
*
* @return string An String containing the select and count query, using unix style newlines
* as linebreaks
*/
public function dump()
{
return "QUERY\n=====\n"
@ -154,8 +274,50 @@ class Query extends AbstractQuery
. "\n\n";
}
/**
* Return the select query
*
* The paginator expects this, so we can't use debug output here
*
* @return Zend_Db_Select
*/
public function __toString()
{
return (string) $this->getSelectQuery();
return strval($this->getSelectQuery());
}
/**
* Parse a backend specific filter expression and return a Query\Node object
*
* @param $expression The expression to parse
* @param $parameters Optional parameters for the expression
*
* @return Node A query node or null if it's an invalid expression
*/
protected function parseFilterExpression($expression, $parameter = null)
{
$splitted = explode(' ', $expression, 3);
if (count($splitted) === 1 && $parameter) {
return Node::createOperatorNode(Node::OPERATOR_EQUALS, $splitted[0], $parameter);
} elseif (count($splitted) === 2 && $parameter) {
Node::createOperatorNode($splitted[0], $splitted[1], is_string($parameter));
return Node::createOperatorNode(Node::OPERATOR_EQUALS, $splitted[0], $parameter);
} elseif (count($splitted) === 3) {
if (trim($splitted[2]) === '?' && is_string($parameter)) {
return Node::createOperatorNode($splitted[1], $splitted[0], $parameter);
} else {
return Node::createOperatorNode($splitted[1], $splitted[0], $splitted[2]);
}
}
return null;
}
public function applyFilter()
{
$parser = new TreeToSqlParser($this);
$parser->treeToSql($this->getFilter(), $this->baseQuery);
$this->clearFilter();
}
}

View File

@ -26,20 +26,16 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Filter\Backend;
namespace Icinga\Data\Db;
use Icinga\Data\DatasourceInterface;
use Icinga\Data\Db\Query;
use Icinga\Data\BaseQuery;
use Icinga\Filter\Query\Tree;
use Icinga\Filter\Query\Node;
use Icinga\Filter\Filterable;
use Icinga\Module\Monitoring\DataView\DataView;
use Icinga\Module\Monitoring\Backend\Ido\Query\AbstractQuery;
/**
* Converter class that takes a query tree and creates an SQL Query from it's state
*/
class IdoQueryConverter
class TreeToSqlParser
{
/**
* The query class to use as the base for converting
@ -59,7 +55,7 @@ class IdoQueryConverter
*
* @param AbstractQuery $query The query to use for conversion
*/
public function __construct(AbstractQuery $query)
public function __construct(BaseQuery $query)
{
$this->query = $query;
}
@ -128,7 +124,9 @@ class IdoQueryConverter
if (!$this->query->isValidFilterTarget($node->left) && $this->query->getMappedField($node->left)) {
return '';
}
$this->query->requireColumn($node->left);
$queryString = $this->query->getMappedField($node->left);
if ($this->query->isAggregateColumn($node->left)) {
$this->type = 'HAVING';
}
@ -174,6 +172,7 @@ class IdoQueryConverter
if ($tree->root == null) {
return;
}
$tree->root = $tree->normalizeTree($tree->root);
$sql = $this->nodeToSqlQuery($tree->root);
if ($this->filtersAggregate()) {
$baseQuery->having($sql);

View File

@ -1,54 +0,0 @@
<?php
/**
* Data Filter
*/
namespace Icinga\Data;
use ArrayIterator;
/**
* This class contains an array of filters
*
* @package Icinga\Data
* @author Icinga-Web Team <info@icinga.org>
* @copyright 2013 Icinga-Web Team <info@icinga.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
*/
class Filter extends ArrayIterator
{
public function without($keys)
{
$filter = new Filter();
$params = $this->toParams();
if (! is_array($keys)) {
$keys = array($keys);
}
foreach ($keys as $key) {
if (array_key_exists($key, $params)) {
unset($params[$key]);
}
}
foreach ($params as $k => $v) {
$filter[] = array($k, $v);
}
return $filter;
}
/**
* Get filter as key-value array
*
* @return array
*/
public function toParams()
{
$params = array();
foreach ($this as $filter) {
$params[$filter[0]] = $filter[1];
}
return $params;
}
}

View File

@ -1,162 +0,0 @@
<?php
namespace Icinga\Data;
use Countable;
interface QueryInterface extends Countable
{
/**
* Constructor
*
* @param DatasourceInterface $ds Your data source
*/
public function __construct(DatasourceInterface $ds, $columns = null);
public function getDatasource();
/**
* Choose a table and the colums you are interested in
*
* Query will return all available columns if none are given here
*
* @return self
*/
public function from($table, $columns = null);
public function columns($columns);
/**
* Use once or multiple times to filter result set
*
* Multiple where calls will be combined by a logical AND operation
*
* @param string $key Column or backend-specific search expression
* @param string $val Search value, must be escaped automagically
*
* @return self
*/
public function where($key, $val = null);
/**
* Sort query result by the given column name
*
* Sort direction can be ascending (self::SORT_ASC, being the default)
* or descending (self::SORT_DESC).
*
* Preferred usage:
* <code>
* $query->sort('column_name ASC')
* </code>
*
* @param string $col Column, may contain direction separated by space
* @param int $dir Sort direction
*
* @return self
*/
public function order($col, $dir = null);
/**
* Limit the result set
*
* @param int $count Return not more than that many rows
* @param int $offset Result starts with this row
*
* @return self
*/
public function limit($count = null, $offset = null);
/**
* Wheter at least one order column has been applied to this Query
*
* @return bool
*/
public function hasOrder();
/**
* Wheter a limit has been applied to this Query
*
* @return bool
*/
public function hasLimit();
/**
* Wheter a starting offset been applied to this Query
*
* @return bool
*/
public function hasOffset();
/**
* Get the query limit
*
* @return int|null
*/
public function getLimit();
/**
* Get the query starting offset
*
* @return int|null
*/
public function getOffset();
/**
* Get the columns that have been asked for with this query
*
* @return array
*/
public function listColumns();
public function getColumns();
/**
* Get the filters that have been applied to this query
*
* @return array
*/
public function listFilters();
/**
* Fetch result as an array of objects
*
* @return array
*/
public function fetchAll();
/**
* Fetch first result row
*
* @return object
*/
public function fetchRow();
/**
* Fetch first result column
*
* @return array
*/
public function fetchColumn();
/**
* Fetch first column value from first result row
*
* @return mixed
*/
public function fetchOne();
/**
* Fetch result as a key/value pair array
*
* @return array
*/
public function fetchPairs();
/**
* Return a pagination adapter for this query
*
* @return \Zend_Paginator
*/
public function paginate($limit = null, $page = null);
}

View File

@ -2,7 +2,7 @@
namespace Icinga\File;
use Icinga\Data\AbstractQuery;
use Icinga\Data\BaseQuery;
class Csv
{
@ -12,7 +12,7 @@ class Csv
{
}
public static function fromQuery(AbstractQuery $query)
public static function fromQuery(BaseQuery $query)
{
$csv = new Csv();
$csv->query = $query;

View File

@ -29,12 +29,11 @@
namespace Icinga\Filter;
use Icinga\Filter\Query\Tree;
interface Filterable
{
public function isValidFilterTarget($field);
public function getMappedField($field);
public function applyFilter(Tree $filter);
public function applyFilter();
public function clearFilter();
public function addFilter($filter);
}

View File

@ -73,7 +73,11 @@ class Tree
$this->insertOrNode($node, $this->root);
break;
case Node::TYPE_OPERATOR:
if ($this->lastNode->type == Node::TYPE_OPERATOR) {
$this->insert(Node::createAndNode());
}
$node->parent = $this->lastNode;
if ($this->lastNode->left == null) {
$this->lastNode->left = $node;
} elseif ($this->lastNode->right == null) {

View File

@ -1,8 +0,0 @@
<?php
namespace Icinga\Objects;
class Host extends Object
{
// Nothing here
}

View File

@ -1,61 +0,0 @@
<?php
namespace Icinga\Objects;
class Object
{
protected $id;
protected $name;
protected $props;
protected $defaults = array();
protected $fromBackend = false;
protected $hasBeenChanged = false;
protected function __construct($props = array())
{
$this->props = $this->defaults;
if (! empty($props)) {
$this->setProperties($props);
}
}
public function setProperties($props)
{
foreach ($props as $key => $val) {
$this->props[$key] = $val;
}
}
protected function set($key, $val)
{
$this->props[$key] = $val;
return $this;
}
public function __set($key, $val)
{
$this->set($key, $val);
}
public function __get($key)
{
if (array_key_exists($key, $this->props)) {
return $this->props[$key];
}
return null;
}
protected function setLoadedFromBackend($loaded = true)
{
$this->fromBackend = $loaded;
return $this;
}
public static function fromBackend($row)
{
$class = get_called_class();
$object = new $class($row);
$object->setLoadedFromBackend();
return $object;
}
}

View File

@ -1,7 +0,0 @@
<?php
namespace Icinga\Objects;
class Service extends Object
{
}

View File

@ -29,7 +29,7 @@
namespace Icinga\Protocol;
/**
* Class AbstractQuery
* Class BaseQuery
* @package Icinga\Protocol
*/
abstract class AbstractQuery

View File

@ -29,13 +29,13 @@
namespace Icinga\Protocol\Statusdat;
use Icinga\Protocol;
use Icinga\Data\AbstractQuery;
use Icinga\Data\BaseQuery;
/**
* Class Query
* @package Icinga\Protocol\Statusdat
*/
class Query extends AbstractQuery
class Query extends BaseQuery
{
/**
* @var array
@ -76,7 +76,7 @@ class Query extends AbstractQuery
/**
* @var array
*/
protected $order_columns = array();
protected $orderColumns = array();
/**
* @var array
@ -108,7 +108,7 @@ class Query extends AbstractQuery
*/
public function hasOrder()
{
return !empty($this->order_columns);
return !empty($this->orderColumns);
}
/**
@ -200,7 +200,7 @@ class Query extends AbstractQuery
$col = $col;
}
$this->order_columns[] = array($col, $dir);
$this->orderColumns[] = array($col, $dir);
}
return $this;
}
@ -275,7 +275,7 @@ class Query extends AbstractQuery
*/
private function orderIndices(array &$indices)
{
if (!empty($this->order_columns)) {
if (!empty($this->orderColumns)) {
foreach ($indices as $type => &$subindices) {
$this->currentType = $type; // we're singlethreaded, so let's do it a bit dirty
usort($subindices, array($this, "orderResult"));
@ -293,7 +293,7 @@ class Query extends AbstractQuery
$o1 = $this->ds->getObjectByName($this->currentType, $a);
$o2 = $this->ds->getObjectByName($this->currentType, $b);
$result = 0;
foreach ($this->order_columns as $col) {
foreach ($this->orderColumns as $col) {
$result += $col[1] * strnatcasecmp($o1->{$col[0]}, $o2->{$col[0]});
}
if ($result > 0) {

View File

@ -190,6 +190,7 @@ class Monitoring_ListController extends MonitoringController
'downtime_trigger_time'
)
)->getQuery();
$this->view->downtimes = $query->paginate();
$this->setupSortControl(array(
'downtime_is_in_effect' => 'Is In Effect',
@ -403,7 +404,7 @@ class Monitoring_ListController extends MonitoringController
if ($this->getParam('format') === 'sql'
&& IcingaConfig::app()->global->get('environment', 'production') === 'development') {
echo '<pre>'
. htmlspecialchars(wordwrap($query->dump()))
. htmlspecialchars(wordwrap($query->__toString()))
. '</pre>';
exit;
}

View File

@ -34,8 +34,8 @@ use \Icinga\Module\Monitoring\Object\Host;
use \Icinga\Module\Monitoring\Object\Service;
use \Icinga\Application\Benchmark;
use \Icinga\Web\Widget\Tabextension\OutputFormat;
use \Icinga\Web\Widget\Tabextension\DashboardAction;
use \Icinga\Web\Widget\Tabextension\BasketAction;
use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Module\Monitoring\Object\AbstractObject;
use \Icinga\Web\Widget\Tabs;
/**
@ -55,28 +55,7 @@ class Monitoring_ShowController extends MonitoringController
*/
public function init()
{
$host = $this->_getParam('host');
$service = $this->_getParam('service');
$this->backend = Backend::createBackend($this->_getParam('backend'));
$object = null;
// TODO: Do not allow wildcards in names!
if ($host !== null) {
// TODO: $this->assertPermission('host/read', $host);
if ($this->getRequest()->getActionName() !== 'host' && $service !== null && $service !== '*') {
// TODO: $this->assertPermission('service/read', $service);
$object = Service::fetch($this->backend, $host, $service);
} else {
$object = Host::fetch($this->backend, $host);
}
}
$this->view->compact = $this->_getParam('view') === 'compact';
if ($object === null) {
// TODO: Notification, not found
$this->redirectNow('monitoring/list/services');
return;
}
$this->view->object = $object;
$this->view->object = AbstractObject::fromRequest($this->getRequest());
$this->createTabs();
}
@ -85,8 +64,7 @@ class Monitoring_ShowController extends MonitoringController
*/
public function serviceAction()
{
$this->view->object->prefetch();
$this->view->preserve = array();
$this->view->object->populate();
}
/**
@ -94,14 +72,15 @@ class Monitoring_ShowController extends MonitoringController
*/
public function hostAction()
{
$this->view->object->prefetch();
$this->view->preserve = array();
$this->view->object->populate();
}
public function historyAction()
{
$this->view->object->populate();
$this->view->object->fetchEventHistory();
$this->view->history = $this->view->object->eventHistory->limit(10)->paginate();
$this->view->history = $this->view->object->eventhistory->limit(10)->paginate();
}
public function servicesAction()

View File

@ -1,15 +1,23 @@
<?= $this->tabs->render($this); ?>
<h1>History</h1>
<?php if($history->count() === 0): ?>
<div class="alert alert-info">
No History Available For This Object
</div>
<?php else: ?>
<?php if (!empty($history)): ?>
<div data-icinga-component="app/mainDetailGrid">
<?= $this->paginationControl($history, null, null, array('preserve' => $this->preserve)); ?>
<table class="table table-condensed">
<tbody>
<?php foreach ($history as $event): ?>
<tr>
<td><?= date('d.m. H:i', $event->timestamp); ?></td>
<td><?= date('d.m. H:i', $event->raw_timestamp); ?></td>
<td>
<?php if ($object instanceof Icinga\Module\Monitoring\Object\Service): ?>

View File

@ -1,251 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\Backend;
use Icinga\Data\DatasourceInterface;
use Icinga\Exception\ProgrammingError;
use Icinga\Application\Benchmark;
use Zend_Config;
class AbstractBackend implements DatasourceInterface
{
protected $config;
public function __construct(Zend_Config $config)
{
if ($config === null) {
// $config = new Zend_Config(array()); ???
}
$this->config = $config;
$this->init();
}
protected function init()
{
}
/**
* Backend entry point
*
* return self
*/
public function select()
{
return $this;
}
/**
* Create a Query object instance for given virtual table and desired fields
*
* Leave fields empty to get all available properties
*
* @param string $virtual_table Virtual table name
* @param array $fields Fields
* @throws \Icinga\Exception\ProgrammingError
* @return self
*/
public function from($virtual_table, $fields = array())
{
$classname = $this->tableToClassName($virtual_table);
if (!class_exists($classname)) {
throw new ProgrammingError(
sprintf(
'Asking for invalid virtual table %s',
$classname
)
);
}
$query = new $classname($this, $fields);
return $query;
}
public function hasView($virtual_table)
{
// TODO: This is no longer enough, have to check for Query right now
return class_exists($this->tableToClassName($virtual_table));
}
protected function tableToClassName($virtual_table)
{
return '\\Icinga\\Module\\Monitoring\\View\\'
// . $this->getName()
// . '\\'
. ucfirst($virtual_table)
. 'View';
}
public function getName()
{
return preg_replace('~^.+\\\(.+?)$~', '$1', get_class($this));
}
public function __toString()
{
return $this->getName();
}
/**
* UGLY temporary host fetch
*
* @param string $host
* @param bool $fetchAll
* @return mixed
*/
public function fetchHost($host, $fetchAll = false)
{
$fields = array(
'host_name',
'host_address',
'host_state',
'host_handled',
'host_icon_image',
'host_in_downtime',
'host_acknowledged',
'host_check_command',
'host_last_state_change',
'host_alias',
'host_output',
'host_long_output',
'host_perfdata',
'host_notes_url',
'host_action_url'
);
if ($fetchAll === true) {
$fields = array_merge(
$fields,
array(
'host_current_check_attempt',
'host_max_check_attempts',
'host_attempt',
'host_last_check',
'host_next_check',
'host_check_type',
'host_last_state_change',
'host_last_hard_state_change',
'host_last_hard_state',
'host_last_time_up',
'host_last_time_down',
'host_last_time_unreachable',
'host_state_type',
'host_last_notification',
'host_next_notification',
'host_no_more_notifications',
'host_notifications_enabled',
'host_problem_has_been_acknowledged',
'host_acknowledgement_type',
'host_current_notification_number',
'host_passive_checks_enabled',
'host_active_checks_enabled',
'host_event_handler_enabled',
'host_flap_detection_enabled',
'host_is_flapping',
'host_percent_state_change',
'host_check_latency',
'host_check_execution_time',
'host_scheduled_downtime_depth',
'host_failure_prediction_enabled',
'host_process_performance_data',
'host_obsessing',
'host_modified_host_attributes',
'host_event_handler',
'host_check_command',
'host_normal_check_interval',
'host_retry_check_interval',
'host_check_timeperiod_object_id',
'host_status_update_time'
)
);
}
$select = $this->select()
->from('status', $fields)
->where('host_name', $host);
return $select->fetchRow();
}
// UGLY temporary service fetch
public function fetchService($host, $service, $fetchAll = false)
{
$fields = array(
'service_description',
'host_name',
'host_address',
'host_state',
'host_handled',
'host_icon_image',
'service_state',
'service_handled',
'service_in_downtime',
'service_acknowledged',
'service_check_command',
'service_last_state_change',
'service_display_name',
'service_output',
'service_long_output',
'service_perfdata',
'service_action_url',
'service_notes_url',
'service_icon_image'
);
if ($fetchAll === true) {
$fields = array_merge(
$fields,
array(
'service_current_check_attempt',
'service_max_check_attempts',
'service_attempt',
'service_last_check',
'service_next_check',
'service_check_type',
'service_last_state_change',
'service_last_hard_state_change',
'service_last_hard_state',
'service_last_time_ok',
'service_last_time_warning',
'service_last_time_unknown',
'service_last_time_critical',
'service_state_type',
'service_last_notification',
'service_next_notification',
'service_no_more_notifications',
'service_notifications_enabled',
'service_problem_has_been_acknowledged',
'service_acknowledgement_type',
'service_current_notification_number',
'service_passive_checks_enabled',
'service_active_checks_enabled',
'service_event_handler_enabled',
'service_flap_detection_enabled',
'service_is_flapping',
'service_percent_state_change',
'service_check_latency',
'service_check_execution_time',
'service_scheduled_downtime_depth',
'service_failure_prediction_enabled',
'service_process_performance_data',
'service_obsessing',
'service_modified_service_attributes',
'service_event_handler',
'service_check_command',
'service_normal_check_interval',
'service_retry_check_interval',
'service_check_timeperiod_object_id',
'service_status_update_time'
)
);
}
$select = $this->select()
->from('status', $fields)
->where('service_description', $service)
->where('host_name', $host);
return $select->fetchRow();
}
}

View File

@ -1,341 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\Backend\Ido\Query;
use Icinga\Data\Db\Query;
use Icinga\Application\Benchmark;
use Icinga\Exception\ProgrammingError;
use Icinga\Filter\Query\Tree;
use Icinga\Filter\Filterable;
use Icinga\Module\Monitoring\Filter\Backend\IdoQueryConverter;
use Icinga\Module\Monitoring\Filter\UrlViewFilter;
abstract class AbstractQuery extends Query implements Filterable
{
protected $prefix;
protected $idxAliasColumn;
protected $idxAliasTable;
protected $columnMap = array();
protected $query;
protected $customVars = array();
protected $joinedVirtualTables = array();
protected $object_id = 'object_id';
protected $host_id = 'host_id';
protected $hostgroup_id = 'hostgroup_id';
protected $service_id = 'service_id';
protected $servicegroup_id = 'servicegroup_id';
protected $contact_id = 'contact_id';
protected $contactgroup_id = 'contactgroup_id';
protected $aggregateColumnIdx = array();
protected $allowCustomVars = false;
public function isAggregateColumn($column)
{
return array_key_exists($column, $this->aggregateColumnIdx);
}
public function order($col, $dir = null)
{
$this->requireColumn($col);
if ($this->isCustomvar($col)) {
// TODO: Doesn't work right now. Does it?
$col = $this->getCustomvarColumnName($col);
} elseif ($this->hasAliasName($col)) {
$col = $this->aliasToColumnName($col);
} else {
throw new \InvalidArgumentException('Can\'t order by column '.$col);
}
$this->order_columns[] = array($col, $dir);
return $this;
}
public function applyFilter(Tree $filter)
{
foreach ($filter->getAttributes() as $target) {
$this->requireColumn($target);
}
$converter = new IdoQueryConverter($this);
$converter->treeToSql($filter, $this->baseQuery);
}
public function isValidFilterTarget($field)
{
return $this->getMappedField($field) !== null;
}
public function getMappedField($field)
{
foreach ($this->columnMap as $columnSource => $columnSet) {
if (isset($columnSet[$field])) {
return $columnSet[$field];
}
}
return null;
}
public function isTimestamp($field)
{
$mapped = $this->getMappedField($field);
if ($mapped === null) {
return false;
}
return stripos($mapped, 'UNIX_TIMESTAMP') !== false;
}
protected function init()
{
parent::init();
// TODO: $this->applyDbSpecificWorkarounds
$this->prefix = $this->ds->getTablePrefix();
if ($this->ds->getDbType() === 'oracle') {
$this->object_id = $this->host_id = $this->service_id
= $this->hostgroup_id = $this->servicegroup_id
= $this->contact_id = $this->contactgroup_id = 'id'; // REALLY?
foreach ($this->columnMap as $table => & $columns) {
foreach ($columns as $key => & $value) {
$value = preg_replace('/UNIX_TIMESTAMP/', 'localts2unixts', $value);
$value = preg_replace('/ COLLATE .+$/', '', $value);
}
}
}
if ($this->ds->getDbType() === 'pgsql') {
foreach ($this->columnMap as $table => & $columns) {
foreach ($columns as $key => & $value) {
$value = preg_replace('/ COLLATE .+$/', '', $value);
$value = preg_replace('/inet_aton\(([[:word:].]+)\)/i', '$1::inet - \'0.0.0.0\'', $value);
}
}
}
$this->joinBaseTables();
$this->prepareAliasIndexes();
}
protected function joinBaseTables()
{
reset($this->columnMap);
$table = key($this->columnMap);
$this->baseQuery = $this->db->select()->from(
array($table => $this->prefix . $table),
array()
);
$this->joinedVirtualTables = array($table => true);
}
protected function prepareAliasIndexes()
{
foreach ($this->columnMap as $tbl => & $cols) {
foreach ($cols as $alias => $col) {
$this->idxAliasTable[$alias] = $tbl;
$this->idxAliasColumn[$alias] = preg_replace('~\n\s*~', ' ', $col);
}
}
}
protected function beforeCreatingCountQuery()
{
}
protected function beforeCreatingSelectQuery()
{
$this->setRealColumns();
$classParts = explode('\\', get_class($this));
Benchmark::measure(sprintf('%s ready to run', array_pop($classParts)));
}
public function setRealColumns()
{
$columns = $this->columns;
$this->columns = array();
if (empty($columns)) {
$columns = $this->getDefaultColumns();
}
foreach ($columns as $alias => $col) {
$this->requireColumn($col);
if ($this->isCustomvar($col)) {
$name = $this->getCustomvarColumnName($col);
} else {
$name = $this->aliasToColumnName($col);
}
if (is_int($alias)) {
$alias = $col;
}
$this->columns[$alias] = preg_replace('|\n|', ' ', $name);
}
return $this;
}
protected function getDefaultColumns()
{
reset($this->columnMap);
$table = key($this->columnMap);
return array_keys($this->columnMap[$table]);
}
protected function requireColumn($alias)
{
if ($this->hasAliasName($alias)) {
$this->requireVirtualTable($this->aliasToTableName($alias));
} elseif ($this->isCustomVar($alias)) {
$this->requireCustomvar($alias);
} else {
throw new ProgrammingError(sprintf('Got invalid column: %s', $alias));
}
return $this;
}
protected function hasAliasName($alias)
{
return array_key_exists($alias, $this->idxAliasColumn);
}
protected function requireVirtualTable($name)
{
if ($this->hasJoinedVirtualTable($name)) {
return $this;
}
return $this->joinVirtualTable($name);
}
protected function joinVirtualTable($table)
{
$func = 'join' . ucfirst($table);
if (method_exists($this, $func)) {
$this->$func();
} else {
throw new ProgrammingError(
sprintf(
'Cannot join "%s", no such table found',
$table
)
);
}
$this->joinedVirtualTables[$table] = true;
return $this;
}
protected function aliasToTableName($alias)
{
return $this->idxAliasTable[$alias];
}
protected function isCustomVar($alias)
{
return $this->allowCustomVars && $alias[0] === '_';
}
protected function requireCustomvar($customvar)
{
if (! $this->hasCustomvar($customvar)) {
$this->joinCustomvar($customvar);
}
return $this;
}
protected function hasCustomvar($customvar)
{
return array_key_exists($customvar, $this->customVars);
}
protected function joinCustomvar($customvar)
{
// TODO: This is not generic enough yet
list($type, $name) = $this->customvarNameToTypeName($customvar);
$alias = ($type === 'host' ? 'hcv_' : 'scv_') . strtolower($name);
$this->customVars[$customvar] = $alias;
// TODO: extend if we allow queries with only hosts / only services
// ($leftcol s.host_object_id vs h.host_object_id
if ($this->hasJoinedVirtualTable('services')) {
$leftcol = 's.' . $type . '_object_id';
} else {
$leftcol = 'h.' . $type . '_object_id';
}
$joinOn = $leftcol
. ' = '
. $alias
. '.object_id'
. ' AND '
. $alias
. '.varname = '
. $this->db->quote(strtoupper($name));
$this->baseQuery->joinLeft(
array($alias => $this->prefix . 'customvariablestatus'),
$joinOn,
array()
);
return $this;
}
protected function customvarNameToTypeName($customvar)
{
// TODO: Improve this:
if (! preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $customvar, $m)) {
throw new ProgrammingError(
sprintf(
'Got invalid custom var: "%s"',
$customvar
)
);
}
return array($m[1], $m[2]);
}
protected function hasJoinedVirtualTable($name)
{
return array_key_exists($name, $this->joinedVirtualTables);
}
protected function getCustomvarColumnName($customvar)
{
return $this->customVars[$customvar] . '.varvalue';
}
public function aliasToColumnName($alias)
{
return $this->idxAliasColumn[$alias];
}
protected function createSubQuery($queryName, $columns = array())
{
$class = '\\'
. substr(__CLASS__, 0, strrpos(__CLASS__, '\\') + 1)
. ucfirst($queryName) . 'Query';
$query = new $class($this->ds, $columns);
return $query;
}
}

View File

@ -4,7 +4,7 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query;
use Zend_Db_Select;
class AllcontactsQuery extends AbstractQuery
class AllcontactsQuery extends IdoQuery
{
protected $columnMap = array(
'contacts' => array(
@ -39,7 +39,7 @@ class AllcontactsQuery extends AbstractQuery
protected $contacts;
protected $contactgroups;
protected $uglySlowConservativeCount = true;
protected $useSubqueryCount = true;
protected function requireColumn($alias)
{

View File

@ -32,7 +32,7 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query;
/**
* Query map for comments
*/
class CommentQuery extends AbstractQuery
class CommentQuery extends IdoQuery
{
protected $columnMap = array(
'comments' => array(

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class CommenthistoryQuery extends AbstractQuery
class CommenthistoryQuery extends IdoQuery
{
protected $columnMap = array(
'commenthistory' => array(

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class ContactQuery extends AbstractQuery
class ContactQuery extends IdoQuery
{
protected $columnMap = array(
'contacts' => array(
@ -33,10 +33,12 @@ class ContactQuery extends AbstractQuery
'hosts' => array(
'host_object_id' => 'ho.object_id',
'host_name' => 'ho.name1 COLLATE latin1_general_ci',
'host' => 'ho.name1 COLLATE latin1_general_ci',
),
'services' => array(
'service_object_id' => 'so.object_id',
'service_host_name' => 'so.name1 COLLATE latin1_general_ci',
'service' => 'so.name1 COLLATE latin1_general_ci',
'service_description' => 'so.name2 COLLATE latin1_general_ci',
)
);

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class ContactgroupQuery extends AbstractQuery
class ContactgroupQuery extends IdoQuery
{
protected $columnMap = array(
'contactgroups' => array(
@ -32,14 +32,16 @@ class ContactgroupQuery extends AbstractQuery
'hosts' => array(
'host_object_id' => 'ho.object_id',
'host_name' => 'ho.name1',
'host' => 'ho.name1'
),
'services' => array(
'service_object_id' => 'so.object_id',
'service_host_name' => 'so.name1 COLLATE latin1_general_ci',
'service' => 'so.name1 COLLATE latin1_general_ci',
'service_description' => 'so.name2 COLLATE latin1_general_ci',
)
);
protected $uglySlowConservativeCount = true;
protected $useSubqueryCount = true;
protected function joinBaseTables()
{

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class CustomvarQuery extends AbstractQuery
class CustomvarQuery extends IdoQuery
{
protected $object_id = 'object_id';

View File

@ -28,7 +28,7 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query;
/**
* Handling downtime queries
*/
class DowntimeQuery extends AbstractQuery
class DowntimeQuery extends IdoQuery
{
/**
* Column map

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class DowntimeendhistoryQuery extends AbstractQuery
class DowntimeendhistoryQuery extends IdoQuery
{
protected $columnMap = array(
'downtimehistory' => array(

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class DowntimestarthistoryQuery extends AbstractQuery
class DowntimestarthistoryQuery extends IdoQuery
{
protected $columnMap = array(
'downtimehistory' => array(

View File

@ -5,7 +5,7 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query;
use \Zend_Db_Select;
use Icinga\Exception\ProgrammingError;
class EventHistoryQuery extends AbstractQuery
class EventHistoryQuery extends IdoQuery
{
protected $subQueries = array();
@ -21,27 +21,27 @@ class EventHistoryQuery extends AbstractQuery
'host_name' => 'eho.name1 COLLATE latin1_general_ci',
'service_description' => 'eho.name2 COLLATE latin1_general_ci',
'object_type' => "CASE WHEN eho.objecttype_id = 1 THEN 'host' ELSE 'service' END",
'timestamp' => 'eh.timestamp',
'raw_timestamp' => 'eh.raw_timestamp',
'state' => 'eh.state',
// 'last_state' => 'eh.last_state',
// 'last_hard_state' => 'eh.last_hard_state',
'attempt' => 'eh.attempt',
'max_attempts' => 'eh.max_attempts',
'output' => 'eh.output', // we do not want long_output
//'problems' => 'CASE WHEN eh.state = 0 OR eh.state IS NULL THEN 0 ELSE 1 END',
'type' => 'eh.type'
'timestamp' => 'eh.timestamp',
'raw_timestamp' => 'UNIX_TIMESTAMP(eh.raw_timestamp)',
'state' => 'eh.state',
'attempt' => 'eh.attempt',
'max_attempts' => 'eh.max_attempts',
'output' => 'eh.output', // we do not want long_output
'type' => 'eh.type',
'service_host_name' => 'eho.name1 COLLATE latin1_general_ci',
'service_description' => 'eho.name2 COLLATE latin1_general_ci'
),
'hostgroups' => array(
'hostgroup' => 'hgo.name1 COLLATE latin1_general_ci',
),
);
protected $uglySlowConservativeCount = true;
protected $useSubqueryCount = true;
protected $maxCount = 1000;
protected function joinBaseTables()
{
// $start = date('Y-m-d H:i:s', time() - 3600 * 24 * 1);
$start = date('Y-m-d H:i:s', time() - 3600 * 24 * 2);
$end = date('Y-m-d H:i:s');
@ -67,14 +67,15 @@ class EventHistoryQuery extends AbstractQuery
$this->createSubQuery('Commenthistory', $columns),
$this->createSubQuery('Notificationhistory', $columns)
);
if ($start) {
foreach ($this->subQueries as $query) {
$query->where('raw_timestamp', '>' . $start);
$query->where('timestamp > ?', $start);
}
}
if ($end) {
foreach ($this->subQueries as $query) {
$query->where('raw_timestamp', '<' . $end);
$query->where('timestamp < ? ', $end);
}
}
$sub = $this->db->select()->union($this->subQueries, Zend_Db_Select::SQL_UNION_ALL);
@ -88,7 +89,6 @@ class EventHistoryQuery extends AbstractQuery
. ' AND eho.is_active = 1',
array()
);
$this->joinedVirtualTables = array('eventhistory' => true);
}

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class HostgroupQuery extends AbstractQuery
class HostgroupQuery extends IdoQuery
{
protected $columnMap = array(
'hostgroups' => array(
@ -12,6 +12,7 @@ class HostgroupQuery extends AbstractQuery
'id' => 'hg.hostgroup_id',
),
'hosts' => array(
'host' => 'ho.name1 COLLATE latin1_general_ci',
'host_name' => 'ho.name1 COLLATE latin1_general_ci'
)
);

View File

@ -28,7 +28,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class HoststatusQuery extends AbstractQuery
class HoststatusQuery extends IdoQuery
{
protected $allowCustomVars = true;
protected $columnMap = array(
@ -135,10 +135,9 @@ class HoststatusQuery extends AbstractQuery
);
protected $hcgSub;
protected function getDefaultColumns()
public function getDefaultColumns()
{
return $this->columnMap['hosts']
+ $this->columnMap['hoststatus'];
return $this->columnMap['hosts'] + $this->columnMap['hoststatus'];
}
protected function joinBaseTables()
@ -187,14 +186,14 @@ class HoststatusQuery extends AbstractQuery
"so.$this->object_id = ss.service_object_id",
array()
);
foreach ($this->columns as $col) {
foreach ($this->getColumns() as $col) {
$real = $this->aliasToColumnName($col);
if (substr($real, 0, 4) === 'SUM(') {
continue;
}
$this->baseQuery->group($real);
}
$this->uglySlowConservativeCount = true;
$this->useSubqueryCount = true;
}
protected function joinHostgroups()

View File

@ -0,0 +1,572 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\Backend\Ido\Query;
use Icinga\Application\Logger;
use Icinga\Data\Db\Query;
use Icinga\Application\Benchmark;
use Icinga\Exception\ProgrammingError;
use Icinga\Filter\Query\Tree;
use Icinga\Module\Monitoring\Filter\UrlViewFilter;
/**
* Base class for Ido Queries
*
* This is the base class for all Ido queries and should be extended for new queries
* The starting point for implementations is the columnMap attribute. This is an asscociative array in the
* following form:
*
* <pre>
* <code>
* array(
* 'virtualTable' => array(
* 'fieldalias1' => 'queryColumn1',
* 'fieldalias2' => 'queryColumn2',
* ....
* ),
* 'virtualTable2' => array(
* 'host' => 'host_name1'
* )
* )
* </code>
* </pre>
*
* This allows you to select e.g. fieldalias1, which automatically calls the query code for joining 'virtualTable'. If
* you afterwards select 'host', 'virtualTable2' will be joined. The joining logic is up to you, in order to make the
* above example work you need to implement the joinVirtualTable() and joinVirtualTable2() method which contain your
* custom (Zend_Db) logic for joining, filtering and querying the data you want.
*
*/
abstract class IdoQuery extends Query
{
/**
* The prefix to use
*
* @var String
*/
protected $prefix;
/**
* The alias name for the index column
*
* @var String
*/
protected $idxAliasColumn;
/**
* The table containing the index column alias
*
* @var String
*/
protected $idxAliasTable;
/**
* The column map containing all filterable columns
*
* This must be overwritten by child classes, in the format
* array(
* 'virtualTable' => array(
* 'fieldalias1' => 'queryColumn1',
* 'fieldalias2' => 'queryColumn2',
* ....
* )
* )
*
* @var array
*/
protected $columnMap = array();
/**
* Custom vars available for this query
*
* @var array
*/
protected $customVars = array();
/**
* An array with all 'virtual' tables that are already joined
*
* Virtual tables are the keys of the columnMap array and require a
* join%VirtualTableName%() method to be defined in the concrete
* query
*
* @var array
*/
protected $joinedVirtualTables = array();
/**
* The primary field name for the object table
*
* @var string
*/
protected $object_id = 'object_id';
/**
* The primary field name for the IDO host table
*
* @var string
*/
protected $host_id = 'host_id';
/**
* The primary field name for the IDO hostgroup table
*
* @var string
*/
protected $hostgroup_id = 'hostgroup_id';
/**
* The primary field name for the IDO service table
*
* @var string
*/
protected $service_id = 'service_id';
/**
* The primary field name for the IDO serviegroup table
*
* @var string
*/
protected $servicegroup_id = 'servicegroup_id';
/**
* The primary field name for the IDO contact table
*
* @var string
*/
protected $contact_id = 'contact_id';
/**
* The primary field name for the IDO contactgroup table
*
* @var string
*/
protected $contactgroup_id = 'contactgroup_id';
/**
* An array containing Column names that cause an aggregation of the query
*
* @var array
*/
protected $aggregateColumnIdx = array();
/**
* True to allow customvar filters and queries
*
* @var bool
*/
protected $allowCustomVars = false;
/**
* Return true when the column is an aggregate column
*
* @param String $column The column to test
* @return bool True when the column is an aggregate column
*/
public function isAggregateColumn($column)
{
return array_key_exists($column, $this->aggregateColumnIdx);
}
/**
* Order the result by the given column
*
* @param string $columnOrAlias The column or column alias to order by
* @param int $dir The sort direction or null to use default direction
*
* @return self Fluent interface
*/
public function order($columnOrAlias, $dir = null)
{
$this->requireColumn($columnOrAlias);
if ($this->isCustomvar($columnOrAlias)) {
$columnOrAlias = $this->getCustomvarColumnName($columnOrAlias);
} elseif ($this->hasAliasName($columnOrAlias)) {
$columnOrAlias = $this->aliasToColumnName($columnOrAlias);
} else {
Logger::info('Can\'t order by column '.$columnOrAlias);
return $this;
}
return parent::order($columnOrAlias, $dir);
}
/**
* Return true when the given field can be used for filtering
*
* @param String $field The field to test
* @return bool True when the field can be used for querying, otherwise false
*/
public function isValidFilterTarget($field)
{
return $this->getMappedField($field) !== null;
}
/**
* Return the resolved field for an alias
*
* @param String $field The alias to resolve
* @return String The resolved alias or null if unknown
*/
public function getMappedField($field)
{
foreach ($this->columnMap as $columnSource => $columnSet) {
if (isset($columnSet[$field])) {
return $columnSet[$field];
}
}
return null;
}
/**
* Return true if an field contains an explicit timestamp
*
* @param String $field The field to test for containing an timestamp
* @return bool True when the field represents an timestamp
*/
public function isTimestamp($field)
{
$mapped = $this->getMappedField($field);
if ($mapped === null) {
return false;
}
return stripos($mapped, 'UNIX_TIMESTAMP') !== false;
}
/**
* Apply oracle specific query initialization
*/
private function initializeForOracle()
{
// Oracle uses the reserved field 'id' for primary keys, so
// these must be used instead of the normally defined ids
$this->object_id = $this->host_id = $this->service_id
= $this->hostgroup_id = $this->servicegroup_id
= $this->contact_id = $this->contactgroup_id = 'id';
foreach ($this->columnMap as &$columns) {
foreach ($columns as &$value) {
$value = preg_replace('/UNIX_TIMESTAMP/', 'localts2unixts', $value);
$value = preg_replace('/ COLLATE .+$/', '', $value);
}
}
}
/**
* Apply postgresql specific query initialization
*/
private function initializeForPostgres()
{
foreach ($this->columnMap as $table => & $columns) {
foreach ($columns as $key => & $value) {
$value = preg_replace('/ COLLATE .+$/', '', $value);
$value = preg_replace('/inet_aton\(([[:word:].]+)\)/i', '$1::inet - \'0.0.0.0\'', $value);
}
}
}
/**
* Set up this query and join the initial tables
*
* @see IdoQuery::initializeForPostgres For postgresql specific setup
*/
protected function init()
{
parent::init();
$this->prefix = $this->ds->getTablePrefix();
if ($this->ds->getDbType() === 'oracle') {
$this->initializeForOracle();
} elseif ($this->ds->getDbType() === 'pgsql') {
$this->initializeForPostgres();
}
$this->joinBaseTables();
$this->prepareAliasIndexes();
}
/**
* Join the base tables for this query
*/
protected function joinBaseTables()
{
reset($this->columnMap);
$table = key($this->columnMap);
$this->baseQuery = $this->db->select()->from(
array($table => $this->prefix . $table),
array()
);
$this->joinedVirtualTables = array($table => true);
}
/**
* Populates the idxAliasTAble and idxAliasColumn properties
*/
protected function prepareAliasIndexes()
{
foreach ($this->columnMap as $tbl => & $cols) {
foreach ($cols as $alias => $col) {
$this->idxAliasTable[$alias] = $tbl;
$this->idxAliasColumn[$alias] = preg_replace('~\n\s*~', ' ', $col);
}
}
}
/**
* Prepare query execution
*
* @see IdoQuery::resolveColumns() For column alias resolving
*/
protected function beforeQueryCreation()
{
$this->resolveColumns();
$classParts = explode('\\', get_class($this));
Benchmark::measure(sprintf('%s ready to run', array_pop($classParts)));
}
/**
* Resolve columns aliases to their database field using the columnMap
*
* @return self Fluent interface
*/
public function resolveColumns()
{
$columns = $this->getColumns();
$resolvedColumns = array();
foreach ($columns as $alias => $col) {
$this->requireColumn($col);
if ($this->isCustomvar($col)) {
$name = $this->getCustomvarColumnName($col);
} else {
$name = $this->aliasToColumnName($col);
}
if (is_int($alias)) {
$alias = $col;
}
$resolvedColumns[$alias] = preg_replace('|\n|', ' ', $name);
}
$this->setColumns($resolvedColumns);
return $this;
}
/**
* Return all columns that will be selected when no columns are given in the constructor or from
*
* @return array An array of column aliases
*/
public function getDefaultColumns()
{
reset($this->columnMap);
$table = key($this->columnMap);
return array_keys($this->columnMap[$table]);
}
/**
* Modify the query to the given alias can be used in the result set or queries
*
* This calls requireVirtualTable if needed
*
* @param $alias The alias of the column to require
*
* @return self Fluent interface
* @see IdoQuery::requireVirtualTable The method initializing required joins
* @throws \Icinga\Exception\ProgrammingError When an unknown column is requested
*/
public function requireColumn($alias)
{
if ($this->hasAliasName($alias)) {
$this->requireVirtualTable($this->aliasToTableName($alias));
} elseif ($this->isCustomVar($alias)) {
$this->requireCustomvar($alias);
} else {
throw new ProgrammingError(sprintf('%s : Got invalid column: %s', get_called_class(), $alias));
}
return $this;
}
/**
* Return true if the given alias exists
*
* @param String $alias The alias to test for
* @return bool True when the alias exists, otherwise false
*/
protected function hasAliasName($alias)
{
return array_key_exists($alias, $this->idxAliasColumn);
}
/**
* Require a virtual table for the given table name if not already required
*
* @param String $name The table name to require
* @return self Fluent interface
*/
protected function requireVirtualTable($name)
{
if ($this->hasJoinedVirtualTable($name)) {
return $this;
}
return $this->joinVirtualTable($name);
}
/**
* Call the method for joining a virtual table
*
* This requires a join$Table() method to exist
*
* @param String $table The table to join by calling join$Table() in the concrete implementation
* @return self Fluent interface
*
* @throws \Icinga\Exception\ProgrammingError If the join method for this table does not exist
*/
protected function joinVirtualTable($table)
{
$func = 'join' . ucfirst($table);
if (method_exists($this, $func)) {
$this->$func();
} else {
throw new ProgrammingError(
sprintf(
'Cannot join "%s", no such table found',
$table
)
);
}
$this->joinedVirtualTables[$table] = true;
return $this;
}
/**
* Get the table for a specific alias
*
* @param String $alias The alias to request the table for
* @return String The table for the alias or null if it doesn't exist
*/
protected function aliasToTableName($alias)
{
return isset($this->idxAliasTable[$alias]) ? $this->idxAliasTable[$alias] : null;
}
/**
* Return true if the given alias denotes a custom variable
*
* @param String $alias The alias to test for being a customvariable
* @return bool True if the alias is a customvariable, otherwise false
*/
protected function isCustomVar($alias)
{
return $this->allowCustomVars && $alias[0] === '_';
}
protected function requireCustomvar($customvar)
{
if (! $this->hasCustomvar($customvar)) {
$this->joinCustomvar($customvar);
}
return $this;
}
protected function hasCustomvar($customvar)
{
return array_key_exists($customvar, $this->customVars);
}
protected function joinCustomvar($customvar)
{
// TODO: This is not generic enough yet
list($type, $name) = $this->customvarNameToTypeName($customvar);
$alias = ($type === 'host' ? 'hcv_' : 'scv_') . strtolower($name);
$this->customVars[$customvar] = $alias;
// TODO: extend if we allow queries with only hosts / only services
// ($leftcol s.host_object_id vs h.host_object_id
if ($this->hasJoinedVirtualTable('services')) {
$leftcol = 's.' . $type . '_object_id';
} else {
$leftcol = 'h.' . $type . '_object_id';
}
$joinOn = $leftcol
. ' = '
. $alias
. '.object_id'
. ' AND '
. $alias
. '.varname = '
. $this->db->quote(strtoupper($name));
$this->baseQuery->joinLeft(
array($alias => $this->prefix . 'customvariablestatus'),
$joinOn,
array()
);
return $this;
}
protected function customvarNameToTypeName($customvar)
{
// TODO: Improve this:
if (! preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $customvar, $m)) {
throw new ProgrammingError(
sprintf(
'Got invalid custom var: "%s"',
$customvar
)
);
}
return array($m[1], $m[2]);
}
protected function hasJoinedVirtualTable($name)
{
return array_key_exists($name, $this->joinedVirtualTables);
}
protected function getCustomvarColumnName($customvar)
{
return $this->customVars[$customvar] . '.varvalue';
}
public function aliasToColumnName($alias)
{
return $this->idxAliasColumn[$alias];
}
protected function createSubQuery($queryName, $columns = array())
{
$class = '\\'
. substr(__CLASS__, 0, strrpos(__CLASS__, '\\') + 1)
. ucfirst($queryName) . 'Query';
$query = new $class($this->ds, $columns);
return $query;
}
}

View File

@ -28,7 +28,7 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query;
/**
* Notification query
*/
class NotificationQuery extends AbstractQuery
class NotificationQuery extends IdoQuery
{
/**
* Column map
@ -44,7 +44,9 @@ class NotificationQuery extends AbstractQuery
),
'objects' => array(
'host_name' => 'o.name1',
'service_description' => 'o.name2'
'service_description' => 'o.name2',
'service' => 'o.name2',
'host_name' => 'o.name1'
),
'contact' => array(
'notification_contact' => 'c_o.name1'

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class NotificationhistoryQuery extends AbstractQuery
class NotificationhistoryQuery extends IdoQuery
{
protected $columnMap = array(
'history' => array(

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class ServicegroupQuery extends AbstractQuery
class ServicegroupQuery extends IdoQuery
{
protected $columnMap = array(
'servicegroups' => array(
@ -10,7 +10,9 @@ class ServicegroupQuery extends AbstractQuery
'servicegroup_alias' => 'sg.alias',
),
'services' => array(
'host' => 'so.name1 COLLATE latin1_general_ci',
'host_name' => 'so.name1 COLLATE latin1_general_ci',
'service' => 'so.name2 COLLATE latin1_general_ci',
'service_host_name' => 'so.name1 COLLATE latin1_general_ci',
'service_description' => 'so.name2 COLLATE latin1_general_ci'
)

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class ServicestatusQuery extends AbstractQuery
class ServicestatusQuery extends IdoQuery
{
protected $allowCustomVars = true;

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class StatehistoryQuery extends AbstractQuery
class StatehistoryQuery extends IdoQuery
{
protected $columnMap = array(
'statehistory' => array(

View File

@ -5,7 +5,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class StatusQuery extends AbstractQuery
class StatusQuery extends IdoQuery
{
protected $allowCustomVars = true;
@ -29,8 +29,6 @@ class StatusQuery extends AbstractQuery
'host_acknowledged' => 'hs.problem_has_been_acknowledged',
'host_in_downtime' => 'CASE WHEN (hs.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
'host_handled' => 'CASE WHEN (hs.problem_has_been_acknowledged + hs.scheduled_downtime_depth) > 0 THEN 1 ELSE 0 END',
'host_does_active_checks' => 'hs.active_checks_enabled',
'host_accepts_passive_checks' => 'hs.passive_checks_enabled',
'host_last_state_change' => 'UNIX_TIMESTAMP(hs.last_state_change)',
'host_last_hard_state' => 'hs.last_hard_state',
'host_last_hard_state_change' => 'UNIX_TIMESTAMP(hs.last_hard_state_change)',
@ -130,8 +128,6 @@ class StatusQuery extends AbstractQuery
'service_acknowledged' => 'ss.problem_has_been_acknowledged',
'service_in_downtime' => 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
'service_handled' => 'CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END',
'service_does_active_checks' => 'ss.active_checks_enabled',
'service_accepts_passive_checks' => 'ss.passive_checks_enabled',
'service_last_state_change' => 'UNIX_TIMESTAMP(ss.last_state_change)',
'service_check_command' => 'ss.check_command',
'service_last_time_ok' => 'ss.last_time_ok',

View File

@ -2,9 +2,9 @@
namespace \Icinga\Module\Monitoring\Backend\Livestatus\Query;
use Icinga\Data\AbstractQuery;
use Icinga\Data\BaseQuery;
class StatusQuery extends AbstractQuery implements Filterable
class StatusQuery extends BaseQuery implements Filterable
{
protected $available_columns = array(
'host_name',

View File

@ -64,7 +64,7 @@ abstract class GroupsummaryQuery extends Query
/**
* @var array
*/
protected $order_columns = array(
protected $orderColumns = array(
'state' => array(
'ASC' => array(
'ok ASC',

View File

@ -31,7 +31,7 @@ namespace Icinga\Module\Monitoring\Backend\Statusdat\Query;
use Icinga\Filter\Query\Tree;
use Icinga\Protocol\Statusdat;
use Icinga\Exception;
use Icinga\Data\AbstractQuery;
use Icinga\Data\BaseQuery;
use Icinga\Protocol\Statusdat\View\MonitoringObjectList as MList;
use Icinga\Protocol\Statusdat\Query as StatusdatQuery;
use Icinga\Filter\Filterable;
@ -40,7 +40,7 @@ use Icinga\Filter\Filterable;
* Class Query
* @package Icinga\Backend\Statusdat
*/
abstract class Query extends AbstractQuery implements Filterable
abstract class Query extends BaseQuery implements Filterable
{
/**
* @var null

View File

@ -51,7 +51,9 @@ class Comment extends DataView
'comment_is_persistent',
'comment_expiration_timestamp',
'host_name',
'service_name'
'service_name',
'host',
'service'
);
}

View File

@ -40,7 +40,9 @@ class Contact extends DataView
'host_name',
'service_object_id',
'service_host_name',
'service_description'
'service_description',
'service',
'host',
);
}

View File

@ -18,7 +18,9 @@ class Contactgroup extends DataView
return array(
'contact_name',
'contactgroup_name',
'contactgroup_alias'
'contactgroup_alias',
'host',
'service'
);
}

View File

@ -4,7 +4,7 @@
namespace Icinga\Module\Monitoring\DataView;
use Icinga\Data\AbstractQuery;
use Icinga\Data\BaseQuery;
use Icinga\Filter\Filterable;
use Icinga\Filter\Query\Tree;
use Icinga\Module\Monitoring\Backend;
@ -19,15 +19,15 @@ abstract class DataView implements Filterable
/**
* Sort in ascending order, default
*/
const SORT_ASC = AbstractQuery::SORT_ASC;
const SORT_ASC = BaseQuery::SORT_ASC;
/**
* Sort in reverse order
*/
const SORT_DESC = AbstractQuery::SORT_DESC;
const SORT_DESC = BaseQuery::SORT_DESC;
/**
* The query used to populate the view
*
* @var AbstractQuery
* @var BaseQuery
*/
private $query;
@ -39,9 +39,7 @@ abstract class DataView implements Filterable
*/
public function __construct(Backend $ds, array $columns = null)
{
$filter = new UrlViewFilter($this);
$this->query = $ds->select()->from(static::getTableName(), $columns === null ? $this->getColumns() : $columns);
$this->applyFilter($filter->parseUrl());
}
/**
@ -63,11 +61,6 @@ abstract class DataView implements Filterable
*/
abstract public function getColumns();
public function applyFilter(Tree $filter)
{
return $this->query->applyFilter($filter);
}
/**
* Create view from request
*
@ -78,8 +71,11 @@ abstract class DataView implements Filterable
*/
public static function fromRequest($request, array $columns = null)
{
$view = new static(Backend::createBackend($request->getParam('backend')), $columns);
$view->filter($request->getParams());
$parser = new UrlViewFilter($view);
$view->getQuery()->setFilter($parser->parseUrl());
$order = $request->getParam('dir');
if ($order !== null) {
if (strtolower($order) === 'desc') {
@ -106,7 +102,9 @@ abstract class DataView implements Filterable
public static function fromParams(array $params, array $columns = null)
{
$view = new static(Backend::createBackend($params['backend']), $columns);
$view->filter($params);
foreach ($params as $key => $value) {
$view->getQuery()->where($key, $value);
}
$order = isset($params['order']) ? $params['order'] : null;
if ($order !== null) {
if (strtolower($order) === 'desc') {
@ -115,6 +113,7 @@ abstract class DataView implements Filterable
$order = self::SORT_ASC;
}
}
$view->sort(
isset($params['sort']) ? $params['sort'] : null,
$order
@ -122,22 +121,6 @@ abstract class DataView implements Filterable
return $view;
}
/**
* Filter rows that match all of the given filters. If a filter is not valid, it's silently ignored
*
* @param array $filters
*
* @see Filterable::isValidFilterTarget()
*/
public function filter(array $filters)
{
foreach ($filters as $column => $filter) {
if ($this->isValidFilterTarget($column)) {
$this->query->where($column, $filter);
}
}
}
/**
* Check whether the given column is a valid filter column, i.e. the view actually provides the column or it's
* a non-queryable filter column
@ -186,10 +169,14 @@ abstract class DataView implements Filterable
);
};
}
$order = $order === null ? (isset($sortColumns['order']) ? $sortColumns['order'] : self::SORT_ASC) : $order;
$order = ($order === self::SORT_ASC) ? 'ASC' : 'DESC';
foreach ($sortColumns['columns'] as $column) {
$this->query->order($column, $order);
}
return $this;
}
/**
@ -214,8 +201,21 @@ abstract class DataView implements Filterable
return $this->query;
}
public function getFilterDomain()
public function applyFilter()
{
return null;
$this->query->applyFilter();
return $this;
}
public function clearFilter()
{
$this->query->clearFilter();
return $this;
}
public function addFilter($filter)
{
$this->query->addFilter($filter);
return $this;
}
}

View File

@ -1,5 +1,29 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\DataView;
@ -14,11 +38,16 @@ class EventHistory extends DataView
public function getColumns()
{
return array(
'raw_timestamp',
'timestamp',
'host',
'service',
'cnt_notification',
'cnt_hard_state',
'cnt_soft_state',
'cnt_downtime_start',
'cnt_downtime_end',
'host_name',
'service_description',
'object_type',
'timestamp',
'raw_timestamp',
'state',
'attempt',
'max_attempts',
@ -46,3 +75,34 @@ class EventHistory extends DataView
);
}
}
=======
'type',
'host',
'service'
);
}
/**
* Return the table name
*
* @return string
*/
public static function getTableName()
{
return 'eventhistory';
}
/**
* Retrieve default sorting rules for particular columns. These involve sort order and potential additional to sort
*
* @return array
*/
public function getSortRules()
{
return array(
'raw_timestamp' => array(
'order' => self::SORT_DESC
)
);
}
}

View File

@ -16,48 +16,60 @@ class HostStatus extends DataView
public function getColumns()
{
return array(
'host',
'host_name',
'host_alias',
'host_address',
'host_state',
'host_state_type',
'host_last_state_change',
'host_address',
'host_handled',
'host_icon_image',
'host_acknowledged',
'host_output',
'host_long_output',
'host_in_downtime',
'host_is_flapping',
'host_acknowledged',
'host_last_state_change',
'host_last_state_change',
'host_last_notification',
'host_last_check',
'host_next_check',
'host_check_execution_time',
'host_check_latency',
'host_output',
'host_long_output',
'host_check_command',
'host_perfdata',
'host_passive_checks_enabled',
'host_obsessing',
'host_notifications_enabled',
'host_unhandled_service_count',
'host_event_handler_enabled',
'host_flap_detection_enabled',
'host_active_checks_enabled',
'host_current_check_attempt',
'host_max_check_attempts',
'host_last_notification',
'host_current_notification_number',
'host_percent_state_change',
'host_is_flapping',
'host_last_comment',
'host_action_url',
'host_notes_url',
'host_last_comment',
'host',
'host_display_name',
'host_alias',
'host_ipv4',
'host_severity',
'host_perfdata',
'host_does_active_checks',
'host_accepts_passive_checks',
'host_last_hard_state',
'host_last_hard_state_change',
'host_last_time_up',
'host_last_time_down',
'host_last_time_unreachable'
'host_percent_state_change'
);
}
/**
* Return the table name
*
* @return string
*/
public static function getTableName()
{
return 'status';
}
/**
* The sort rules for this query
*
* @return array
*/
public function getSortRules()
{
return array(

View File

@ -0,0 +1,75 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\DataView;
/**
* View for hostgroups
*/
class Hostgroup extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
*/
public function getColumns()
{
return array(
'host',
'hostgroup_name',
'hostgroup_alias'
);
}
/**
* Return the table name for this view
*
* @return string
*/
public static function getTableName()
{
return 'hostgroup';
}
/**
* Retrieve default sorting rules for particular columns. These involve sort order and potential additional to sort
*
* @return array
*/
public function getSortRules()
{
return array(
'hostgroup_name' => array(
'order' => self::SORT_ASC
)
);
}
}

View File

@ -21,7 +21,9 @@ class Notification extends DataView
'notification_start_time',
'notification_contact',
'notification_information',
'notification_command'
'notification_command',
'host',
'service'
);
}

View File

@ -38,6 +38,10 @@ class ServiceStatus extends DataView
'service_action_url',
'service_notes_url',
'service_last_comment',
'service_last_check',
'service_next_check',
'service_last_notification',
'service_check_command',
'host_icon_image',
'host_acknowledged',
'host_output',
@ -56,8 +60,8 @@ class ServiceStatus extends DataView
'host_ipv4',
'host_severity',
'host_perfdata',
'host_does_active_checks',
'host_accepts_passive_checks',
'host_active_checks_enabled',
'host_passive_checks_enabled',
'host_last_hard_state',
'host_last_hard_state_change',
'host_last_time_up',
@ -66,8 +70,8 @@ class ServiceStatus extends DataView
'service',
'service_hard_state',
'service_perfdata',
'service_does_active_checks',
'service_accepts_passive_checks',
'service_active_checks_enabled',
'service_passive_checks_enabled',
'service_last_hard_state',
'service_last_hard_state_change',
'service_last_time_ok',

View File

@ -0,0 +1,70 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\DataView;
class Servicegroup extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
*/
public function getColumns()
{
return array(
'service',
'host',
'servicegroup_name',
'servicegroup_alias'
);
}
public static function getTableName()
{
return 'servicegroup';
}
/**
* Retrieve default sorting rules for particular columns. These involve sort order and potential additional to sort
*
* @return array
*/
public function getSortRules()
{
return array(
'servicegroup_name' => array(
'order' => self::SORT_ASC
)
);
}
}

View File

@ -1,244 +1,187 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\Object;
use Icinga\Data\AbstractQuery as Query;
use Icinga\Data\BaseQuery as Query;
use \Icinga\Module\Monitoring\Backend;
use Icinga\Module\Monitoring\DataView\Contact;
use Icinga\Module\Monitoring\DataView\Contactgroup;
use Icinga\Module\Monitoring\DataView\Downtime;
use Icinga\Module\Monitoring\DataView\EventHistory;
use Icinga\Module\Monitoring\DataView\Hostgroup;
use Icinga\Module\Monitoring\DataView\HostStatus;
use Icinga\Module\Monitoring\DataView\Comment;
use Icinga\Module\Monitoring\DataView\Servicegroup;
use Icinga\Module\Monitoring\DataView\ServiceStatus;
use Icinga\Web\Request;
/**
* Generic icinga object with belongings
*/
abstract class AbstractObject
{
protected $backend;
const TYPE_HOST = 1;
const TYPE_SERVICE = 2;
protected $type;
public $type = self::TYPE_HOST;
public $prefix = 'host_';
protected $name1;
public $comments = array();
public $downtimes = array();
public $hostgroups = array();
public $servicegroups = array();
public $contacts = array();
public $contactgroups = array();
public $customvars = array();
public $events = array();
protected $name2;
private $request = null;
protected $properties;
protected $foreign = array();
public function __construct(Backend $backend, $name1, $name2 = null)
public function __construct(Request $request)
{
$this->backend = $backend;
$this->name1 = $name1;
$this->name2 = $name2;
if ($name1 && $name2) {
$this->type = 2;
} elseif ($name1 && !$name2) {
$this->type = 1;
}
$this->properties = (array) $this->fetchObject();
}
public static function fetch(Backend $backend, $name1, $name2 = null)
{
return new static($backend, $name1, $name2);
}
abstract protected function fetchObject();
public function __isset($key)
{
return $this->$key !== null;
}
public function __get($key)
{
if (isset($this->properties[$key])) {
return $this->properties[$key];
}
if (array_key_exists($key, $this->foreign)) {
if ($this->foreign[$key] === null) {
$func = 'fetch' . ucfirst($key);
if (! method_exists($this, $func)) {
return null;
}
$this->$func($key);
$this->request = $request;
$properties = $this->getProperties();
if ($properties) {
foreach ($properties as $key => $value) {
$this->$key = $value;
}
return $this->foreign[$key];
}
return null;
}
public function prefetch()
{
return $this;
}
abstract protected function getProperties();
abstract protected function applyObjectFilter(Query $query);
protected function fetchHostgroups()
public function fetchComments()
{
$this->foreign['hostgroups'] = $this->applyObjectFilter(
$this->backend->select()->from(
'hostgroup',
array(
'hostgroup_name',
'hostgroup_alias'
)
$this->comments = Comment::fromRequest(
$this->request,
array(
'comment_timestamp',
'comment_author',
'comment_data',
'comment_type',
)
)->fetchPairs();
)->getQuery()
->where('comment_objecttype_id', 1)
->fetchAll();
return $this;
}
protected function fetchServicegroups()
public function fetchDowntimes()
{
$this->foreign['servicegroups'] = $this->applyObjectFilter(
$this->backend->select()->from(
'servicegroup',
array(
'servicegroup_name',
'servicegroup_alias'
)
$this->downtimes = Downtime::fromRequest(
$this->request,
array(
'downtime_type',
'downtime_author_name',
'downtime_comment_data',
'downtime_is_fixed',
'downtime_duration',
'downtime_entry_time',
'downtime_scheduled_start_time',
'downtime_scheduled_end_time',
'downtime_was_started',
'downtime_actual_start_time',
'downtime_is_in_effect',
'downtime_triggered_by_id',
)
)->fetchPairs();
)->getQuery()->fetchAll();
return $this;
}
protected function fetchContacts()
public function fetchHostgroups()
{
$this->foreign['contacts'] = $this->applyObjectFilter(
$this->backend->select()->from(
'contact',
array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
)
$this->hostgroups = Hostgroup::fromRequest(
$this->request,
array(
'hostgroup_name',
'hostgroup_alias'
)
)->fetchAll();
)->getQuery()->fetchPairs();
return $this;
}
protected function fetchContactgroups()
public function fetchContacts()
{
$this->foreign['contactgroups'] = $this->applyObjectFilter(
$this->backend->select()->from(
'contactgroup',
array(
'contactgroup_name',
'contactgroup_alias',
)
$this->contacts = Contact::fromRequest(
$this->request,
array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
)
)->fetchAll();
)->getQuery()
->where('host_name', $this->host_name)
->fetchAll();
return $this;
}
protected function fetchComments()
public function fetchServicegroups()
{
$this->foreign['comments'] = $this->applyObjectFilter(
$this->backend->select()->from(
'comment',
array(
'comment_timestamp',
'comment_author',
'comment_data',
'comment_type',
'comment_internal_id'
)
)->where('comment_objecttype_id', $this->type)
)->fetchAll();
$this->servicegroups = Servicegroup::fromRequest(
$this->request,
array(
'servicegroup_name',
'servicegroup_alias',
)
)->getQuery()->fetchPairs();
return $this;
}
protected function fetchCustomvars()
public function fetchContactgroups()
{
$this->foreign['customvars'] = $this->applyObjectFilter(
$this->backend->select()->from(
'customvar',
array(
'varname',
'varvalue'
)
)->where('varname', '-*PW*,-*PASS*,-*COMMUNITY*')
)->fetchPairs();
$this->contactgroups = Contactgroup::fromRequest(
$this->request,
array(
'contactgroup_name',
'contactgroup_alias'
)
)->getQuery()->fetchAll();
return $this;
}
public function fetchEventHistory()
{
$this->foreign['eventHistory'] = $this->applyObjectFilter(
$this->backend->select()->from(
'eventHistory',
array(
'object_type',
'host_name',
'service_description',
'timestamp',
'state',
'attempt',
'max_attempts',
'output',
'type'
)
$this->eventhistory = EventHistory::fromRequest(
$this->request,
array(
'object_type',
'host_name',
'service_description',
'timestamp',
'raw_timestamp',
'state',
'attempt',
'max_attempts',
'output',
'type'
)
);
)->sort('timestamp', 'DESC')->getQuery();
return $this;
}
public function fetchDowtimes()
public function __get($param)
{
$this->foreign['downtimes'] = $this->applyObjectFilter(
$this->backend->select()->from(
'downtime',
array(
'host_name',
'object_type',
'service_host_name',
'service_description',
'downtime_type',
'downtime_author_name',
'downtime_comment_data',
'downtime_is_fixed',
'downtime_duration',
'downtime_entry_time',
'downtime_scheduled_start_time',
'downtime_scheduled_end_time',
'downtime_was_started',
'downtime_actual_start_time',
'downtime_actual_start_time_usec',
'downtime_is_in_effect',
'downtime_trigger_time',
'downtime_triggered_by_id',
'downtime_internal_downtime_id'
)
)
)->fetchAll(9);
return $this;
if (substr($param, 0, strlen($this->prefix)) === $this->prefix) {
return false;
}
$expandedName = $this->prefix . strtolower($param);
return $this->$expandedName;
}
public function getRequest()
{
return $this->request;
}
abstract public function populate();
public static function fromRequest(Request $request)
{
if ($request->has('service') && $request->has('host')) {
return new Service($request);
} else if ($request->has('host')) {
return new Host($request);
}
}
}

View File

@ -1,133 +1,31 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\Object;
use Icinga\Data\AbstractQuery as Query;
use Icinga\Data\BaseQuery as Query;
use Icinga\Module\Monitoring\DataView\HostStatus;
/**
* Represent a host object
*/
class Host extends AbstractObject
{
protected $foreign = array(
'hostgroups' => null,
'contacts' => null,
'contactgroups' => null,
'customvars' => null,
'comments' => null,
'downtimes' => null,
'customvars' => null
);
/**
* Statename
*/
public function stateName()
{
// TODO
}
public $type = self::TYPE_HOST;
public $prefix = 'host_';
private $view = null;
/**
* Filter object belongings
*
* @param Query $query
*
* @return Query
*/
protected function applyObjectFilter(Query $query)
{
return $query->where('host_name', $this->name1);
}
/**
* Load foreign object data
*
* @return self
*/
public function prefetch()
public function populate()
{
return $this->fetchHostgroups()
$this->fetchComments()
->fetchDowntimes()
->fetchHostgroups()
->fetchContacts()
->fetchContactgroups()
->fetchCustomvars()
->fetchComments()
->fetchDowtimes()
->fetchCustomvars();
->fetchContactGroups();
}
/**
* Load object data
* @return object
*/
protected function fetchObject()
protected function getProperties()
{
return $this->backend->select()->from(
'status',
array(
'host_name',
'host_alias',
'host_address',
'host_state',
'host_handled',
'host_in_downtime',
'in_downtime' => 'host_in_downtime',
'host_acknowledged',
'host_last_state_change',
'last_state_change' => 'host_last_state_change',
'last_notification' => 'host_last_notification',
'last_check' => 'host_last_check',
'next_check' => 'host_next_check',
'check_execution_time' => 'host_check_execution_time',
'check_latency' => 'host_check_latency',
'output' => 'host_output',
'long_output' => 'host_long_output',
'check_command' => 'host_check_command',
'perfdata' => 'host_perfdata',
'host_icon_image',
'passive_checks_enabled' => 'host_passive_checks_enabled',
'obsessing' => 'host_obsessing',
'notifications_enabled' => 'host_notifications_enabled',
'event_handler_enabled' => 'host_event_handler_enabled',
'flap_detection_enabled' => 'host_flap_detection_enabled',
'active_checks_enabled' => 'host_active_checks_enabled',
'current_check_attempt' => 'host_current_check_attempt',
'max_check_attempts' => 'host_max_check_attempts',
'last_notification' => 'host_last_notification',
'current_notification_number' => 'host_current_notification_number',
'percent_state_change' => 'host_percent_state_change',
'is_flapping' => 'host_is_flapping',
'last_comment' => 'host_last_comment',
'action_url' => 'host_action_url',
'notes_url' => 'host_notes_url',
'percent_state_change' => 'host_percent_state_change'
)
)->where('host_name', $this->name1)->fetchRow();
$this->view = HostStatus::fromRequest($this->getRequest());
return $this->view->getQuery()->fetchRow();
}
}

View File

@ -1,148 +1,30 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* 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>
* @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\Module\Monitoring\Object;
use Icinga\Data\AbstractQuery as Query;
use Icinga\Data\BaseQuery as Query;
use Icinga\Module\Monitoring\DataView\ServiceStatus;
/**
* Represent a single service
*/
class Service extends AbstractObject
{
/**
* Foreign references to objects
*
* @var array
*/
protected $foreign = array(
'servicegroups' => null,
'contacts' => null,
'contactgroups' => null,
'customvars' => null,
'comments' => null,
'downtimes' => null,
'customvars' => null
);
/**
* Statename
*/
public function stateName()
{
// TODO
}
public $type = self::TYPE_SERVICE;
public $prefix = 'service_';
private $view = null;
/**
* Filter foreign object belongings
*
* @param Query $query
*
* @return Query
*/
protected function applyObjectFilter(Query $query)
public function populate()
{
return $query->where('service_host_name', $this->name1)
->where('service_description', $this->name2);
}
/**
* Collect foreign data
*
* @return self
*/
public function prefetch()
{
return $this->fetchServicegroups()
$this->fetchComments()
->fetchDowntimes()
->fetchHostgroups()
->fetchServicegroups()
->fetchContacts()
->fetchContactgroups()
->fetchCustomvars()
->fetchComments()
->fetchDowtimes()
->fetchCustomvars();
->fetchContactGroups();
}
/**
* Load object data
*
* @return object
*/
protected function fetchObject()
protected function getProperties()
{
return $this->backend->select()->from(
'status',
array(
'host_name',
'host_alias',
'host_address',
'host_state',
'host_handled',
'host_in_downtime',
'host_acknowledged',
'host_last_state_change',
'service_description',
'service_state',
'service_handled',
'service_acknowledged',
'service_in_downtime',
'service_last_state_change',
'last_check' => 'service_last_check',
'next_check' => 'service_next_check',
'check_execution_time' => 'service_check_execution_time',
'check_latency' => 'service_check_latency',
'output' => 'service_output',
'long_output' => 'service_long_output',
'check_command' => 'service_check_command',
'perfdata' => 'service_perfdata',
'current_check_attempt' => 'service_current_check_attempt',
'max_check_attempts' => 'service_max_check_attempts',
'state_type' => 'service_state_type',
'passive_checks_enabled' => 'service_passive_checks_enabled',
'last_state_change' => 'service_last_state_change',
'last_notification' => 'service_last_notification',
'current_notification_number' => 'service_current_notification_number',
'is_flapping' => 'service_is_flapping',
'percent_state_change' => 'service_percent_state_change',
'in_downtime' => 'service_in_downtime',
'passive_checks_enabled' => 'service_passive_checks_enabled',
'obsessing' => 'service_obsessing',
'notifications_enabled' => 'service_notifications_enabled',
'event_handler_enabled' => 'service_event_handler_enabled',
'flap_detection_enabled' => 'service_flap_detection_enabled',
'active_checks_enabled' => 'service_active_checks_enabled',
'last_comment' => 'service_last_comment',
'action_url' => 'service_action_url',
'notes_url' => 'service_notes_url'
)
)
->where('host_name', $this->name1)
->where('service_description', $this->name2)
->fetchRow();
$this->view = ServiceStatus::fromRequest($this->getRequest());
return $this->view->getQuery()->fetchRow();
}
}

View File

@ -1,339 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
use Icinga\Data\AbstractQuery;
use Icinga\Data\Filter;
/**
* AbstractView provides consistent views to our Icinga Backends
*
* TODO: * This could be renamed to AbstractView
* * We might need more complex filters (let's do the simple ones first)
*
* You should not directly instantiate such a view but always go through the
* Monitoring Backend. Using the Backend's select() method selecting from
* 'virtualtable' returns a Icinga\Module\Monitoring\View\VirtualtableView instance.
*
* Usage example:
* <code>
* use \Icinga\Module\Monitoring\Backend;
* $backend = Backend::getInstance();
* $query = $backend->select()->from('viewname', array(
* 'one_column',
* 'another_column',
* 'alias' => 'whatever_column',
* ))->where('any_column', $search);
*
* print_r($query->fetchAll());
* </code>
*
* What we see in the example is that:
* * you can (and should) use a defined set of columns when issueing a query
* * you can use proper alias names to have an influence on column names
* in the result set
* * the AbstractView behaves like any Query object and provides useful
* methods such as fetchAll, count, fetchPairs and so on
*
* If you want to fill a dropdown form element with all your hostgroups
* starting with "net", using the hostgroup name as the form elements value but
* showing the hostgroup aliases in the dropdown you would probably do this as
* follows:
*
* <code>
* $pairs = $backend->select->from(
* 'hostgroups',
* array('hostgroup_name', 'hostgroup_alias')
* )->where('hostgroup_name', 'net*')->fetchPairs();
* $formElement->setMultiOptions($pairs);
* </code>
*
* AbstractView is a proxy to your Backend Query. While both are Query objects
* providing partially the same interface, they are not directly related to
* each other.
*/
class AbstractView extends AbstractQuery
{
/**
* Stores the backend-specific Query Object
* @var AbstractQuery
*/
protected $query;
/**
* All the columns provided by this View MUST be specified here
* @var Array
*/
protected $availableColumns = array();
/**
* Columns available for search only but not in result sets
* @var Array
*/
protected $specialFilters = array();
/**
* All views COULD have a generic column called 'search', if available the
* real column name is defined here.
* TODO: This may be subject to change as a "search" could involve multiple
* columns
* @var string
*/
protected $searchColumn;
/**
* Defines default sorting rules for specific column names. This helps in
* providing "intelligent" sort defaults for different columns (involving
* also other columns where needed)
* @var Array
*/
protected $sortDefaults = array();
/**
* Filters that will be enforced (e.g. AND for SQL), will be used for auth
* restrictions
*
* TODO: rename to enforcedFilters?
*
* @var Array
*/
protected $forcedFilters = array();
/**
* Whether this view provides a specific column name
*
* @param string $column Column name
* @return bool
*/
public function hasColumn($column)
{
return in_array($column, $this->availableColumns);
}
// TODO: Not sure about this yet
public function getDefaultColumns()
{
return $this->availableColumns;
}
/**
* Get a list of all available column names
*
* This might be useful for dynamic frontend tables or similar
*
* @return Array
*/
public function getAvailableColumns()
{
return $this->availableColumns;
}
/**
* Extract and apply filters and sort rules from a given request object
*
* TODO: Enforce Icinga\Web\Request (or similar) as soon as we replaced
* Zend_Controller_Request
*
* @param mixed $request The request object
* @return self
*/
public function applyRequest($request)
{
return $this->applyRequestFilters($request)
->applyRequestSorting($request);
}
/**
* Extract and apply sort column and directon from given request object
*
* @param mixed $request The request object
* @return self
*/
protected function applyRequestSorting($request)
{
return $this->order(
// TODO: Use first sortDefaults entry if available, fall back to
// column if not
$request->getParam('sort', $this->getDefaultSortColumn()),
$request->getParam('dir')
);
}
/**
* Extract and apply filters from a given request object
*
* Columns not fitting any defined available column or special filter column
* will be silently ignored.
*
* @param mixed $request The request object
* @return self
*/
protected function applyRequestFilters($request)
{
foreach ($request->getParams() as $key => $value) {
if ($key === 'search' && $value !== '') {
if (strpos($value, '=') === false) {
if ($this->searchColumn !== null) {
$this->where($this->searchColumn, $value);
}
} else {
list($k, $v) = preg_split('~\s*=\s*~', $value, 2);
if ($this->isValidFilterColumn($k)) {
$this->where($k, $v);
}
}
continue;
}
if ($this->isValidFilterColumn($key)) {
$this->where($key, $value);
}
}
return $this;
}
// TODO: applyAuthFilters(Auth $auth = null)
// AbstractView will enforce restrictions as provided by the Auth
// backend. Those filters work like normal ones and have to be stored
// by applyAuthFilters to $this->forcedFilters
/**
* Apply an array of filters. This might become obsolete or even improved
* and accept Filter objects - this is still to be defined.
*
* @param Array $filters Filter array
* @return self
*/
public function applyFilters($filters)
{
foreach ($filters as $col => $filter) {
$this->where($col, $filter);
}
return $this;
}
/**
* Gives you a filter object with all applied filters excluding auth filters
* Might be used to build URLs fitting query objects.
*
* Please take care, as Url has been improved the Filter object might
* become subject to change
*
* @return Filter
*/
public function getAppliedFilter()
{
return new Filter($this->filters);
}
public function hasSingleSortColumn()
{
return count($this->order_columns) === 1;
}
public function getFirstSortColumn()
{
return $this->order_columns[0];
}
protected function getDefaultSortColumn()
{
if (empty($this->sortDefaults)) {
return $this->availableColumns[0];
} else {
reset($this->sortDefaults);
return key($this->sortDefaults);
}
}
/**
* Default sort direction for given column, ASCending if not defined
*
* @param String $col Column name
* @return int
*/
protected function getDefaultSortDir($col)
{
if (isset($this->sortDefaults[$col]['default_dir'])) {
return $this->sortDefaults[$col]['default_dir'];
}
return self::SORT_ASC;
}
/**
* getQuery gives you an instance of the Query object implementing this
* view for the chosen backend.
*
* @return AbstractQuery
*/
public function getQuery()
{
if ($this->query === null) {
$classParts = preg_split('|\\\|', get_class($this));
$class = substr(
array_pop($classParts),
0,
-4
) . 'Query';
$class = '\\' . get_class($this->ds) . '\\Query\\' . $class;
$query = new $class($this->ds, $this->columns);
foreach ($this->filters as $f) {
$query->where($f[0], $f[1]);
}
foreach ($this->forcedFilters as $col => $filter) {
$query->where($col, $filter);
}
foreach ($this->order_columns as $col) {
if (isset($this->sortDefaults[$col[0]]['columns'])) {
foreach ($this->sortDefaults[$col[0]]['columns'] as $c) {
$query->order($c, $col[1]);
}
} else {
$query->order($col[0], $col[1]);
}
}
$this->query = $query;
}
if ($this->hasLimit()) {
$this->query->limit($this->getLimit(), $this->getOffset());
}
return $this->query;
}
public function count()
{
return $this->getQuery()->count();
}
public function fetchAll()
{
return $this->getQuery()->fetchAll();
}
public function fetchRow()
{
return $this->getQuery()->fetchRow();
}
public function fetchColumn()
{
return $this->getQuery()->fetchColumn();
}
public function fetchPairs()
{
return $this->getQuery()->fetchPairs();
}
public function isValidFilterColumn($column)
{
if (in_array($column, $this->specialFilters)) {
return true;
}
return in_array($column, $this->availableColumns);
}
}

View File

@ -1,50 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class AllcontactsView extends AbstractView
{
protected $query;
protected $availableColumns = array(
'host_name',
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
'contact_notify_hosts',
'contact_notify_services',
'contact_has_host_notfications',
'contact_has_service_notfications',
'contact_can_submit_commands',
'contact_notify_service_recovery',
'contact_notify_service_warning',
'contact_notify_service_critical',
'contact_notify_service_unknown',
'contact_notify_service_flapping',
'contact_notify_service_downtime',
'contact_notify_host_recovery',
'contact_notify_host_down',
'contact_notify_host_unreachable',
'contact_notify_host_flapping',
'contact_notify_host_downtime',
'host_object_id',
'host_name',
'service_object_id',
'service_host_name',
'service_description',
/* 'contact_alias',
'contact_email',
'contact_pager',
'contact_notify_hosts',
'contact_notify_services',
*/
);
/*
protected $sortDefaults = array(
'contact_alias' => array(
'default_dir' => self::SORT_ASC
)
);*/
}

View File

@ -1,44 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class ContactView extends AbstractView
{
protected $query;
protected $availableColumns = array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
'contact_notify_hosts',
'contact_notify_services',
'contact_has_host_notfications',
'contact_has_service_notfications',
'contact_can_submit_commands',
'contact_notify_service_recovery',
'contact_notify_service_warning',
'contact_notify_service_critical',
'contact_notify_service_unknown',
'contact_notify_service_flapping',
'contact_notify_service_downtime',
'contact_notify_host_recovery',
'contact_notify_host_down',
'contact_notify_host_unreachable',
'contact_notify_host_flapping',
'contact_notify_host_downtime',
'host_object_id',
'host_name',
'service_object_id',
'service_host_name',
'service_description',
);
protected $specialFilters = array();
protected $sortDefaults = array(
'contact_alias' => array(
'default_dir' => self::SORT_ASC
)
);
}

View File

@ -1,47 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class ContactgroupView extends AbstractView
{
protected $query;
protected $availableColumns = array(
'contactgroup_name',
'contactgroup_alias',
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
'contact_notify_hosts',
'contact_notify_services',
'contact_has_host_notfications',
'contact_has_service_notfications',
'contact_can_submit_commands',
'contact_notify_service_recovery',
'contact_notify_service_warning',
'contact_notify_service_critical',
'contact_notify_service_unknown',
'contact_notify_service_flapping',
'contact_notify_service_downtime',
'contact_notify_host_recovery',
'contact_notify_host_down',
'contact_notify_host_unreachable',
'contact_notify_host_flapping',
'contact_notify_host_downtime',
'host_object_id',
'host_name',
'service_description'
);
protected $specialFilters = array();
protected $sortDefaults = array(
'contactgroup_alias' => array(
'default_dir' => self::SORT_ASC
)
);
}

View File

@ -1,23 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class CustomvarView extends AbstractView
{
protected $query;
protected $availableColumns = array(
'varname',
'varvalue',
'object_type',
);
protected $specialFilters = array();
protected $sortDefaults = array(
'varname' => array(
'varname' => self::SORT_ASC,
'varvalue' => self::SORT_ASC,
)
);
}

View File

@ -1,82 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Icinga 2 Web - Head for multiple monitoring frontends
* 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>
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\View;
/**
* Class DowntimeView
*/
class DowntimeView extends AbstractView
{
/**
* Query object
* @var mixed
*/
protected $query;
/**
* Available columns
* @var string[]
*/
protected $availableColumns = array(
'host_name',
'object_type',
'service_host_name',
'service_description',
'downtime_type',
'downtime_author_name',
'downtime_comment_data',
'downtime_is_fixed',
'downtime_duration',
'downtime_entry_time',
'downtime_scheduled_start_time',
'downtime_scheduled_end_time',
'downtime_was_started',
'downtime_actual_start_time',
'downtime_actual_start_time_usec',
'downtime_is_in_effect',
'downtime_trigger_time',
'downtime_triggered_by_id',
'downtime_internal_downtime_id'
);
/**
* Filters
* @var array
*/
protected $specialFilters = array();
/**
* Default sorting of data set
* @var array
*/
protected $sortDefaults = array(
'downtime_is_in_effect' => array(
'default_dir' => self::SORT_DESC
),
'downtime_actual_start_time' => array(
'default_dir' => self::SORT_DESC
)
);
}

View File

@ -1,36 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class EventHistoryView extends AbstractView
{
protected $query;
protected $availableColumns = array(
'raw_timestamp',
'timestamp',
'host',
'service',
'host_name',
'state',
'last_state',
'last_hard_state',
'attempt',
'max_attempts',
'output',
'type'
);
protected $specialFilters = array(
'hostgroup',
);
protected $sortDefaults = array(
'raw_timestamp' => array(
'default_dir' => self::SORT_DESC
),
'timestamp' => array(
'default_dir' => self::SORT_DESC
),
);
}

View File

@ -1,22 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class HostgroupView extends AbstractView
{
protected $query;
protected $availableColumns = array(
'hostgroups',
'hostgroup_name',
'hostgroup_alias',
);
protected $specialFilters = array();
protected $sortDefaults = array(
'hostgroup_alias' => array(
'default_dir' => self::SORT_ASC
)
);
}

View File

@ -1,90 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class HoststatusView extends AbstractView
{
protected $query;
protected $searchColumn = 'host';
protected $availableColumns = array(
// Hosts
'host',
'host_name',
'host_display_name',
'host_alias',
'host_address',
'host_ipv4',
'host_icon_image',
// Hoststatus
'host_state',
'host_problem',
'host_severity',
'host_state_type',
'host_output',
'host_long_output',
'host_perfdata',
'host_acknowledged',
'host_in_downtime',
'host_handled',
'host_does_active_checks',
'host_accepts_passive_checks',
'host_last_state_change',
'host_last_hard_state',
'host_last_hard_state_change',
'host_notifications_enabled',
'host_last_time_up',
'host_last_time_down',
'host_last_time_unreachable',
'host_current_check_attempt',
'host_max_check_attempts',
// Services
'services_cnt',
'services_problem',
'services_problem_handled',
'services_problem_unhandled',
);
protected $specialFilters = array(
'hostgroup',
'servicegroup',
'contact',
'contactgroup',
);
protected $sortDefaults = array(
'host_name' => array(
'columns' => array(
'host_name',
),
'default_dir' => self::SORT_ASC
),
'host_address' => array(
'columns' => array(
'host_ipv4',
'service_description'
),
'default_dir' => self::SORT_ASC
),
'host_last_state_change' => array(
'default_dir' => self::SORT_DESC
),
'host_severity' => array(
'columns' => array(
'host_severity',
'host_last_state_change',
),
'default_dir' => self::SORT_DESC
)
);
public function isValidFilterColumn($column)
{
if ($column[0] === '_'
&& preg_match('~^_host~', $column)
) {
return true;
}
return parent::isValidFilterColumn($column);
}
}

View File

@ -1,59 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Icinga 2 Web - Head for multiple monitoring frontends
* 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>
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\View;
/**
* NotificationView
*/
class NotificationView extends AbstractView
{
/**
* Available columns provided by this view
*
* @var array
*/
protected $availableColumns = array(
'host_name',
'service_description',
'notification_type',
'notification_reason',
'notification_start_time',
'notification_contact',
'notification_information',
'notification_command'
);
/**
* Default sorting rules
*
* @var array
*/
protected $sortDefaults = array(
'notification_start_time' => array(
'default_dir' => self::SORT_DESC
)
);
}

View File

@ -1,21 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class ServicegroupView extends AbstractView
{
protected $query;
protected $availableColumns = array(
'servicegroup_name',
'servicegroup_alias',
);
protected $specialFilters = array();
protected $sortDefaults = array(
'servicegroup_alias' => array(
'default_dir' => self::SORT_ASC
)
);
}

View File

@ -1,25 +0,0 @@
<?php
namespace Icinga\Monitoring\View;
use Icinga\Module\Monitoring\View\AbstractView;
class StatehistoryView extends AbstractView
{
protected $availableColumns = array(
'raw_timestamp',
'timestamp',
'state',
'attempt',
'max_attempts',
'output',
'type'
);
protected $sortDefaults = array(
'timestamp' => array(
'columns' => array('raw_timestamp'),
'default_dir' => self::SORT_DESC
),
);
}

View File

@ -1,135 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\View;
class StatusView extends AbstractView
{
protected $query;
// protected $searchColumn = 'host'; -> besser in der Query, 'search' mitgeben
protected $availableColumns = array(
// Hosts
'host',
'host_name',
'host_display_name',
'host_alias',
'host_address',
'host_ipv4',
'host_icon_image',
// Hoststatus
'host_state',
'host_problems',
'host_severity',
'host_state_type',
'host_output',
'host_long_output',
'host_perfdata',
'host_acknowledged',
'host_in_downtime',
'host_handled',
'host_does_active_checks',
'host_accepts_passive_checks',
'host_last_state_change',
'host_last_hard_state',
'host_last_hard_state_change',
'host_notifications_enabled',
'host_last_time_up',
'host_last_time_down',
'host_last_time_unreachable',
'host_unhandled_service_count',
// Services
'service',
'service_description',
'service_display_name',
// Servicetatus
'current_state',
'service_state',
'service_state_type',
'service_hard_state',
'service_output',
'service_long_output',
'service_perfdata',
'service_acknowledged',
'service_in_downtime',
'service_handled',
'service_does_active_checks',
'service_accepts_passive_checks',
'service_last_state_change',
'service_last_hard_state',
'service_last_hard_state_change',
'service_notifications_enabled',
'service_last_time_ok',
'service_last_time_warning',
'service_last_time_critical',
'service_last_time_unknown',
'object_type',
// Status
'problems',
'handled',
'severity'
);
protected $specialFilters = array(
'hostgroups',
'servicegroups'
);
protected $sortDefaults = array(
'host_name' => array(
'columns' => array(
'host_name',
),
'default_dir' => self::SORT_ASC
),
'service_host_name' => array(
'columns' => array(
'service_host_name',
'service_description'
),
'default_dir' => self::SORT_ASC
),
'host_address' => array(
'columns' => array(
'host_ipv4',
'service_description'
),
'default_dir' => self::SORT_ASC
),
'host_last_state_change' => array(
'default_dir' => self::SORT_DESC
),
'service_last_state_change' => array(
'default_dir' => self::SORT_DESC
),
'severity' => array(
'columns' => array(
'severity',
'host_name',
'service_last_state_change',
),
'default_dir' => self::SORT_DESC
),
'host_severity' => array(
'columns' => array(
'host_severity',
'host_last_state_change',
),
'default_dir' => self::SORT_DESC
)
);
public function isValidFilterColumn($column)
{
if ($column[0] === '_'
&& preg_match('~^_(?:host|service)_~', $column)
) {
return true;
}
return parent::isValidFilterColumn($column);
}
}

View File

@ -8,7 +8,7 @@ require_once realpath(__DIR__ . '/../../../../../../library/Icinga/Test/BaseTest
use Icinga\Test\BaseTestCase;
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/test/php/testlib/MonitoringControllerTest.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/Filter/Backend/IdoQueryConverter.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/Filter/Backend/TreeToSqlParser.php);
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/DataView/DataView.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/DataView/HostStatus.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/DataView/Notification.php'));

View File

@ -7,7 +7,7 @@ use Icinga\Test\BaseTestCase;
require_once realpath(__DIR__ . '/../../../../../../library/Icinga/Test/BaseTestCase.php');
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/test/php/testlib/MonitoringControllerTest.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/Filter/Backend/IdoQueryConverter.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/Filter/Backend/TreeToSqlParser.php);
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/DataView/DataView.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/DataView/ServiceStatus.php'));
require_once(realpath(BaseTestCase::$moduleDir . '/monitoring/library/Monitoring/DataView/Notification.php'));

View File

@ -156,7 +156,7 @@ abstract class MonitoringControllerTest extends Zend_Test_PHPUnit_ControllerTest
private function requireBase()
{
require_once('Application/Benchmark.php');
require_once('Data/AbstractQuery.php');
require_once('Data/BaseQuery.php');
require_once('Data/DatasourceInterface.php');
require_once('Data/Db/Connection.php');
require_once('Data/Db/Query.php');

View File

@ -6,7 +6,7 @@ use Icinga\Protocol\Livestatus\Connection;
use Icinga\Protocol\Livestatus\Query;
use PHPUnit_Framework_TestCase as TestCase;
require_once('../../library/Icinga/Protocol/AbstractQuery.php');
require_once('../../library/Icinga/Protocol/BaseQuery.php');
require_once('../../library/Icinga/Protocol/Livestatus/Connection.php');
require_once('../../library/Icinga/Protocol/Livestatus/Query.php');

View File

@ -1,9 +1,9 @@
<?php
namespace Tests\Icinga\Protocol\Statusdat;
require_once("../../library/Icinga/Data/QueryInterface.php");
require_once("../../library/Icinga/Data/AbstractQuery.php");
require_once("../../library/Icinga/Protocol/Statusdat/Query.php");
require_once('../../library/Icinga/Data/QueryInterface.php');
require_once('../../library/Icinga/Data/BaseQuery.php');
require_once('../../library/Icinga/Protocol/Statusdat/Query.php');
require_once(dirname(__FILE__)."/ReaderMock.php");
use Icinga\Protocol\Statusdat as Statusdat;

View File

@ -12,8 +12,7 @@ class StatusdatTestLoader extends LibraryLoader
require_once 'Zend/Config.php';
require_once 'Zend/Cache.php';
require_once 'Zend/Log.php';
require_once($libPath."/Data/AbstractQuery.php");
require_once($libPath."/Application/Logger.php");
require_once($libPath."/Data/BaseQuery.php require_once($libPath."/Application/Logger.php");
require_once($libPath."/Filter/Filterable.php");
require_once($libPath."/Data/DatasourceInterface.php");
$statusdat = realpath($libPath."/Protocol/Statusdat/");

View File

@ -25,8 +25,7 @@ require_once '../../modules/monitoring/library/Monitoring/View/AbstractView.php'
require_once '../../modules/monitoring/library/Monitoring/View/StatusView.php';
require_once '../../modules/monitoring/library/Monitoring/Backend.php';
require_once '../../library/Icinga/Protocol/AbstractQuery.php';
require_once '../../library/Icinga/Data/ResourceFactory.php';
require_once '../../library/Icinga/Protocol/BaseQuery.phpequire_once '../../library/Icinga/Data/ResourceFactory.php';
class QueryAdapterTest extends PHPUnit_Framework_TestCase
{