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; 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) public function hasId($id)
{ {
foreach ($this->filters() as $filter) { foreach ($this->filters() as $filter) {

View File

@ -55,11 +55,8 @@ class TacticalController extends Controller
$this->setupFilterControl($stats, null, ['host', 'service'], ['format']); $this->setupFilterControl($stats, null, ['host', 'service'], ['format']);
$this->view->setHelperFunction('filteredUrl', function ($path, array $params) { $this->view->setHelperFunction('filteredUrl', function ($path, array $params) {
$filter = clone $this->view->filterEditor->getFilter(); $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); $this->handleFormatRequest($stats);

View File

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

View File

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

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Monitoring\Backend\Ido\Query; namespace Icinga\Module\Monitoring\Backend\Ido\Query;
use Icinga\Data\Filter\FilterNot;
use Zend_Db_Expr; use Zend_Db_Expr;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Application\Hook; use Icinga\Application\Hook;
@ -559,7 +560,7 @@ abstract class IdoQuery extends DbQuery
if (count($expr) === 1 && strpos($expr[0], '&') !== false) { if (count($expr) === 1 && strpos($expr[0], '&') !== false) {
// Our current filter implementation does not specify & as a control character so the count of the // Our current filter implementation does not specify & as a control character so the count of the
// expression array is always one in this case // expression array is always one in this case
$expr = explode('&', $expr[0]); $expr = array_unique(explode('&', $expr[0]));
$subQueryFilter->setExpression($expr); $subQueryFilter->setExpression($expr);
$and = true; $and = true;
} else { } else {
@ -691,6 +692,60 @@ abstract class IdoQuery extends DbQuery
$filter->setColumn($column); $filter->setColumn($column);
} else { } 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) { foreach ($filter->filters() as $child) {
$replacement = $this->requireFilterColumns($child); $replacement = $this->requireFilterColumns($child);
if ($replacement !== null) { if ($replacement !== null) {

View File

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