MDL-19717 workshop manual allocator - pagination support and performance issues

This commit is contained in:
David Mudrak 2010-01-04 18:07:38 +00:00
parent 87a5368df1
commit aa40adbf9f
4 changed files with 319 additions and 230 deletions

View file

@ -33,6 +33,9 @@ require_once(dirname(dirname(dirname(__FILE__))) . '/locallib.php'); // works
*/
class workshop_manual_allocator implements workshop_allocator {
/** participants per page */
const PERPAGE = 30;
/** constants that are used to pass status messages between init() and ui() */
const MSG_ADDED = 1;
const MSG_NOSUBMISSION = 2;
@ -129,15 +132,17 @@ class workshop_manual_allocator implements workshop_allocator {
* Prints user interface - current allocation and a form to edit it
*/
public function ui() {
global $PAGE, $OUTPUT;
global $PAGE, $OUTPUT, $DB;
$pagingvar = 'page';
$page = optional_param($pagingvar, 0, PARAM_INT);
$hlauthorid = -1; // highlight this author
$hlreviewerid = -1; // highlight this reviewer
$msg = new stdClass(); // message to render
$m = optional_param('m', '', PARAM_ALPHANUMEXT); // message stdClass
$m = optional_param('m', '', PARAM_ALPHANUMEXT); // message code
if ($m) {
$m = explode('-', $m); // unserialize
$m = explode('-', $m);
switch ($m[0]) {
case self::MSG_ADDED:
$hlauthorid = $m[1];
@ -190,56 +195,170 @@ class workshop_manual_allocator implements workshop_allocator {
}
}
$peers = array();
$rs = $this->workshop->get_allocations_recordset();
if (!is_null($rs)) {
foreach ($rs as $allocation) {
$currentuserid = $allocation->authorid;
if (!isset($peers[$currentuserid])) {
$peers[$currentuserid] = new stdClass();
$peers[$currentuserid]->id = $allocation->authorid;
$peers[$currentuserid]->firstname = $allocation->authorfirstname;
$peers[$currentuserid]->lastname = $allocation->authorlastname;
$peers[$currentuserid]->picture = $allocation->authorpicture;
$peers[$currentuserid]->imagealt = $allocation->authorimagealt;
$peers[$currentuserid]->submissionid = $allocation->submissionid;
$peers[$currentuserid]->submissiontitle = $allocation->submissiontitle;
$peers[$currentuserid]->submissiongrade = $allocation->submissiongrade;
$peers[$currentuserid]->reviewedby = array(); // users who are reviewing this user's submission
$peers[$currentuserid]->reviewerof = array(); // users whom submission is being reviewed by this user
}
if (!empty($allocation->reviewerid)) {
// example: "submission of user with id 45 is reviewed by user with id 87 in the assessment record 12"
$peers[$currentuserid]->reviewedby[$allocation->reviewerid] = $allocation->assessmentid;
}
}
$rs->close();
if ($hlauthorid > 0 and $hlreviewerid > 0) {
// display just those users, no pagination
$participants = get_users_by_capability($PAGE->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
'u.id,u.lastname,u.firstname,u.picture,u.imagealt', 'u.lastname,u.firstname,u.id',
'', '', '', '', false, false, true);
$participants = array_intersect_key($participants, array($hlauthorid => null, $hlreviewerid => null));
} else {
// the paginated list of users to be displayed in the middle column ("Participant")
$participants = get_users_by_capability($PAGE->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
'u.id,u.lastname,u.firstname,u.picture,u.imagealt', 'u.lastname,u.firstname,u.id',
$page * self::PERPAGE, self::PERPAGE, '', '', false, false, true);
}
foreach ($peers as $author) {
foreach ($author->reviewedby as $reviewerid => $assessmentid) {
if (isset($peers[$reviewerid])) {
// example: "user with id 87 is reviewer of the work submitted by user id 45 in the assessment record 12"
$peers[$reviewerid]->reviewerof[$author->id] = $assessmentid;
// this will hold the information needed to display user names and pictures
$userinfo = $participants;
// load the participants' submissions
$submissions = $this->workshop->get_submissions(array_keys($participants), false);
// get current reviewers
$reviewers = array();
if ($submissions) {
list($submissionids, $params) = $DB->get_in_or_equal(array_keys($submissions), SQL_PARAMS_NAMED);
$sql = "SELECT a.id AS assessmentid, a.submissionid,
r.id AS reviewerid, r.lastname, r.firstname, r.picture, r.imagealt,
s.id AS submissionid, s.userid AS authorid
FROM {workshop_assessments} a
JOIN {user} r ON (a.userid = r.id)
JOIN {workshop_submissions} s ON (a.submissionid = s.id)
WHERE a.submissionid $submissionids";
$reviewers = $DB->get_records_sql($sql, $params);
foreach ($reviewers as $reviewer) {
if (!isset($userinfo[$reviewer->reviewerid])) {
$userinfo[$reviewer->reviewerid] = new stdClass();
$userinfo[$reviewer->reviewerid]->id = $reviewer->reviewerid;
$userinfo[$reviewer->reviewerid]->firstname = $reviewer->firstname;
$userinfo[$reviewer->reviewerid]->lastname = $reviewer->lastname;
$userinfo[$reviewer->reviewerid]->picture = $reviewer->picture;
$userinfo[$reviewer->reviewerid]->imagealt = $reviewer->imagealt;
$userinfo[$reviewer->reviewerid]->firstname = $reviewer->firstname;
}
}
}
// get current reviewees
list($participantids, $params) = $DB->get_in_or_equal(array_keys($participants), SQL_PARAMS_NAMED);
$params['workshopid'] = $this->workshop->id;
$sql = "SELECT a.id AS assessmentid, a.submissionid,
u.id AS reviewerid,
s.id AS submissionid,
r.id AS revieweeid, r.lastname, r.firstname, r.picture, r.imagealt
FROM {user} u
JOIN {workshop_assessments} a ON (a.userid = u.id)
JOIN {workshop_submissions} s ON (a.submissionid = s.id)
JOIN {user} r ON (s.userid = r.id)
WHERE u.id $participantids AND s.workshopid = :workshopid";
$reviewees = $DB->get_records_sql($sql, $params);
foreach ($reviewees as $reviewee) {
if (!isset($userinfo[$reviewee->revieweeid])) {
$userinfo[$reviewee->revieweeid] = new stdClass();
$userinfo[$reviewee->revieweeid]->id = $reviewee->revieweeid;
$userinfo[$reviewee->revieweeid]->firstname = $reviewee->firstname;
$userinfo[$reviewee->revieweeid]->lastname = $reviewee->lastname;
$userinfo[$reviewee->revieweeid]->picture = $reviewee->picture;
$userinfo[$reviewee->revieweeid]->imagealt = $reviewee->imagealt;
$userinfo[$reviewee->revieweeid]->firstname = $reviewee->firstname;
}
}
// the information about the allocations
$allocations = array();
foreach ($participants as $participant) {
$allocations[$participant->id] = new stdClass;
$allocations[$participant->id]->userid = $participant->id;
$allocations[$participant->id]->submissionid = null;
$allocations[$participant->id]->reviewedby = array();
$allocations[$participant->id]->reviewerof = array();
}
unset($participants);
foreach ($submissions as $submission) {
$allocations[$submission->authorid]->submissionid = $submission->id;
$allocations[$submission->authorid]->submissiontitle = $submission->title;
$allocations[$submission->authorid]->submissiongrade = $submission->grade;
}
unset($submissions);
foreach($reviewers as $reviewer) {
$allocations[$reviewer->authorid]->reviewedby[$reviewer->reviewerid] = $reviewer->assessmentid;
}
unset($reviewers);
foreach($reviewees as $reviewee) {
$allocations[$reviewee->reviewerid]->reviewerof[$reviewee->revieweeid] = $reviewee->assessmentid;
}
unset($reviewees);
// we have all data, let us pass it to the renderer and return the output
$wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE);
$uioutput = $PAGE->theme->get_renderer('workshopallocation_manual', $PAGE);
// prepare data to be displayed
$data = new stdClass();
$data->wsoutput = $wsoutput;
$data->peers = $peers;
$data->authors = $this->workshop->get_potential_authors($PAGE->context);
$data->reviewers = $this->workshop->get_potential_reviewers($PAGE->context);
$data->hlauthorid = $hlauthorid;
$data->hlreviewerid = $hlreviewerid;
$data->msg = $msg;
$data->useselfassessment = $this->workshop->useselfassessment;
return $uioutput->display_allocations($data);
// prepare data to be displayed
$data = new stdClass();
$data->wsoutput = $wsoutput;
$data->allocations = $allocations;
$data->userinfo = $userinfo;
$data->authors = $this->workshop->get_potential_authors($PAGE->context);
$data->reviewers = $this->workshop->get_potential_reviewers($PAGE->context);
$data->hlauthorid = $hlauthorid;
$data->hlreviewerid = $hlreviewerid;
$data->selfassessment = $this->workshop->useselfassessment;
// prepare paging bar
$pagingbar = new moodle_paging_bar();
$pagingbar->totalcount = count($data->authors);
$pagingbar->page = $page;
$pagingbar->perpage = self::PERPAGE;
$pagingbar->baseurl = $PAGE->url;
$pagingbar->pagevar = $pagingvar;
$pagingbar->nocurr = true;
$pagingbarout = $OUTPUT->paging_bar($pagingbar);
return $pagingbarout . $wsoutput->status_message($msg) . $uioutput->display_allocations($data) . $pagingbarout;
}
/**
* Returns the list of all allocations where the given users are involved
*
* We must use recordset here because we do not have any unique identifier available
*
* @param array [userid] => whatever
* @return moodle_recordset|null
*/
protected function get_allocations_recordset(array $users) {
global $DB, $PAGE;
if (empty($users)) {
return null;
}
if (count($users) > 9999) {
throw coding_exception('two many users');
}
list($authorids, $authorparams) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED, 'a0000');
list($reviewerids, $reviewerparams) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED, 'r0000');
$params = array_merge($authorparams, $reviewerparams);
$params['workshopid'] = $this->workshop->id;
$sql = "SELECT author.id AS authorid, author.firstname AS authorfirstname, author.lastname AS authorlastname,
author.picture AS authorpicture, author.imagealt AS authorimagealt,
s.id AS submissionid, s.title AS submissiontitle, s.grade AS submissiongrade,
a.id AS assessmentid, a.timecreated AS timeallocated, a.userid AS reviewerid,
reviewer.firstname AS reviewerfirstname, reviewer.lastname AS reviewerlastname,
reviewer.picture as reviewerpicture, reviewer.imagealt AS reviewerimagealt
FROM {user} author
LEFT JOIN {workshop_submissions} s ON (s.userid = author.id)
LEFT JOIN {workshop_assessments} a ON (s.id = a.submissionid)
LEFT JOIN {user} reviewer ON (a.userid = reviewer.id)
WHERE (author.id $authorids OR reviewer.id $reviewerids) AND (s.id IS NULL OR s.workshopid = :workshopid)
ORDER BY author.lastname,author.firstname,author.id,reviewer.lastname,reviewer.firstname,reviewer.id";
return $DB->get_recordset_sql($sql, $params);
}
}

View file

@ -56,16 +56,16 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
*/
public function display_allocations(stdClass $data) {
$wsoutput = $data->wsoutput; // moodle_mod_workshop_renderer
$peers = $data->peers; // array prepared array of all allocations data
$authors = $data->authors; // array submission authors
$allocations = $data->allocations; // array prepared array of all allocations data
$userinfo = $data->userinfo; // names and pictures of all required users
$authors = $data->authors; // array potential reviewees
$reviewers = $data->reviewers; // array potential submission reviewers
$hlauthorid = $data->hlauthorid; // int id of the author to highlight
$hlreviewerid = $data->hlreviewerid; // int id of the reviewer to highlight
$useselfassessment = $data->useselfassessment; // bool is the self-assessment allowed in this workshop?
$msg = $data->msg; // stdClass message to display
$selfassessment = $data->selfassessment; // bool is the self-assessment allowed in this workshop?
$wsoutput = $this->page->theme->get_renderer('mod_workshop', $this->page);
if (empty($peers)) {
if (empty($allocations)) {
return $wsoutput->status_message((object)array('text' => get_string('nosubmissions', 'workshop')));
}
@ -77,41 +77,39 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
$table->rowclasses = array();
$table->colclasses = array('reviewedby', 'peer', 'reviewerof');
$table->data = array();
foreach ($peers as $user) {
foreach ($allocations as $allocation) {
$row = array();
$row[] = $this->reviewers_of_participant($user, $peers, $reviewers, $useselfassessment);
$row[] = $this->participant($user);
$row[] = $this->reviewees_of_participant($user, $peers, $authors, $useselfassessment);
$row[] = $this->reviewers_of_participant($allocation, $userinfo, $reviewers, $selfassessment);
$row[] = $this->participant($allocation, $userinfo);
$row[] = $this->reviewees_of_participant($allocation, $userinfo, $authors, $selfassessment);
$thisrowclasses = array();
if ($user->id == $hlauthorid) {
if ($allocation->userid == $hlauthorid) {
$thisrowclasses[] = 'highlightreviewedby';
}
if ($user->id == $hlreviewerid) {
if ($allocation->userid == $hlreviewerid) {
$thisrowclasses[] = 'highlightreviewerof';
}
$table->rowclasses[] = implode(' ', $thisrowclasses);
$table->data[] = $row;
}
return $this->output->container($wsoutput->status_message($msg) . $this->output->table($table), 'manual-allocator');
return $this->output->container($this->output->table($table), 'manual-allocator');
}
/**
* Returns information about the workshop participant
*
* @param stdClass $user participant data
* @param workshop API
* @return string HTML code
*/
protected function participant(stdClass $user) {
$o = $this->output->user_picture($user, $this->page->course->id);
$o .= fullname($user);
protected function participant(stdClass $allocation, array $userinfo) {
$o = $this->output->user_picture($userinfo[$allocation->userid], $this->page->course->id);
$o .= fullname($userinfo[$allocation->userid]);
$o .= $this->output->container_start(array('submission'));
if (is_null($user->submissionid)) {
if (is_null($allocation->submissionid)) {
$o .= $this->output->container(get_string('nosubmissionfound', 'workshop'), 'info');
} else {
$o .= $this->output->container(format_string($user->submissiontitle), 'title');
if (is_null($user->submissiongrade)) {
$o .= $this->output->container(format_string($allocation->submissiontitle), 'title');
if (is_null($allocation->submissiongrade)) {
$o .= $this->output->container(get_string('nogradeyet', 'workshop'), array('grade', 'missing'));
} else {
$o .= $this->output->container(get_string('alreadygraded', 'workshop'), array('grade', 'missing'));
@ -124,41 +122,38 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
/**
* Returns information about the current reviewers of the given participant and a selector do add new one
*
* @param stdClass $user participant data
* @param array $peers objects with properties to display picture and fullname
* @param array $reviewers potential reviewers
* @param bool $useselfassessment shall a user be offered as a reviewer of him/herself
* @return string html code
*/
protected function reviewers_of_participant(stdClass $user, array $peers, array $reviewers, $useselfassessment) {
protected function reviewers_of_participant(stdClass $allocation, array $userinfo, array $reviewers, $selfassessment) {
$o = '';
if (is_null($user->submissionid)) {
if (is_null($allocation->submissionid)) {
$o .= $this->output->container(get_string('nothingtoreview', 'workshop'), 'info');
} else {
$exclude = array();
if (! $useselfassessment) {
$exclude[$user->id] = true;
if (! $selfassessment) {
$exclude[$allocation->userid] = true;
}
// todo add an option to exclude users without own submission
$options = $this->users_to_menu_options($reviewers, $exclude);
if ($options) {
$handler = new moodle_url($this->page->url, array('mode' => 'new', 'of' => $user->id, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'by', $options, 'addreviewof' . $user->id, '',
get_string('addreviewer', 'workshopallocation_manual'));
$handler = new moodle_url($this->page->url,
array('mode' => 'new', 'of' => $allocation->userid, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'by', $options, 'addreviewof' . $allocation->userid, '',
get_string('addreviewer', 'workshopallocation_manual'));
$select->nothinglabel = get_string('chooseuser', 'workshop');
$select->set_label(get_string('addreviewer', 'workshopallocation_manual'), $select->id);
$o .= $this->output->select($select);
}
}
$o .= $this->output->output_start_tag('ul', array());
foreach ($user->reviewedby as $reviewerid => $assessmentid) {
foreach ($allocation->reviewedby as $reviewerid => $assessmentid) {
$o .= $this->output->output_start_tag('li', array());
$userpic = new moodle_user_picture();
$userpic->user = $peers[$reviewerid];
$userpic->courseid = $this->page->course->id;
$userpic->size = 16;
$o .= $this->output->user_picture($userpic);
$o .= fullname($peers[$reviewerid]);
$allocationpic = new moodle_user_picture();
$allocationpic->user = $userinfo[$reviewerid];
$allocationpic->courseid = $this->page->course->id;
$allocationpic->size = 16;
$o .= $this->output->user_picture($allocationpic);
$o .= fullname($userinfo[$reviewerid]);
// delete icon
$handler = new moodle_url($this->page->url, array('mode' => 'del', 'what' => $assessmentid, 'sesskey' => sesskey()));
@ -173,28 +168,25 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
/**
* Returns information about the current reviewees of the given participant and a selector do add new one
*
* @param stdClass $user participant data
* @param array $peers objects with properties to display picture and fullname
* @param array $authors potential authors to be reviewed
* @param bool $useselfassessment shall a user be offered as a reviewer of him/herself
* @return string html code
*/
protected function reviewees_of_participant(stdClass $user, array $peers, array $authors, $useselfassessment) {
protected function reviewees_of_participant(stdClass $allocation, array $userinfo, array $authors, $selfassessment) {
$o = '';
if (is_null($user->submissionid)) {
if (is_null($allocation->submissionid)) {
$o .= $this->output->container(get_string('withoutsubmission', 'workshop'), 'info');
}
$exclude = array();
if (! $useselfassessment) {
$exclude[$user->id] = true;
if (! $selfassessment) {
$exclude[$allocation->userid] = true;
$o .= $this->output->container(get_string('selfassessmentdisabled', 'workshop'), 'info');
}
// todo add an option to exclude users without own submission
$options = $this->users_to_menu_options($authors, $exclude);
if ($options) {
$handler = new moodle_url($this->page->url, array('mode' => 'new', 'by' => $user->id, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'of', $options, 'addreviewby' . $user->id, '',
get_string('addreviewee', 'workshopallocation_manual'));
$handler = new moodle_url($this->page->url,
array('mode' => 'new', 'by' => $allocation->userid, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'of', $options, 'addreviewby' . $allocation->userid, '',
get_string('addreviewee', 'workshopallocation_manual'));
$select->nothinglabel = get_string('chooseuser', 'workshop');
$select->set_label(get_string('addreviewee', 'workshopallocation_manual'), $select->id);
$o .= $this->output->select($select);
@ -202,14 +194,14 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
$o .= $this->output->container(get_string('nothingtoreview', 'workshop'), 'info');
}
$o .= $this->output->output_start_tag('ul', array());
foreach ($user->reviewerof as $authorid => $assessmentid) {
foreach ($allocation->reviewerof as $authorid => $assessmentid) {
$o .= $this->output->output_start_tag('li', array());
$userpic = new moodle_user_picture();
$userpic->user = $peers[$authorid];
$userpic->courseid = $this->page->course->id;
$userpic->size = 16;
$o .= $this->output->user_picture($userpic, $this->page->course->id);
$o .= fullname($peers[$authorid]);
$allocationpic = new moodle_user_picture();
$allocationpic->user = $userinfo[$authorid];
$allocationpic->courseid = $this->page->course->id;
$allocationpic->size = 16;
$o .= $this->output->user_picture($allocationpic, $this->page->course->id);
$o .= fullname($userinfo[$authorid]);
// delete icon
$handler = new moodle_url($this->page->url, array('mode' => 'del', 'what' => $assessmentid, 'sesskey' => sesskey()));
@ -252,6 +244,4 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
return $this->output->action_icon($icon);
}
}