parent
24da98be83
commit
dac61eda19
|
@ -71,13 +71,14 @@ class FilterController extends ActionController
|
||||||
$this->setupQueries();
|
$this->setupQueries();
|
||||||
$this->view->form->setRequest($this->getRequest());
|
$this->view->form->setRequest($this->getRequest());
|
||||||
|
|
||||||
|
|
||||||
if ($this->view->form->isSubmittedAndValid()) {
|
if ($this->view->form->isSubmittedAndValid()) {
|
||||||
$tree = $this->registry->createQueryTreeForFilter($this->view->form->getValue('query'));
|
$tree = $this->registry->createQueryTreeForFilter($this->view->form->getValue('query'));
|
||||||
$this->view->tree = new \Icinga\Web\Widget\FilterBadgeRenderer($tree);
|
$this->view->tree = new \Icinga\Web\Widget\FilterBadgeRenderer($tree);
|
||||||
|
$view = \Icinga\Module\Monitoring\DataView\HostAndServiceStatus::fromRequest($this->getRequest());
|
||||||
|
$cv = new \Icinga\Module\Monitoring\Filter\Backend\IdoQueryConverter($view);
|
||||||
|
$this->view->sqlString = $cv->treeToSql($tree);
|
||||||
|
$this->view->params = $cv->getParams();
|
||||||
} else if ($this->getRequest()->getHeader('accept') == 'application/json') {
|
} else if ($this->getRequest()->getHeader('accept') == 'application/json') {
|
||||||
|
|
||||||
$this->getResponse()->setHeader('Content-Type', 'application/json');
|
$this->getResponse()->setHeader('Content-Type', 'application/json');
|
||||||
$this->_helper->json($this->parse($this->getRequest()->getParam('query', '')));
|
$this->_helper->json($this->parse($this->getRequest()->getParam('query', '')));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,8 @@ echo $this->form;
|
||||||
|
|
||||||
if ($this->tree) {
|
if ($this->tree) {
|
||||||
echo $this->tree->render($this);
|
echo $this->tree->render($this);
|
||||||
|
echo '<br/><pre><code>';
|
||||||
|
echo $this->sqlString;
|
||||||
|
echo '</pre></code>';
|
||||||
|
print_r($this->params);
|
||||||
}
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?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\Data;
|
||||||
|
|
||||||
|
|
||||||
|
interface Filterable
|
||||||
|
{
|
||||||
|
public function isValidFilterTarget($targetOrColumn);
|
||||||
|
public function resolveFilterTarget($targetOrColumn);
|
||||||
|
|
||||||
|
}
|
|
@ -134,9 +134,6 @@ class Domain extends QueryProposer
|
||||||
foreach ($this->attributes as $attributeHandler) {
|
foreach ($this->attributes as $attributeHandler) {
|
||||||
if ($attributeHandler->isValidQuery($query)) {
|
if ($attributeHandler->isValidQuery($query)) {
|
||||||
$node = $attributeHandler->convertToTreeNode($query);
|
$node = $attributeHandler->convertToTreeNode($query);
|
||||||
if ($node) {
|
|
||||||
$node->context = $this->label;
|
|
||||||
}
|
|
||||||
return $node;
|
return $node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ class Node
|
||||||
const OPERATOR_GREATER_EQ = '>=';
|
const OPERATOR_GREATER_EQ = '>=';
|
||||||
const OPERATOR_LESS_EQ = '<=';
|
const OPERATOR_LESS_EQ = '<=';
|
||||||
|
|
||||||
|
const CONTEXT_TIMESTRING = 'timestring';
|
||||||
/**
|
/**
|
||||||
* Array containing all possible operators
|
* Array containing all possible operators
|
||||||
*
|
*
|
||||||
|
@ -90,6 +91,13 @@ class Node
|
||||||
*/
|
*/
|
||||||
public $right;
|
public $right;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional information for this node (like that it represents a date)
|
||||||
|
*
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
public $context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method for creating operator nodes
|
* Factory method for creating operator nodes
|
||||||
*
|
*
|
||||||
|
|
|
@ -166,7 +166,9 @@ class TimeRangeSpecifier extends FilterType
|
||||||
if ($operator === null || $timeQuery === null) {
|
if ($operator === null || $timeQuery === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Node::createOperatorNode($operator, $leftOperand, $timeQuery);
|
$node = Node::createOperatorNode($operator, $leftOperand, $timeQuery);
|
||||||
|
$node->context = Node::CONTEXT_TIMESTRING;
|
||||||
|
return $node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?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\Web\Widget;
|
||||||
|
|
||||||
|
|
||||||
|
use Icinga\Filter\Query\Tree;
|
||||||
|
use Icinga\Filter\Query\Node;
|
||||||
|
use Zend_View_Abstract;
|
||||||
|
|
||||||
|
class FilterBadgeRenderer implements Widget
|
||||||
|
{
|
||||||
|
private $tree;
|
||||||
|
private $conjunctionCellar = '';
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(Tree $tree)
|
||||||
|
{
|
||||||
|
$this->tree = $tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function nodeToBadge(Node $node)
|
||||||
|
{
|
||||||
|
if ($node->type === Node::TYPE_OPERATOR) {
|
||||||
|
return ' <a class="btn btn-default btn-xs">'
|
||||||
|
. $this->conjunctionCellar . ' '
|
||||||
|
. ucfirst($node->left) . ' '
|
||||||
|
. $node->operator . ' '
|
||||||
|
. $node->right . '</a>';
|
||||||
|
}
|
||||||
|
$result = '';
|
||||||
|
$result .= $this->nodeToBadge($node->left);
|
||||||
|
$this->conjunctionCellar = $node->type;
|
||||||
|
$result .= $this->nodeToBadge($node->right);
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders this widget via the given view and returns the
|
||||||
|
* HTML as a string
|
||||||
|
*
|
||||||
|
* @param \Zend_View_Abstract $view
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function render(Zend_View_Abstract $view)
|
||||||
|
{
|
||||||
|
if ($this->tree->root == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return $this->nodeToBadge($this->tree->root);
|
||||||
|
}
|
||||||
|
}
|
|
@ -232,7 +232,7 @@ abstract class AbstractQuery extends Query
|
||||||
return array_key_exists($alias, $this->idxAliasColumn);
|
return array_key_exists($alias, $this->idxAliasColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function aliasToColumnName($alias)
|
public function aliasToColumnName($alias)
|
||||||
{
|
{
|
||||||
return $this->idxAliasColumn[$alias];
|
return $this->idxAliasColumn[$alias];
|
||||||
}
|
}
|
||||||
|
@ -402,4 +402,15 @@ abstract class AbstractQuery extends Query
|
||||||
|
|
||||||
return $filter;
|
return $filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMappedColumn($name)
|
||||||
|
{
|
||||||
|
foreach ($this->columnMap as $column => $results) {
|
||||||
|
if (isset($results[$name])) {
|
||||||
|
return $results[$name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ abstract class DataView
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function isValidFilterColumn($column)
|
public function isValidFilterColumn($column)
|
||||||
{
|
{
|
||||||
return in_array($column, $this->getColumns()) || in_array($column, $this->getFilterColumns());
|
return in_array($column, $this->getColumns()) || in_array($column, $this->getFilterColumns());
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ class HostAndServiceStatus extends DataView
|
||||||
return array('hostgroups', 'servicegroups', 'service_problems');
|
return array('hostgroups', 'servicegroups', 'service_problems');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isValidFilterColumn($column)
|
public function isValidFilterColumn($column)
|
||||||
{
|
{
|
||||||
if ($column[0] === '_'
|
if ($column[0] === '_'
|
||||||
&& preg_match('/^_(?:host|service)_/', $column)
|
&& preg_match('/^_(?:host|service)_/', $column)
|
||||||
|
|
|
@ -31,15 +31,90 @@ namespace Icinga\Module\Monitoring\Filter\Backend;
|
||||||
|
|
||||||
|
|
||||||
use Icinga\Filter\Query\Tree;
|
use Icinga\Filter\Query\Tree;
|
||||||
|
use Icinga\Filter\Query\Node;
|
||||||
|
use Icinga\Module\Monitoring\DataView\DataView;
|
||||||
|
|
||||||
|
|
||||||
class IdoQueryConverter
|
class IdoQueryConverter
|
||||||
{
|
{
|
||||||
|
private $view;
|
||||||
|
private $query;
|
||||||
|
private $params = array();
|
||||||
|
|
||||||
|
public function getParams()
|
||||||
|
{
|
||||||
|
return $this->params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(DataView $view, array $initialParams = array())
|
||||||
|
{
|
||||||
|
$this->view = $view;
|
||||||
|
$this->query = $this->view->getQuery();
|
||||||
|
$this->params = $initialParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSqlOperator($operator)
|
||||||
|
{
|
||||||
|
switch($operator) {
|
||||||
|
case Node::OPERATOR_EQUALS:
|
||||||
|
return 'LIKE';
|
||||||
|
case Node::OPERATOR_EQUALS_NOT:
|
||||||
|
return 'NOT LIKE';
|
||||||
|
default:
|
||||||
|
return $operator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function nodeToSqlQuery(Node $node)
|
||||||
|
{
|
||||||
|
if ($node->type !== Node::TYPE_OPERATOR) {
|
||||||
|
return $this->parseConjunctionNode($node);
|
||||||
|
} else {
|
||||||
|
return $this->parseOperatorNode($node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseConjunctionNode(Node $node)
|
||||||
|
{
|
||||||
|
$queryString = '';
|
||||||
|
$leftQuery = $this->nodeToSqlQuery($node->left);
|
||||||
|
$rightQuery = $this->nodeToSqlQuery($node->right);
|
||||||
|
if ($leftQuery != '') {
|
||||||
|
$queryString .= $leftQuery . ' ';
|
||||||
|
}
|
||||||
|
if ($rightQuery != '') {
|
||||||
|
$queryString .= (($queryString !== '') ? $node->type . ' ' : ' ') . $rightQuery;
|
||||||
|
}
|
||||||
|
return $queryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseOperatorNode(Node $node)
|
||||||
|
{
|
||||||
|
if (!$this->view->isValidFilterColumn($node->left) && $this->query->getMappedColumn($node->left)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$queryString = $this->query->getMappedColumn($node->left);
|
||||||
|
$queryString .= ' ' . (is_integer($node->right) ? $node->operator : $this->getSqlOperator($node->operator));
|
||||||
|
$queryString .= ' ? ';
|
||||||
|
$this->params[] = $this->getParameterValue($node);
|
||||||
|
return $queryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getParameterValue(Node $node) {
|
||||||
|
|
||||||
|
switch($node->context) {
|
||||||
|
case Node::CONTEXT_TIMESTRING:
|
||||||
|
return strtotime($node->right);
|
||||||
|
default:
|
||||||
|
return $node->right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function treeToSql(Tree $tree)
|
public function treeToSql(Tree $tree)
|
||||||
{
|
{
|
||||||
if ($tree->root = null) {
|
if ($tree->root == null) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
return $this->nodeToSqlQuery($tree->root);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue