/**
  * Use a static cache to try and reduce DB calls.
  *
  * @param int $userid The user id for this submission
  * @param int $group The groupid (returned)
  * @param stdClass|false $submission The stdClass submission or false (returned)
  * @param int $attemptnumber Return a specific attempt number (-1 for latest)
  */
 protected function get_group_and_submission($userid, &$group, &$submission, $attemptnumber)
 {
     $group = false;
     if (isset($this->submissiongroups[$userid])) {
         $group = $this->submissiongroups[$userid];
     } else {
         $group = $this->setaskment->get_submission_group($userid, false);
         $this->submissiongroups[$userid] = $group;
     }
     $groupid = 0;
     if ($group) {
         $groupid = $group->id;
     }
     // Static cache is keyed by groupid and attemptnumber.
     // We may need both the latest and previous attempt in the same page.
     if (isset($this->groupsubmissions[$groupid . ':' . $attemptnumber])) {
         $submission = $this->groupsubmissions[$groupid . ':' . $attemptnumber];
     } else {
         $submission = $this->setaskment->get_group_submission($userid, $groupid, false, $attemptnumber);
         $this->groupsubmissions[$groupid . ':' . $attemptnumber] = $submission;
     }
 }
 /**
  * Save multiple student grades for a single setaskment.
  *
  * @param int $setaskmentid The id of the setaskment
  * @param boolean $applytoall If set to true and this is a team setaskment,
  * apply the grade to all members of the group
  * @param array $grades grade data for one or more students that includes
  *                  userid - The id of the student being graded
  *                  grade - The grade (ignored if the setaskment uses advanced grading)
  *                  attemptnumber - The attempt number
  *                  addattempt - Allow another attempt
  *                  workflowstate - New workflow state
  *                  plugindata - Custom data used by plugins
  *                  advancedgradingdata - Optional Advanced grading data
  * @throws invalid_parameter_exception if multiple grades are supplied for
  * a team setaskment that has $applytoall set to true
  * @return null
  * @since Moodle 2.7
  */
 public static function save_grades($setaskmentid, $applytoall = false, $grades)
 {
     global $CFG, $USER;
     require_once "{$CFG->dirroot}/mod/setask/locallib.php";
     $params = self::validate_parameters(self::save_grades_parameters(), array('setaskmentid' => $setaskmentid, 'applytoall' => $applytoall, 'grades' => $grades));
     $cm = get_coursemodule_from_instance('setask', $params['setaskmentid'], 0, false, MUST_EXIST);
     $context = context_module::instance($cm->id);
     self::validate_context($context);
     $setaskment = new setask($context, $cm, null);
     if ($setaskment->get_instance()->teamsubmission && $params['applytoall']) {
         // Check that only 1 user per submission group is provided.
         $groupids = array();
         foreach ($params['grades'] as $gradeinfo) {
             $group = $setaskment->get_submission_group($gradeinfo['userid']);
             if (in_array($group->id, $groupids)) {
                 throw new invalid_parameter_exception('Multiple grades for the same team have been supplied ' . ' this is not permitted when the applytoall flag is set');
             } else {
                 $groupids[] = $group->id;
             }
         }
     }
     foreach ($params['grades'] as $gradeinfo) {
         $gradedata = (object) $gradeinfo['plugindata'];
         $gradedata->addattempt = $gradeinfo['addattempt'];
         $gradedata->attemptnumber = $gradeinfo['attemptnumber'];
         $gradedata->workflowstate = $gradeinfo['workflowstate'];
         $gradedata->applytoall = $params['applytoall'];
         $gradedata->grade = $gradeinfo['grade'];
         if (!empty($gradeinfo['advancedgradingdata'])) {
             $advancedgrading = array();
             $criteria = reset($gradeinfo['advancedgradingdata']);
             foreach ($criteria as $key => $criterion) {
                 $details = array();
                 foreach ($criterion as $value) {
                     foreach ($value['fillings'] as $filling) {
                         $details[$value['criterionid']] = $filling;
                     }
                 }
                 $advancedgrading[$key] = $details;
             }
             $gradedata->advancedgrading = $advancedgrading;
         }
         $setaskment->save_grade($gradeinfo['userid'], $gradedata);
     }
     return null;
 }