Skip to content

Commit

Permalink
Merge branch 'MDL-26956' of git://github.com/timhunt/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
danpoltawski committed Apr 2, 2013
2 parents 73b8f19 + 0e0a980 commit 15c2b2c
Show file tree
Hide file tree
Showing 9 changed files with 361 additions and 77 deletions.
67 changes: 63 additions & 4 deletions enrol/locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -139,10 +154,13 @@ public function get_total_users() {
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;
Expand Down Expand Up @@ -183,7 +201,8 @@ public function get_total_other_users() {
* 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
Expand All @@ -200,14 +219,17 @@ public function get_users($sort, $direction='ASC', $page=0, $perpage=25) {
$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);
$sql = "SELECT DISTINCT $ufields, ul.timeaccess AS lastseen
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') {
Expand All @@ -222,6 +244,37 @@ public function get_users($sort, $direction='ASC', $page=0, $perpage=25) {
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.
*
Expand Down Expand Up @@ -795,6 +848,12 @@ public function get_url_params() {
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;
}

Expand Down
18 changes: 5 additions & 13 deletions enrol/renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -56,7 +58,8 @@ protected function render_course_enrolment_users_table(course_enrolment_users_ta
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
Expand Down Expand Up @@ -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;
}
}

/**
Expand Down
15 changes: 13 additions & 2 deletions enrol/users.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
$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);
Expand All @@ -44,7 +51,7 @@
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)));
Expand Down Expand Up @@ -195,6 +202,10 @@
}
}

$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());
Expand All @@ -213,5 +224,5 @@

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();
48 changes: 47 additions & 1 deletion enrol/users_forms.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,50 @@ function definition() {

$this->set_data(array('action'=>'addmember', 'user'=>$user->id));
}
}
}


/**
* 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'));
$mform->setType('search', PARAM_RAW);

// 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']);
$mform->setType('id', PARAM_INT);
}
}
89 changes: 89 additions & 0 deletions lib/datalib.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,95 @@ function search_users($courseid, $groupid, $searchtext, $sort='', array $excepti
}
}

/**
* Returns SQL used to search through user table to find users (in a query
* which may also join and apply other conditions).
*
* You can combine this SQL with an existing query by adding 'AND $sql' to the
* WHERE clause of your query (where $sql is the first element in the array
* returned by this function), and merging in the $params array to the parameters
* of your query (where $params is the second element). Your query should use
* named parameters such as :param, rather than the question mark style.
*
* There are examples of basic usage in the unit test for this function.
*
* @param string $search the text to search for (empty string = find all)
* @param string $u the table alias for the user table in the query being
* built. May be ''.
* @param bool $searchanywhere If true (default), searches in the middle of
* names, otherwise only searches at start
* @param array $extrafields Array of extra user fields to include in search
* @param array $exclude Array of user ids to exclude (empty = don't exclude)
* @param array $includeonly If specified, only returns users that have ids
* incldued in this array (empty = don't restrict)
* @return array an array with two elements, a fragment of SQL to go in the
* where clause the query, and an associative array containing any required
* parameters (using named placeholders).
*/
function users_search_sql($search, $u = 'u', $searchanywhere = true, array $extrafields = array(),
array $exclude = array(), array $includeonly = array()) {
global $DB, $CFG;
$params = array();
$tests = array();

if ($u) {
$u .= '.';
}

// If we have a $search string, put a field LIKE '$search%' condition on each field.
if ($search) {
$conditions = array(
$DB->sql_fullname($u . 'firstname', $u . 'lastname'),
$conditions[] = $u . 'lastname'
);
foreach ($extrafields as $field) {
$conditions[] = $u . $field;
}
if ($searchanywhere) {
$searchparam = '%' . $search . '%';
} else {
$searchparam = $search . '%';
}
$i = 0;
foreach ($conditions as $key => $condition) {
$conditions[$key] = $DB->sql_like($condition, ":con{$i}00", false, false);
$params["con{$i}00"] = $searchparam;
$i++;
}
$tests[] = '(' . implode(' OR ', $conditions) . ')';
}

// Add some additional sensible conditions.
$tests[] = $u . "id <> :guestid";
$params['guestid'] = $CFG->siteguest;
$tests[] = $u . 'deleted = 0';
$tests[] = $u . 'confirmed = 1';

// If we are being asked to exclude any users, do that.
if (!empty($exclude)) {
list($usertest, $userparams) = $DB->get_in_or_equal($exclude, SQL_PARAMS_NAMED, 'ex', false);
$tests[] = $u . 'id ' . $usertest;
$params = array_merge($params, $userparams);
}

// If we are validating a set list of userids, add an id IN (...) test.
if (!empty($includeonly)) {
list($usertest, $userparams) = $DB->get_in_or_equal($includeonly, SQL_PARAMS_NAMED, 'val');
$tests[] = $u . 'id ' . $usertest;
$params = array_merge($params, $userparams);
}

// In case there are no tests, add one result (this makes it easier to combine
// this with an existing query as you can always add AND $sql).
if (empty($tests)) {
$tests[] = '1 = 1';
}

// Combing the conditions and return.
return array(implode(' AND ', $tests), $params);
}


/**
* This function generates the standard ORDER BY clause for use when generating
* lists of users. If you don't have a reason to use a different order, then
Expand Down
16 changes: 16 additions & 0 deletions lib/formslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,22 @@ function display() {
$this->_form->display();
}

/**
* Renders the html form (same as display, but returns the result).
*
* Note that you can only output this rendered result once per page, as
* it contains IDs which must be unique.
*
* @return string HTML code for the form
*/
public function render() {
ob_start();
$this->display();
$out = ob_get_contents();
ob_end_clean();
return $out;
}

/**
* Form definition. Abstract method - always override!
*/
Expand Down
Loading

0 comments on commit 15c2b2c

Please sign in to comment.