[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/mod/quiz/report/grading/ -> report.php (source)

   1  <?php  // $Id: report.php,v 1.25.2.13 2008/08/12 06:07:13 tjhunt Exp $
   2  /**
   3   * Quiz report to help teachers manually grade quiz questions that need it.
   4   *
   5   * @package quiz
   6   * @subpackage reports
   7   */
   8  
   9  // Flow of the file:
  10  //     Get variables, run essential queries
  11  //     Check for post data submitted.  If exists, then process data (the data is the grades and comments for essay questions)
  12  //     Check for userid, attemptid, or gradeall and for questionid.  If found, print out the appropriate essay question attempts
  13  //     Switch:
  14  //         first case: print out all essay questions in quiz and the number of ungraded attempts
  15  //         second case: print out all users and their attempts for a specific essay question
  16  
  17  require_once($CFG->dirroot . "/mod/quiz/editlib.php");
  18  require_once($CFG->libdir . '/tablelib.php');
  19  
  20  /**
  21   * Quiz report to help teachers manually grade quiz questions that need it.
  22   *
  23   * @package quiz
  24   * @subpackage reports
  25   */
  26  class quiz_report extends quiz_default_report {
  27      /**
  28       * Displays the report.
  29       */
  30      function display($quiz, $cm, $course) {
  31          global $CFG, $QTYPES;
  32          
  33          $viewoptions = array('mode'=>'grading', 'q'=>$quiz->id);
  34  
  35          if ($questionid = optional_param('questionid', 0, PARAM_INT)){
  36              $viewoptions += array('questionid'=>$questionid);
  37          }
  38          
  39          // grade question specific parameters
  40          $gradeungraded  = optional_param('gradeungraded', 0, PARAM_INT);
  41          
  42          if ($userid    = optional_param('userid', 0, PARAM_INT)){
  43              $viewoptions += array('userid'=>$userid);
  44          }
  45          if ($attemptid = optional_param('attemptid', 0, PARAM_INT)){
  46              $viewoptions += array('attemptid'=>$attemptid);
  47          }
  48          if ($gradeall  = optional_param('gradeall', 0, PARAM_INT)){
  49              $viewoptions += array('gradeall'=> $gradeall);
  50          }
  51          if ($gradeungraded  = optional_param('gradeungraded', 0, PARAM_INT)){
  52              $viewoptions += array('gradeungraded'=> $gradeungraded);
  53          }
  54          if ($gradenextungraded  = optional_param('gradenextungraded', 0, PARAM_INT)){
  55              $viewoptions += array('gradenextungraded'=> $gradenextungraded);
  56          }
  57          
  58          
  59          $this->cm = $cm;
  60          
  61          $this->print_header_and_tabs($cm, $course, $quiz, $reportmode="grading");
  62  
  63          // Check permissions
  64          $this->context = get_context_instance(CONTEXT_MODULE, $cm->id);
  65          if (!has_capability('mod/quiz:grade', $this->context)) {
  66              notify(get_string('gradingnotallowed', 'quiz_grading'));
  67              return true;
  68          }
  69  
  70          $gradeableqs = quiz_report_load_questions($quiz);
  71          foreach ($gradeableqs as $qid => $questionformenu){
  72              if (!$QTYPES[$questionformenu->qtype]->is_manual_graded()){
  73                  unset($gradeableqs[$qid]);
  74              }
  75          }
  76          
  77          if (empty($gradeableqs)) {
  78              print_heading(get_string('noessayquestionsfound', 'quiz'));
  79              return true;
  80          } else if (count($gradeableqs)==1){
  81              $questionid = array_shift(array_keys($gradeableqs));
  82          }
  83  
  84          $currentgroup = groups_get_activity_group($this->cm, true);
  85          $this->users     = get_users_by_capability($this->context, 'mod/quiz:attempt','','','','',$currentgroup,'',false);
  86          $this->userids   = implode(',', array_keys($this->users));
  87  
  88  
  89          if (!empty($questionid)) {
  90              if (!isset($gradeableqs[$questionid])){
  91                  error("Gradeable question with id $questionid not found");
  92              } else {
  93                  $question =& $gradeableqs[$questionid];
  94              }
  95              $question->maxgrade = get_field('quiz_question_instances', 'grade', 'quiz', $quiz->id, 'question', $question->id);
  96  
  97              // Some of the questions code is optimised to work with several questions
  98              // at once so it wants the question to be in an array. The array key
  99              // must be the question id.
 100              $key = $question->id;
 101              $questions[$key] = &$question;
 102  
 103              // We need to add additional questiontype specific information to
 104              // the question objects.
 105              if (!get_question_options($questions)) {
 106                  error("Unable to load questiontype specific question information");
 107              }
 108              // This will have extended the question object so that it now holds
 109              // all the information about the questions that may be needed later.
 110          }
 111  
 112          add_to_log($course->id, "quiz", "manualgrading", "report.php?mode=grading&amp;q=$quiz->id", "$quiz->id", "$cm->id");
 113  
 114          echo '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:1000;"></div>'; // for overlib
 115  
 116          if ($data = data_submitted()) {  // post data submitted, process it
 117              confirm_sesskey();
 118  
 119              // now go through all of the responses and save them.
 120              $allok = true;
 121              foreach($data->manualgrades as $uniqueid => $response) {
 122                  // get our attempt
 123                  $uniqueid = clean_param($uniqueid, PARAM_INT);
 124                  if (!$attempt = get_record_sql("SELECT * FROM {$CFG->prefix}quiz_attempts " .
 125                                  "WHERE uniqueid = $uniqueid AND " .
 126                                  "userid IN ($this->userids) AND " .
 127                                  "quiz=".$quiz->id)){
 128                      error('No such attempt ID exists');
 129                  }
 130  
 131                  // Load the state for this attempt (The questions array was created earlier)
 132                  $states = get_question_states($questions, $quiz, $attempt);
 133                  // The $states array is indexed by question id but because we are dealing
 134                  // with only one question there is only one entry in this array
 135                  $state = &$states[$question->id];
 136  
 137                  // the following will update the state and attempt
 138                  $error = question_process_comment($question, $state, $attempt, $response['comment'], $response['grade']);
 139                  if (is_string($error)) {
 140                      notify($error);
 141                      $allok = false;
 142                  } else if ($state->changed) {
 143                      // If the state has changed save it and update the quiz grade
 144                      save_question_session($question, $state);
 145                      quiz_save_best_grade($quiz, $attempt->userid);
 146                  }
 147              }
 148  
 149              if ($allok) {
 150                  notify(get_string('changessaved', 'quiz'), 'notifysuccess');
 151              } else {
 152                  notify(get_string('changessavedwitherrors', 'quiz'), 'notifysuccess');
 153              }
 154          }
 155          $this->viewurl = new moodle_url($CFG->wwwroot.'/mod/quiz/report.php', $viewoptions); 
 156          /// find out current groups mode
 157  
 158          if ($groupmode = groups_get_activity_groupmode($this->cm)) {   // Groups are being used
 159              groups_print_activity_menu($this->cm, $this->viewurl->out(false, array('userid'=>0, 'attemptid'=>0)));
 160          }
 161  
 162          echo '<div class="quizattemptcounts">' . quiz_num_attempt_summary($quiz, $cm, true, $currentgroup) . '</div>';
 163  
 164          if(empty($this->users)) {
 165              if ($currentgroup){
 166                  notify(get_string('nostudentsingroup'));
 167              } else {
 168                  notify(get_string('nostudentsyet'));
 169              }
 170              return true;
 171          }
 172          $gradeablequestionids = implode(',',array_keys($gradeableqs));
 173          $qattempts = quiz_get_total_qas_graded_and_ungraded($quiz, $gradeablequestionids, $this->userids);
 174          if(empty($qattempts)) {
 175              notify(get_string('noattemptstoshow', 'quiz'));
 176              return true;
 177          }
 178          $qmenu = array();
 179          foreach ($gradeableqs as $qid => $questionformenu){
 180              $a= new object();
 181              $a->number = $gradeableqs[$qid]->number;
 182              $a->name = $gradeableqs[$qid]->name;
 183              $a->gradedattempts =$qattempts[$qid]->gradedattempts;
 184              $a->totalattempts =$qattempts[$qid]->totalattempts;
 185              $a->openspan ='';
 186              $a->closespan ='';
 187              $qmenu[$qid]= get_string('questiontitle', 'quiz_grading', $a);
 188          }
 189          if (count($gradeableqs)!=1){
 190              $qurl = fullclone($this->viewurl);
 191              $qurl->remove_params('questionid', 'attemptid', 'gradeall', 'gradeungraded', 'gradenextungraded');
 192              $menu = popup_form(($qurl->out()).'&amp;questionid=',$qmenu, 'questionid', $questionid, 'choose', '', '', true);
 193              echo '<div class="mdl-align">'.$menu.'</div>';
 194          }
 195          if (!$questionid){
 196              return true;
 197          }
 198          $a= new object();
 199          $a->number = $question->number;
 200          $a->name = $question->name;
 201          $a->gradedattempts =$qattempts[$question->id]->gradedattempts;
 202          $a->totalattempts =$qattempts[$question->id]->totalattempts;
 203          $a->openspan ='<span class="highlightgraded">';
 204          $a->closespan ='</span>';
 205          print_heading(get_string('questiontitle', 'quiz_grading', $a));
 206  
 207          // our 3 different views
 208          // the first one displays all of the manually graded questions in the quiz
 209          // with the number of ungraded attempts for each question
 210  
 211          // the second view displays the users who have answered the essay question
 212          // and all of their attempts at answering the question
 213  
 214          // the third prints the question with a comment
 215          // and grade form underneath it
 216  
 217          $ungraded = $qattempts[$questionid]->totalattempts- $qattempts[$questionid]->gradedattempts;
 218          if ($gradenextungraded ||$gradeungraded || $gradeall || $userid || $attemptid){
 219              $this->print_questions_and_form($quiz, $question, $userid, $attemptid, $gradeungraded, $gradenextungraded, $ungraded);
 220          } else {
 221              $this->view_question($quiz, $question, $qattempts[$questionid]->totalattempts, $ungraded);
 222          }
 223          return true;
 224      }
 225  
 226      /**
 227       * Prints a table with users and their attempts
 228       *
 229       * @return void
 230       * @todo Add current grade to the table
 231       *       Finnish documenting
 232       **/
 233      function view_question($quiz, $question, $totalattempts, $ungraded) {
 234          global $CFG;
 235  
 236  
 237          $usercount = count($this->users);
 238  
 239          // set up table
 240          $tablecolumns = array('picture', 'fullname', 'timefinish', 'grade');
 241          $tableheaders = array('', get_string('name'), get_string("completedon", "quiz"), '');
 242  
 243          $table = new flexible_table('mod-quiz-report-grading');
 244  
 245          $table->define_columns($tablecolumns);
 246          $table->define_headers($tableheaders);
 247          $table->define_baseurl($this->viewurl->out());
 248  
 249          $table->sortable(true);
 250          $table->initialbars($usercount>20);  // will show initialbars if there are more than 20 users
 251          $table->pageable(true);
 252          $table->collapsible(true);
 253  
 254          $table->column_suppress('fullname');
 255          $table->column_suppress('picture');
 256          $table->column_suppress('grade');
 257  
 258          $table->column_class('picture', 'picture');
 259  
 260          // attributes in the table tag
 261          $table->set_attribute('cellspacing', '0');
 262          $table->set_attribute('id', 'attempts');
 263          $table->set_attribute('class', 'generaltable generalbox');
 264          $table->set_attribute('align', 'center');
 265          //$table->set_attribute('width', '50%');
 266  
 267          // get it ready!
 268          $table->setup();
 269  
 270          list($select, $from, $where) = $this->attempts_sql($quiz->id, true, $question->id);
 271  
 272          if($table->get_sql_where()) { // forgot what this does
 273              $where .= 'AND '.$table->get_sql_where();
 274          }
 275  
 276          // sorting of the table
 277          if($sort = $table->get_sql_sort()) {
 278              $sort = 'ORDER BY '.$sort;  // seems like I would need to have u. or qa. infront of the ORDER BY attribues... but seems to work..
 279          } else {
 280              // my default sort rule
 281              $sort = 'ORDER BY u.firstname, u.lastname, qa.timefinish ASC';
 282          }
 283  
 284          // set up the pagesize
 285          $table->pagesize(QUIZ_REPORT_DEFAULT_PAGE_SIZE, $totalattempts);
 286  
 287          // get the attempts and process them
 288          if ($attempts = get_records_sql($select.$from.$where.$sort,$table->get_page_start(), $table->get_page_size())) {
 289              // grade all link
 290              $links = "<strong><a href=\"report.php?mode=grading&amp;gradeall=1&amp;q=$quiz->id&amp;questionid=$question->id\">".get_string('gradeall', 'quiz_grading', $totalattempts).'</a></strong>';
 291              if ($ungraded>0){
 292                  $links .="<br /><strong><a href=\"report.php?mode=grading&amp;gradeungraded=1&amp;q=$quiz->id&amp;questionid=$question->id\">".get_string('gradeungraded', 'quiz_grading', $ungraded).'</a></strong>';
 293                  if ($ungraded>QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE){
 294                      $links .="<br /><strong><a href=\"report.php?mode=grading&amp;gradenextungraded=1&amp;q=$quiz->id&amp;questionid=$question->id\">".get_string('gradenextungraded', 'quiz_grading', QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE).'</a></strong>';
 295                  }
 296              }
 297              $table->add_data_keyed(array('grade'=> $links));
 298              $table->add_separator();
 299              foreach($attempts as $attempt) {
 300  
 301                  $picture = print_user_picture($attempt->userid, $quiz->course, $attempt->picture, false, true);
 302  
 303                  // link to student profile
 304                  $userlink = "<a href=\"$CFG->wwwroot/user/view.php?id=$attempt->userid&amp;course=$quiz->course\">".
 305                              fullname($attempt, true).'</a>';
 306  
 307                  $gradedclass = question_state_is_graded($attempt)?' class="highlightgraded" ':'';
 308                  $gradedstring = question_state_is_graded($attempt)?(' '.get_string('graded','quiz_grading')):'';
 309  
 310                  // link for the attempt
 311                  $attemptlink = "<a {$gradedclass}href=\"report.php?mode=grading&amp;q=$quiz->id&amp;questionid=$question->id&amp;attemptid=$attempt->attemptid\">".
 312                          userdate($attempt->timefinish, get_string('strftimedatetime')).
 313                          $gradedstring.'</a>';
 314  
 315                  // grade all attempts for this user
 316                  $gradelink = "<a href=\"report.php?mode=grading&amp;q=$quiz->id&amp;questionid=$question->id&amp;userid=$attempt->userid\">".
 317                          get_string('grade').'</a>';
 318  
 319                  $table->add_data( array($picture, $userlink, $attemptlink, $gradelink) );
 320              }
 321              $table->add_separator();
 322              $table->add_data_keyed(array('grade'=> $links));
 323              // print everything here
 324              echo '<div id="tablecontainer">';
 325              $table->print_html();
 326              echo '</div>';
 327          } else {
 328              notify(get_string('noattemptstoshow', 'quiz'));
 329          }
 330      }
 331  
 332  
 333      /**
 334       * Prints questions with comment and grade form underneath each question
 335       *
 336       * @return void
 337       * @todo Finish documenting this function
 338       **/
 339      function print_questions_and_form($quiz, $question, $userid, $attemptid, $gradeungraded, $gradenextungraded, $ungraded) {
 340          global $CFG;
 341  
 342          // TODO get the context, and put in proper roles an permissions checks.
 343          $context = NULL;
 344  
 345          $questions[$question->id] = &$question;
 346          $usehtmleditor = can_use_richtext_editor();
 347  
 348          list($select, $from, $where) = $this->attempts_sql($quiz->id, false, $question->id, $userid, $attemptid, $gradeungraded, $gradenextungraded);
 349  
 350          $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
 351          
 352          if ($gradenextungraded){
 353              $attempts = get_records_sql($select.$from.$where.$sort, 0, QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE);
 354          } else {
 355              $attempts = get_records_sql($select.$from.$where.$sort);
 356          }
 357          if ($attempts){
 358              $firstattempt = current($attempts);
 359              $fullname = fullname($firstattempt);
 360              if ($gradeungraded) { // getting all ungraded attempts
 361                  print_heading(get_string('gradingungraded','quiz_grading', $ungraded), '', 3);
 362              } else if ($gradenextungraded) { // getting next ungraded attempts
 363                  print_heading(get_string('gradingnextungraded','quiz_grading', QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE), '', 3);
 364              } else if ($userid){
 365                  print_heading(get_string('gradinguser','quiz_grading', $fullname), '', 3);
 366              } else if ($attemptid){
 367                  $a = new object();
 368                  $a->fullname = $fullname;
 369                  $a->attempt = $firstattempt->attempt;
 370                  print_heading(get_string('gradingattempt','quiz_grading', $a), '', 3);
 371              } else {
 372                  print_heading(get_string('gradingall','quiz_grading', count($attempts)), '', 3);
 373              }
 374      
 375              // Display the form with one part for each selected attempt
 376      
 377              echo '<form method="post" action="report.php">'.
 378                  '<input type="hidden" name="mode" value="grading" />'.
 379                  '<input type="hidden" name="q" value="'.$quiz->id.'" />'.
 380                  '<input type="hidden" name="sesskey" value="'.sesskey().'" />'.
 381                  '<input type="hidden" name="questionid" value="'.$question->id.'" />';
 382      
 383              foreach ($attempts as $attempt) {
 384      
 385                  // Load the state for this attempt (The questions array was created earlier)
 386                  $states = get_question_states($questions, $quiz, $attempt);
 387                  // The $states array is indexed by question id but because we are dealing
 388                  // with only one question there is only one entry in this array
 389                  $state = &$states[$question->id];
 390      
 391                  $options = quiz_get_reviewoptions($quiz, $attempt, $context);
 392                  unset($options->questioncommentlink);
 393                  $copy = $state->manualcomment;
 394                  $state->manualcomment = '';
 395      
 396                  $options->readonly = 1;
 397                  
 398                  $gradedclass = question_state_is_graded($state)?' class="highlightgraded" ':'';
 399                  $gradedstring = question_state_is_graded($state)?(' '.get_string('graded','quiz_grading')):'';
 400                  $a = new object();
 401                  $a->fullname = fullname($attempt, true);
 402                  $a->attempt = $attempt->attempt;
 403                  
 404                  // print the user name, attempt count, the question, and some more hidden fields
 405                  echo '<div class="boxaligncenter" width="80%" style="clear:left;padding:15px;">';
 406                  echo "<span$gradedclass>".get_string('gradingattempt','quiz_grading', $a);
 407                  echo $gradedstring."</span>";
 408      
 409                  print_question($question, $state, '', $quiz, $options);
 410      
 411                  $prefix         = "manualgrades[$attempt->uniqueid]";
 412                  $grade          = round($state->last_graded->grade, 3);
 413                  $state->manualcomment = $copy;
 414      
 415                  include($CFG->dirroot . '/question/comment.html');
 416      
 417                  echo '</div>';
 418              }
 419              echo '<div class="boxaligncenter"><input type="submit" value="'.get_string('savechanges').'" /></div>'.
 420                  '</form>';
 421      
 422              if ($usehtmleditor) {
 423                  use_html_editor();
 424              }
 425          } else {
 426              notify(get_string('noattemptstoshow', 'quiz'));
 427          }
 428      }
 429      
 430      function attempts_sql($quizid, $wantstateevent=false, $questionid=0, $userid=0, $attemptid=0, $gradeungraded=0, $gradenextungraded=0){
 431          global $CFG;
 432          // this sql joins the attempts table and the user table
 433          $select = 'SELECT qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, qa.preview,
 434                      u.id AS userid, u.firstname, u.lastname, u.picture ';
 435          if ($wantstateevent && $questionid){
 436              $select .= ', qs.event ';
 437          }
 438          $from   = 'FROM '.$CFG->prefix.'user u, ' .
 439                  $CFG->prefix.'quiz_attempts qa ';
 440          if (($wantstateevent|| $gradenextungraded || $gradeungraded) && $questionid){
 441              $from .= "LEFT JOIN {$CFG->prefix}question_sessions qns " .
 442                      "ON (qns.attemptid = qa.uniqueid AND qns.questionid = $questionid) ";
 443              $from .=  "LEFT JOIN  {$CFG->prefix}question_states qs " .
 444                      "ON (qs.id = qns.newgraded AND qs.question = $questionid) ";
 445          }
 446          if ($gradenextungraded || $gradeungraded) { // get ungraded attempts
 447              $where = 'WHERE u.id IN ('.$this->userids.') AND qs.event NOT IN ('.QUESTION_EVENTS_GRADED.') ';
 448          } else if ($userid) { // get all the attempts for a specific user
 449              $where = 'WHERE u.id='.$userid.' ';
 450          } else if ($attemptid) { // get a specific attempt
 451              $where = 'WHERE qa.id='.$attemptid.' ';
 452          } else { // get all user attempts
 453              $where  = 'WHERE u.id IN ('.$this->userids.') ';
 454          }
 455          
 456          $where .= ' AND u.id = qa.userid AND qa.quiz = '.$quizid;
 457          // ignore previews
 458          $where .= ' AND preview = 0 ';
 459  
 460          $where .= ' AND qa.timefinish != 0 ';
 461  
 462          return array($select, $from, $where);
 463      }
 464  
 465  }
 466  
 467  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7