setFilter($props['filter']);
}
if (array_key_exists('query', $props)) {
$this->setQuery($props['query']);
}
}
public function setFilter(Filter $filter)
{
$this->filter = $filter;
return $this;
}
public function getFilter()
{
if ($this->filter === null) {
$this->filter = Filter::fromQueryString((string) $this->url()->getParams());
}
return $this->filter;
}
/**
* Set columns to search in
*
* @param array $searchColumns
*
* @return $this
*/
public function setSearchColumns(array $searchColumns = null)
{
$this->searchColumns = $searchColumns;
return $this;
}
public function setUrl($url)
{
$this->url = $url;
return $this;
}
protected function url()
{
if ($this->url === null) {
$this->url = Url::fromRequest();
}
return $this->url;
}
protected function preservedUrl()
{
if ($this->preservedUrl === null) {
$this->preservedUrl = $this->url()->with($this->preservedParams);
}
return $this->preservedUrl;
}
/**
* Set the query to filter
*
* @param Filterable $query
*
* @return $this
*/
public function setQuery(Filterable $query)
{
$this->query = $query;
return $this;
}
public function ignoreParams()
{
$this->ignoreParams = func_get_args();
return $this;
}
public function preserveParams()
{
$this->preserveParams = func_get_args();
return $this;
}
/**
* Get whether the filter control is visible
*
* @return bool
*/
public function isVisible()
{
return $this->visible;
}
/**
* Set whether the filter control is visible
*
* @param bool $visible
*
* @return $this
*/
public function setVisible($visible)
{
$this->visible = (bool) $visible;
return $this;
}
protected function redirectNow($url)
{
$response = Icinga::app()->getFrontController()->getResponse();
$response->redirectAndExit($url);
}
protected function mergeRootExpression($filter, $column, $sign, $expression)
{
$found = false;
if ($filter->isChain() && $filter->getOperatorName() === 'AND') {
foreach ($filter->filters() as $f) {
if ($f->isExpression()
&& $f->getColumn() === $column
&& $f->getSign() === $sign
) {
$f->setExpression($expression);
$found = true;
break;
}
}
} elseif ($filter->isExpression()) {
if ($filter->getColumn() === $column && $filter->getSign() === $sign) {
$filter->setExpression($expression);
$found = true;
}
}
if (! $found) {
$filter = $filter->andFilter(
Filter::expression($column, $sign, $expression)
);
}
return $filter;
}
protected function resetSearchColumns(Filter &$filter)
{
if ($filter->isChain()) {
$filters = &$filter->filters();
if (!($empty = empty($filters))) {
foreach ($filters as $k => &$f) {
if (false === $this->resetSearchColumns($f)) {
unset($filters[$k]);
}
}
}
return $empty || !empty($filters);
}
return $filter->isExpression() ? !(
in_array($filter->getColumn(), $this->searchColumns)
&&
$filter->getSign() === '='
) : true;
}
public function handleRequest($request)
{
$this->setUrl($request->getUrl()->without($this->ignoreParams));
$params = $this->url()->getParams();
$preserve = array();
foreach ($this->preserveParams as $key) {
if (null !== ($value = $params->shift($key))) {
$preserve[$key] = $value;
}
}
$this->preservedParams = $preserve;
$add = $params->shift('addFilter');
$remove = $params->shift('removeFilter');
$strip = $params->shift('stripFilter');
$modify = $params->shift('modifyFilter');
$search = null;
if ($request->isPost()) {
$search = $request->getPost('q');
}
if ($search === null) {
$search = $params->shift('q');
}
$filter = $this->getFilter();
if ($search !== null) {
if (strpos($search, '=') !== false) {
list($k, $v) = preg_split('/=/', $search);
$filter = $this->mergeRootExpression($filter, trim($k), '=', ltrim($v));
} else {
if ($this->searchColumns === null && $this->query instanceof FilterColumns) {
$this->searchColumns = $this->query->getSearchColumns($search);
}
if (! empty($this->searchColumns)) {
if (! $this->resetSearchColumns($filter)) {
$filter = Filter::matchAll();
}
$filters = array();
$search = trim($search);
foreach ($this->searchColumns as $searchColumn) {
$filters[] = Filter::expression($searchColumn, '=', "*$search*");
}
$filter = $filter->andFilter(new FilterOr($filters));
} else {
Notification::error(mt('monitoring', 'Cannot search here'));
return $this;
}
}
$url = Url::fromRequest()->onlyWith($this->preserveParams);
$urlParams = $url->getParams();
$url->setQueryString($filter->toQueryString());
foreach ($urlParams->toArray(false) as $key => $value) {
$url->getParams()->addEncoded($key, $value);
}
$this->redirectNow($url);
}
if ($remove) {
$redirect = $this->url();
if ($filter->getById($remove)->isRootNode()) {
$redirect->setQueryString('');
} else {
$filter->removeId($remove);
$redirect->setQueryString($filter->toQueryString())->getParams()->add('modifyFilter');
}
$this->redirectNow($redirect->addParams($preserve));
}
if ($strip) {
$redirect = $this->url();
$subId = $strip . '-1';
if ($filter->getId() === $strip) {
$filter = $filter->getById($strip . '-1');
} else {
$filter->replaceById($strip, $filter->getById($strip . '-1'));
}
$redirect->setQueryString($filter->toQueryString())->getParams()->add('modifyFilter');
$this->redirectNow($redirect->addParams($preserve));
}
if ($modify) {
if ($request->isPost()) {
if ($request->get('cancel') === 'Cancel') {
$this->redirectNow($this->preservedUrl()->without('modifyFilter'));
}
if ($request->get('formUID') === 'FilterEditor') {
$filter = $this->applyChanges($request->getPost());
$url = $this->url()->setQueryString($filter->toQueryString())->addParams($preserve);
$url->getParams()->add('modifyFilter');
$addFilter = $request->get('add_filter');
if ($addFilter !== null) {
$url->setParam('addFilter', $addFilter);
}
$removeFilter = $request->get('remove_filter');
if ($removeFilter !== null) {
$url->setParam('removeFilter', $removeFilter);
}
$this->redirectNow($url);
}
}
$this->url()->getParams()->add('modifyFilter');
}
if ($add) {
$this->addFilterToId($add);
}
if ($this->query !== null && $request->isGet()) {
$this->query->applyFilter($this->getFilter());
}
return $this;
}
protected function select($name, $list, $selected, $attributes = null)
{
$view = $this->view();
if ($attributes === null) {
$attributes = '';
} else {
$attributes = $view->propertiesToString($attributes);
}
$html = sprintf(
'' . "\n\n";
return $html;
}
protected function addFilterToId($id)
{
$this->addTo = $id;
return $this;
}
protected function removeIndex($idx)
{
$this->selectedIdx = $idx;
return $this;
}
protected function removeLink(Filter $filter)
{
return "';
}
protected function addLink(Filter $filter)
{
return "';
}
protected function stripLink(Filter $filter)
{
return $this->view()->qlink(
'',
$this->preservedUrl()->with('stripFilter', $filter->getId()),
null,
array(
'icon' => 'minus',
'title' => t('Strip this filter')
)
);
}
protected function cancelLink()
{
return $this->view()->qlink(
'',
$this->preservedUrl()->without('addFilter'),
null,
array(
'icon' => 'cancel',
'title' => t('Cancel this operation')
)
);
}
protected function renderFilter($filter, $level = 0)
{
if ($level === 0 && $filter->isChain() && $filter->isEmpty()) {
return '
- ' . $this->renderNewFilter() . '
';
}
if ($filter instanceof FilterChain) {
return $this->renderFilterChain($filter, $level);
} elseif ($filter instanceof FilterExpression) {
return $this->renderFilterExpression($filter);
} else {
throw new ProgrammingError('Got a Filter being neither expression nor chain');
}
}
protected function renderFilterChain(FilterChain $filter, $level)
{
$html = ' '
. $this->selectOperator($filter)
. $this->removeLink($filter)
. ($filter->count() === 1 ? $this->stripLink($filter) : '')
. $this->addLink($filter);
if ($filter->isEmpty() && ! $this->addTo) {
return $html;
}
$parts = array();
foreach ($filter->filters() as $f) {
$parts[] = '' . $this->renderFilter($f, $level + 1) . '';
}
if ($this->addTo && $this->addTo == $filter->getId()) {
$parts[] = '' . $this->renderNewFilter() .$this->cancelLink(). '';
}
$class = $level === 0 ? ' class="datafilter"' : '';
$html .= sprintf(
"\n",
$class,
implode("", $parts)
);
return $html;
}
protected function renderFilterExpression(FilterExpression $filter)
{
if ($this->addTo && $this->addTo === $filter->getId()) {
return
preg_replace(
'/ class="autosubmit"/',
' class="autofocus"',
$this->selectOperator()
)
. '- '
. $this->selectColumn($filter)
. $this->selectSign($filter)
. $this->text($filter)
. $this->removeLink($filter)
. $this->addLink($filter)
. '
- '
. $this->renderNewFilter() .$this->cancelLink()
. '
'
;
} else {
return $this->selectColumn($filter)
. $this->selectSign($filter)
. $this->text($filter)
. $this->removeLink($filter)
. $this->addLink($filter)
;
}
}
protected function text(Filter $filter = null)
{
$value = $filter === null ? '' : $filter->getExpression();
if (is_array($value)) {
$value = '(' . implode('|', $value) . ')';
}
return sprintf(
'',
$this->elementId('value', $filter),
$this->view()->escape($value)
);
}
protected function renderNewFilter()
{
$html = $this->selectColumn()
. $this->selectSign()
. $this->text();
return preg_replace(
'/ class="autosubmit"/',
'',
$html
);
}
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($prefix, Filter $filter = null)
{
if ($filter === null) {
return $prefix . '_new_' . ($this->addTo ?: '0');
} else {
return $prefix . '_' . $filter->getId();
}
}
protected function selectOperator(Filter $filter = null)
{
$ops = array(
'AND' => 'AND',
'OR' => 'OR',
'NOT' => 'NOT'
);
return $this->select(
$this->elementId('operator', $filter),
$ops,
$filter === null ? null : $filter->getOperatorName(),
array('style' => 'width: 5em')
);
}
protected function selectSign(Filter $filter = null)
{
$signs = array(
'=' => '=',
'!=' => '!=',
'>' => '>',
'<' => '<',
'>=' => '>=',
'<=' => '<=',
);
return $this->select(
$this->elementId('sign', $filter),
$signs,
$filter === null ? null : $filter->getSign(),
array('style' => 'width: 4em')
);
}
public function setColumns(array $columns = null)
{
$this->cachedColumnSelect = $columns ? $this->arrayForSelect($columns) : null;
return $this;
}
protected function selectColumn(Filter $filter = null)
{
$active = $filter === null ? null : $filter->getColumn();
if ($this->cachedColumnSelect === null && $this->query === null) {
return sprintf(
'',
$this->elementId('column', $filter),
$this->view()->escape($active) // Escape attribute?
);
}
if ($this->cachedColumnSelect === null && $this->query instanceof FilterColumns) {
$this->cachedColumnSelect = $this->arrayForSelect($this->query->getFilterColumns(), true);
asort($this->cachedColumnSelect);
} elseif ($this->cachedColumnSelect === null) {
throw new ProgrammingError('No columns set nor does the query provide any');
}
$cols = $this->cachedColumnSelect;
if ($active && !isset($cols[$active])) {
$cols[$active] = str_replace('_', ' ', ucfirst(ltrim($active, '_')));
}
return $this->select($this->elementId('column', $filter), $cols, $active);
}
protected function applyChanges($changes)
{
$filter = $this->filter;
$pairs = array();
$addTo = null;
$add = array();
foreach ($changes as $k => $v) {
if (preg_match('/^(column|value|sign|operator)((?:_new)?)_([\d-]+)$/', $k, $m)) {
if ($m[2] === '_new') {
if ($addTo !== null && $addTo !== $m[3]) {
throw new \Exception('F...U');
}
$addTo = $m[3];
$add[$m[1]] = $v;
} else {
$pairs[$m[3]][$m[1]] = $v;
}
}
}
$operators = array();
foreach ($pairs as $id => $fs) {
if (array_key_exists('operator', $fs)) {
$operators[$id] = $fs['operator'];
} else {
$f = $filter->getById($id);
$f->setColumn($fs['column']);
if ($f->getSign() !== $fs['sign']) {
if ($f->isRootNode()) {
$filter = $f->setSign($fs['sign']);
} else {
$filter->replaceById($id, $f->setSign($fs['sign']));
}
}
$f->setExpression($fs['value']);
}
}
krsort($operators, SORT_NATURAL);
foreach ($operators as $id => $operator) {
$f = $filter->getById($id);
if ($f->getOperatorName() !== $operator) {
if ($f->isRootNode()) {
$filter = $f->setOperatorName($operator);
} else {
$filter->replaceById($id, $f->setOperatorName($operator));
}
}
}
if ($addTo !== null) {
if ($addTo === '0') {
$filter = Filter::expression($add['column'], $add['sign'], $add['value']);
} else {
$parent = $filter->getById($addTo);
$f = Filter::expression($add['column'], $add['sign'], $add['value']);
if (isset($add['operator'])) {
switch ($add['operator']) {
case 'AND':
if ($parent->isExpression()) {
if ($parent->isRootNode()) {
$filter = Filter::matchAll(clone $parent, $f);
} else {
$filter = $filter->replaceById($addTo, Filter::matchAll(clone $parent, $f));
}
} else {
$parent->addFilter(Filter::matchAll($f));
}
break;
case 'OR':
if ($parent->isExpression()) {
if ($parent->isRootNode()) {
$filter = Filter::matchAny(clone $parent, $f);
} else {
$filter = $filter->replaceById($addTo, Filter::matchAny(clone $parent, $f));
}
} else {
$parent->addFilter(Filter::matchAny($f));
}
break;
case 'NOT':
if ($parent->isExpression()) {
if ($parent->isRootNode()) {
$filter = Filter::not(Filter::matchAll($parent, $f));
} else {
$filter = $filter->replaceById($addTo, Filter::not(Filter::matchAll($parent, $f)));
}
} else {
$parent->addFilter(Filter::not($f));
}
break;
}
} else {
$parent->addFilter($f);
}
}
}
return $filter;
}
public function renderSearch()
{
$preservedUrl = $this->preservedUrl();
$html = ' ';
if ($this->filter->isEmpty()) {
$title = t('Filter this list');
} else {
$title = t('Modify this filter');
if (! $this->filter->isEmpty()) {
$title .= ': ' . $this->view()->escape($this->filter);
}
}
return $html
. ''
. ''
. '';
}
public function render()
{
if (! $this->visible) {
return '';
}
if (! $this->preservedUrl()->getParam('modifyFilter')) {
return ''
. $this->renderSearch()
. $this->view()->escape($this->shorten($this->filter, 50))
. '
';
}
return ''
. $this->renderSearch()
. '
'
. '
';
}
protected function shorten($string, $length)
{
if (strlen($string) > $length) {
return substr($string, 0, $length) . '...';
}
return $string;
}
public function __toString()
{
try {
return $this->render();
} catch (Exception $e) {
return 'ERROR in FilterEditor: ' . $e->getMessage();
}
}
}