MDL-19717 workshop manual allocator - pagination support and performance issues
authorDavid Mudrak <david.mudrak@gmail.com>
Mon, 4 Jan 2010 18:07:38 +0000 (18:07 +0000)
committerDavid Mudrak <david.mudrak@gmail.com>
Mon, 4 Jan 2010 18:07:38 +0000 (18:07 +0000)
mod/workshop/allocation.php
mod/workshop/allocation/manual/lib.php
mod/workshop/allocation/manual/renderer.php
mod/workshop/locallib.php

index 6fcfb748f2962f63696dcab6e0a838b729d948d3..5ebf93870c4cd7d98e6b2d790238311560fbb211 100644 (file)
@@ -57,7 +57,7 @@ $initresult = $allocator->init();
 $wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE);
 echo $OUTPUT->header();
 
-$allocators = $workshop->installed_allocators();
+$allocators = workshop::installed_allocators();
 $currenttab = 'allocation';
 include(dirname(__FILE__) . '/tabs.php');
 
index 2182cb6b2d48b4c7da4e217147fa596ecf1d868b..147e8b0ac55af90164f45966990ae20d71236f4e 100644 (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;
+        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);
+        }
+
+
+        // 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;
                 }
             }
-            $rs->close();
         }
 
-        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;
-                }
+        // 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);
+        $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);
+    }
+
+
+
 }
index 8d408f39d55967e13f0ca904656d1be50b02ad58..769bd5aabb6f935fc27fb7442188a5d75e1143a1 100644 (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);
 
     }
-
-
 }
index 0b12eaa48994c84b9b570de9ad69dd0923545bdb..e914532304a1fbfdfdf5f5ba7ceb95d4d74aad39 100644 (file)
@@ -91,47 +91,60 @@ class workshop {
                                         // 3rd normal form with no real performance gain
     }
 
+    ////////////////////////////////////////////////////////////////////////////////
+    // Static methods                                                             //
+    ////////////////////////////////////////////////////////////////////////////////
+
     /**
-     * Given a list of user ids, returns the filtered one containing just ids of users with own submission
-     *
-     * Example submissions are ignored.
+     * Return list of available allocation methods
      *
-     * @param array $userids
-     * @return array
+     * @return array Array ['string' => 'string'] of localized allocation method names
      */
-    protected function users_with_submission(array $userids) {
-        global $DB;
-
-        if (empty($userids)) {
-            return array();
+    public static function installed_allocators() {
+        $installed = get_plugin_list('workshopallocation');
+        $forms = array();
+        foreach ($installed as $allocation => $allocationpath) {
+            if (file_exists($allocationpath . '/lib.php')) {
+                $forms[$allocation] = get_string('pluginname', 'workshopallocation_' . $allocation);
+            }
         }
-        $userswithsubmission = array();
-        list($usql, $uparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
-        $sql = "SELECT id,userid
-                  FROM {workshop_submissions}
-                 WHERE example = 0 AND workshopid = :workshopid AND userid $usql";
-        $params = array('workshopid' => $this->id);
-        $params = array_merge($params, $uparams);
-        $submissions = $DB->get_records_sql($sql, $params);
-        foreach ($submissions as $submission) {
-            $userswithsubmission[$submission->userid] = null;
+        // usability - make sure that manual allocation appears the first
+        if (isset($forms['manual'])) {
+            $m = array('manual' => $forms['manual']);
+            unset($forms['manual']);
+            $forms = array_merge($m, $forms);
         }
+        return $forms;
+    }
 
-        return $userswithsubmission;
+    /**
+     * Returns an array of options for the editors that are used for submitting and assessing instructions
+     *
+     * @param stdClass $context
+     * @return array
+     */
+    public static function instruction_editors_options(stdClass $context) {
+        return array('subdirs' => 1, 'maxbytes' => 0, 'maxfiles' => EDITOR_UNLIMITED_FILES,
+                     'changeformat' => 1, 'context' => $context, 'noclean' => 1, 'trusttext' => 0);
     }
 
+    ////////////////////////////////////////////////////////////////////////////////
+    // Workshop API                                                               //
+    ////////////////////////////////////////////////////////////////////////////////
+
     /**
      * Fetches all users with the capability mod/workshop:submit in the current context
      *
      * The returned objects contain id, lastname and firstname properties and are ordered by lastname,firstname
      *
+     * @todo handle with limits and groups
      * @param stdClass $context
      * @param bool $musthavesubmission If true, return only users who have already submitted. All possible authors otherwise.
      * @return array array[userid] => stdClass{->id ->lastname ->firstname}
      */
     public function get_potential_authors(stdClass $context, $musthavesubmission=true) {
         $users = get_users_by_capability($context, 'mod/workshop:submit',
-                    'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
+                    'u.id,u.lastname,u.firstname', 'u.lastname,u.firstname,u.id', 0, 1000, '', '', false, false, true);
         if ($musthavesubmission) {
             $users = array_intersect_key($users, $this->users_with_submission(array_keys($users)));
         }
@@ -143,13 +156,14 @@ class workshop {
      *
      * The returned objects contain id, lastname and firstname properties and are ordered by lastname,firstname
      *
+     * @todo handle with limits and groups
      * @param stdClass $context
      * @param bool $musthavesubmission If true, return only users who have already submitted. All possible users otherwise.
      * @return array array[userid] => stdClass{->id ->lastname ->firstname}
      */
     public function get_potential_reviewers(stdClass $context, $musthavesubmission=false) {
         $users = get_users_by_capability($context, 'mod/workshop:peerassess',
-                    'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
+                    'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname,u.id', 0, 1000, '', '', false, false, true);
         if ($musthavesubmission) {
             // users without their own submission can not be reviewers
             $users = array_intersect_key($users, $this->users_with_submission(array_keys($users)));
@@ -201,6 +215,26 @@ class workshop {
         return $grouped;
     }
 
+    /**
+     * Returns the list of all allocations (it est assigned assessments) in the workshop
+     *
+     * Assessments of example submissions are ignored
+     *
+     * @return array
+     */
+    public function get_allocations() {
+        global $DB;
+
+        $sql = 'SELECT a.id, a.submissionid, a.userid AS reviewerid,
+                       s.userid AS authorid
+                  FROM {workshop_assessments} a
+            INNER JOIN {workshop_submissions} s ON (a.submissionid = s.id)
+                 WHERE s.example = 0 AND s.workshopid = :workshopid';
+        $params = array('workshopid' => $this->id);
+
+        return $DB->get_records_sql($sql, $params);
+    }
+
     /**
      * Returns submissions from this workshop
      *
@@ -365,56 +399,6 @@ class workshop {
         return $DB->get_records_sql($sql, $params);
     }
 
-    /**
-     * Returns the list of allocations in the workshop
-     *
-     * This returns the list of all users who can submit their work or review submissions (or both
-     * which is the common case). So basically this is to return list of all students participating
-     * in the workshop. For every participant, it adds information about their submission and their
-     * reviews, if such information is available (null elsewhere).
-     *
-     * The returned structure is recordset of objects with following properties:
-     * [authorid] [authorfirstname] [authorlastname] [authorpicture] [authorimagealt]
-     * [submissionid] [submissiontitle] [submissiongrade] [assessmentid]
-     * [timeallocated] [reviewerid] [reviewerfirstname] [reviewerlastname]
-     * [reviewerpicture] [reviewerimagealt]
-     *
-     * TODO This should be refactored when capability handling proposed by Petr is implemented so that
-     * we can check capabilities directly in SQL joins.
-     * Note that the returned recordset includes participants without submission as well as those
-     * without any review allocated yet.
-     *
-     * @return null|stdClass moodle_recordset
-     */
-    public function get_allocations_recordset() {
-        global $DB, $PAGE;
-
-        $users = get_users_by_capability($PAGE->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
-                    'u.id', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
-
-        if (empty($users)) {
-            return null;
-        }
-
-        list($usql, $params) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED);
-        $params['workshopid'] = $this->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 $usql AND (s.id IS NULL OR s.workshopid = :workshopid)
-              ORDER BY author.lastname,author.firstname,reviewer.lastname,reviewer.firstname";
-
-        return $DB->get_recordset_sql($sql, $params);
-    }
-
     /**
      * Allocate a submission to a user for review
      *
@@ -506,28 +490,6 @@ class workshop {
         return $this->evaluationinstance;
     }
 
-    /**
-     * Return list of available allocation methods
-     *
-     * @return array Array ['string' => 'string'] of localized allocation method names
-     */
-    public function installed_allocators() {
-        $installed = get_plugin_list('workshopallocation');
-        $forms = array();
-        foreach ($installed as $allocation => $allocationpath) {
-            if (file_exists($allocationpath . '/lib.php')) {
-                $forms[$allocation] = get_string('pluginname', 'workshopallocation_' . $allocation);
-            }
-        }
-        // usability - make sure that manual allocation appears the first
-        if (isset($forms['manual'])) {
-            $m = array('manual' => $forms['manual']);
-            unset($forms['manual']);
-            $forms = array_merge($m, $forms);
-        }
-        return $forms;
-    }
-
     /**
      * Returns instance of submissions allocator
      *
@@ -761,22 +723,19 @@ class workshop {
             $task->link = $this->allocation_url();
             $authors     = array();
             $allocations = array(); // 'submissionid' => isallocated
-            $rs = $this->get_allocations_recordset();
-            if (!is_null($rs)) {
-                foreach ($rs as $allocation) {
-                    if (!isset($authors[$allocation->authorid])) {
-                        $authors[$allocation->authorid] = true;
+            $records = $this->get_allocations();
+            foreach ($records as $allocation) {
+                if (!isset($authors[$allocation->authorid])) {
+                    $authors[$allocation->authorid] = true;
+                }
+                if (isset($allocation->submissionid)) {
+                    if (!isset($allocations[$allocation->submissionid])) {
+                        $allocations[$allocation->submissionid] = false;
                     }
-                    if (isset($allocation->submissionid)) {
-                        if (!isset($allocations[$allocation->submissionid])) {
-                            $allocations[$allocation->submissionid] = false;
-                        }
-                        if (!empty($allocation->reviewerid)) {
-                            $allocations[$allocation->submissionid] = true;
-                        }
+                    if (!empty($allocation->reviewerid)) {
+                        $allocations[$allocation->submissionid] = true;
                     }
                 }
-                $rs->close();
             }
             $numofauthors     = count($authors);
             $numofsubmissions = count($allocations);
@@ -914,19 +873,6 @@ class workshop {
         return $this->grading_strategy_instance()->form_ready();
     }
 
-    /**
-     * @return array of available workshop phases
-     */
-    protected function available_phases() {
-        return array(
-            self::PHASE_SETUP       => true,
-            self::PHASE_SUBMISSION  => true,
-            self::PHASE_ASSESSMENT  => true,
-            self::PHASE_EVALUATION  => true,
-            self::PHASE_CLOSED      => true,
-        );
-    }
-
     /**
      * Switch to a new workshop phase
      *
@@ -966,17 +912,51 @@ class workshop {
         return $grade;
     }
 
-// Static methods
+    ////////////////////////////////////////////////////////////////////////////////
+    // Internal methods (implementation details)                                  //
+    ////////////////////////////////////////////////////////////////////////////////
 
     /**
-     * Returns an array of options for the editors that are used for submitting and assessing instructions
+     * Given a list of user ids, returns the filtered one containing just ids of users with own submission
      *
-     * @param stdClass $context
+     * Example submissions are ignored.
+     *
+     * @param array $userids
      * @return array
      */
-    public static function instruction_editors_options(stdClass $context) {
-        return array('subdirs' => 1, 'maxbytes' => 0, 'maxfiles' => EDITOR_UNLIMITED_FILES,
-                     'changeformat' => 1, 'context' => $context, 'noclean' => 1, 'trusttext' => 0);
+    protected function users_with_submission(array $userids) {
+        global $DB;
+
+        if (empty($userids)) {
+            return array();
+        }
+        $userswithsubmission = array();
+        list($usql, $uparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
+        $sql = "SELECT id,userid
+                  FROM {workshop_submissions}
+                 WHERE example = 0 AND workshopid = :workshopid AND userid $usql";
+        $params = array('workshopid' => $this->id);
+        $params = array_merge($params, $uparams);
+        $submissions = $DB->get_records_sql($sql, $params);
+        foreach ($submissions as $submission) {
+            $userswithsubmission[$submission->userid] = null;
+        }
+
+        return $userswithsubmission;
     }
 
+    /**
+     * @return array of available workshop phases
+     */
+    protected function available_phases() {
+        return array(
+            self::PHASE_SETUP       => true,
+            self::PHASE_SUBMISSION  => true,
+            self::PHASE_ASSESSMENT  => true,
+            self::PHASE_EVALUATION  => true,
+            self::PHASE_CLOSED      => true,
+        );
+    }
+
+
 }