From b1eac5a5c2e3829c8d345079099ac6277ae3820e Mon Sep 17 00:00:00 2001
From: "Bradley M. Froehle" <brad.froehle@gmail.com>
Date: Thu, 17 Nov 2011 12:14:35 -0800
Subject: [PATCH] #8

---
 core/modules/user/user.admin.inc |   28 +++++++++++-----
 core/modules/user/user.api.php   |   29 ++++++++++++++++
 core/modules/user/user.module    |   67 ++++++++++++++++++-------------------
 3 files changed, 81 insertions(+), 43 deletions(-)

diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index 4789e7e..7ecdb45 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -33,7 +33,7 @@ function user_admin($callback_arg = '') {
  */
 function user_filter_form() {
   $session = isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array();
-  $filters = user_filters();
+  $filters = module_invoke_all('user_filters');
 
   $i = 0;
   $form['filters'] = array(
@@ -108,19 +108,14 @@ function user_filter_form() {
  */
 function user_filter_form_submit($form, &$form_state) {
   $op = $form_state['values']['op'];
-  $filters = user_filters();
+  $filters = module_invoke_all('user_filters');
   switch ($op) {
     case t('Filter'):
     case t('Refine'):
       // Apply every filter that has a choice selected other than 'any'.
       foreach ($filters as $filter => $options) {
         if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
-          // Merge an array of arrays into one if necessary.
-          $options = ($filter == 'permission') ? form_options_flatten($filters[$filter]['options']) : $filters[$filter]['options'];
-          // Only accept valid selections offered on the dropdown, block bad input.
-          if (isset($options[$form_state['values'][$filter]])) {
-            $_SESSION['user_overview_filter'][] = array($filter, $form_state['values'][$filter]);
-          }
+          $_SESSION['user_overview_filter'][] = array($filter, $form_state['values'][$filter]);
         }
       }
       break;
@@ -158,7 +153,22 @@ function user_admin_account() {
 
   $query = db_select('users', 'u');
   $query->condition('u.uid', 0, '<>');
-  user_build_filter_query($query);
+
+  // Build a list of all user filters and all applied user filters.
+  $filters = module_invoke_all('user_filters');
+  $applied_filters = isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array();
+
+  // Call the callback function for each applied filter.
+  foreach ($applied_filters as $applied_filter) {
+    list($filter, $value) = $applied_filter;
+    $function = $filters[$filter]['callback'];
+    $args = array($query, $value);
+    // Add in callback arguments if present.
+    if (isset($filters[$filter]['callback arguments'])) {
+      $args = array_merge($args, $filters[$filter]['callback arguments']);
+    }
+    call_user_func_array($function, $args);
+  }
 
   $count_query = clone $query;
   $count_query->addExpression('COUNT(u.uid)');
diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php
index 8cf788c..2c4ccb7 100644
--- a/core/modules/user/user.api.php
+++ b/core/modules/user/user.api.php
@@ -183,6 +183,35 @@ function hook_user_operations() {
 }
 
 /**
+ * Add user filtering options.
+ *
+ * This hook enables modules to allow custom filtering methods at admin/people.
+ *
+ * @return
+ *  An array of filters. Each filter is an associative array that contains the
+ *  following key-value pairs:
+ *  - title: The label for the filter, displayed next to the dropdown menu.
+ *  - options: An associative array of filter options, displayed in a dropdown
+ *    menu. No filtering will occur for an item keyed as '[any]'.
+ *  - callback: The function to call for the filtering.
+ *  - callback arguments: Optional. An array of additional arguments, beyond
+ *    the SelectQuery and filter, to pass to the callback function.
+ */
+function hook_user_filters() {
+  $filters = array();
+  $filters['status'] = array(
+    'title' => t('status'),
+    'options' => array(
+      '[any]' => t('any'),
+      1 => t('active'),
+      0 => t('blocked'),
+    ),
+    'callback' => 'user_build_filter_query_status',
+  );
+  return $filters;
+}
+
+/**
  * A user account is about to be created or updated.
  *
  * This hook is primarily intended for modules that want to store properties in
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 260124c..ee4bffc 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -3293,9 +3293,9 @@ function user_multiple_cancel_confirm_submit($form, &$form_state) {
 }
 
 /**
- * List user administration filters that can be applied.
+ * Implements hook_user_filters().
  */
-function user_filters() {
+function user_user_filters() {
   // Regular filters
   $filters = array();
   $roles = user_roles(TRUE);
@@ -3303,10 +3303,10 @@ function user_filters() {
   if (count($roles)) {
     $filters['role'] = array(
       'title' => t('role'),
-      'field' => 'ur.rid',
       'options' => array(
         '[any]' => t('any'),
       ) + $roles,
+      'callback' => 'user_build_filter_query_role',
     );
   }
 
@@ -3326,53 +3326,52 @@ function user_filters() {
     'options' => array(
       '[any]' => t('any'),
     ) + $options,
+    'callback' => 'user_build_filter_query_permission',
   );
 
   $filters['status'] = array(
     'title' => t('status'),
-    'field' => 'u.status',
     'options' => array(
       '[any]' => t('any'),
       1 => t('active'),
       0 => t('blocked'),
     ),
+    'callback' => 'user_build_filter_query_status',
   );
   return $filters;
 }
 
 /**
- * Extends a query object for user administration filters based on session.
- *
- * @param $query
- *   Query object that should be filtered.
+ * User filter callback; filter by user permission.
  */
-function user_build_filter_query(SelectQuery $query) {
-  $filters = user_filters();
-  // Extend Query with filter conditions.
-  foreach (isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array() 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') {
-      $account = new stdClass();
-      $account->uid = 'user_filter';
-      $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
-      if (user_access($value, $account)) {
-        continue;
-      }
-      $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
-      $permission_alias = $query->join('role_permission', 'p', $users_roles_alias . '.rid = %alias.rid');
-      $query->condition($permission_alias . '.permission', $value);
-    }
-    elseif ($key == 'role') {
-      $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
-      $query->condition($users_roles_alias . '.rid' , $value);
-    }
-    else {
-      $query->condition($filters[$key]['field'], $value);
-    }
+function user_build_filter_query_permission(SelectQuery $query, $value) {
+  // 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.
+  $account = new stdClass();
+  $account->uid = 'user_filter';
+  $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
+  if (user_access($value, $account)) {
+    return;
   }
+  $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
+  $permission_alias = $query->join('role_permission', 'p', $users_roles_alias . '.rid = %alias.rid');
+  $query->condition($permission_alias . '.permission', $value);
+}
+
+/**
+ * User filter callback; filter by user role.
+ */
+function user_build_filter_query_role(SelectQuery $query, $value) {
+  $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
+  $query->condition($users_roles_alias . '.rid' , $value);
+}
+
+/**
+ * User filter callback; filter by user status.
+ */
+function user_build_filter_query_status(SelectQuery $query, $value) {
+  $query->condition('u.status', $value);
 }
 
 /**
-- 
1.7.7.1

