summaryrefslogtreecommitdiffstats
path: root/application/views/helpers/FormDataFilter.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--application/views/helpers/FormDataFilter.php564
1 files changed, 564 insertions, 0 deletions
diff --git a/application/views/helpers/FormDataFilter.php b/application/views/helpers/FormDataFilter.php
new file mode 100644
index 0000000..d8bc508
--- /dev/null
+++ b/application/views/helpers/FormDataFilter.php
@@ -0,0 +1,564 @@
+<?php
+
+use Icinga\Data\Filter\Filter;
+use Icinga\Data\Filter\FilterChain;
+use Icinga\Data\Filter\FilterExpression;
+use Icinga\Data\FilterColumns;
+use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Web\Form\Element\Boolean;
+use Icinga\Module\Director\Web\Form\IconHelper;
+
+/**
+ * View helper for extensible sets
+ *
+ * Avoid complaints about class names:
+ * @codingStandardsIgnoreStart
+ */
+class Zend_View_Helper_FormDataFilter extends Zend_View_Helper_FormElement
+{
+ private $fieldName;
+
+ private $cachedColumnSelect;
+
+ private $query;
+
+ private $suggestionContext;
+
+ /**
+ * Generates an 'extensible set' element.
+ *
+ * @codingStandardsIgnoreEnd
+ *
+ * @param string|array $name If a string, the element name. If an
+ * array, all other parameters are ignored, and the array elements
+ * are used in place of added parameters.
+ *
+ * @param mixed $value The element value.
+ *
+ * @param array $attribs Attributes for the element tag.
+ *
+ * @return string The element XHTML.
+ * @throws Zend_Form_Exception
+ */
+ public function formDataFilter($name, $value = null, $attribs = null)
+ {
+ $info = $this->_getInfo($name, $value, $attribs);
+ extract($info); // id, name, value, attribs, options, listsep, disable
+ if (array_key_exists('columns', $attribs)) {
+ $this->setColumns($attribs['columns']);
+ unset($attribs['columns']);
+ }
+
+ if (array_key_exists('suggestionContext', $attribs)) {
+ $this->setSuggestionContext($attribs['suggestionContext']);
+ unset($attribs['suggestionContext']);
+ }
+
+ // TODO: check for columns in attribs, preserve & remove them from the
+ // array use attribs? class etc? disabled?
+ // override _getInfo?
+ $this->fieldName = $name;
+
+ if ($value === null) {
+ $value = $this->emptyExpression();
+ } elseif (is_string($value)) {
+ $value = Filter::fromQueryString($value);
+ }
+
+ return $this->beginRoot()
+ . $this->renderFilter($value)
+ . $this->endRoot();
+ }
+
+ /**
+ * @param Filter $filter
+ * @return string
+ * @throws Zend_Form_Exception
+ */
+ protected function renderFilter(Filter $filter)
+ {
+ if ($filter instanceof FilterChain) {
+ return $this->renderFilterChain($filter);
+ } elseif ($filter instanceof FilterExpression) {
+ return $this->renderFilterExpression($filter);
+ } else {
+ throw new InvalidArgumentException('Got a Filter being neither expression nor chain');
+ }
+ }
+
+ protected function beginRoot()
+ {
+ return '<ul class="filter-root">';
+ }
+
+ protected function endRoot()
+ {
+ return '</ul>';
+ }
+
+ /**
+ * @param FilterChain $filter
+ * @return string
+ * @throws Zend_Form_Exception
+ */
+ protected function renderFilterChain(FilterChain $filter)
+ {
+ $parts = array();
+ foreach ($filter->filters() as $f) {
+ $parts[] = $this->renderFilter($f);
+ }
+
+ return $this->beginChain($filter)
+ . implode('', $parts)
+ . $this->endChain($filter);
+ }
+
+ protected function beginChain(FilterChain $filter)
+ {
+ $list = $filter->isEmpty() ? '' : '<ul>' . "\n";
+
+ return '<li class="filter-chain"><span class="handle"> </span>'
+ . $this->selectOperator($filter)
+ . $this->removeLink($filter)
+ . $this->addLink($filter)
+ . ($filter->count() === 1 ? $this->stripLink($filter) : '')
+ . $list;
+ }
+
+ protected function endChain(FilterChain $filter)
+ {
+ $list = $filter->isEmpty() ? '' : "</ul>\n";
+ return $list . "</li>\n";
+ }
+
+ protected function beginExpression(FilterExpression $filter)
+ {
+ return '<div class="filter-expression">' . "\n";
+ }
+
+ protected function endExpression(FilterExpression $filter)
+ {
+ return "</div>\n";
+ }
+
+ protected function beginElement(FilterExpression $filter)
+ {
+ return '<div class="expression-wrapper">' . "\n";
+ }
+
+ protected function endElement(FilterExpression $filter)
+ {
+ return "</div>\n";
+ }
+
+ /**
+ * @param FilterExpression $filter
+ * @return string
+ * @throws Zend_Form_Exception
+ */
+ protected function filterExpressionHtml(FilterExpression $filter)
+ {
+ return $this->selectColumn($filter)
+ . $this->selectSign($filter)
+ . $this->beginElement($filter)
+ . $this->element($filter)
+ . $this->endElement($filter)
+ . $this->removeLink($filter)
+ . $this->expandLink($filter);
+ }
+
+ /**
+ * @param FilterExpression $filter
+ * @return string
+ * @throws Zend_Form_Exception
+ */
+ protected function renderFilterExpression(FilterExpression $filter)
+ {
+ return $this->beginExpression($filter)
+ . $this->filterExpressionHtml($filter)
+ . $this->endExpression($filter);
+ }
+
+ /**
+ * @param FilterExpression|null $filter
+ * @return Boolean|string
+ * @throws Zend_Form_Exception
+ */
+ protected function element(FilterExpression $filter = null)
+ {
+ if ($filter) {
+ // TODO: Make this configurable
+ $type = 'host';
+ $prefixLen = strlen($type) + 1;
+ $filter = clone($filter);
+ $col = $filter->getColumn();
+
+ if ($this->columnIsJson($filter)) {
+ $col = $filter->getExpression();
+ $filter->setExpression(json_decode($filter->getColumn()));
+ } else {
+ $filter->setExpression(json_decode($filter->getExpression()));
+ }
+
+ if (($filter->getExpression() === true) || ($filter->getExpression() === false)) {
+ return '';
+ }
+ $dummy = IcingaObject::createByType($type);
+ if ($dummy->hasProperty($col)) {
+ if ($dummy->propertyIsBoolean($col)) {
+ return $this->boolean($filter);
+ }
+ }
+
+ if (substr($col, -7) === '.groups' && $dummy->supportsGroups()) {
+ $type = substr($col, 0, -7);
+
+ return $this->selectGroup($type, $filter);
+ } elseif (substr($col, $prefixLen, 5) === 'vars.') {
+ $var = substr($col, $prefixLen + 5);
+
+ return $this->text($filter, "DataListValues!${var}");
+ }
+ }
+
+ return $this->text($filter);
+ }
+
+ /**
+ * @param $type
+ * @param FilterExpression $filter
+ * @return Zend_Form_Element
+ */
+ protected function selectGroup($type, FilterExpression $filter)
+ {
+ return $this->view->formText(
+ $this->elementId('value', $filter),
+ $filter->getExpression(),
+ [
+ 'class' => 'director-suggest',
+ 'data-suggestion-context' => "${type}groupnames",
+ ]
+ );
+ }
+
+ /**
+ * @param FilterExpression|null $filter
+ * @return Boolean
+ * @throws Zend_Form_Exception
+ */
+ protected function boolean(FilterExpression $filter = null)
+ {
+ $value = $filter === null ? '' : $filter->getExpression();
+
+ $el = new Boolean(
+ $this->elementId('value', $filter),
+ array(
+ 'value' => $value,
+ 'decorators' => array('ViewHelper'),
+ )
+ );
+
+ return $el;
+ }
+
+ protected function columnIsJson(FilterExpression $filter)
+ {
+ $col = $filter->getColumn();
+ return strlen($col) && $col[0] === '"';
+ }
+
+ /**
+ * @param FilterExpression|null $filter
+ * @param string $suggestionContext
+ *
+ * @return mixed
+ */
+ protected function text(FilterExpression $filter = null, $suggestionContext = null)
+ {
+ $attr = null;
+ if ($suggestionContext !== null) {
+ $attr = [
+ 'class' => 'director-suggest',
+ 'data-suggestion-context' => $suggestionContext,
+ ];
+ }
+
+ $value = $filter === null ? '' : $filter->getExpression();
+ if (is_array($value)) {
+ return $this->view->formIplExtensibleSet(
+ $this->elementId('value', $filter),
+ $value,
+ $attr
+ );
+ }
+
+ return $this->view->formText(
+ $this->elementId('value', $filter),
+ $value,
+ $attr
+ );
+ }
+
+ /**
+ * @return \Icinga\Data\Filter\FilterExpression
+ */
+ protected function emptyExpression()
+ {
+ return Filter::expression('', '=', '');
+ }
+
+ protected function arrayForSelect($array, $flip = false)
+ {
+ $res = array();
+ foreach ($array as $k => $v) {
+ if (is_int($k)) {
+ $res[$v] = ucwords(str_replace('_', ' ', $v));
+ } elseif ($flip) {
+ $res[$v] = $k;
+ } else {
+ $res[$k] = $v;
+ }
+ }
+
+ // sort($res);
+ return $res;
+ }
+
+ protected function elementId($field, Filter $filter = null)
+ {
+ $prefix = $this->fieldName . '[id_';
+ $suffix = '][' . $field . ']';
+
+ return $prefix . $filter->getId() . $suffix;
+ }
+
+ /**
+ * @param FilterChain|null $filter
+ * @return mixed
+ */
+ protected function selectOperator(FilterChain $filter = null)
+ {
+ $ops = [
+ 'AND' => 'AND',
+ 'OR' => 'OR',
+ 'NOT' => 'NOT'
+ ];
+
+ return $this->select(
+ $this->elementId('operator', $filter),
+ $ops,
+ $filter === null ? null : $filter->getOperatorName(),
+ ['class' => 'operator autosubmit']
+ );
+ }
+
+ protected function selectSign(FilterExpression $filter = null)
+ {
+ $signs = [
+ '=' => '=',
+ '!=' => '!=',
+ '>' => '>',
+ '<' => '<',
+ '>=' => '>=',
+ '<=' => '<=',
+ 'in' => 'in',
+ 'contains' => 'contains',
+ 'true' => 'is true (or set)',
+ 'false' => 'is false (or not set)',
+ ];
+
+ if ($filter === null) {
+ $sign = null;
+ } else {
+ if ($this->columnIsJson($filter)) {
+ $sign = 'contains';
+ } else {
+ $expression = json_decode($filter->getExpression());
+ if ($expression === true) {
+ $sign = 'true';
+ } elseif ($expression === false) {
+ $sign = 'false';
+ } elseif (is_array($expression)) {
+ $sign = 'in';
+ } else {
+ $sign = $filter->getSign();
+ }
+ }
+ }
+
+ $class = 'sign autosubmit';
+ if (strlen($sign) > 3) {
+ $class .= ' wide';
+ }
+
+ return $this->select(
+ $this->elementId('sign', $filter),
+ $signs,
+ $sign,
+ array('class' => $class)
+ );
+ }
+
+ public function setColumns(array $columns = null)
+ {
+ $this->cachedColumnSelect = $columns ? $this->arrayForSelect($columns) : null;
+ return $this;
+ }
+
+ protected function getSuggestionContext()
+ {
+ return $this->suggestionContext;
+ }
+
+ protected function setSuggestionContext($context)
+ {
+ $this->suggestionContext = $context;
+ }
+
+ protected function selectColumn(FilterExpression $filter = null)
+ {
+ $active = $filter === null ? null : $filter->getColumn();
+ if ($filter && $this->columnIsJson($filter)) {
+ $active = $filter->getExpression();
+ }
+
+ if ($context = $this->getSuggestionContext()) {
+ return $this->view->formText(
+ $this->elementId('column', $filter),
+ $active,
+ [
+ 'class' => 'column autosubmit director-suggest',
+ 'data-suggestion-context' => $context,
+ ]
+ );
+ }
+ if ($this->hasColumnList()) {
+ $cols = $this->getColumnList();
+ if ($active && !isset($cols[$active])) {
+ $cols[$active] = str_replace(
+ '_',
+ ' ',
+ ucfirst(ltrim($active, '_'))
+ ); // ??
+ }
+
+ $cols = $this->optionalEnum($cols);
+
+ return $this->select(
+ $this->elementId('column', $filter),
+ $cols,
+ $active,
+ ['class' => 'column autosubmit']
+ );
+ } else {
+ return $this->view->formText(
+ $this->elementId('column', $filter),
+ $active,
+ ['class' => 'column autosubmit']
+ );
+ }
+ }
+
+ protected function optionalEnum($enum)
+ {
+ return array_merge(
+ array(null => $this->view->translate('- please choose -')),
+ $enum
+ );
+ }
+
+ protected function hasColumnList()
+ {
+ return $this->cachedColumnSelect !== null || $this->query !== null;
+ }
+
+ protected function getColumnList()
+ {
+ if ($this->cachedColumnSelect === null) {
+ $this->fetchColumnList();
+ }
+
+ return $this->cachedColumnSelect;
+ }
+
+ protected function fetchColumnList()
+ {
+ if ($this->query instanceof FilterColumns) {
+ $this->cachedColumnSelect = $this->arrayForSelect(
+ $this->query->getFilterColumns(),
+ true
+ );
+ asort($this->cachedColumnSelect);
+ } elseif ($this->cachedColumnSelect === null) {
+ throw new RuntimeException('No columns set nor does the query provide any');
+ }
+ }
+
+ protected function select($name, $list, $selected, $attributes = null)
+ {
+ return $this->view->formSelect($name, $selected, $attributes, $list);
+ }
+
+ protected function removeLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'cancel',
+ t('Remove this part of your filter')
+ );
+ }
+
+ protected function addLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'plus',
+ t('Add another filter')
+ );
+ }
+
+ protected function expandLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'angle-double-right',
+ t('Wrap this expression into an operator')
+ );
+ }
+
+ protected function stripLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'minus',
+ t('Strip this operator, preserve child nodes')
+ );
+ }
+
+ protected function filterActionButton(Filter $filter, $action, $title)
+ {
+ return $this->iconButton(
+ $this->getActionButtonName($filter),
+ $action,
+ $title
+ );
+ }
+
+ protected function getActionButtonName(Filter $filter)
+ {
+ return sprintf(
+ '%s[id_%s][action]',
+ $this->fieldName,
+ $filter->getId()
+ );
+ }
+
+ protected function iconButton($name, $icon, $title)
+ {
+ return $this->view->formSubmit(
+ $name,
+ IconHelper::instance()->iconCharacter($icon),
+ array('class' => 'icon-button', 'title' => $title)
+ );
+ }
+}