Index: includes/filter.inc
===================================================================
RCS file: includes/filter.inc
diff -N includes/filter.inc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ includes/filter.inc 24 May 2009 07:48:04 -0000
@@ -0,0 +1,310 @@
+name = $name;
+ $this->initialize();
+
+ return $this;
+ }
+
+ protected function initialize() {
+ if (!isset($_SESSION['filter'][$this->name])) {
+ $_SESSION['filter'][$this->name] = array();
+ }
+ $this->filter =& $_SESSION['filter'][$this->name];
+ $this->elements = module_invoke_all('filter_elements_' . $this->name, $this);
+ $this->addTag('filter_' . $this->name);
+ $this->addMetaData('filter', $this->filter);
+ $this->addMetaData('elements', $this->elements);
+ }
+
+ public function execute() {
+ // Add simple conditions of the currently active filters to the query.
+ // @todo: Implement additional simple filter configurations.
+ foreach ($this->filter as $name => $values) {
+ foreach ($values as $value) {
+ if (isset($this->elements[$name]['field'])) {
+ // Check if we need to do a LIKE comparison.
+ if (preg_match('/([\*%]+)/', $value)) {
+ // Replace wildcards with PDO wildcards.
+ $this->condition($this->elements[$name]['field'], preg_replace('!\*+!', '%', $value), 'LIKE');
+ }
+ else {
+ $this->condition($this->elements[$name]['field'], $value);
+ }
+ }
+ }
+ }
+
+ return $this->query->execute();
+ }
+
+ /**
+ * Return the defined filter name.
+ *
+ * @return
+ * The previously defined filter.
+ */
+ public function getFilterName() {
+ return $this->name;
+ }
+
+ /**
+ * Return the loaded, currently active filters for that query.
+ *
+ * @return
+ * Array with active filters.
+ */
+ public function getFilter() {
+ return $this->filter;
+ }
+
+ /**
+ * Get the form definition of the active filter.
+ *
+ * @see filter_extender_form
+ *
+ * @param $title
+ * Fieldset title that should be used for that form.
+ */
+ public function getForm($title = NULL) {
+
+ // Only display a form if filter elements were found.
+ if (empty($this->elements)) {
+ return array();
+ }
+
+ if ($title == NULL) {
+ $title = t('Only display items where');
+ }
+
+ // Note: #query is a workaround becase we can't directly call a object
+ // method for the form submit.
+ $form = array(
+ '#title' => $title,
+ '#type' => 'fieldset',
+ '#weight' => -50,
+ '#theme' => 'filter_selection_form',
+ '#query' => $this,
+ );
+
+ $i = 0;
+ foreach ($this->filter as $name => $values) {
+ $params = array(
+ '%property' => $this->elements[$name]['title'],
+ '%value' => join(t(' and '), $this->getFilterDescription($name, $values)
+ ));
+ if ($i++ > 0) {
+ $form['current'][] = array('#markup' => t('and where %property is %value', $params));
+ }
+ else {
+ $form['current'][] = array('#markup' => t('%property is %value', $params));
+ }
+ }
+
+ // Create a select for each filter element.
+ foreach ($this->elements as $name => $element) {
+ $names[$name] = $element['title'];
+
+ // Display a select if pre-defined options are available.
+ if (isset($element['options'])) {
+ $form['status'][$name] = array(
+ '#type' => 'select',
+ '#options' => $element['options'],
+ );
+ } else {
+ // If not, use a textfield, optionally with an autocomplete path.
+ $form['status'][$name] = array(
+ '#type' => 'textfield',
+ '#size' => 19,
+ );
+ if (isset($element['autocomplete_path'])) {
+ $form['status'][$name]['#autocomplete_path'] = $element['autocomplete_path'];
+ }
+ }
+ }
+
+ // Create list of filter elements.
+ $form['filter'] = array(
+ '#type' => 'radios',
+ '#options' => $names,
+ );
+
+ $form['buttons']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => (count($this->filter) ? t('Refine') : t('Filter')),
+ '#submit' => array('filter_extender_form_submit'),
+ );
+ if (count($this->filter)) {
+ $form['buttons']['undo'] = array(
+ '#type' => 'submit',
+ '#value' => t('Undo'),
+ '#submit' => array('filter_extender_form_submit'),
+ );
+ $form['buttons']['reset'] = array(
+ '#type' => 'submit',
+ '#value' => t('Reset'),
+ '#submit' => array('filter_extender_form_submit'),
+ );
+ }
+ return $form;
+ }
+
+ /**
+ * Handle the filter form submit.
+ *
+ * Because this can't be called directly, it's called by the helper function
+ * filter_extender_form_submit.
+ *
+ * @see filter_extender_form_submit()
+ */
+ public function submitForm($form, &$form_state) {
+ switch ($form_state['values']['op']) {
+ case t('Filter'):
+ case t('Refine'):
+ if (!empty($form_state['values']['filter'])) {
+ $name = $form_state['values']['filter'];
+ $value = $form_state['values'][$name];
+
+ // Only add the new filter of multiple is enabled, override the
+ // current value if not.
+ if (isset($this->elements[$name]['multiple']) && $this->elements[$name]['multiple']) {
+ $this->filter[$name][$value] = $value;
+ }
+ else {
+ $this->filter[$name] = array($value => $value);
+ }
+ }
+ break;
+ case t('Undo'):
+ array_pop($this->filter);
+ break;
+ case t('Reset'):
+ $this->filter = array();
+ break;
+ }
+ }
+
+ /**
+ * Return an array of filter values that should be displayed in the form.
+ *
+ * @param $name
+ * Name of the filter.
+ * @param $values
+ * Array of values that should be displayed.
+ * @return
+ * Array of filter values, either the values itself or the text of the
+ * selected options.
+ */
+ protected function getFilterDescription($name, $values) {
+ if (isset($this->elements[$name]['options'])) {
+ $options = $this->elements[$name]['options'];
+ if (count(array_filter($this->elements[$name]['options'], 'is_array')) > 0) {
+ $options = call_user_func_array('array_merge', $this->elements[$name]['options']);
+ }
+ return array_intersect_key($options, $values);
+ } else {
+ return $values;
+ }
+ }
+}
+
+/**
+ * Theme filter selector form.
+ *
+ * @ingroup themeable
+ */
+function theme_filter_selection_form($form) {
+ $output = '';
+ if (!empty($form['current'])) {
+ $output .= '
';
+ foreach (element_children($form['current']) as $key) {
+ $output .= '' . drupal_render($form['current'][$key]) . '
';
+ }
+ $output .= '
';
+ }
+
+ $output .= '' . (!empty($form['current']) ? '- ' . t('and') . ' ' . t('where') . '
' : '') . '- ';
+ foreach (element_children($form['filter']) as $key) {
+ $output .= drupal_render($form['filter'][$key]);
+ }
+ $output .= '
- ' . t('is') . '
- ';
+
+ foreach (element_children($form['status']) as $key) {
+ $output .= drupal_render($form['status'][$key]);
+ }
+ $output .= '
';
+ $output .= '' . drupal_render($form['buttons']) . '
';
+ return $output;
+}
+
+/**
+ * Form for the filter of the passed in $query object.
+ *
+ * This is a helper function because we can't directly call a object method with
+ * drupal_get_form(). Only use this if you don't already have a $form object
+ * that could be extended.
+ *
+ * @param $query
+ * SelectQuery object that is already extend with Filter.
+ * @return
+ */
+function filter_extender_form($query) {
+ return $query->getForm();
+}
+
+/**
+ * Helper function for submitting the filter form.
+ *
+ * @see filter_extender_form()
+ */
+function filter_extender_form_submit($form, &$form_state) {
+ $form['filter']['#query']->submitForm($form, $form_state);
+}
\ No newline at end of file
Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.50
diff -u -p -r1.50 user.admin.inc
--- modules/user/user.admin.inc 22 May 2009 11:33:18 -0000 1.50
+++ modules/user/user.admin.inc 24 May 2009 07:48:04 -0000
@@ -19,7 +19,6 @@ function user_admin($callback_arg = '')
$build['user_multiple_cancel_confirm'] = drupal_get_form('user_multiple_cancel_confirm');
}
else {
- $build['user_filter_form'] = drupal_get_form('user_filter_form');
$build['user_admin_account'] = drupal_get_form('user_admin_account');
}
}
@@ -27,104 +26,6 @@ function user_admin($callback_arg = '')
}
/**
- * Form builder; Return form for user administration filters.
- *
- * @ingroup forms
- * @see user_filter_form_submit()
- */
-function user_filter_form() {
- if (!isset($_SESSION['user_overview_filter'])) {
- drupal_set_session('user_overview_filter', array());
- }
- $session = &$_SESSION['user_overview_filter'];
- $filters = user_filters();
-
- $i = 0;
- $form['filters'] = array(
- '#type' => 'fieldset',
- '#title' => t('Show only users where'),
- '#theme' => 'user_filters',
- );
- foreach ($session as $filter) {
- list($type, $value) = $filter;
- // Merge an array of arrays into one if necessary.
- $options = $type == 'permission' ? call_user_func_array('array_merge', $filters[$type]['options']) : $filters[$type]['options'];
- $params = array('%property' => $filters[$type]['title'] , '%value' => $options[$value]);
- if ($i++ > 0) {
- $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $params));
- }
- else {
- $form['filters']['current'][] = array('#markup' => t('%property is %value', $params));
- }
- }
-
- foreach ($filters as $key => $filter) {
- $names[$key] = $filter['title'];
- $form['filters']['status'][$key] = array(
- '#type' => 'select',
- '#options' => $filter['options'],
- );
- }
-
- $form['filters']['filter'] = array(
- '#type' => 'radios',
- '#options' => $names,
- );
- $form['filters']['buttons']['submit'] = array(
- '#type' => 'submit',
- '#value' => (count($session) ? t('Refine') : t('Filter')),
- );
- if (count($session)) {
- $form['filters']['buttons']['undo'] = array(
- '#type' => 'submit',
- '#value' => t('Undo'),
- );
- $form['filters']['buttons']['reset'] = array(
- '#type' => 'submit',
- '#value' => t('Reset'),
- );
- }
-
- drupal_add_js('misc/form.js');
-
- return $form;
-}
-
-/**
- * Process result from user administration filter form.
- */
-function user_filter_form_submit($form, &$form_state) {
- $op = $form_state['values']['op'];
- $filters = user_filters();
- switch ($op) {
- case t('Filter'): case t('Refine'):
- if (isset($form_state['values']['filter'])) {
- $filter = $form_state['values']['filter'];
- // Merge an array of arrays into one if necessary.
- $options = $filter == 'permission' ? call_user_func_array('array_merge', $filters[$filter]['options']) : $filters[$filter]['options'];
- if (isset($options[$form_state['values'][$filter]])) {
- if (!isset($_SESSION['user_overview_filter'])) {
- drupal_set_session('user_overview_filter', array());
- }
- $_SESSION['user_overview_filter'][] = array($filter, $form_state['values'][$filter]);
- }
- }
- break;
- case t('Undo'):
- array_pop($_SESSION['user_overview_filter']);
- break;
- case t('Reset'):
- drupal_set_session('user_overview_filter', array());
- break;
- case t('Update'):
- return;
- }
-
- $form_state['redirect'] = 'admin/user/user';
- return;
-}
-
-/**
* Form builder; User administration page.
*
* @ingroup forms
@@ -143,14 +44,16 @@ function user_admin_account() {
t('Operations')
);
- $query = db_select('users', 'u');
- $query->leftJoin('users_roles', 'ur', 'u.uid = ur.uid');
- $query->condition('u.uid', 0, '<>');
- user_build_filter_query($query);
+ // Extend with Filter early so that the count query gets the same filters applied.
+ $query = db_select('users', 'u')->extend('Filter');
+ $query
+ ->filterName('user_admin')
+ ->condition('u.uid', 0, '<>');
$count_query = clone $query;
$count_query->addExpression('COUNT(DISTINCT u.uid)');
+ // Extend with PagerDefault and Tablesort now, as the count query doesn't need them.
$query = $query->extend('PagerDefault')->extend('TableSort');
$query
->fields('u', array('uid', 'name', 'status', 'created', 'access'))
@@ -158,6 +61,8 @@ function user_admin_account() {
->orderByHeader($header)
->setCountQuery($count_query);
$result = $query->execute();
+ // Load filter form.
+ $form['filter'] = $query->getForm(t('Only display users where...'));
$form['options'] = array(
'#type' => 'fieldset',
@@ -177,6 +82,9 @@ function user_admin_account() {
$form['options']['submit'] = array(
'#type' => 'submit',
'#value' => t('Update'),
+ // Only run the update validate and submit function for the Update button.
+ '#submit' => array('user_admin_account_update'),
+ '#validate' => array('user_admin_account_update_validate'),
);
$destination = drupal_get_destination();
@@ -211,7 +119,7 @@ function user_admin_account() {
/**
* Submit the user administration update form.
*/
-function user_admin_account_submit($form, &$form_state) {
+function user_admin_account_update($form, &$form_state) {
$operations = module_invoke_all('user_operations', $form_state);
$operation = $operations[$form_state['values']['operation']];
// Filter out unchecked accounts.
@@ -230,7 +138,10 @@ function user_admin_account_submit($form
}
}
-function user_admin_account_validate($form, &$form_state) {
+/**
+ * Validate the user administration update form.
+ */
+function user_admin_account_update_validate($form, &$form_state) {
$form_state['values']['accounts'] = array_filter($form_state['values']['accounts']);
if (count($form_state['values']['accounts']) == 0) {
form_set_error('', t('No users selected.'));
@@ -819,7 +730,8 @@ function theme_user_admin_account($form)
t('Operations')
);
- $output = drupal_render($form['options']);
+ $output = drupal_render($form['filter']);
+ $output .= drupal_render($form['options']);
if (isset($form['name']) && is_array($form['name'])) {
foreach (element_children($form['name']) as $key) {
$rows[] = array(
@@ -870,49 +782,3 @@ function theme_user_admin_new_role($form
return $output;
}
-
-/**
- * Theme user administration filter form.
- *
- * @ingroup themeable
- */
-function theme_user_filter_form($form) {
- $output = '';
- $output .= drupal_render($form['filters']);
- $output .= '
';
- $output .= drupal_render_children($form);
- return $output;
-}
-
-/**
- * Theme user administration filter selector.
- *
- * @ingroup themeable
- */
-function theme_user_filters($form) {
- $output = '';
-
- return $output;
-}
Index: modules/user/user.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.css,v
retrieving revision 1.10
diff -u -p -r1.10 user.css
--- modules/user/user.css 9 Oct 2008 04:19:44 -0000 1.10
+++ modules/user/user.css 24 May 2009 07:48:04 -0000
@@ -12,12 +12,6 @@
#user-login-form {
text-align: center;
}
-#user-admin-filter ul {
- list-style-type: none;
- padding: 0;
- margin: 0;
- width: 100%;
-}
#user-admin-buttons {
float: left; /* LTR */
margin-left: 0.5em; /* LTR */
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.990
diff -u -p -r1.990 user.module
--- modules/user/user.module 22 May 2009 08:04:40 -0000 1.990
+++ modules/user/user.module 24 May 2009 07:48:06 -0000
@@ -69,14 +69,6 @@ function user_theme() {
'arguments' => array('form' => NULL),
'file' => 'user.admin.inc',
),
- 'user_filter_form' => array(
- 'arguments' => array('form' => NULL),
- 'file' => 'user.admin.inc',
- ),
- 'user_filters' => array(
- 'arguments' => array('form' => NULL),
- 'file' => 'user.admin.inc',
- ),
'user_signature' => array(
'arguments' => array('signature' => NULL),
),
@@ -2432,18 +2424,24 @@ function _user_sort($a, $b) {
}
/**
- * List user administration filters that can be applied.
+ * Implementation of hook_filter_elements_filtername().
*/
-function user_filters() {
+function user_filter_elements_user_admin() {
// Regular filters
$filters = array();
+ $filters['name'] = array(
+ 'title' => t('username'),
+ 'autocomplete_path' => 'user/autocomplete',
+ 'field' => 'u.name',
+ );
+
$roles = user_roles(TRUE);
unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role.
if (count($roles)) {
$filters['role'] = array(
'title' => t('role'),
- 'field' => 'ur.rid',
'options' => $roles,
+ 'multiple' => TRUE,
);
}
@@ -2461,6 +2459,7 @@ function user_filters() {
$filters['permission'] = array(
'title' => t('permission'),
'options' => $options,
+ 'multiple' => TRUE,
);
$filters['status'] = array(
@@ -2472,32 +2471,36 @@ function user_filters() {
}
/**
- * Extends a query object for user administration filters based on session.
+ * Extends a query object for user permission filters.
*
* @param $query
* Query object that should be filtered.
*/
-function user_build_filter_query(SelectQuery $query) {
- $filters = user_filters();
-
- // Extend Query with filter conditions.
- foreach ($_SESSION['user_overview_filter'] as $filter) {
- list($key, $value) = $filter;
- // This checks to see if this permission filter is an enabled permission for
- // the authenticated role. If so, then all users would be listed, and we can
- // skip adding it to the filter query.
- if ($key == 'permission') {
+function user_query_filter_user_admin_alter($query) {
+ // Extend Query with permission conditions.
+ $filter = $query->getMetaData('filter');
+ if (isset($filter['permission'])) {
+ $i = 0;
+ $query->leftJoin('users_roles', 'ur', 'u.uid = ur.uid');
+ foreach ($filter['permission'] as $value) {
$account = new stdClass();
$account->uid = 'user_filter';
$account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
if (user_access($value, $account)) {
continue;
}
- $query->leftJoin('role_permission', 'p', 'ur.rid = p.rid');
- $query->condition(db_or()->condition('u.uid', 1)->condition('p.permission', $value));
+ $query->leftjoin('role_permission', "p$i", "ur.rid = p$i.rid");
+ $query->condition(db_or()->condition("u.uid", 1)->condition("p$i.permission", $value));
+ $i++;
}
- else {
- $query->condition($filters[$key]['field'], $value);
+ }
+
+ if (isset($filter['role'])) {
+ $i = 0;
+ foreach ($filter['role'] as $value) {
+ $table = $query->leftJoin('users_roles', "ur$i", "ur$i.uid = u.uid");
+ $query->condition("ur$i.rid", $value);
+ $i++;
}
}
}