Merge branch 'feature/provide-a-complete-list-of-filter-columns-9029'

resolves #9029
This commit is contained in:
Johannes Meyer 2015-08-17 15:41:54 +02:00
commit 0ac2a8898a
42 changed files with 541 additions and 450 deletions

View File

@ -54,19 +54,12 @@ class GroupController extends AuthBackendController
}
$query = $backend->select(array('group_name'));
$filterEditor = Widget::create('filterEditor')
->setQuery($query)
->setSearchColumns(array('group', 'user'))
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
->ignoreParams('page')
->handleRequest($this->getRequest());
$query->applyFilter($filterEditor->getFilter());
$this->setupFilterControl($filterEditor);
$this->view->groups = $query;
$this->view->backend = $backend;
$this->setupPaginationControl($query);
$this->setupFilterControl($query);
$this->setupLimitControl();
$this->setupSortControl(
array(
@ -101,15 +94,7 @@ class GroupController extends AuthBackendController
->from('group_membership', array('user_name'))
->where('group_name', $groupName);
$filterEditor = Widget::create('filterEditor')
->setQuery($members)
->setSearchColumns(array('user'))
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'group')
->ignoreParams('page')
->handleRequest($this->getRequest());
$members->applyFilter($filterEditor->getFilter());
$this->setupFilterControl($filterEditor);
$this->setupFilterControl($members, null, array('user'));
$this->setupPaginationControl($members);
$this->setupLimitControl();
$this->setupSortControl(

View File

@ -54,19 +54,12 @@ class UserController extends AuthBackendController
}
$query = $backend->select(array('user_name'));
$filterEditor = Widget::create('filterEditor')
->setQuery($query)
->setSearchColumns(array('user'))
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
->ignoreParams('page')
->handleRequest($this->getRequest());
$query->applyFilter($filterEditor->getFilter());
$this->setupFilterControl($filterEditor);
$this->view->users = $query;
$this->view->backend = $backend;
$this->setupPaginationControl($query);
$this->setupFilterControl($query);
$this->setupLimitControl();
$this->setupSortControl(
array(
@ -100,15 +93,11 @@ class UserController extends AuthBackendController
$memberships = $this->loadMemberships(new User($userName))->select();
$filterEditor = Widget::create('filterEditor')
->setQuery($memberships)
->setSearchColumns(array('group_name'))
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'user')
->ignoreParams('page')
->handleRequest($this->getRequest());
$memberships->applyFilter($filterEditor->getFilter());
$this->setupFilterControl($filterEditor);
$this->setupFilterControl(
$memberships,
array('group_name' => t('User Group')),
array('group_name')
);
$this->setupPaginationControl($memberships);
$this->setupLimitControl();
$this->setupSortControl(

View File

@ -61,7 +61,14 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
*
* @var array
*/
protected $filterColumns = array('user');
protected $blacklistedQueryColumns = array('user');
/**
* The search columns being provided
*
* @var array
*/
protected $searchColumns = array('user');
/**
* The default sort rules to be applied on a query
@ -98,6 +105,23 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
}
}
/**
* Initialize this repository's filter columns
*
* @return array
*/
protected function initializeFilterColumns()
{
$userLabel = t('Username') . ' ' . t('(Case insensitive)');
return array(
$userLabel => 'user',
t('Username') => 'user_name',
t('Active') => 'is_active',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
);
}
/**
* Insert a table row with the given data
*

View File

@ -50,7 +50,14 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
*
* @var array
*/
protected $filterColumns = array('user');
protected $blacklistedQueryColumns = array('user');
/**
* The search columns being provided
*
* @var array
*/
protected $searchColumns = array('user');
/**
* The default sort rules to be applied on a query
@ -243,6 +250,21 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
);
}
/**
* Initialize this repository's filter columns
*
* @return array
*/
protected function initializeFilterColumns()
{
return array(
t('Username') => 'user_name',
t('Active') => 'is_active',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
);
}
/**
* Initialize this repository's conversion rules
*

View File

@ -71,7 +71,14 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
*
* @var array
*/
protected $filterColumns = array('group', 'user');
protected $blacklistedQueryColumns = array('group', 'user');
/**
* The search columns being provided
*
* @var array
*/
protected $searchColumns = array('group', 'user');
/**
* The value conversion rules to apply on a query or statement
@ -97,6 +104,26 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
}
}
/**
* Initialize this repository's filter columns
*
* @return array
*/
protected function initializeFilterColumns()
{
$userLabel = t('Username') . ' ' . t('(Case insensitive)');
$groupLabel = t('User Group') . ' ' . t('(Case insensitive)');
return array(
$userLabel => 'user',
t('Username') => 'user_name',
$groupLabel => 'group',
t('User Group') => 'group_name',
t('Parent') => 'parent',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
);
}
/**
* Insert a table row with the given data
*

View File

@ -32,7 +32,14 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter
*
* @var array
*/
protected $filterColumns = array('group');
protected $blacklistedQueryColumns = array('group');
/**
* The search columns being provided
*
* @var array
*/
protected $searchColumns = array('group');
/**
* The value conversion rules to apply on a query or statement
@ -55,6 +62,21 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter
$this->ds->getConfigObject()->setKeyColumn('name');
}
/**
* Initialize this repository's filter columns
*
* @return array
*/
protected function initializeFilterColumns()
{
return array(
t('User Group') => 'group',
t('Parent') => 'parent',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
);
}
/**
* Add a new group to this backend
*

View File

@ -83,7 +83,14 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
*
* @var array
*/
protected $filterColumns = array('group', 'user');
protected $blacklistedQueryColumns = array('group', 'user');
/**
* The search columns being provided
*
* @var array
*/
protected $searchColumns = array('group', 'user');
/**
* The default sort rules to be applied on a query
@ -457,6 +464,21 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
return array('group' => $columns, 'group_membership' => $columns);
}
/**
* Initialize this repository's filter columns
*
* @return array
*/
protected function initializeFilterColumns()
{
return array(
t('Username') => 'user',
t('User Group') => 'group_name',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
);
}
/**
* Initialize this repository's conversion rules
*

View File

@ -0,0 +1,21 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Data;
interface FilterColumns
{
/**
* Return a filterable's filter columns with their optional label as key
*
* @return array
*/
public function getFilterColumns();
/**
* Return a filterable's search columns
*
* @return array
*/
public function getSearchColumns();
}

View File

@ -64,19 +64,43 @@ abstract class Repository implements Selectable
* 'alias2' => 'column3'
* )
* )
* <pre><code>
* </code></pre>
*
* @var array
*/
protected $queryColumns;
/**
* The columns (or aliases) which are not permitted to be queried. (by design)
* The columns (or aliases) which are not permitted to be queried
*
* Blacklisted query columns can still occur in a filter expression or sort rule.
*
* @var array An array of strings
*/
protected $blacklistedQueryColumns;
/**
* The filter columns being provided
*
* This may be intialized by concrete repository implementations, in the following format
* <pre><code>
* array(
* 'alias_or_column_name',
* 'label_to_show_in_the_filter_editor' => 'alias_or_column_name'
* )
* </code></pre>
*
* @var array
*/
protected $filterColumns;
/**
* The search columns (or aliases) being provided
*
* @var array An array of strings
*/
protected $searchColumns;
/**
* The sort rules to be applied on a query
*
@ -98,7 +122,7 @@ abstract class Repository implements Selectable
* // Ascendant sort by default
* )
* )
* <pre><code>
* </code></pre>
* Note that it's mandatory to supply the alias name in case there is one.
*
* @var array
@ -260,6 +284,33 @@ abstract class Repository implements Selectable
/**
* Return the columns (or aliases) which are not permitted to be queried
*
* Calls $this->initializeBlacklistedQueryColumns() in case $this->blacklistedQueryColumns is null.
*
* @return array
*/
public function getBlacklistedQueryColumns()
{
if ($this->blacklistedQueryColumns === null) {
$this->blacklistedQueryColumns = $this->initializeBlacklistedQueryColumns();
}
return $this->blacklistedQueryColumns;
}
/**
* Overwrite this in your repository implementation in case you
* need to initialize the blacklisted query columns lazily
*
* @return array
*/
protected function initializeBlacklistedQueryColumns()
{
return array();
}
/**
* Return the filter columns being provided
*
* Calls $this->initializeFilterColumns() in case $this->filterColumns is null.
*
* @return array
@ -283,6 +334,32 @@ abstract class Repository implements Selectable
return array();
}
/**
* Return the search columns being provided
*
* Calls $this->initializeSearchColumns() in case $this->searchColumns is null.
*
* @return array
*/
public function getSearchColumns()
{
if ($this->searchColumns === null) {
$this->searchColumns = $this->initializeSearchColumns();
}
return $this->searchColumns;
}
/**
* Overwrite this in your repository implementation in case you need to initialize the search columns lazily
*
* @return array
*/
protected function initializeSearchColumns()
{
return array();
}
/**
* Return the sort rules to be applied on a query
*
@ -781,10 +858,10 @@ abstract class Repository implements Selectable
throw new ProgrammingError('Table name "%s" not found', $table);
}
$filterColumns = $this->getFilterColumns();
$blacklist = $this->getBlacklistedQueryColumns();
$columns = array();
foreach ($queryColumns[$table] as $alias => $column) {
if (! in_array(is_string($alias) ? $alias : $column, $filterColumns)) {
if (! in_array(is_string($alias) ? $alias : $column, $blacklist)) {
$columns[$alias] = $column;
}
}
@ -874,7 +951,8 @@ abstract class Repository implements Selectable
return false;
}
return !in_array($alias, $this->getFilterColumns()) && $this->validateQueryColumnAssociation($table, $name);
return !in_array($alias, $this->getBlacklistedQueryColumns())
&& $this->validateQueryColumnAssociation($table, $name);
}
/**
@ -898,8 +976,8 @@ abstract class Repository implements Selectable
throw new QueryException(t('Query column "%s" not found'), $name);
}
if (in_array($alias, $this->getFilterColumns())) {
throw new QueryException(t('Filter column "%s" cannot be queried'), $name);
if (in_array($alias, $this->getBlacklistedQueryColumns())) {
throw new QueryException(t('Column "%s" cannot be queried'), $name);
}
if (! $this->validateQueryColumnAssociation($table, $alias)) {
@ -985,8 +1063,8 @@ abstract class Repository implements Selectable
throw new StatementException('Statement column "%s" not found', $name);
}
if (in_array($alias, $this->getFilterColumns())) {
throw new StatementException('Filter column "%s" cannot be referenced in a statement', $name);
if (in_array($alias, $this->getBlacklistedQueryColumns())) {
throw new StatementException('Column "%s" cannot be referenced in a statement', $name);
}
if (! $this->validateQueryColumnAssociation($table, $alias)) {

View File

@ -10,13 +10,14 @@ use Icinga\Application\Benchmark;
use Icinga\Application\Logger;
use Icinga\Data\QueryInterface;
use Icinga\Data\Filter\Filter;
use Icinga\Data\FilterColumns;
use Icinga\Data\SortRules;
use Icinga\Exception\QueryException;
/**
* Query class supposed to mediate between a repository and its datasource's query
*/
class RepositoryQuery implements QueryInterface, SortRules, Iterator
class RepositoryQuery implements QueryInterface, SortRules, FilterColumns, Iterator
{
/**
* The repository being used
@ -141,6 +142,26 @@ class RepositoryQuery implements QueryInterface, SortRules, Iterator
return $columns;
}
/**
* Return this query's available filter columns with their optional label as key
*
* @return array
*/
public function getFilterColumns()
{
return $this->repository->getFilterColumns();
}
/**
* Return this query's available search columns
*
* @return array
*/
public function getSearchColumns()
{
return $this->repository->getSearchColumns();
}
/**
* Filter this query using the given column and value
*

View File

@ -3,6 +3,7 @@
namespace Icinga\Web;
use Icinga\Data\Filterable;
use Icinga\Data\Sortable;
use Icinga\Data\QueryInterface;
use Icinga\Exception\Http\HttpNotFoundException;
@ -140,16 +141,51 @@ class Controller extends ModuleActionController
}
/**
* Set the view property `filterEditor' to the given FilterEditor
* Create a FilterEditor widget and apply the user's chosen filter options on the given filterable
*
* In case the current view has been requested as compact this method does nothing.
* The widget is set on the `filterEditor' view property only if the current view has not been requested as compact.
* The optional $filterColumns parameter should be an array of key-value pairs where the key is the name of the
* column and the value the label to show to the user. The optional $searchColumns parameter should be an array
* of column names to be used to handle quick searches.
*
* @param Form $editor The FilterEditor
* If the given filterable is an instance of Icinga\Data\FilterColumns, $filterable->getFilterColumns() and
* $filterable->getSearchColumns() is called to provide the respective columns if $filterColumns or $searchColumns
* is not given.
*
* @param Filterable $filterable The filterable to create a filter editor for
* @param array $filterColumns The filter columns to offer to the user
* @param array $searchColumns The search columns to utilize for quick searches
*
* @return $this
*
* @todo Preserving and ignoring parameters should be configurable (another two method params? property magic?)
*/
protected function setupFilterControl($editor)
{
protected function setupFilterControl(
Filterable $filterable,
array $filterColumns = null,
array $searchColumns = null
) {
$editor = Widget::create('filterEditor')
->setQuery($filterable)
->preserveParams(
'limit',
'sort',
'dir',
'format',
'view',
'user',
'group',
'backend',
'stateType',
'addColumns',
'problems',
'_dev'
)
->ignoreParams('page')
->setColumns($filterColumns)
->setSearchColumns($searchColumns)
->handleRequest($this->getRequest());
if (! $this->view->compact) {
$this->view->filterEditor = $editor;
}

View File

@ -3,6 +3,8 @@
namespace Icinga\Web\Widget;
use Icinga\Data\Filterable;
use Icinga\Data\FilterColumns;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterExpression;
use Icinga\Data\Filter\FilterChain;
@ -25,6 +27,11 @@ class FilterEditor extends AbstractWidget
*/
private $filter;
/**
* The query to filter
*
* @var Filterable
*/
protected $query;
protected $url;
@ -41,7 +48,7 @@ class FilterEditor extends AbstractWidget
protected $ignoreParams = array();
protected $searchColumns = null;
protected $searchColumns;
/**
* @var string
@ -84,7 +91,7 @@ class FilterEditor extends AbstractWidget
*
* @return $this
*/
public function setSearchColumns(array $searchColumns)
public function setSearchColumns(array $searchColumns = null)
{
$this->searchColumns = $searchColumns;
return $this;
@ -112,7 +119,14 @@ class FilterEditor extends AbstractWidget
return $this->preservedUrl;
}
public function setQuery($query)
/**
* Set the query to filter
*
* @param Filterable $query
*
* @return $this
*/
public function setQuery(Filterable $query)
{
$this->query = $query;
return $this;
@ -219,19 +233,25 @@ class FilterEditor extends AbstractWidget
if (strpos($search, '=') !== false) {
list($k, $v) = preg_split('/=/', $search);
$filter = $this->mergeRootExpression($filter, trim($k), '=', ltrim($v));
} elseif (! empty($this->searchColumns)) {
if (! $this->resetSearchColumns($filter)) {
$filter = Filter::matchAll();
}
$filters = array();
$search = ltrim($search);
foreach ($this->searchColumns as $searchColumn) {
$filters[] = Filter::expression($searchColumn, '=', "*$search*");
}
$filter = $filter->andFilter(new FilterOr($filters));
} else {
Notification::error(mt('monitoring', 'Cannot search here'));
return $this;
if ($this->searchColumns === null && $this->query instanceof FilterColumns) {
$this->searchColumns = $this->query->getSearchColumns();
}
if (! empty($this->searchColumns)) {
if (! $this->resetSearchColumns($filter)) {
$filter = Filter::matchAll();
}
$filters = array();
$search = ltrim($search);
foreach ($this->searchColumns as $searchColumn) {
$filters[] = Filter::expression($searchColumn, '=', "*$search*");
}
$filter = $filter->andFilter(new FilterOr($filters));
} else {
Notification::error(mt('monitoring', 'Cannot search here'));
return $this;
}
}
$url = $this->url()->setQueryString(
@ -284,6 +304,11 @@ class FilterEditor extends AbstractWidget
if ($add) {
$this->addFilterToId($add);
}
if ($this->query !== null && $request->isGet()) {
$this->query->applyFilter($this->getFilter());
}
return $this;
}
@ -482,12 +507,14 @@ class FilterEditor extends AbstractWidget
);
}
protected function arrayForSelect($array)
protected function arrayForSelect($array, $flip = false)
{
$res = array();
foreach ($array as $k => $v) {
if (is_int($k)) {
$res[$v] = $v;
$res[$v] = ucwords(str_replace('_', ' ', $v));
} elseif ($flip) {
$res[$v] = $k;
} else {
$res[$k] = $v;
}
@ -540,9 +567,9 @@ class FilterEditor extends AbstractWidget
);
}
public function setColumns(array $columns)
public function setColumns(array $columns = null)
{
$this->cachedColumnSelect = $this->arrayForSelect($columns);
$this->cachedColumnSelect = $columns ? $this->arrayForSelect($columns) : null;
return $this;
}
@ -558,20 +585,15 @@ class FilterEditor extends AbstractWidget
);
}
if ($this->cachedColumnSelect === null) {
$this->cachedColumnSelect = $this->arrayForSelect($this->query->getColumns());
if ($this->cachedColumnSelect === null && $this->query instanceof FilterColumns) {
$this->cachedColumnSelect = $this->arrayForSelect($this->query->getFilterColumns(), true);
asort($this->cachedColumnSelect);
}
$cols = $this->cachedColumnSelect;
$seen = false;
foreach ($cols as $k => & $v) {
$v = str_replace('_', ' ', ucfirst($v));
if ($k === $active) {
$seen = true;
}
} elseif ($this->cachedColumnSelect === null) {
throw new ProgrammingError('No columns set nor does the query provide any');
}
if (!$seen) {
$cols = $this->cachedColumnSelect;
if ($active && !isset($cols[$active])) {
$cols[$active] = str_replace('_', ' ', ucfirst(ltrim($active, '_')));
}

View File

@ -10,7 +10,6 @@ use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Web\Widget\Tabextension\OutputFormat;
use Icinga\Web\Widget\Tabs;
use Icinga\Data\Filter\Filter;
use Icinga\Web\Widget;
use Icinga\Module\Monitoring\Forms\StatehistoryForm;
use Icinga\Module\Monitoring\DataView\DataView;
@ -616,20 +615,7 @@ class Monitoring_ListController extends Controller
*/
protected function filterQuery(DataView $dataView)
{
$editor = Widget::create('filterEditor')
->setQuery($dataView)
->preserveParams(
'limit', 'sort', 'dir', 'format', 'view', 'backend',
'stateType', 'addColumns', '_dev', 'problems'
)
->ignoreParams('page')
->setSearchColumns($dataView->getSearchColumns())
->handleRequest($this->getRequest());
$dataView->applyFilter($editor->getFilter());
$this->setupFilterControl($editor);
$this->view->filter = $editor->getFilter();
$this->setupFilterControl($dataView);
$this->handleFormatRequest($dataView);
return $dataView;
}

View File

@ -68,7 +68,7 @@ foreach ($summary as $entry) {
Filter::expression('timestamp', '<', strtotime($day . ' 23:59:59')),
Filter::expression('timestamp', '>', strtotime($day . ' 00:00:00')),
$form->getFilter(),
$filter
Filter::fromQueryString($this->url()->getParams()->toString())
);
$data[$day] = array(
'value' => $value,

View File

@ -6,7 +6,7 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query;
class CustomvarQuery extends IdoQuery
{
protected $columnMap = array(
'customvars' => array(
'customvariablestatus' => array(
'varname' => 'cvs.varname',
'varvalue' => 'cvs.varvalue',
'is_json' => 'cvs.is_json',
@ -38,7 +38,7 @@ class CustomvarQuery extends IdoQuery
protected function joinBaseTables()
{
if (version_compare($this->getIdoVersion(), '1.12.0', '<')) {
$this->columnMap['customvars']['is_json'] = '(0)';
$this->columnMap['customvariablestatus']['is_json'] = '(0)';
}
$this->select->from(
@ -50,8 +50,29 @@ class CustomvarQuery extends IdoQuery
array()
);
$this->joinedVirtualTables = array(
'customvars' => true,
'objects' => true
'customvariablestatus' => true,
'objects' => true
);
}
/**
* {@inheritdoc}
*/
public function getGroup()
{
$group = parent::getGroup();
if (! empty($group) && $this->ds->getDbType() === 'pgsql') {
foreach ($this->columnMap as $table => $columns) {
$pk = ($table === 'objects' ? 'cvo.' : 'cvs.') . $this->getPrimaryKeyColumn($table);
foreach ($columns as $alias => $_) {
if (! in_array($pk, $group, true) && in_array($alias, $group, true)) {
$group[] = $pk;
break;
}
}
}
}
return $group;
}
}

View File

@ -553,6 +553,31 @@ abstract class IdoQuery extends DbQuery
return stripos($mapped, 'UNIX_TIMESTAMP') !== false;
}
/**
* Return whether the given alias or column name provides case insensitive value comparison
*
* @param string $aliasOrColumn
*
* @return bool
*/
public function isCaseInsensitive($aliasOrColumn)
{
if ($this->isCustomVar($aliasOrColumn)) {
return false;
}
$column = $this->getMappedField($aliasOrColumn) ?: $aliasOrColumn;
if (! $column) {
return false;
}
if (! empty($this->columnsWithoutCollation)) {
return in_array($column, $this->columnsWithoutCollation) || strpos($column, 'LOWER') !== 0;
}
return preg_match('/ COLLATE .+$/', $column) === 1;
}
/**
* Apply oracle specific query initialization
*/
@ -795,6 +820,16 @@ abstract class IdoQuery extends DbQuery
return isset($this->idxAliasTable[$alias]) ? $this->idxAliasTable[$alias] : null;
}
/**
* Return whether this query allows to join custom variables
*
* @return bool
*/
public function allowsCustomVars()
{
return $this->allowCustomVars;
}
/**
* Return true if the given alias denotes a custom variable
*

View File

@ -9,9 +9,7 @@ namespace Icinga\Module\Monitoring\DataView;
class Command extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
* {@inheritdoc}
*/
public function getColumns()
{

View File

@ -8,19 +8,6 @@ namespace Icinga\Module\Monitoring\DataView;
*/
class Comment extends DataView
{
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* {@inheritdoc}
*/
@ -46,7 +33,7 @@ class Comment extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'comment_author',

View File

@ -5,18 +5,6 @@ namespace Icinga\Module\Monitoring\DataView;
class Contact extends DataView
{
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_' && preg_match('/^_(?:host|service)_/', $column)) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* {@inheritdoc}
*/
@ -63,7 +51,7 @@ class Contact extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'contact',

View File

@ -5,18 +5,6 @@ namespace Icinga\Module\Monitoring\DataView;
class Contactgroup extends DataView
{
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_' && preg_match('/^_(?:host|service)_/', $column)) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* {@inheritdoc}
*/
@ -68,7 +56,7 @@ class Contactgroup extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'contactgroup', 'contact',

View File

@ -3,15 +3,10 @@
namespace Icinga\Module\Monitoring\DataView;
/**
* Represent customvar view
*/
class Customvar extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
* {@inheritdoc}
*/
public function getColumns()
{
@ -28,9 +23,7 @@ class Customvar extends DataView
}
/**
* Retrieve default sorting rules for particular columns. These involve sort order and potential additional to sort
*
* @return array
* {@inheritdoc}
*/
public function getSortRules()
{
@ -44,7 +37,10 @@ class Customvar extends DataView
);
}
public function getFilterColumns()
/**
* {@inheritdoc}
*/
public function getStaticFilterColumns()
{
return array('host', 'service', 'contact');
}

View File

@ -4,6 +4,7 @@
namespace Icinga\Module\Monitoring\DataView;
use IteratorAggregate;
use Icinga\Data\FilterColumns;
use Icinga\Data\QueryInterface;
use Icinga\Data\SortRules;
use Icinga\Data\Filter\Filter;
@ -19,7 +20,7 @@ use Icinga\Module\Monitoring\Backend\MonitoringBackend;
/**
* A read-only view of an underlying query
*/
abstract class DataView implements QueryInterface, SortRules, IteratorAggregate
abstract class DataView implements QueryInterface, SortRules, FilterColumns, IteratorAggregate
{
/**
* The query used to populate the view
@ -34,6 +35,13 @@ abstract class DataView implements QueryInterface, SortRules, IteratorAggregate
protected $isSorted = false;
/**
* The cache for all filter columns
*
* @var array
*/
protected $filterColumns;
/**
* Create a new view
*
@ -45,18 +53,6 @@ abstract class DataView implements QueryInterface, SortRules, IteratorAggregate
$this->connection = $connection;
$this->query = $connection->query($this->getQueryName(), $columns);
$this->filter = Filter::matchAll();
$this->init();
}
/**
* Initializer for `distinct purposes
*
* Implemented for `distinct as workaround
*
* @TODO Subject to change, see #7344
*/
public function init()
{
}
/**
@ -185,23 +181,93 @@ abstract class DataView implements QueryInterface, SortRules, IteratorAggregate
}
/**
* 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
* Check whether the given column is a valid filter column
*
* @param string $column
* @param string $column
*
* @return bool
*/
public function isValidFilterTarget($column)
{
return in_array($column, $this->getColumns()) || in_array($column, $this->getFilterColumns());
return in_array($column, $this->getFilterColumns());
}
/**
* Return all filter columns with their optional label as key
*
* This will merge the results of self::getColumns(), self::getStaticFilterColumns() and
* self::getDynamicFilterColumns() *once*. (i.e. subsequent calls of this function will
* return the same result.)
*
* @return array
*/
public function getFilterColumns()
{
if ($this->filterColumns === null) {
$columns = array_merge(
$this->getColumns(),
$this->getStaticFilterColumns(),
$this->getDynamicFilterColumns()
);
$this->filterColumns = array();
foreach ($columns as $label => $column) {
if (is_int($label)) {
$label = ucwords(str_replace('_', ' ', $column));
}
if ($this->query->isCaseInsensitive($column)) {
$label .= ' ' . t('(Case insensitive)');
}
$this->filterColumns[$label] = $column;
}
}
return $this->filterColumns;
}
/**
* Return all static filter columns
*
* @return array
*/
public function getStaticFilterColumns()
{
return array();
}
/**
* Return all dynamic filter columns such as custom variables
*
* @return array
*/
public function getDynamicFilterColumns()
{
$columns = array();
if (! $this->query->allowsCustomVars()) {
return $columns;
}
$query = MonitoringBackend::instance()
->select()
->from('customvar', array('varname', 'object_type'))
->where('is_json', 0)
->where('object_type_id', array(1, 2))
->getQuery()->group(array('varname', 'object_type'));
foreach ($query as $row) {
if ($row->object_type === 'host') {
$label = t('Host') . ' ' . ucwords(str_replace('_', ' ', $row->varname));
$columns[$label] = '_host_' . $row->varname;
} else { // $row->object_type === 'service'
$label = t('Service') . ' ' . ucwords(str_replace('_', ' ', $row->varname));
$columns[$label] = '_service_' . $row->varname;
}
}
return $columns;
}
public function getFilter()
{
return $this->filter;

View File

@ -8,19 +8,6 @@ namespace Icinga\Module\Monitoring\DataView;
*/
class Downtime extends DataView
{
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* {@inheritdoc}
*/
@ -53,7 +40,7 @@ class Downtime extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'downtime_author',

View File

@ -8,20 +8,6 @@ class Eventgrid extends DataView
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_' && preg_match('/^_(?:host|service)_/', $column)) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* Retrieve columns provided by this view
*
* @return array
*/
public function getColumns()
{
return array(
@ -61,7 +47,7 @@ class Eventgrid extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias',

View File

@ -8,20 +8,6 @@ class EventHistory extends DataView
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_' && preg_match('/^_(?:host|service)_/', $column)) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* Retrieve columns provided by this view
*
* @return array
*/
public function getColumns()
{
return array(
@ -57,7 +43,7 @@ class EventHistory extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias',

View File

@ -31,7 +31,7 @@ class Hostcomment extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias',
@ -40,17 +40,4 @@ class Hostcomment extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
}

View File

@ -36,7 +36,7 @@ class Hostdowntime extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias',
@ -45,17 +45,4 @@ class Hostdowntime extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
}

View File

@ -22,7 +22,7 @@ class Hostgroup extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias', 'host_display_name', 'host_name',
@ -31,18 +31,4 @@ class Hostgroup extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
} else {
return parent::isValidFilterTarget($column);
}
}
}

View File

@ -44,7 +44,7 @@ class Hostgroupsummary extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'hosts_severity',
@ -95,18 +95,4 @@ class Hostgroupsummary extends DataView
)
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
} else {
return parent::isValidFilterTarget($column);
}
}
}

View File

@ -64,7 +64,7 @@ class HostStatus extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host',
@ -83,9 +83,7 @@ class HostStatus extends DataView
}
/**
* The sort rules for this query
*
* @return array
* {@inheritdoc}
*/
public function getSortRules()
{
@ -112,17 +110,4 @@ class HostStatus extends DataView
)
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
}

View File

@ -27,7 +27,7 @@ class Hoststatussummary extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias', 'host_display_name', 'host_name',
@ -36,18 +36,4 @@ class Hoststatussummary extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
} else {
return in_array($column, $this->getFilterColumns());
}
}
}

View File

@ -8,21 +8,6 @@ class Notification extends DataView
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* Retrieve columns provided by this view
*
* @return array
*/
public function getColumns()
{
return array(
@ -74,7 +59,7 @@ class Notification extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'contact',

View File

@ -9,9 +9,7 @@ namespace Icinga\Module\Monitoring\DataView;
class Programstatus extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
* {@inheritdoc}
*/
public function getColumns()
{
@ -45,9 +43,7 @@ class Programstatus extends DataView
}
/**
* Retrieve default sorting rules for particular columns. These involve sort order and potential additional to sort
*
* @return array
* {@inheritdoc}
*/
public function getSortRules()
{

View File

@ -9,9 +9,7 @@ namespace Icinga\Module\Monitoring\DataView;
class Runtimesummary extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
* {@inheritdoc}
*/
public function getColumns()
{
@ -27,9 +25,7 @@ class Runtimesummary extends DataView
}
/**
* Retrieve default sorting rules for particular columns. These involve sort order and potential additional to sort
*
* @return array
* {@inheritdoc}
*/
public function getSortRules()
{

View File

@ -9,9 +9,7 @@ namespace Icinga\Module\Monitoring\DataView;
class Runtimevariables extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
* {@inheritdoc}
*/
public function getColumns()
{
@ -23,9 +21,7 @@ class Runtimevariables extends DataView
}
/**
* Retrieve default sorting rules for particular columns. These involve sort order and potential additional to sort
*
* @return array
* {@inheritdoc}
*/
public function getSortRules()
{

View File

@ -34,7 +34,7 @@ class Servicecomment extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias',
@ -43,17 +43,4 @@ class Servicecomment extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
}

View File

@ -36,7 +36,7 @@ class Servicedowntime extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias',
@ -45,17 +45,4 @@ class Servicedowntime extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
}

View File

@ -3,8 +3,6 @@
namespace Icinga\Module\Monitoring\DataView;
/**
* Service group view */
class Servicegroup extends DataView
{
/**
@ -21,7 +19,7 @@ class Servicegroup extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias', 'host_display_name', 'host_name',
@ -30,18 +28,4 @@ class Servicegroup extends DataView
'servicegroup'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
} else {
return parent::isValidFilterTarget($column);
}
}
}

View File

@ -39,7 +39,7 @@ class Servicegroupsummary extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'services_severity',
@ -83,18 +83,4 @@ class Servicegroupsummary extends DataView
)
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
} else {
return parent::isValidFilterTarget($column);
}
}
}

View File

@ -6,9 +6,7 @@ namespace Icinga\Module\Monitoring\DataView;
class ServiceStatus extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
* {@inheritdoc}
*/
public function getColumns()
{
@ -97,6 +95,9 @@ class ServiceStatus extends DataView
);
}
/**
* {@inheritdoc}
*/
public function getSortRules()
{
return array(
@ -142,7 +143,10 @@ class ServiceStatus extends DataView
);
}
public function getFilterColumns()
/**
* {@inheritdoc}
*/
public function getStaticFilterColumns()
{
return array(
'host',
@ -157,16 +161,6 @@ class ServiceStatus extends DataView
);
}
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
}
return parent::isValidFilterTarget($column);
}
/**
* {@inheritdoc}
*/

View File

@ -32,7 +32,7 @@ class Servicestatussummary extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias', 'host_display_name', 'host_name',
@ -41,18 +41,4 @@ class Servicestatussummary extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
} else {
return in_array($column, $this->getFilterColumns());
}
}
}

View File

@ -6,9 +6,7 @@ namespace Icinga\Module\Monitoring\DataView;
class StatusSummary extends DataView
{
/**
* Retrieve columns provided by this view
*
* @return array
* {@inheritdoc}
*/
public function getColumns()
{
@ -100,7 +98,7 @@ class StatusSummary extends DataView
/**
* {@inheritdoc}
*/
public function getFilterColumns()
public function getStaticFilterColumns()
{
return array(
'host', 'host_alias', 'host_display_name', 'host_name',
@ -109,18 +107,4 @@ class StatusSummary extends DataView
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
);
}
/**
* {@inheritdoc}
*/
public function isValidFilterTarget($column)
{
if ($column[0] === '_'
&& preg_match('/^_(?:host|service)_/', $column)
) {
return true;
} else {
return in_array($column, $this->getFilterColumns());
}
}
}