Merge branch 'bugfix/usergroup-search-does-not-work-10370'

fixes #10370
fixes #10367
This commit is contained in:
Johannes Meyer 2015-11-10 14:08:51 +01:00
commit 7f5118a06a
11 changed files with 318 additions and 237 deletions

View File

@ -97,7 +97,7 @@ class GroupController extends AuthBackendController
->from('group_membership', array('user_name'))
->where('group_name', $groupName);
$this->setupFilterControl($members, null, array('user'));
$this->setupFilterControl($members, null, array('user'), array('group'));
$this->setupPaginationControl($members);
$this->setupLimitControl();
$this->setupSortControl(

View File

@ -99,7 +99,8 @@ class UserController extends AuthBackendController
$this->setupFilterControl(
$memberships,
array('group_name' => t('User Group')),
array('group_name')
array('group'),
array('user')
);
$this->setupPaginationControl($memberships);
$this->setupLimitControl();
@ -259,6 +260,7 @@ class UserController extends AuthBackendController
$alreadySeen[$groupName] = null;
$groups[] = (object) array(
'group_name' => $groupName,
'group' => $groupName,
'backend' => $backend
);
}

View File

@ -12,7 +12,6 @@ use Icinga\Exception\ProgrammingError;
use Icinga\Repository\LdapRepository;
use Icinga\Repository\RepositoryQuery;
use Icinga\Protocol\Ldap\LdapException;
use Icinga\Protocol\Ldap\Expression;
use Icinga\User;
class LdapUserBackend extends LdapRepository implements UserBackendInterface, Inspectable
@ -203,12 +202,30 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
$query = parent::select($columns);
$query->getQuery()->setBase($this->baseDn);
if ($this->filter) {
$query->getQuery()->where(new Expression($this->filter));
$query->getQuery()->setNativeFilter($this->filter);
}
return $query;
}
/**
* Initialize this repository's virtual tables
*
* @return array
*
* @throws ProgrammingError In case $this->userClass has not been set yet
*/
protected function initializeVirtualTables()
{
if ($this->userClass === null) {
throw new ProgrammingError('It is required to set the object class where to find users first');
}
return array(
'user' => $this->userClass
);
}
/**
* Initialize this repository's query columns
*
@ -318,29 +335,6 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
return ((int) $value) >= $bigBang->diff($now)->days;
}
/**
* Validate that the requested table exists
*
* This will return $this->userClass in case $table equals "user".
*
* @param string $table The table to validate
* @param RepositoryQuery $query An optional query to pass as context
* (unused by the base implementation)
*
* @return string
*
* @throws ProgrammingError In case the given table does not exist
*/
public function requireTable($table, RepositoryQuery $query = null)
{
$table = parent::requireTable($table, $query);
if ($table === 'user') {
$table = $this->userClass;
}
return $table;
}
/**
* Validate that the given column is a valid query target and return it or the actual name if it's an alias
*

View File

@ -9,7 +9,7 @@ use Icinga\Application\Logger;
use Icinga\Data\ConfigObject;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\ProgrammingError;
use Icinga\Protocol\Ldap\Expression;
use Icinga\Protocol\Ldap\LdapException;
use Icinga\Repository\LdapRepository;
use Icinga\Repository\RepositoryQuery;
use Icinga\User;
@ -368,12 +368,26 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
{
$query = parent::select($columns);
$query->getQuery()->setBase($this->groupBaseDn);
if ($this->groupFilter) {
// TODO(jom): This should differentiate between groups and their memberships
$query->getQuery()->where(new Expression($this->groupFilter));
return $query;
}
/**
* Initialize this repository's virtual tables
*
* @return array
*
* @throws ProgrammingError In case $this->groupClass has not been set yet
*/
protected function initializeVirtualTables()
{
if ($this->groupClass === null) {
throw new ProgrammingError('It is required to set the object class where to find groups first');
}
return $query;
return array(
'group' => $this->groupClass,
'group_membership' => $this->groupClass
);
}
/**
@ -420,7 +434,7 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
protected function initializeFilterColumns()
{
return array(
t('Username') => 'user',
t('Username') => 'user_name',
t('User Group') => 'group_name',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
@ -473,24 +487,28 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
*/
protected function persistUserName($name)
{
$userDn = $this->ds
->select()
->from($this->userClass, array())
->where($this->userNameAttribute, $name)
->setUsePagedResults(false)
->fetchDn();
if ($userDn) {
return $userDn;
}
try {
$userDn = $this->ds
->select()
->from($this->userClass, array())
->where($this->userNameAttribute, $name)
->setUsePagedResults(false)
->fetchDn();
if ($userDn) {
return $userDn;
}
$groupDn = $this->ds
->select()
->from($this->groupClass, array())
->where($this->groupNameAttribute, $name)
->setUsePagedResults(false)
->fetchDn();
if ($groupDn) {
return $groupDn;
$groupDn = $this->ds
->select()
->from($this->groupClass, array())
->where($this->groupNameAttribute, $name)
->setUsePagedResults(false)
->fetchDn();
if ($groupDn) {
return $groupDn;
}
} catch (LdapException $_) {
// pass
}
Logger::debug('Unable to persist uid or gid "%s" in repository "%s". No DN found.', $name, $this->getName());
@ -516,11 +534,8 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
/**
* Validate that the requested table exists
*
* This will return $this->groupClass in case $table equals "group" or "group_membership".
*
* @param string $table The table to validate
* @param RepositoryQuery $query An optional query to pass as context
* (unused by the base implementation)
*
* @return string
*
@ -528,12 +543,11 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
*/
public function requireTable($table, RepositoryQuery $query = null)
{
$table = parent::requireTable($table, $query);
if ($table === 'group' || $table === 'group_membership') {
$table = $this->groupClass;
if ($query !== null && $table === 'group' && $this->groupFilter) {
$query->getQuery()->setNativeFilter($this->groupFilter);
}
return $table;
return parent::requireTable($table, $query);
}
/**
@ -576,7 +590,7 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
->setBase($this->userBaseDn)
->setUsePagedResults(false);
if ($this->userFilter) {
$userQuery->where(new Expression($this->userFilter));
$userQuery->setNativeFilter($this->userFilter);
}
if (($queryValue = $userQuery->fetchDn()) === null) {
@ -590,7 +604,7 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
->where($this->groupMemberAttribute, $queryValue)
->setBase($this->groupBaseDn);
if ($this->groupFilter) {
$groupQuery->where(new Expression($this->groupFilter));
$groupQuery->setNativeFilter($this->groupFilter);
}
$groups = array();

View File

@ -125,17 +125,26 @@ abstract class FilterChain extends Filter
return $this;
}
public function listFilteredColumns()
/**
* List and return all column names referenced in this filter
*
* @param array $columns The columns listed so far
*
* @return array
*/
public function listFilteredColumns(array $columns = array())
{
$columns = array();
foreach ($this->filters as $filter) {
if ($filter instanceof FilterExpression) {
$columns[] = $filter->getColumn();
$column= $filter->getColumn();
if (! in_array($column, $columns, true)) {
$columns[] = $column;
}
} else {
$columns += $filter->listFilteredColumns();
$columns = $filter->listFilteredColumns($columns);
}
}
// array_unique?
return $columns;
}

View File

@ -1,30 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Protocol\Ldap;
class Expression
{
protected $value;
public function __construct($value)
{
$this->value = $value;
}
public function setValue($value)
{
$this->value = $value;
return $this;
}
public function getValue()
{
return $this->value;
}
public function __toString()
{
return (string) $this->getValue();
}
}

View File

@ -308,12 +308,8 @@ class LdapCapabilities
ldap_error($ds)
);
}
$cap = new LdapCapabilities(
$connection->cleanupAttributes(
ldap_get_attributes($ds, $entry),
array_flip($fields)
)
);
$cap = new LdapCapabilities($connection->cleanupAttributes(ldap_get_attributes($ds, $entry), $fields));
return $cap;
}

View File

@ -7,13 +7,14 @@ use Exception;
use ArrayIterator;
use Icinga\Application\Config;
use Icinga\Application\Logger;
use Icinga\Application\Platform;
use Icinga\Data\ConfigObject;
use Icinga\Data\Inspectable;
use Icinga\Data\Inspection;
use Icinga\Data\Selectable;
use Icinga\Data\Sortable;
use Icinga\Exception\InspectionException;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterChain;
use Icinga\Data\Filter\FilterExpression;
use Icinga\Exception\ProgrammingError;
use Icinga\Protocol\Ldap\LdapException;
@ -694,18 +695,30 @@ class LdapConnection implements Selectable, Inspectable
));
} else {
foreach ($query->getOrder() as $rule) {
if (! in_array($rule[0], $fields)) {
if (! in_array($rule[0], $fields, true)) {
$fields[] = $rule[0];
}
}
}
}
$unfoldAttribute = $query->getUnfoldAttribute();
if ($unfoldAttribute) {
foreach ($query->getFilter()->listFilteredColumns() as $filterColumn) {
$fieldKey = array_search($filterColumn, $fields, true);
if ($fieldKey === false || is_string($fieldKey)) {
$fields[] = $filterColumn;
}
}
}
$results = @ldap_search(
$ds,
$query->getBase() ?: $this->rootDn,
(string) $query,
array_values($fields),
$unfoldAttribute
? array_unique(array_values($fields))
: array_values($fields),
0, // Attributes and values
$serverSorting && $limit ? $offset + $limit : 0
);
@ -727,25 +740,21 @@ class LdapConnection implements Selectable, Inspectable
$count = 0;
$entries = array();
$entry = ldap_first_entry($ds, $results);
$unfoldAttribute = $query->getUnfoldAttribute();
do {
if ($unfoldAttribute) {
$rows = $this->cleanupAttributes(
ldap_get_attributes($ds, $entry),
array_flip($fields),
$unfoldAttribute
);
$rows = $this->cleanupAttributes(ldap_get_attributes($ds, $entry), $fields, $unfoldAttribute);
if (is_array($rows)) {
// TODO: Register the DN the same way as a section name in the ArrayDatasource!
foreach ($rows as $row) {
$count += 1;
if (! $serverSorting || $offset === 0 || $offset < $count) {
$entries[] = $row;
}
if ($query->getFilter()->matches($row)) {
$count += 1;
if (! $serverSorting || $offset === 0 || $offset < $count) {
$entries[] = $row;
}
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
break;
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
break;
}
}
}
} else {
@ -759,7 +768,7 @@ class LdapConnection implements Selectable, Inspectable
if (! $serverSorting || $offset === 0 || $offset < $count) {
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
ldap_get_attributes($ds, $entry),
array_flip($fields)
$fields
);
}
}
@ -811,16 +820,25 @@ class LdapConnection implements Selectable, Inspectable
$serverSorting = false;//$this->getCapabilities()->hasOid(LdapCapabilities::LDAP_SERVER_SORT_OID);
if (! $serverSorting && $query->hasOrder()) {
foreach ($query->getOrder() as $rule) {
if (! in_array($rule[0], $fields)) {
if (! in_array($rule[0], $fields, true)) {
$fields[] = $rule[0];
}
}
}
$unfoldAttribute = $query->getUnfoldAttribute();
if ($unfoldAttribute) {
foreach ($query->getFilter()->listFilteredColumns() as $filterColumn) {
$fieldKey = array_search($filterColumn, $fields, true);
if ($fieldKey === false || is_string($fieldKey)) {
$fields[] = $filterColumn;
}
}
}
$count = 0;
$cookie = '';
$entries = array();
$unfoldAttribute = $query->getUnfoldAttribute();
do {
// Do not request the pagination control as a critical extension, as we want the
// server to return results even if the paged search request cannot be satisfied
@ -839,7 +857,9 @@ class LdapConnection implements Selectable, Inspectable
$ds,
$base,
$queryString,
array_values($fields),
$unfoldAttribute
? array_unique(array_values($fields))
: array_values($fields),
0, // Attributes and values
$serverSorting && $limit ? $offset + $limit : 0
);
@ -857,7 +877,8 @@ class LdapConnection implements Selectable, Inspectable
} elseif (ldap_count_entries($ds, $results) === 0) {
if (in_array(
ldap_errno($ds),
array(static::LDAP_SIZELIMIT_EXCEEDED, static::LDAP_ADMINLIMIT_EXCEEDED)
array(static::LDAP_SIZELIMIT_EXCEEDED, static::LDAP_ADMINLIMIT_EXCEEDED),
true
)) {
Logger::warning(
'Unable to request more than %u results. Does the server allow paged search requests? (%s)',
@ -872,22 +893,19 @@ class LdapConnection implements Selectable, Inspectable
$entry = ldap_first_entry($ds, $results);
do {
if ($unfoldAttribute) {
$rows = $this->cleanupAttributes(
ldap_get_attributes($ds, $entry),
array_flip($fields),
$unfoldAttribute
);
$rows = $this->cleanupAttributes(ldap_get_attributes($ds, $entry), $fields, $unfoldAttribute);
if (is_array($rows)) {
// TODO: Register the DN the same way as a section name in the ArrayDatasource!
foreach ($rows as $row) {
$count += 1;
if (! $serverSorting || $offset === 0 || $offset < $count) {
$entries[] = $row;
}
if ($query->getFilter()->matches($row)) {
$count += 1;
if (! $serverSorting || $offset === 0 || $offset < $count) {
$entries[] = $row;
}
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
break;
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
break;
}
}
}
} else {
@ -901,7 +919,7 @@ class LdapConnection implements Selectable, Inspectable
if (! $serverSorting || $offset === 0 || $offset < $count) {
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
ldap_get_attributes($ds, $entry),
array_flip($fields)
$fields
);
}
}
@ -963,8 +981,17 @@ class LdapConnection implements Selectable, Inspectable
// necessary to create another array to map attributes case insensitively to their requested counterparts.
// This does also apply the virtual alias handling. (Since an LDAP server does not handle such)
$loweredFieldMap = array();
foreach ($requestedFields as $name => $alias) {
$loweredFieldMap[strtolower($name)] = is_string($alias) ? $alias : $name;
foreach ($requestedFields as $alias => $name) {
$loweredName = strtolower($name);
if (isset($loweredFieldMap[$loweredName])) {
if (! is_array($loweredFieldMap[$loweredName])) {
$loweredFieldMap[$loweredName] = array($loweredFieldMap[$loweredName]);
}
$loweredFieldMap[$loweredName][] = is_string($alias) ? $alias : $name;
} else {
$loweredFieldMap[$loweredName] = is_string($alias) ? $alias : $name;
}
}
$cleanedAttributes = array();
@ -982,12 +1009,18 @@ class LdapConnection implements Selectable, Inspectable
$requestedAttributeName = isset($loweredFieldMap[strtolower($attribute_name)])
? $loweredFieldMap[strtolower($attribute_name)]
: $attribute_name;
$cleanedAttributes[$requestedAttributeName] = $attribute_value;
if (is_array($requestedAttributeName)) {
foreach ($requestedAttributeName as $requestedName) {
$cleanedAttributes[$requestedName] = $attribute_value;
}
} else {
$cleanedAttributes[$requestedAttributeName] = $attribute_value;
}
}
// The result may not contain all requested fields, so populate the cleaned
// result with the missing fields and their value being set to null
foreach ($requestedFields as $name => $alias) {
foreach ($requestedFields as $alias => $name) {
if (! is_string($alias)) {
$alias = $name;
}
@ -1003,6 +1036,14 @@ class LdapConnection implements Selectable, Inspectable
&& isset($cleanedAttributes[$unfoldAttribute])
&& is_array($cleanedAttributes[$unfoldAttribute])
) {
$siblings = array();
foreach ($loweredFieldMap as $loweredName => $requestedNames) {
if (is_array($requestedNames) && in_array($unfoldAttribute, $requestedNames, true)) {
$siblings = array_diff($requestedNames, array($unfoldAttribute));
break;
}
}
$values = $cleanedAttributes[$unfoldAttribute];
unset($cleanedAttributes[$unfoldAttribute]);
$baseRow = (object) $cleanedAttributes;
@ -1010,6 +1051,10 @@ class LdapConnection implements Selectable, Inspectable
foreach ($values as $value) {
$row = clone $baseRow;
$row->{$unfoldAttribute} = $value;
foreach ($siblings as $sibling) {
$row->{$sibling} = $value;
}
$rows[] = $row;
}
@ -1184,6 +1229,93 @@ class LdapConnection implements Selectable, Inspectable
return $dir;
}
/**
* Render and return a valid LDAP filter representation of the given filter
*
* @param Filter $filter
* @param int $level
*
* @return string
*/
public function renderFilter(Filter $filter, $level = 0)
{
if ($filter->isExpression()) {
/** @var $filter FilterExpression */
return $this->renderFilterExpression($filter);
}
/** @var $filter FilterChain */
$parts = array();
foreach ($filter->filters() as $filterPart) {
$part = $this->renderFilter($filterPart, $level + 1);
if ($part) {
$parts[] = $part;
}
}
if (empty($parts)) {
return '';
}
$format = '%1$s(%2$s)';
if (count($parts) === 1) {
$format = '%2$s';
}
if ($level === 0) {
$format = '(' . $format . ')';
}
return sprintf($format, $filter->getOperatorSymbol(), implode(')(', $parts));
}
/**
* Render and return a valid LDAP filter expression of the given filter
*
* @param FilterExpression $filter
*
* @return string
*/
protected function renderFilterExpression(FilterExpression $filter)
{
$column = $filter->getColumn();
$sign = $filter->getSign();
$expression = $filter->getExpression();
$format = '%1$s%2$s%3$s';
if ($expression === null || $expression === true) {
$expression = '*';
} elseif (is_array($expression)) {
$seqFormat = '|(%s)';
if ($sign === '!=') {
$seqFormat = '!(' . $seqFormat . ')';
$sign = '=';
}
$seqParts = array();
foreach ($expression as $expressionValue) {
$seqParts[] = sprintf(
$format,
LdapUtils::quoteForSearch($column),
$sign,
LdapUtils::quoteForSearch($expressionValue, true)
);
}
return sprintf($seqFormat, implode(')(', $seqParts));
}
if ($sign === '!=') {
$format = '!(%1$s=%3$s)';
}
return sprintf(
$format,
LdapUtils::quoteForSearch($column),
$sign,
LdapUtils::quoteForSearch($expression, true)
);
}
/**
* Inspect if this LDAP Connection is working as expected
*

View File

@ -4,23 +4,12 @@
namespace Icinga\Protocol\Ldap;
use Icinga\Data\SimpleQuery;
use Icinga\Data\Filter\Filter;
use Icinga\Exception\NotImplementedError;
/**
* LDAP query class
*/
class LdapQuery extends SimpleQuery
{
/**
* This query's filters
*
* Currently just a basic key/value pair based array. Can be removed once Icinga\Data\Filter is supported.
*
* @var array
*/
protected $filters;
/**
* The base dn being used for this query
*
@ -42,12 +31,18 @@ class LdapQuery extends SimpleQuery
*/
protected $unfoldAttribute;
/**
* This query's native LDAP filter
*
* @var string
*/
protected $nativeFilter;
/**
* Initialize this query
*/
protected function init()
{
$this->filters = array();
$this->usePagedResults = false;
}
@ -120,6 +115,29 @@ class LdapQuery extends SimpleQuery
return $this->unfoldAttribute;
}
/**
* Set this query's native LDAP filter
*
* @param string $filter
*
* @return $this
*/
public function setNativeFilter($filter)
{
$this->nativeFilter = $filter;
return $this;
}
/**
* Return this query's native LDAP filter
*
* @return string
*/
public function getNativeFilter()
{
return $this->nativeFilter;
}
/**
* Choose an objectClass and the columns you are interested in
*
@ -127,53 +145,10 @@ class LdapQuery extends SimpleQuery
*/
public function from($target, array $fields = null)
{
$this->filters['objectClass'] = $target;
$this->where('objectClass', $target);
return parent::from($target, $fields);
}
/**
* Add a new filter to the query
*
* @param string $condition Column to search in
* @param mixed $value Value to look for (asterisk wildcards are allowed)
*
* @return $this
*/
public function where($condition, $value = null)
{
// TODO: Adjust this once support for Icinga\Data\Filter is available
if ($condition instanceof Expression) {
$this->filters[] = $condition;
} else {
$this->filters[$condition] = $value;
}
return $this;
}
public function getFilter()
{
throw new NotImplementedError('Support for Icinga\Data\Filter is still missing. Use $this->where() instead');
}
public function addFilter(Filter $filter)
{
// TODO: This should be considered a quick fix only.
// Drop this entirely once support for Icinga\Data\Filter is available
if ($filter->isExpression()) {
$this->where($filter->getColumn(), $filter->getExpression());
} elseif ($filter->isChain()) {
foreach ($filter->filters() as $chainOrExpression) {
$this->addFilter($chainOrExpression);
}
}
}
public function setFilter(Filter $filter)
{
throw new NotImplementedError('Support for Icinga\Data\Filter is still missing. Use $this->where() instead');
}
/**
* Fetch result as tree
*
@ -225,36 +200,18 @@ class LdapQuery extends SimpleQuery
}
/**
* Return the LDAP filter to be applied on this query
* Render and return this query's filter
*
* @return string
*
* @throws LdapException In case the objectClass filter does not exist
*/
protected function renderFilter()
public function renderFilter()
{
if (! isset($this->filters['objectClass'])) {
throw new LdapException('Object class is mandatory');
$filter = $this->ds->renderFilter($this->filter);
if ($this->nativeFilter) {
$filter = '(&(' . $this->nativeFilter . ')' . $filter . ')';
}
$parts = array();
foreach ($this->filters as $key => $value) {
if ($value instanceof Expression) {
$parts[] = (string) $value;
} else {
$parts[] = sprintf(
'%s=%s',
LdapUtils::quoteForSearch($key),
LdapUtils::quoteForSearch($value, true)
);
}
}
if (count($parts) > 1) {
return '(&(' . implode(')(', $parts) . '))';
} else {
return '(' . $parts[0] . ')';
}
return $filter;
}
/**

View File

@ -186,6 +186,7 @@ class Controller extends ModuleActionController
* @param Filterable $filterable The filterable to create a filter editor for
* @param array $filterColumns The filter columns to offer to the user
* @param array $searchColumns The search columns to utilize for quick searches
* @param array $preserveParams The url parameters to preserve
*
* @return $this
*
@ -194,25 +195,26 @@ class Controller extends ModuleActionController
protected function setupFilterControl(
Filterable $filterable,
array $filterColumns = null,
array $searchColumns = null
array $searchColumns = null,
array $preserveParams = null
) {
$editor = Widget::create('filterEditor')
$defaultPreservedParams = array(
'limit', // setupPaginationControl()
'sort', // setupSortControl()
'dir', // setupSortControl()
'backend', // Framework
'_dev' // Framework
);
$editor = Widget::create('filterEditor');
call_user_func_array(
array($editor, 'preserveParams'),
array_merge($defaultPreservedParams, $preserveParams ?: array())
);
$editor
->setQuery($filterable)
->preserveParams(
'limit',
'sort',
'dir',
'format',
'view',
'user',
'group',
'backend',
'stateType',
'addColumns',
'problems',
'_dev'
)
->ignoreParams('page')
->ignoreParams('page') // setupPaginationControl()
->setColumns($filterColumns)
->setSearchColumns($searchColumns)
->handleRequest($this->getRequest());

View File

@ -574,7 +574,12 @@ class ListController extends Controller
*/
protected function filterQuery(DataView $dataView)
{
$this->setupFilterControl($dataView);
$this->setupFilterControl($dataView, null, null, array(
'format', // handleFormatRequest()
'stateType', // hostsAction() and servicesAction()
'addColumns', // addColumns()
'problems' // servicegridAction()
));
$this->handleFormatRequest($dataView);
return $dataView;
}