Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mudrd8mz committed Apr 13, 2012
1 parent 668a499 commit 0ee608e
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 118 deletions.
284 changes: 174 additions & 110 deletions mod/workshop/allocation/random/lib.php
Expand Up @@ -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;

Expand All @@ -67,120 +63,122 @@ public function init() {
$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');
$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;
}
$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();
$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 {
$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();
// 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 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);
// 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);
}
}
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;
} 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.
$this->workshop->delete_assessment($delassessments);
}
return $o;
}

/**
Expand Down Expand Up @@ -447,14 +445,14 @@ protected function random_allocation($authors, $reviewers, $assessments, &$o, ar
$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;
Expand Down Expand Up @@ -599,15 +597,15 @@ protected function random_allocation($authors, $reviewers, $assessments, &$o, ar
} // 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) {
$returned[] = array($squareid => $circleid);
}
}
}
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) {
Expand Down Expand Up @@ -699,3 +697,69 @@ protected function filter_current_assessments(&$newallocations, $assessments) {
}
}
}


/**
* 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;
}
}
6 changes: 3 additions & 3 deletions mod/workshop/allocation/random/settings_form.php
Expand Up @@ -63,15 +63,15 @@ public function definition() {
$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);

Expand Down
11 changes: 6 additions & 5 deletions mod/workshop/allocation/random/version.php
Expand Up @@ -17,14 +17,15 @@
/**
* Defines the version of the subplugin
*
* @package workshopallocation
* @subpackage random
* @package workshopallocation_random
* @subpackage mod_workshop
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
* @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';
$plugin->component = 'workshopallocation_random';
$plugin->version = 2012032800;
$plugin->requires = 2012032300;
$plugin->maturity = MATURITY_STABLE;

0 comments on commit 0ee608e

Please sign in to comment.