diff --git a/application/controllers/FilterController.php b/application/controllers/FilterController.php index ed9761b70..3754e4070 100644 --- a/application/controllers/FilterController.php +++ b/application/controllers/FilterController.php @@ -71,13 +71,14 @@ class FilterController extends ActionController $this->setupQueries(); $this->view->form->setRequest($this->getRequest()); - if ($this->view->form->isSubmittedAndValid()) { $tree = $this->registry->createQueryTreeForFilter($this->view->form->getValue('query')); $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') { - $this->getResponse()->setHeader('Content-Type', 'application/json'); $this->_helper->json($this->parse($this->getRequest()->getParam('query', ''))); } diff --git a/application/views/scripts/filter/index.phtml b/application/views/scripts/filter/index.phtml index 1bcdb6a43..5e6a63d37 100644 --- a/application/views/scripts/filter/index.phtml +++ b/application/views/scripts/filter/index.phtml @@ -4,4 +4,8 @@ echo $this->form; if ($this->tree) { echo $this->tree->render($this); + echo '
';
+  echo $this->sqlString;
+  echo '
'; + print_r($this->params); } \ No newline at end of file diff --git a/library/Icinga/Data/Filterable.php b/library/Icinga/Data/Filterable.php new file mode 100644 index 000000000..376384ad2 --- /dev/null +++ b/library/Icinga/Data/Filterable.php @@ -0,0 +1,38 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + + +namespace Icinga\Data; + + +interface Filterable +{ + public function isValidFilterTarget($targetOrColumn); + public function resolveFilterTarget($targetOrColumn); + +} \ No newline at end of file diff --git a/library/Icinga/Filter/Domain.php b/library/Icinga/Filter/Domain.php index e5e5ca197..bbfea2b4f 100644 --- a/library/Icinga/Filter/Domain.php +++ b/library/Icinga/Filter/Domain.php @@ -134,9 +134,6 @@ class Domain extends QueryProposer foreach ($this->attributes as $attributeHandler) { if ($attributeHandler->isValidQuery($query)) { $node = $attributeHandler->convertToTreeNode($query); - if ($node) { - $node->context = $this->label; - } return $node; } } diff --git a/library/Icinga/Filter/Query/Node.php b/library/Icinga/Filter/Query/Node.php index 92c3c9475..ab32f478c 100644 --- a/library/Icinga/Filter/Query/Node.php +++ b/library/Icinga/Filter/Query/Node.php @@ -45,6 +45,7 @@ class Node const OPERATOR_GREATER_EQ = '>='; const OPERATOR_LESS_EQ = '<='; + const CONTEXT_TIMESTRING = 'timestring'; /** * Array containing all possible operators * @@ -90,6 +91,13 @@ class Node */ public $right; + /** + * Additional information for this node (like that it represents a date) + * + * @var mixed + */ + public $context; + /** * Factory method for creating operator nodes * diff --git a/library/Icinga/Filter/Type/TimeRangeSpecifier.php b/library/Icinga/Filter/Type/TimeRangeSpecifier.php index 5b511160c..1a0bbab22 100644 --- a/library/Icinga/Filter/Type/TimeRangeSpecifier.php +++ b/library/Icinga/Filter/Type/TimeRangeSpecifier.php @@ -166,7 +166,9 @@ class TimeRangeSpecifier extends FilterType if ($operator === null || $timeQuery === null) { return null; } - return Node::createOperatorNode($operator, $leftOperand, $timeQuery); + $node = Node::createOperatorNode($operator, $leftOperand, $timeQuery); + $node->context = Node::CONTEXT_TIMESTRING; + return $node; } /** diff --git a/library/Icinga/Web/Widget/FilterBadgeRenderer.php b/library/Icinga/Web/Widget/FilterBadgeRenderer.php new file mode 100644 index 000000000..02c27bdd5 --- /dev/null +++ b/library/Icinga/Web/Widget/FilterBadgeRenderer.php @@ -0,0 +1,81 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{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 ' ' + . $this->conjunctionCellar . ' ' + . ucfirst($node->left) . ' ' + . $node->operator . ' ' + . $node->right . ''; + } + $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); + } +} \ No newline at end of file diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php index 411b2e539..8bb47a051 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php @@ -232,7 +232,7 @@ abstract class AbstractQuery extends Query return array_key_exists($alias, $this->idxAliasColumn); } - protected function aliasToColumnName($alias) + public function aliasToColumnName($alias) { return $this->idxAliasColumn[$alias]; } @@ -402,4 +402,15 @@ abstract class AbstractQuery extends Query return $filter; } + + public function getMappedColumn($name) + { + foreach ($this->columnMap as $column => $results) { + if (isset($results[$name])) { + return $results[$name]; + } + } + + return null; + } } diff --git a/modules/monitoring/library/Monitoring/DataView/DataView.php b/modules/monitoring/library/Monitoring/DataView/DataView.php index 3d6b2a48f..718170ee1 100644 --- a/modules/monitoring/library/Monitoring/DataView/DataView.php +++ b/modules/monitoring/library/Monitoring/DataView/DataView.php @@ -150,7 +150,7 @@ abstract class DataView * * @return bool */ - protected function isValidFilterColumn($column) + public function isValidFilterColumn($column) { return in_array($column, $this->getColumns()) || in_array($column, $this->getFilterColumns()); } diff --git a/modules/monitoring/library/Monitoring/DataView/HostAndServiceStatus.php b/modules/monitoring/library/Monitoring/DataView/HostAndServiceStatus.php index cd9f073ec..bb6c0d6f5 100644 --- a/modules/monitoring/library/Monitoring/DataView/HostAndServiceStatus.php +++ b/modules/monitoring/library/Monitoring/DataView/HostAndServiceStatus.php @@ -121,7 +121,7 @@ class HostAndServiceStatus extends DataView return array('hostgroups', 'servicegroups', 'service_problems'); } - protected function isValidFilterColumn($column) + public function isValidFilterColumn($column) { if ($column[0] === '_' && preg_match('/^_(?:host|service)_/', $column) diff --git a/modules/monitoring/library/Monitoring/Filter/Backend/IdoQueryConverter.php b/modules/monitoring/library/Monitoring/Filter/Backend/IdoQueryConverter.php index 134b5aa16..36fa8319f 100644 --- a/modules/monitoring/library/Monitoring/Filter/Backend/IdoQueryConverter.php +++ b/modules/monitoring/library/Monitoring/Filter/Backend/IdoQueryConverter.php @@ -31,15 +31,90 @@ namespace Icinga\Module\Monitoring\Filter\Backend; use Icinga\Filter\Query\Tree; +use Icinga\Filter\Query\Node; +use Icinga\Module\Monitoring\DataView\DataView; + 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) { - if ($tree->root = null) { + if ($tree->root == null) { return ''; } + return $this->nodeToSqlQuery($tree->root); } } \ No newline at end of file