From 0ee608e99dc8da484432d1c1e21771a2162eeeed Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Wed, 28 Mar 2012 15:30:20 +0200 Subject: [PATCH] MDL-32235 preparing the random allocator's API The random allocator's init() method was split into two logical parts. The init() now handles data from the form and executes the new execute() method to do the actual job. The execute() method will be called by the future scheduled allocator, too. --- mod/workshop/allocation/random/lib.php | 296 +++++++++++------- .../allocation/random/settings_form.php | 6 +- mod/workshop/allocation/random/version.php | 11 +- 3 files changed, 189 insertions(+), 124 deletions(-) diff --git a/mod/workshop/allocation/random/lib.php b/mod/workshop/allocation/random/lib.php index 0aef31f8368..2e13d0f969e 100644 --- a/mod/workshop/allocation/random/lib.php +++ b/mod/workshop/allocation/random/lib.php @@ -40,10 +40,6 @@ class workshop_random_allocator implements workshop_allocator { /** constants used to pass status messages between init() and ui() */ const MSG_SUCCESS = 1; - /** constants used in allocation settings form */ - const USERTYPE_AUTHOR = 1; - const USERTYPE_REVIEWER = 2; - /** workshop instance */ protected $workshop; @@ -67,122 +63,124 @@ class workshop_random_allocator implements workshop_allocator { $customdata['workshop'] = $this->workshop; $this->mform = new workshop_random_allocator_form($PAGE->url, $customdata); if ($this->mform->is_cancelled()) { - redirect($PAGE->url->out(false)); + redirect($this->workshop->view_url()); } else if ($settings = $this->mform->get_data()) { - // process validated data - if (!confirm_sesskey()) { - throw new moodle_exception('confirmsesskeybad'); - } - $o = array(); // list of output messages - $numofreviews = required_param('numofreviews', PARAM_INT); - $numper = required_param('numper', PARAM_INT); - $excludesamegroup = optional_param('excludesamegroup', false, PARAM_BOOL); - $removecurrent = optional_param('removecurrent', false, PARAM_BOOL); - $assesswosubmission = optional_param('assesswosubmission', false, PARAM_BOOL); - $addselfassessment = optional_param('addselfassessment', false, PARAM_BOOL); - $musthavesubmission = empty($assesswosubmission); - - $authors = $this->workshop->get_potential_authors(); - $authors = $this->workshop->get_grouped($authors); - $reviewers = $this->workshop->get_potential_reviewers($musthavesubmission); - $reviewers = $this->workshop->get_grouped($reviewers); - $assessments = $this->workshop->get_all_assessments(); - - $newallocations = array(); // array of array(reviewer => reviewee) - - if ($numofreviews) { - if ($removecurrent) { - // behave as if there were no current assessments - $curassessments = array(); - } else { - $curassessments = $assessments; - } - $options = array(); - $options['numofreviews'] = $numofreviews; - $options['numper'] = $numper; - $options['excludesamegroup'] = $excludesamegroup; - $randomallocations = $this->random_allocation($authors, $reviewers, $curassessments, $o, $options); - $newallocations = array_merge($newallocations, $randomallocations); - $o[] = 'ok::' . get_string('numofrandomlyallocatedsubmissions', 'workshopallocation_random', count($randomallocations)); - unset($randomallocations); - } - if ($addselfassessment) { - $selfallocations = $this->self_allocation($authors, $reviewers, $assessments); - $newallocations = array_merge($newallocations, $selfallocations); - $o[] = 'ok::' . get_string('numofselfallocatedsubmissions', 'workshopallocation_random', count($selfallocations)); - unset($selfallocations); - } - if (empty($newallocations)) { - $o[] = 'info::' . get_string('noallocationtoadd', 'workshopallocation_random'); - } else { - $newnonexistingallocations = $newallocations; - $this->filter_current_assessments($newnonexistingallocations, $assessments); - $this->add_new_allocations($newnonexistingallocations, $authors, $reviewers); - $allreviewers = $reviewers[0]; - $allreviewersreloaded = false; - foreach ($newallocations as $newallocation) { - list($reviewerid, $authorid) = each($newallocation); - $a = new stdClass(); - if (isset($allreviewers[$reviewerid])) { - $a->reviewername = fullname($allreviewers[$reviewerid]); - } else { - // this may happen if $musthavesubmission is true but the reviewer - // of the re-used assessment has not submitted anything. let us reload - // the list of reviewers name including those without their submission - if (!$allreviewersreloaded) { - $allreviewers = $this->workshop->get_potential_reviewers(false); - $allreviewersreloaded = true; - } - if (isset($allreviewers[$reviewerid])) { - $a->reviewername = fullname($allreviewers[$reviewerid]); - } else { - // this should not happen usually unless the list of participants was changed - // in between two cycles of allocations - $a->reviewername = '#'.$reviewerid; - } - } - if (isset($authors[0][$authorid])) { - $a->authorname = fullname($authors[0][$authorid]); - } else { - $a->authorname = '#'.$authorid; - } - if (in_array($newallocation, $newnonexistingallocations)) { - $o[] = 'ok::indent::' . get_string('allocationaddeddetail', 'workshopallocation_random', $a); - } else { - $o[] = 'ok::indent::' . get_string('allocationreuseddetail', 'workshopallocation_random', $a); - } - } - } - if ($removecurrent) { - $delassessments = $this->get_unkept_assessments($assessments, $newallocations, $addselfassessment); - // random allocator should not be able to delete assessments that have already been graded - // by reviewer - $o[] = 'info::' . get_string('numofdeallocatedassessment', 'workshopallocation_random', count($delassessments)); - foreach ($delassessments as $delassessmentkey => $delassessmentid) { - $a = new stdclass(); - $a->authorname = fullname((object)array( - 'lastname' => $assessments[$delassessmentid]->authorlastname, - 'firstname' => $assessments[$delassessmentid]->authorfirstname)); - $a->reviewername = fullname((object)array( - 'lastname' => $assessments[$delassessmentid]->reviewerlastname, - 'firstname' => $assessments[$delassessmentid]->reviewerfirstname)); - if (!is_null($assessments[$delassessmentid]->grade)) { - $o[] = 'error::indent::' . get_string('allocationdeallocategraded', 'workshopallocation_random', $a); - unset($delassessments[$delassessmentkey]); - } else { - $o[] = 'info::indent::' . get_string('assessmentdeleteddetail', 'workshopallocation_random', $a); - } - } - $this->workshop->delete_assessment($delassessments); - } - return $o; + $settings = workshop_random_allocator_setting::instance_from_object($settings); + return $this->execute($settings); } else { // this branch is executed if the form is submitted but the data // doesn't validate and the form should be redisplayed // or on the first display of the form. + return array(); } } + /** + * Executes the allocation based on the given settings + * + * @param workshop_random_allocator_setting $settings + * @return array of output messages + */ + public function execute(workshop_random_allocator_setting $settings) { + + $o = array(); + + $authors = $this->workshop->get_potential_authors(); + $authors = $this->workshop->get_grouped($authors); + $reviewers = $this->workshop->get_potential_reviewers(!$settings->assesswosubmission); + $reviewers = $this->workshop->get_grouped($reviewers); + $assessments = $this->workshop->get_all_assessments(); + + $newallocations = array(); // array of array(reviewer => reviewee) + + if ($settings->numofreviews) { + if ($settings->removecurrent) { + // behave as if there were no current assessments + $curassessments = array(); + } else { + $curassessments = $assessments; + } + $options = array(); + $options['numofreviews'] = $settings->numofreviews; + $options['numper'] = $settings->numper; + $options['excludesamegroup'] = $settings->excludesamegroup; + $randomallocations = $this->random_allocation($authors, $reviewers, $curassessments, $o, $options); + $newallocations = array_merge($newallocations, $randomallocations); + $o[] = 'ok::' . get_string('numofrandomlyallocatedsubmissions', 'workshopallocation_random', count($randomallocations)); + unset($randomallocations); + } + if ($settings->addselfassessment) { + $selfallocations = $this->self_allocation($authors, $reviewers, $assessments); + $newallocations = array_merge($newallocations, $selfallocations); + $o[] = 'ok::' . get_string('numofselfallocatedsubmissions', 'workshopallocation_random', count($selfallocations)); + unset($selfallocations); + } + if (empty($newallocations)) { + $o[] = 'info::' . get_string('noallocationtoadd', 'workshopallocation_random'); + } else { + $newnonexistingallocations = $newallocations; + $this->filter_current_assessments($newnonexistingallocations, $assessments); + $this->add_new_allocations($newnonexistingallocations, $authors, $reviewers); + $allreviewers = $reviewers[0]; + $allreviewersreloaded = false; + foreach ($newallocations as $newallocation) { + list($reviewerid, $authorid) = each($newallocation); + $a = new stdClass(); + if (isset($allreviewers[$reviewerid])) { + $a->reviewername = fullname($allreviewers[$reviewerid]); + } else { + // this may happen if $settings->assesswosubmission is false but the reviewer + // of the re-used assessment has not submitted anything. let us reload + // the list of reviewers name including those without their submission + if (!$allreviewersreloaded) { + $allreviewers = $this->workshop->get_potential_reviewers(false); + $allreviewersreloaded = true; + } + if (isset($allreviewers[$reviewerid])) { + $a->reviewername = fullname($allreviewers[$reviewerid]); + } else { + // this should not happen usually unless the list of participants was changed + // in between two cycles of allocations + $a->reviewername = '#'.$reviewerid; + } + } + if (isset($authors[0][$authorid])) { + $a->authorname = fullname($authors[0][$authorid]); + } else { + $a->authorname = '#'.$authorid; + } + if (in_array($newallocation, $newnonexistingallocations)) { + $o[] = 'ok::indent::' . get_string('allocationaddeddetail', 'workshopallocation_random', $a); + } else { + $o[] = 'ok::indent::' . get_string('allocationreuseddetail', 'workshopallocation_random', $a); + } + } + } + if ($settings->removecurrent) { + $delassessments = $this->get_unkept_assessments($assessments, $newallocations, $settings->addselfassessment); + // random allocator should not be able to delete assessments that have already been graded + // by reviewer + $o[] = 'info::' . get_string('numofdeallocatedassessment', 'workshopallocation_random', count($delassessments)); + foreach ($delassessments as $delassessmentkey => $delassessmentid) { + $a = new stdclass(); + $a->authorname = fullname((object)array( + 'lastname' => $assessments[$delassessmentid]->authorlastname, + 'firstname' => $assessments[$delassessmentid]->authorfirstname)); + $a->reviewername = fullname((object)array( + 'lastname' => $assessments[$delassessmentid]->reviewerlastname, + 'firstname' => $assessments[$delassessmentid]->reviewerfirstname)); + if (!is_null($assessments[$delassessmentid]->grade)) { + $o[] = 'error::indent::' . get_string('allocationdeallocategraded', 'workshopallocation_random', $a); + unset($delassessments[$delassessmentkey]); + } else { + $o[] = 'info::indent::' . get_string('assessmentdeleteddetail', 'workshopallocation_random', $a); + } + } + $this->workshop->delete_assessment($delassessments); + } + return $o; + } + /** * Returns the HTML code to print the user interface */ @@ -447,14 +445,14 @@ class workshop_random_allocator implements workshop_allocator { $numofreviews = $options['numofreviews']; $numper = $options['numper']; - if (self::USERTYPE_AUTHOR == $numper) { + if (workshop_random_allocator_setting::NUMPER_SUBMISSION == $numper) { // circles are authors, squares are reviewers $o[] = 'info::'.get_string('resultnumperauthor', 'workshopallocation_random', $numofreviews); $allcircles = $authors; $allsquares = $reviewers; // get current workload list($circlelinks, $squarelinks) = $this->convert_assessments_to_links($assessments); - } elseif (self::USERTYPE_REVIEWER == $numper) { + } elseif (workshop_random_allocator_setting::NUMPER_REVIEWER == $numper) { // circles are reviewers, squares are authors $o[] = 'info::'.get_string('resultnumperreviewer', 'workshopallocation_random', $numofreviews); $allcircles = $reviewers; @@ -599,7 +597,7 @@ class workshop_random_allocator implements workshop_allocator { } // end of all iterations over circles in the group } // end of processing circle groups $returned = array(); - if (self::USERTYPE_AUTHOR == $numper) { + if (workshop_random_allocator_setting::NUMPER_SUBMISSION == $numper) { // circles are authors, squares are reviewers foreach ($circlelinks as $circleid => $squares) { foreach ($squares as $squareid) { @@ -607,7 +605,7 @@ class workshop_random_allocator implements workshop_allocator { } } } - if (self::USERTYPE_REVIEWER == $numper) { + if (workshop_random_allocator_setting::NUMPER_REVIEWER == $numper) { // circles are reviewers, squares are authors foreach ($circlelinks as $circleid => $squares) { foreach ($squares as $squareid) { @@ -699,3 +697,69 @@ class workshop_random_allocator implements workshop_allocator { } } } + + +/** + * Data object defining the settings structure for the random allocator + */ +class workshop_random_allocator_setting { + + /** aim to a number of reviews per one submission {@see self::$numper} */ + const NUMPER_SUBMISSION = 1; + /** aim to a number of reviews per one reviewer {@see self::$numper} */ + const NUMPER_REVIEWER = 2; + + /** @var int number of reviews */ + public $numofreviews; + /** @var int either {@link self::NUMPER_SUBMISSION} or {@link self::NUMPER_REVIEWER} */ + public $numper; + /** @var bool prevent reviews by peers from the same group */ + public $excludesamegroup; + /** @var bool remove current allocations */ + public $removecurrent; + /** @var bool participants can assess without having submitted anything */ + public $assesswosubmission; + /** @var bool add self-assessments */ + public $addselfassessment; + + /** + * Use the factory method {@link self::instance_from_object()} + */ + protected function __construct() { + } + + /** + * Factory method making the instance from data in the passed object + * + * @param stdClass $data an object holding the values for our public properties + * @return workshop_random_allocator_setting + */ + public static function instance_from_object(stdClass $data) { + $i = new self(); + + if (!isset($data->numofreviews)) { + throw new coding_exception('Missing value of the numofreviews property'); + } else { + $i->numofreviews = (int)$data->numofreviews; + } + + if (!isset($data->numper)) { + throw new coding_exception('Missing value of the numper property'); + } else { + $i->numper = (int)$data->numper; + if ($i->numper !== self::NUMPER_SUBMISSION and $i->numper !== self::NUMPER_REVIEWER) { + throw new coding_exception('Invalid value of the numper property'); + } + } + + foreach (array('excludesamegroup', 'removecurrent', 'assesswosubmission', 'addselfassessment') as $k) { + if (isset($data->$k)) { + $i->$k = (bool)$data->$k; + } else { + $i->$k = false; + } + } + + return $i; + } +} diff --git a/mod/workshop/allocation/random/settings_form.php b/mod/workshop/allocation/random/settings_form.php index b4620354f42..28a523db6a2 100644 --- a/mod/workshop/allocation/random/settings_form.php +++ b/mod/workshop/allocation/random/settings_form.php @@ -63,15 +63,15 @@ class workshop_random_allocator_form extends moodleform { $mform->addElement('static', 'groupmode', get_string('groupmode', 'group'), $grouplabel); $options_numper = array( - workshop_random_allocator::USERTYPE_AUTHOR => get_string('numperauthor', 'workshopallocation_random'), - workshop_random_allocator::USERTYPE_REVIEWER => get_string('numperreviewer', 'workshopallocation_random') + workshop_random_allocator_setting::NUMPER_SUBMISSION => get_string('numperauthor', 'workshopallocation_random'), + workshop_random_allocator_setting::NUMPER_REVIEWER => get_string('numperreviewer', 'workshopallocation_random') ); $grpnumofreviews = array(); $grpnumofreviews[] = $mform->createElement('select', 'numofreviews', '', workshop_random_allocator::available_numofreviews_list()); $mform->setDefault('numofreviews', $plugindefaults->numofreviews); $grpnumofreviews[] = $mform->createElement('select', 'numper', '', $options_numper); - $mform->setDefault('numper', workshop_random_allocator::USERTYPE_AUTHOR); + $mform->setDefault('numper', workshop_random_allocator_setting::NUMPER_SUBMISSION); $mform->addGroup($grpnumofreviews, 'grpnumofreviews', get_string('numofreviews', 'workshopallocation_random'), array(' '), false); diff --git a/mod/workshop/allocation/random/version.php b/mod/workshop/allocation/random/version.php index e412a93ce3b..73e2e36d71a 100644 --- a/mod/workshop/allocation/random/version.php +++ b/mod/workshop/allocation/random/version.php @@ -17,14 +17,15 @@ /** * Defines the version of the subplugin * - * @package workshopallocation - * @subpackage random + * @package workshopallocation_random + * @subpackage mod_workshop * @copyright 2009 David Mudrak * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2010090501; -$plugin->requires = 2010090501; // Requires this Moodle version -$plugin->component = 'workshopallocation_random'; \ No newline at end of file +$plugin->component = 'workshopallocation_random'; +$plugin->version = 2012032800; +$plugin->requires = 2012032300; +$plugin->maturity = MATURITY_STABLE; \ No newline at end of file