Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/workshop/allocation/random/lib.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00027 defined('MOODLE_INTERNAL') || die();
00028 
00029 global $CFG;    // access to global variables during unit test
00030 
00031 require_once(dirname(dirname(__FILE__)) . '/lib.php');                  // interface definition
00032 require_once(dirname(dirname(dirname(__FILE__))) . '/locallib.php');    // workshop internal API
00033 require_once(dirname(__FILE__) . '/settings_form.php');                 // settings form
00034 
00038 class workshop_random_allocator implements workshop_allocator {
00039 
00041     const MSG_SUCCESS       = 1;
00042 
00044     const USERTYPE_AUTHOR   = 1;
00045     const USERTYPE_REVIEWER = 2;
00046 
00048     protected $workshop;
00049 
00051     protected $mform;
00052 
00056     public function __construct(workshop $workshop) {
00057         $this->workshop = $workshop;
00058     }
00059 
00063     public function init() {
00064         global $PAGE;
00065 
00066         $customdata = array();
00067         $customdata['workshop'] = $this->workshop;
00068         $this->mform = new workshop_random_allocator_form($PAGE->url, $customdata);
00069         if ($this->mform->is_cancelled()) {
00070             redirect($PAGE->url->out(false));
00071         } else if ($settings = $this->mform->get_data()) {
00072             // process validated data
00073             if (!confirm_sesskey()) {
00074                 throw new moodle_exception('confirmsesskeybad');
00075             }
00076             $o                  = array();      // list of output messages
00077             $numofreviews       = required_param('numofreviews', PARAM_INT);
00078             $numper             = required_param('numper', PARAM_INT);
00079             $excludesamegroup   = optional_param('excludesamegroup', false, PARAM_BOOL);
00080             $removecurrent      = optional_param('removecurrent', false, PARAM_BOOL);
00081             $assesswosubmission = optional_param('assesswosubmission', false, PARAM_BOOL);
00082             $addselfassessment  = optional_param('addselfassessment', false, PARAM_BOOL);
00083             $musthavesubmission = empty($assesswosubmission);
00084 
00085             $authors            = $this->workshop->get_potential_authors();
00086             $authors            = $this->workshop->get_grouped($authors);
00087             $reviewers          = $this->workshop->get_potential_reviewers($musthavesubmission);
00088             $reviewers          = $this->workshop->get_grouped($reviewers);
00089             $assessments        = $this->workshop->get_all_assessments();
00090 
00091             $newallocations     = array();      // array of array(reviewer => reviewee)
00092 
00093             if ($numofreviews) {
00094                 if ($removecurrent) {
00095                     // behave as if there were no current assessments
00096                     $curassessments = array();
00097                 } else {
00098                     $curassessments = $assessments;
00099                 }
00100                 $options                     = array();
00101                 $options['numofreviews']     = $numofreviews;
00102                 $options['numper']           = $numper;
00103                 $options['excludesamegroup'] = $excludesamegroup;
00104                 $randomallocations  = $this->random_allocation($authors, $reviewers, $curassessments, $o, $options);
00105                 $newallocations     = array_merge($newallocations, $randomallocations);
00106                 $o[] = 'ok::' . get_string('numofrandomlyallocatedsubmissions', 'workshopallocation_random', count($randomallocations));
00107                 unset($randomallocations);
00108             }
00109             if ($addselfassessment) {
00110                 $selfallocations    = $this->self_allocation($authors, $reviewers, $assessments);
00111                 $newallocations     = array_merge($newallocations, $selfallocations);
00112                 $o[] = 'ok::' . get_string('numofselfallocatedsubmissions', 'workshopallocation_random', count($selfallocations));
00113                 unset($selfallocations);
00114             }
00115             if (empty($newallocations)) {
00116                 $o[] = 'info::' . get_string('noallocationtoadd', 'workshopallocation_random');
00117             } else {
00118                 $newnonexistingallocations = $newallocations;
00119                 $this->filter_current_assessments($newnonexistingallocations, $assessments);
00120                 $this->add_new_allocations($newnonexistingallocations, $authors, $reviewers);
00121                 $allreviewers = $reviewers[0];
00122                 $allreviewersreloaded = false;
00123                 foreach ($newallocations as $newallocation) {
00124                     list($reviewerid, $authorid) = each($newallocation);
00125                     $a = new stdClass();
00126                     if (isset($allreviewers[$reviewerid])) {
00127                         $a->reviewername = fullname($allreviewers[$reviewerid]);
00128                     } else {
00129                         // this may happen if $musthavesubmission is true but the reviewer
00130                         // of the re-used assessment has not submitted anything. let us reload
00131                         // the list of reviewers name including those without their submission
00132                         if (!$allreviewersreloaded) {
00133                             $allreviewers = $this->workshop->get_potential_reviewers(false);
00134                             $allreviewersreloaded = true;
00135                         }
00136                         if (isset($allreviewers[$reviewerid])) {
00137                             $a->reviewername = fullname($allreviewers[$reviewerid]);
00138                         } else {
00139                             // this should not happen usually unless the list of participants was changed
00140                             // in between two cycles of allocations
00141                             $a->reviewername = '#'.$reviewerid;
00142                         }
00143                     }
00144                     if (isset($authors[0][$authorid])) {
00145                         $a->authorname = fullname($authors[0][$authorid]);
00146                     } else {
00147                         $a->authorname = '#'.$authorid;
00148                     }
00149                     if (in_array($newallocation, $newnonexistingallocations)) {
00150                         $o[] = 'ok::indent::' . get_string('allocationaddeddetail', 'workshopallocation_random', $a);
00151                     } else {
00152                         $o[] = 'ok::indent::' . get_string('allocationreuseddetail', 'workshopallocation_random', $a);
00153                     }
00154                 }
00155             }
00156             if ($removecurrent) {
00157                 $delassessments = $this->get_unkept_assessments($assessments, $newallocations, $addselfassessment);
00158                 // random allocator should not be able to delete assessments that have already been graded
00159                 // by reviewer
00160                 $o[] = 'info::' . get_string('numofdeallocatedassessment', 'workshopallocation_random', count($delassessments));
00161                 foreach ($delassessments as $delassessmentkey => $delassessmentid) {
00162                     $a = new stdclass();
00163                     $a->authorname      = fullname((object)array(
00164                             'lastname'  => $assessments[$delassessmentid]->authorlastname,
00165                             'firstname' => $assessments[$delassessmentid]->authorfirstname));
00166                     $a->reviewername    = fullname((object)array(
00167                             'lastname'  => $assessments[$delassessmentid]->reviewerlastname,
00168                             'firstname' => $assessments[$delassessmentid]->reviewerfirstname));
00169                     if (!is_null($assessments[$delassessmentid]->grade)) {
00170                         $o[] = 'error::indent::' . get_string('allocationdeallocategraded', 'workshopallocation_random', $a);
00171                         unset($delassessments[$delassessmentkey]);
00172                     } else {
00173                         $o[] = 'info::indent::' . get_string('assessmentdeleteddetail', 'workshopallocation_random', $a);
00174                     }
00175                 }
00176                 $this->workshop->delete_assessment($delassessments);
00177             }
00178             return $o;
00179         } else {
00180             // this branch is executed if the form is submitted but the data
00181             // doesn't validate and the form should be redisplayed
00182             // or on the first display of the form.
00183         }
00184     }
00185 
00189     public function ui() {
00190         global $PAGE;
00191 
00192         $output = $PAGE->get_renderer('mod_workshop');
00193 
00194         $m = optional_param('m', null, PARAM_INT);  // status message code
00195         $message = new workshop_message();
00196         if ($m == self::MSG_SUCCESS) {
00197             $message->set_text(get_string('randomallocationdone', 'workshopallocation_random'));
00198             $message->set_type(workshop_message::TYPE_OK);
00199         }
00200 
00201         $out  = $output->container_start('random-allocator');
00202         $out .= $output->render($message);
00203         // the nasty hack follows to bypass the sad fact that moodle quickforms do not allow to actually
00204         // return the HTML content, just to display it
00205         ob_start();
00206         $this->mform->display();
00207         $out .= ob_get_contents();
00208         ob_end_clean();
00209 
00210         // if there are some not-grouped participant in a group mode, warn the user
00211         $gmode = groups_get_activity_groupmode($this->workshop->cm, $this->workshop->course);
00212         if (VISIBLEGROUPS == $gmode or SEPARATEGROUPS == $gmode) {
00213             $users = $this->workshop->get_potential_authors() + $this->workshop->get_potential_reviewers();
00214             $users = $this->workshop->get_grouped($users);
00215             if (isset($users[0])) {
00216                 $nogroupusers = $users[0];
00217                 foreach ($users as $groupid => $groupusers) {
00218                     if ($groupid == 0) {
00219                         continue;
00220                     }
00221                     foreach ($groupusers as $groupuserid => $groupuser) {
00222                         unset($nogroupusers[$groupuserid]);
00223                     }
00224                 }
00225                 if (!empty($nogroupusers)) {
00226                     $list = array();
00227                     foreach ($nogroupusers as $nogroupuser) {
00228                         $list[] = fullname($nogroupuser);
00229                     }
00230                     $a = implode(', ', $list);
00231                     $out .= $output->box(get_string('nogroupusers', 'workshopallocation_random', $a), 'generalbox warning nogroupusers');
00232                 }
00233             }
00234         }
00235 
00236         // TODO $out .= $output->heading(get_string('stats', 'workshopallocation_random'));
00237 
00238         $out .= $output->container_end();
00239 
00240         return $out;
00241     }
00242 
00252     public static function delete_instance($workshopid) {
00253         return;
00254     }
00255 
00263     public static function available_numofreviews_list() {
00264         $options = array();
00265         $options[30] = 30;
00266         $options[20] = 20;
00267         $options[15] = 15;
00268         for ($i = 10; $i >= 0; $i--) {
00269             $options[$i] = $i;
00270         }
00271         return $options;
00272     }
00273 
00285     protected function self_allocation($authors=array(), $reviewers=array(), $assessments=array()) {
00286         if (!isset($authors[0]) || !isset($reviewers[0])) {
00287             // no authors or no reviewers
00288             return array();
00289         }
00290         $alreadyallocated = array();
00291         foreach ($assessments as $assessment) {
00292             if ($assessment->authorid == $assessment->reviewerid) {
00293                 $alreadyallocated[$assessment->authorid] = 1;
00294             }
00295         }
00296         $add = array(); // list of new allocations to be created
00297         foreach ($authors[0] as $authorid => $author) {
00298             // for all authors in all groups
00299             if (isset($reviewers[0][$authorid])) {
00300                 // if the author can be reviewer
00301                 if (!isset($alreadyallocated[$authorid])) {
00302                     // and the allocation does not exist yet, then
00303                     $add[] = array($authorid => $authorid);
00304                 }
00305             }
00306         }
00307         return $add;
00308     }
00309 
00318     protected function add_new_allocations(array $newallocations, array $dataauthors, array $datareviewers) {
00319         global $DB;
00320 
00321         $newallocations = $this->get_unique_allocations($newallocations);
00322         $authorids      = $this->get_author_ids($newallocations);
00323         $submissions    = $this->workshop->get_submissions($authorids);
00324         $submissions    = $this->index_submissions_by_authors($submissions);
00325         foreach ($newallocations as $newallocation) {
00326             list($reviewerid, $authorid) = each($newallocation);
00327             if (!isset($submissions[$authorid])) {
00328                 throw new moodle_exception('unabletoallocateauthorwithoutsubmission', 'workshop');
00329             }
00330             $submission = $submissions[$authorid];
00331             $status = $this->workshop->add_allocation($submission, $reviewerid, 1, true);   // todo configurable weight?
00332             if (workshop::ALLOCATION_EXISTS == $status) {
00333                 debugging('newallocations array contains existing allocation, this should not happen');
00334             }
00335         }
00336     }
00337 
00347     protected function index_submissions_by_authors($submissions) {
00348         $byauthor = array();
00349         if (is_array($submissions)) {
00350             foreach ($submissions as $submissionid => $submission) {
00351                 if (isset($byauthor[$submission->authorid])) {
00352                     throw new moodle_exception('moresubmissionsbyauthor', 'workshop');
00353                 }
00354                 $byauthor[$submission->authorid] = $submission;
00355             }
00356         }
00357         return $byauthor;
00358     }
00359 
00366     protected function get_author_ids($newallocations) {
00367         $authors = array();
00368         foreach ($newallocations as $newallocation) {
00369             $authorid = reset($newallocation);
00370             if (!in_array($authorid, $authors)) {
00371                 $authors[] = $authorid;
00372             }
00373         }
00374         return $authors;
00375     }
00376 
00383     protected function get_unique_allocations($newallocations) {
00384         return array_merge(array_map('unserialize', array_unique(array_map('serialize', $newallocations))));
00385     }
00386 
00400     protected function get_unkept_assessments($assessments, $newallocations, $keepselfassessments) {
00401         $keepids = array(); // keep these assessments
00402         foreach ($assessments as $assessmentid => $assessment) {
00403             $aaid = $assessment->authorid;
00404             $arid = $assessment->reviewerid;
00405             if (($keepselfassessments) && ($aaid == $arid)) {
00406                 $keepids[$assessmentid] = null;
00407                 continue;
00408             }
00409             foreach ($newallocations as $newallocation) {
00410                 list($nrid, $naid) = each($newallocation);
00411                 if (array($arid, $aaid) == array($nrid, $naid)) {
00412                     // re-allocation found - let us continue with the next assessment
00413                     $keepids[$assessmentid] = null;
00414                     continue 2;
00415                 }
00416             }
00417         }
00418         return array_keys(array_diff_key($assessments, $keepids));
00419     }
00420 
00441     protected function random_allocation($authors, $reviewers, $assessments, &$o, array $options) {
00442         if (empty($authors) || empty($reviewers)) {
00443             // nothing to be done
00444             return array();
00445         }
00446 
00447         $numofreviews = $options['numofreviews'];
00448         $numper       = $options['numper'];
00449 
00450         if (self::USERTYPE_AUTHOR == $numper) {
00451             // circles are authors, squares are reviewers
00452             $o[] = 'info::'.get_string('resultnumperauthor', 'workshopallocation_random', $numofreviews);
00453             $allcircles = $authors;
00454             $allsquares = $reviewers;
00455             // get current workload
00456             list($circlelinks, $squarelinks) = $this->convert_assessments_to_links($assessments);
00457         } elseif (self::USERTYPE_REVIEWER == $numper) {
00458             // circles are reviewers, squares are authors
00459             $o[] = 'info::'.get_string('resultnumperreviewer', 'workshopallocation_random', $numofreviews);
00460             $allcircles = $reviewers;
00461             $allsquares = $authors;
00462             // get current workload
00463             list($squarelinks, $circlelinks) = $this->convert_assessments_to_links($assessments);
00464         } else {
00465             throw new moodle_exception('unknownusertypepassed', 'workshop');
00466         }
00467         // get the users that are not in any group. in visible groups mode, these users are exluded
00468         // from allocation by this method
00469         // $nogroupcircles is array (int)$userid => undefined
00470         if (isset($allcircles[0])) {
00471             $nogroupcircles = array_flip(array_keys($allcircles[0]));
00472         } else {
00473             $nogroupcircles = array();
00474         }
00475         foreach ($allcircles as $circlegroupid => $circles) {
00476             if ($circlegroupid == 0) {
00477                 continue;
00478             }
00479             foreach ($circles as $circleid => $circle) {
00480                 unset($nogroupcircles[$circleid]);
00481             }
00482         }
00483         // $o[] = 'debug::circle links = ' . json_encode($circlelinks);
00484         // $o[] = 'debug::square links = ' . json_encode($squarelinks);
00485         $squareworkload         = array();  // individual workload indexed by squareid
00486         $squaregroupsworkload   = array();    // group workload indexed by squaregroupid
00487         foreach ($allsquares as $squaregroupid => $squares) {
00488             $squaregroupsworkload[$squaregroupid] = 0;
00489             foreach ($squares as $squareid => $square) {
00490                 if (!isset($squarelinks[$squareid])) {
00491                     $squarelinks[$squareid] = array();
00492                 }
00493                 $squareworkload[$squareid] = count($squarelinks[$squareid]);
00494                 $squaregroupsworkload[$squaregroupid] += $squareworkload[$squareid];
00495             }
00496             $squaregroupsworkload[$squaregroupid] /= count($squares);
00497         }
00498         unset($squaregroupsworkload[0]);    // [0] is not real group, it contains all users
00499         // $o[] = 'debug::square workload = ' . json_encode($squareworkload);
00500         // $o[] = 'debug::square group workload = ' . json_encode($squaregroupsworkload);
00501         $gmode = groups_get_activity_groupmode($this->workshop->cm, $this->workshop->course);
00502         if (SEPARATEGROUPS == $gmode) {
00503             // shuffle all groups but [0] which means "all users"
00504             $circlegroups = array_keys(array_diff_key($allcircles, array(0 => null)));
00505             shuffle($circlegroups);
00506         } else {
00507             // all users will be processed at once
00508             $circlegroups = array(0);
00509         }
00510         // $o[] = 'debug::circle groups = ' . json_encode($circlegroups);
00511         foreach ($circlegroups as $circlegroupid) {
00512             $o[] = 'debug::processing circle group id ' . $circlegroupid;
00513             $circles = $allcircles[$circlegroupid];
00514             // iterate over all circles in the group until the requested number of links per circle exists
00515             // or it is not possible to fulfill that requirment
00516             // during the first iteration, we try to make sure that at least one circlelink exists. during the
00517             // second iteration, we try to allocate two, etc.
00518             for ($requiredreviews = 1; $requiredreviews <= $numofreviews; $requiredreviews++) {
00519                 $this->shuffle_assoc($circles);
00520                 $o[] = 'debug::iteration ' . $requiredreviews;
00521                 foreach ($circles as $circleid => $circle) {
00522                     if (VISIBLEGROUPS == $gmode and isset($nogroupcircles[$circleid])) {
00523                         $o[] = 'debug::skipping circle id ' . $circleid;
00524                         continue;
00525                     }
00526                     $o[] = 'debug::processing circle id ' . $circleid;
00527                     if (!isset($circlelinks[$circleid])) {
00528                         $circlelinks[$circleid] = array();
00529                     }
00530                     $keeptrying     = true;     // is there a chance to find a square for this circle?
00531                     $failedgroups   = array();  // array of groupids where the square should be chosen from (because
00532                                                 // of their group workload) but it was not possible (for example there
00533                                                 // was the only square and it had been already connected
00534                     while ($keeptrying && (count($circlelinks[$circleid]) < $requiredreviews)) {
00535                         // firstly, choose a group to pick the square from
00536                         if (NOGROUPS == $gmode) {
00537                             if (in_array(0, $failedgroups)) {
00538                                 $keeptrying = false;
00539                                 $o[] = 'error::indent::'.get_string('resultnomorepeers', 'workshopallocation_random');
00540                                 break;
00541                             }
00542                             $targetgroup = 0;
00543                         } elseif (SEPARATEGROUPS == $gmode) {
00544                             if (in_array($circlegroupid, $failedgroups)) {
00545                                 $keeptrying = false;
00546                                 $o[] = 'error::indent::'.get_string('resultnomorepeersingroup', 'workshopallocation_random');
00547                                 break;
00548                             }
00549                             $targetgroup = $circlegroupid;
00550                         } elseif (VISIBLEGROUPS == $gmode) {
00551                             $trygroups = array_diff_key($squaregroupsworkload, array(0 => null));   // all but [0]
00552                             $trygroups = array_diff_key($trygroups, array_flip($failedgroups));     // without previous failures
00553                             if ($options['excludesamegroup']) {
00554                                 // exclude groups the circle is member of
00555                                 $excludegroups = array();
00556                                 foreach (array_diff_key($allcircles, array(0 => null)) as $exgroupid => $exgroupmembers) {
00557                                     if (array_key_exists($circleid, $exgroupmembers)) {
00558                                         $excludegroups[$exgroupid] = null;
00559                                     }
00560                                 }
00561                                 $trygroups = array_diff_key($trygroups, $excludegroups);
00562                             }
00563                             $targetgroup = $this->get_element_with_lowest_workload($trygroups);
00564                         }
00565                         if ($targetgroup === false) {
00566                             $keeptrying = false;
00567                             $o[] = 'error::indent::'.get_string('resultnotenoughpeers', 'workshopallocation_random');
00568                             break;
00569                         }
00570                         $o[] = 'debug::indent::next square should be from group id ' . $targetgroup;
00571                         // now, choose a square from the target group
00572                         $trysquares = array_intersect_key($squareworkload, $allsquares[$targetgroup]);
00573                         // $o[] = 'debug::indent::individual workloads in this group are ' . json_encode($trysquares);
00574                         unset($trysquares[$circleid]);  // can't allocate to self
00575                         $trysquares = array_diff_key($trysquares, array_flip($circlelinks[$circleid])); // can't re-allocate the same
00576                         $targetsquare = $this->get_element_with_lowest_workload($trysquares);
00577                         if (false === $targetsquare) {
00578                             $o[] = 'debug::indent::unable to find an available square. trying another group';
00579                             $failedgroups[] = $targetgroup;
00580                             continue;
00581                         }
00582                         $o[] = 'debug::indent::target square = ' . $targetsquare;
00583                         // ok - we have found the square
00584                         $circlelinks[$circleid][]       = $targetsquare;
00585                         $squarelinks[$targetsquare][]   = $circleid;
00586                         $squareworkload[$targetsquare]++;
00587                         $o[] = 'debug::indent::increasing square workload to ' . $squareworkload[$targetsquare];
00588                         if ($targetgroup) {
00589                             // recalculate the group workload
00590                             $squaregroupsworkload[$targetgroup] = 0;
00591                             foreach ($allsquares[$targetgroup] as $squareid => $square) {
00592                                 $squaregroupsworkload[$targetgroup] += $squareworkload[$squareid];
00593                             }
00594                             $squaregroupsworkload[$targetgroup] /= count($allsquares[$targetgroup]);
00595                             $o[] = 'debug::indent::increasing group workload to ' . $squaregroupsworkload[$targetgroup];
00596                         }
00597                     } // end of processing this circle
00598                 } // end of one iteration of processing circles in the group
00599             } // end of all iterations over circles in the group
00600         } // end of processing circle groups
00601         $returned = array();
00602         if (self::USERTYPE_AUTHOR == $numper) {
00603             // circles are authors, squares are reviewers
00604             foreach ($circlelinks as $circleid => $squares) {
00605                 foreach ($squares as $squareid) {
00606                     $returned[] = array($squareid => $circleid);
00607                 }
00608             }
00609         }
00610         if (self::USERTYPE_REVIEWER == $numper) {
00611             // circles are reviewers, squares are authors
00612             foreach ($circlelinks as $circleid => $squares) {
00613                 foreach ($squares as $squareid) {
00614                     $returned[] = array($circleid => $squareid);
00615                 }
00616             }
00617         }
00618         return $returned;
00619     }
00620 
00627     protected function convert_assessments_to_links($assessments) {
00628         $authorlinks    = array(); // [authorid]    => array(reviewerid, reviewerid, ...)
00629         $reviewerlinks  = array(); // [reviewerid]  => array(authorid, authorid, ...)
00630         foreach ($assessments as $assessment) {
00631             if (!isset($authorlinks[$assessment->authorid])) {
00632                 $authorlinks[$assessment->authorid] = array();
00633             }
00634             if (!isset($reviewerlinks[$assessment->reviewerid])) {
00635                 $reviewerlinks[$assessment->reviewerid] = array();
00636             }
00637             $authorlinks[$assessment->authorid][]   = $assessment->reviewerid;
00638             $reviewerlinks[$assessment->reviewerid][] = $assessment->authorid;
00639             }
00640         return array($authorlinks, $reviewerlinks);
00641     }
00642 
00652     protected function get_element_with_lowest_workload($workload) {
00653         $precision = 10;
00654 
00655         if (empty($workload)) {
00656             return false;
00657         }
00658         $minload = round(min($workload), $precision);
00659         $minkeys = array();
00660         foreach ($workload as $key => $val) {
00661             if (round($val, $precision) == $minload) {
00662                 $minkeys[$key] = $val;
00663             }
00664         }
00665         return array_rand($minkeys);
00666     }
00667 
00674     protected function shuffle_assoc(&$array) {
00675         if (count($array) > 1) {
00676             // $keys needs to be an array, no need to shuffle 1 item or empty arrays, anyway
00677             $keys = array_keys($array);
00678             shuffle($keys);
00679             foreach($keys as $key) {
00680                 $new[$key] = $array[$key];
00681             }
00682             $array = $new;
00683         }
00684         return true; // because this behaves like in-built shuffle(), which returns true
00685     }
00686 
00694     protected function filter_current_assessments(&$newallocations, $assessments) {
00695         foreach ($assessments as $assessment) {
00696             $allocation     = array($assessment->reviewerid => $assessment->authorid);
00697             $foundat        = array_keys($newallocations, $allocation);
00698             $newallocations = array_diff_key($newallocations, array_flip($foundat));
00699         }
00700     }
00701 }
 All Data Structures Namespaces Files Functions Variables Enumerations