Merge pull request #3868 from Icinga/feature/subquery-filter-in-chain

Support subquery filters in filter chains
This commit is contained in:
Johannes Meyer 2019-07-30 09:28:21 +02:00 committed by GitHub
commit 00e499024f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 18 deletions

View File

@ -21,6 +21,22 @@ abstract class FilterChain extends Filter
protected $allowedColumns;
/**
* Set the filters
*
* @param array $filters
*
* @return $this
*/
public function setFilters(array $filters)
{
$this->filters = $filters;
$this->refreshChildIds();
return $this;
}
public function hasId($id)
{
foreach ($this->filters() as $filter) {

View File

@ -55,11 +55,8 @@ class TacticalController extends Controller
$this->setupFilterControl($stats, null, ['host', 'service'], ['format']);
$this->view->setHelperFunction('filteredUrl', function ($path, array $params) {
$filter = clone $this->view->filterEditor->getFilter();
foreach ($params as $column => $value) {
$filter = $filter->andFilter($filter->where($column, $value));
}
return $this->view->url($path)->setQueryString($filter->toQueryString());
return $this->view->url($path)->setParams($params)->addFilter($filter);
});
$this->handleFormatRequest($stats);

View File

@ -1,4 +1,5 @@
<?php
use Icinga\Module\Monitoring\Web\Widget\StateBadges;
if (! $this->compact): ?>
@ -42,12 +43,15 @@ if (! $this->compact): ?>
<th>
<?= $this->qlink(
$hostGroup->hostgroup_alias,
$this->url('monitoring/list/hosts')->addFilter($this->filterEditor->getFilter()),
array('hostgroup_name' => $hostGroup->hostgroup_name, 'sort' => 'host_severity'),
array('title' => sprintf(
$this
->url('monitoring/list/hosts')
->setParams(['hostgroup_name' => $hostGroup->hostgroup_name])
->addFilter($this->filterEditor->getFilter()),
['sort' => 'host_severity'],
['title' => sprintf(
$this->translate('List all hosts in the group "%s"'),
$hostGroup->hostgroup_alias
))
)]
) ?>
</th>
<td>
@ -140,12 +144,18 @@ if (! $this->compact): ?>
<td class="count-col">
<?= $this->qlink(
$hostGroup->services_total,
$this->url('monitoring/list/services')->addFilter($this->filterEditor->getFilter()),
array('hostgroup_name' => $hostGroup->hostgroup_name, 'sort' => 'service_severity'),
array('title' => sprintf(
$this->translate('List all services of all hosts in host group "%s"'),
$hostGroup->hostgroup_alias
), 'class' => 'badge')
$this
->url('monitoring/list/services')
->setParams(['hostgroup_name' => $hostGroup->hostgroup_name])
->addFilter($this->filterEditor->getFilter()),
['sort' => 'service_severity'],
[
'title' => sprintf(
$this->translate('List all services of all hosts in host group "%s"'),
$hostGroup->hostgroup_alias
),
'class' => 'badge'
]
) ?>
</td>
<td>

View File

@ -38,9 +38,12 @@ if (! $this->compact): ?>
<th>
<?= $this->qlink(
$serviceGroup->servicegroup_alias,
$this->url('monitoring/list/services')->addFilter($this->filterEditor->getFilter()),
array('servicegroup_name' => $serviceGroup->servicegroup_name, 'sort' => 'service_severity'),
array('title' => sprintf($this->translate('List all services in the group "%s"'), $serviceGroup->servicegroup_alias))
$this
->url('monitoring/list/services')
->setParams(['servicegroup_name' => $serviceGroup->servicegroup_name])
->addFilter($this->filterEditor->getFilter()),
['sort' => 'service_severity'],
['title' => sprintf($this->translate('List all services in the group "%s"'), $serviceGroup->servicegroup_alias)]
) ?>
</th>
<td>

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
use Icinga\Data\Filter\FilterNot;
use Zend_Db_Expr;
use Icinga\Application\Icinga;
use Icinga\Application\Hook;
@ -559,7 +560,7 @@ abstract class IdoQuery extends DbQuery
if (count($expr) === 1 && strpos($expr[0], '&') !== false) {
// Our current filter implementation does not specify & as a control character so the count of the
// expression array is always one in this case
$expr = explode('&', $expr[0]);
$expr = array_unique(explode('&', $expr[0]));
$subQueryFilter->setExpression($expr);
$and = true;
} else {
@ -691,6 +692,60 @@ abstract class IdoQuery extends DbQuery
$filter->setColumn($column);
} else {
if (! $filter instanceof FilterNot) {
// Allow subquery filters in a filter chain
$columns = $filter->listFilteredColumns();
if (count($columns) === 1) {
$column = $columns[0];
$virtualTable = $this->aliasToTableName($column);
if (isset($this->subQueryTargets[$virtualTable])) {
$lastSign = null;
$filters = [];
$expressions = [];
foreach ($filter->filters() as $child) {
switch (true) {
case $child instanceof FilterExpression:
$expression = $child->getExpression();
if (! is_array($expression)) {
break;
}
// Move to default
default:
$filters[] = $child;
continue 2;
}
if ($lastSign === null) {
$lastSign = $child->getSign();
} else {
$sign = $child->getSign();
if ($sign !== $lastSign) {
$filters[] = new FilterExpression(
$column,
$lastSign,
$filter->getOperatorSymbol() === '&'
? [implode('&', $expressions)]
: $expressions
);
$expressions = [];
$lastSign = $sign;
}
}
$expressions[] = $expression;
}
if (! empty($expressions)) {
$filters[] = new FilterExpression(
$column,
$lastSign,
$filter->getOperatorSymbol() === '&'
? [implode('&', $expressions)]
: $expressions
);
}
$filter->setFilters($filters);
}
}
}
foreach ($filter->filters() as $child) {
$replacement = $this->requireFilterColumns($child);
if ($replacement !== null) {

View File

@ -298,6 +298,8 @@ class ServicegroupQuery extends IdoQuery
$additionalFilter = clone $filter;
}
$this->requireVirtualTable('members');
$query->joinVirtualTable('members');
return ['sgm.service_object_id', 'so.object_id'];