From 71638033eb9fac6b89dc5cd337b2e0d9ad079bfd Mon Sep 17 00:00:00 2001 From: sam marshall Date: Wed, 27 Mar 2013 14:56:20 +0000 Subject: [PATCH] MDL-26956 (3) Enrol: Add filter options to enrolments screen --- enrol/locallib.php | 67 ++++++++++++++++++++++++++++++++++++--- enrol/renderer.php | 18 +++-------- enrol/users.php | 15 +++++++-- enrol/users_forms.php | 46 ++++++++++++++++++++++++++- theme/base/style/core.css | 11 +++++++ 5 files changed, 137 insertions(+), 20 deletions(-) diff --git a/enrol/locallib.php b/enrol/locallib.php index 3f6a50622fb..e4ece1e672b 100644 --- a/enrol/locallib.php +++ b/enrol/locallib.php @@ -53,6 +53,16 @@ class course_enrolment_manager { * @var string */ protected $instancefilter = null; + /** + * Limits the focus of the manager to users with specified role + * @var int + */ + protected $rolefilter = 0; + /** + * Limits the focus of the manager to users who match search string + * @var string + */ + protected $searchfilter = ''; /** * The total number of users enrolled in the course @@ -110,12 +120,17 @@ class course_enrolment_manager { * @param moodle_page $moodlepage * @param stdClass $course * @param string $instancefilter + * @param int $rolefilter If non-zero, filters to users with specified role + * @param string $searchfilter If non-blank, filters to users with search text */ - public function __construct(moodle_page $moodlepage, $course, $instancefilter = null) { + public function __construct(moodle_page $moodlepage, $course, $instancefilter = null, + $rolefilter = 0, $searchfilter = '') { $this->moodlepage = $moodlepage; $this->context = context_course::instance($course->id); $this->course = $course; $this->instancefilter = $instancefilter; + $this->rolefilter = $rolefilter; + $this->searchfilter = $searchfilter; } /** @@ -139,10 +154,13 @@ class course_enrolment_manager { global $DB; if ($this->totalusers === null) { list($instancessql, $params, $filter) = $this->get_instance_sql(); + list($filtersql, $moreparams) = $this->get_filter_sql(); + $params += $moreparams; $sqltotal = "SELECT COUNT(DISTINCT u.id) FROM {user} u JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) - JOIN {enrol} e ON (e.id = ue.enrolid)"; + JOIN {enrol} e ON (e.id = ue.enrolid) + WHERE $filtersql"; $this->totalusers = (int)$DB->count_records_sql($sqltotal, $params); } return $this->totalusers; @@ -183,7 +201,8 @@ class course_enrolment_manager { * Gets all of the users enrolled in this course. * * If a filter was specified this will be the users who were enrolled - * in this course by means of that instance. + * in this course by means of that instance. If role or search filters were + * specified then these will also be applied. * * @global moodle_database $DB * @param string $sort @@ -200,6 +219,8 @@ class course_enrolment_manager { $key = md5("$sort-$direction-$page-$perpage"); if (!array_key_exists($key, $this->users)) { list($instancessql, $params, $filter) = $this->get_instance_sql(); + list($filtersql, $moreparams) = $this->get_filter_sql(); + $params += $moreparams; $extrafields = get_extra_user_fields($this->get_context()); $extrafields[] = 'lastaccess'; $ufields = user_picture::fields('u', $extrafields); @@ -207,7 +228,8 @@ class course_enrolment_manager { FROM {user} u JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) JOIN {enrol} e ON (e.id = ue.enrolid) - LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id)"; + LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id) + WHERE $filtersql"; if ($sort === 'firstname') { $sql .= " ORDER BY u.firstname $direction, u.lastname $direction"; } else if ($sort === 'lastname') { @@ -222,6 +244,37 @@ class course_enrolment_manager { return $this->users[$key]; } + /** + * Obtains WHERE clause to filter results by defined search and role filter + * (instance filter is handled separately in JOIN clause, see + * get_instance_sql). + * + * @return array Two-element array with SQL and params for WHERE clause + */ + protected function get_filter_sql() { + global $DB; + + // Search condition. + $extrafields = get_extra_user_fields($this->get_context()); + list($sql, $params) = users_search_sql($this->searchfilter, 'u', true, $extrafields); + + // Role condition. + if ($this->rolefilter) { + // Get context SQL. + $contextids = $this->context->get_parent_context_ids(); + $contextids[] = $this->context->id; + list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED); + $params += $contextparams; + + // Role check condition. + $sql .= " AND (SELECT COUNT(1) FROM {role_assignments} ra WHERE ra.userid = u.id " . + "AND ra.roleid = :roleid AND ra.contextid $contextsql) > 0"; + $params['roleid'] = $this->rolefilter; + } + + return array($sql, $params); + } + /** * Gets and array of other users. * @@ -795,6 +848,12 @@ class course_enrolment_manager { if (!empty($this->instancefilter)) { $args['ifilter'] = $this->instancefilter; } + if (!empty($this->rolefilter)) { + $args['role'] = $this->rolefilter; + } + if ($this->searchfilter !== '') { + $args['search'] = $this->searchfilter; + } return $args; } diff --git a/enrol/renderer.php b/enrol/renderer.php index de8505c262b..3804a9f7ffb 100644 --- a/enrol/renderer.php +++ b/enrol/renderer.php @@ -36,9 +36,11 @@ class core_enrol_renderer extends plugin_renderer_base { * Renders a course enrolment table * * @param course_enrolment_table $table + * @param moodleform $mform Form that contains filter controls * @return string */ - protected function render_course_enrolment_users_table(course_enrolment_users_table $table) { + public function render_course_enrolment_users_table(course_enrolment_users_table $table, + moodleform $mform) { $table->initialise_javascript(); @@ -56,7 +58,8 @@ class core_enrol_renderer extends plugin_renderer_base { if (!empty($buttonhtml)) { $content .= $buttonhtml; } - $content .= $this->output->render($table->get_enrolment_type_filter()); + $content .= $mform->render(); + $content .= $this->output->render($table->get_paging_bar()); // Check if the table has any bulk operations. If it does we want to wrap the table in a @@ -707,17 +710,6 @@ class course_enrolment_users_table extends course_enrolment_table { * @var array */ protected static $sortablefields = array('firstname', 'lastname', 'email', 'lastaccess'); - - /** - * Gets the enrolment type filter control for this table - * - * @return single_select - */ - public function get_enrolment_type_filter() { - $selector = new single_select($this->manager->get_moodlepage()->url, 'ifilter', array(0=>get_string('all')) + (array)$this->manager->get_enrolment_instance_names(), $this->manager->get_enrolment_filter(), array()); - $selector->set_label( get_string('enrolmentinstances', 'enrol')); - return $selector; - } } /** diff --git a/enrol/users.php b/enrol/users.php index d33174a2e05..4b46be4ec53 100644 --- a/enrol/users.php +++ b/enrol/users.php @@ -32,6 +32,13 @@ require_once("$CFG->dirroot/group/lib.php"); $id = required_param('id', PARAM_INT); // course id $action = optional_param('action', '', PARAM_ALPHANUMEXT); $filter = optional_param('ifilter', 0, PARAM_INT); +$search = optional_param('search', '', PARAM_RAW); +$role = optional_param('role', 0, PARAM_INT); + +// When users reset the form, redirect back to first page without other params. +if (optional_param('resetbutton', '', PARAM_RAW) !== '') { + redirect('users.php?id=' . $id); +} $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); $context = context_course::instance($course->id, MUST_EXIST); @@ -44,7 +51,7 @@ require_login($course); require_capability('moodle/course:enrolreview', $context); $PAGE->set_pagelayout('admin'); -$manager = new course_enrolment_manager($PAGE, $course, $filter); +$manager = new course_enrolment_manager($PAGE, $course, $filter, $role, $search); $table = new course_enrolment_users_table($manager, $PAGE); $PAGE->set_url('/enrol/users.php', $manager->get_url_params()+$table->get_url_params()); navigation_node::override_active_url(new moodle_url('/enrol/users.php', array('id' => $id))); @@ -195,6 +202,10 @@ if (!has_capability('moodle/course:viewhiddenuserfields', $context)) { } } +$filterform = new enrol_users_filter_form('users.php', array('manager' => $manager, 'id' => $id), + 'get', '', array('id' => 'filterform')); +$filterform->set_data(array('search' => $search, 'ifilter' => $filter, 'role' => $role)); + $table->set_fields($fields, $renderer); $canassign = has_capability('moodle/role:assign', $manager->get_context()); @@ -213,5 +224,5 @@ $PAGE->set_heading($PAGE->title); echo $OUTPUT->header(); echo $OUTPUT->heading(get_string('enrolledusers', 'enrol')); -echo $renderer->render($table); +echo $renderer->render_course_enrolment_users_table($table, $filterform); echo $OUTPUT->footer(); diff --git a/enrol/users_forms.php b/enrol/users_forms.php index 390774c0f43..34af19f66e1 100644 --- a/enrol/users_forms.php +++ b/enrol/users_forms.php @@ -131,4 +131,48 @@ class enrol_users_addmember_form extends moodleform { $this->set_data(array('action'=>'addmember', 'user'=>$user->id)); } -} \ No newline at end of file +} + + +/** + * Form that lets users filter the enrolled user list. + */ +class enrol_users_filter_form extends moodleform { + function definition() { + global $CFG, $DB; + + $manager = $this->_customdata['manager']; + + $mform = $this->_form; + + // Text search box. + $mform->addElement('text', 'search', get_string('search')); + + // Filter by enrolment plugin type. + $mform->addElement('select', 'ifilter', get_string('enrolmentinstances', 'enrol'), + array(0 => get_string('all')) + (array)$manager->get_enrolment_instance_names()); + + // Role select dropdown includes all roles, but using course-specific + // names if applied. The reason for not restricting to roles that can + // be assigned at course level is that upper-level roles display in the + // enrolments table so it makes sense to let users filter by them. + $allroles = get_all_roles($manager->get_context()); + $rolenames = array(); + foreach ($allroles as $id => $role) { + $rolenames[$id] = $role->name; + } + $mform->addElement('select', 'role', get_string('role'), + array(0 => get_string('all')) + $rolenames); + + // Submit button does not use add_action_buttons because that adds + // another fieldset which causes the CSS style to break in an unfixable + // way due to fieldset quirks. + $group = array(); + $group[] = $mform->createElement('submit', 'submitbutton', get_string('filter')); + $group[] = $mform->createElement('submit', 'resetbutton', get_string('reset')); + $mform->addGroup($group, 'buttons', '', ' ', false); + + // Add hidden fields required by page. + $mform->addElement('hidden', 'id', $this->_customdata['id']); + } +} diff --git a/theme/base/style/core.css b/theme/base/style/core.css index 8816b8eca86..fec4e280468 100644 --- a/theme/base/style/core.css +++ b/theme/base/style/core.css @@ -615,11 +615,22 @@ body.tag .managelink {padding: 5px;} .userenrolment .col_enrol .enrolment {float:left;padding:3px;margin:3px;} .userenrolment .col_enrol .enrolment a {float:right;margin-left:3px;} #page-enrol-users .enrol_user_buttons {float:right;} +#page-enrol-users .enrol_user_buttons .singlebutton {margin-top: 2px; line-height: 2;} #page-enrol-users .enrol_user_buttons .enrolusersbutton {margin-left:1em;display:inline;} #page-enrol-users .enrol_user_buttons .enrolusersbutton div, #page-enrol-users .enrol_user_buttons .enrolusersbutton form {display:inline;} #page-enrol-users .enrol_user_buttons .enrolusersbutton input {padding-left:6px;padding-right:6px;} #page-enrol-users.dir-rtl .col_userdetails .subfield_picture {float: right;} +#page-enrol-users #filterform div, +#page-enrol-users #filterform fieldset {display:inline;float:none;clear:none;width:auto;margin:0;line-height:2;} +#page-enrol-users #filterform .fitem {white-space:nowrap;} +#page-enrol-users #filterform fieldset > div {display:block;float:left;background:#f2f2f2;padding:2px;} +#page-enrol-users #filterform select, +#page-enrol-users #filterform .ftext input {width:8em;} +#page-enrol-users #filterform #fitem_id_role, +#page-enrol-users #filterform #fitem_id_ifilter, +#page-enrol-users #filterform #fgroup_id_buttons {margin-left:0.5em;} +#page-enrol-users .paging { clear: right; } /** * Overide for RTL layout