Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/quiz/report/grading/report.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00027 defined('MOODLE_INTERNAL') || die();
00028 
00029 require_once($CFG->dirroot . '/mod/quiz/report/grading/gradingsettings_form.php');
00030 
00031 
00042 class quiz_grading_report extends quiz_default_report {
00043     const DEFAULT_PAGE_SIZE = 5;
00044     const DEFAULT_ORDER = 'random';
00045 
00046     protected $viewoptions = array();
00047     protected $questions;
00048     protected $currentgroup;
00049     protected $users;
00050     protected $cm;
00051     protected $quiz;
00052     protected $context;
00053 
00054     public function display($quiz, $cm, $course) {
00055         global $CFG, $DB, $PAGE;
00056 
00057         $this->quiz = $quiz;
00058         $this->cm = $cm;
00059         $this->course = $course;
00060 
00061         // Get the URL options.
00062         $slot = optional_param('slot', null, PARAM_INT);
00063         $questionid = optional_param('qid', null, PARAM_INT);
00064         $grade = optional_param('grade', null, PARAM_ALPHA);
00065 
00066         $includeauto = optional_param('includeauto', false, PARAM_BOOL);
00067         if (!in_array($grade, array('all', 'needsgrading', 'autograded', 'manuallygraded'))) {
00068             $grade = null;
00069         }
00070         $pagesize = optional_param('pagesize', self::DEFAULT_PAGE_SIZE, PARAM_INT);
00071         $page = optional_param('page', 0, PARAM_INT);
00072         $order = optional_param('order', self::DEFAULT_ORDER, PARAM_ALPHA);
00073 
00074         // Assemble the options requried to reload this page.
00075         $optparams = array('includeauto', 'page');
00076         foreach ($optparams as $param) {
00077             if ($$param) {
00078                 $this->viewoptions[$param] = $$param;
00079             }
00080         }
00081         if ($pagesize != self::DEFAULT_PAGE_SIZE) {
00082             $this->viewoptions['pagesize'] = $pagesize;
00083         }
00084         if ($order != self::DEFAULT_ORDER) {
00085             $this->viewoptions['order'] = $order;
00086         }
00087 
00088         // Check permissions
00089         $this->context = get_context_instance(CONTEXT_MODULE, $cm->id);
00090         require_capability('mod/quiz:grade', $this->context);
00091         $shownames = has_capability('quiz/grading:viewstudentnames', $this->context);
00092         $showidnumbers = has_capability('quiz/grading:viewidnumber', $this->context);
00093 
00094         // Validate order.
00095         if (!in_array($order, array('random', 'date', 'student', 'idnumber'))) {
00096             $order = self::DEFAULT_ORDER;
00097         } else if (!$shownames && $order == 'student') {
00098             $order = self::DEFAULT_ORDER;
00099         } else if (!$showidnumbers && $order == 'idnumber') {
00100             $order = self::DEFAULT_ORDER;
00101         }
00102         if ($order == 'random') {
00103             $page = 0;
00104         }
00105 
00106         // Get the list of questions in this quiz.
00107         $this->questions = quiz_report_get_significant_questions($quiz);
00108         if ($slot && !array_key_exists($slot, $this->questions)) {
00109             throw new moodle_exception('unknownquestion', 'quiz_grading');
00110         }
00111 
00112         // Process any submitted data.
00113         if ($data = data_submitted() && confirm_sesskey() && $this->validate_submitted_marks()) {
00114             $this->process_submitted_data();
00115 
00116             redirect($this->grade_question_url($slot, $questionid, $grade, $page + 1));
00117         }
00118 
00119         // Get the group, and the list of significant users.
00120         $this->currentgroup = $this->get_current_group($cm, $course, $this->context);
00121         if ($this->currentgroup == self::NO_GROUPS_ALLOWED) {
00122             $this->users = array();
00123         } else {
00124             $this->users = get_users_by_capability($this->context,
00125                     array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'), '', '', '', '',
00126                     $this->currentgroup, '', false);
00127         }
00128 
00129         // Start output.
00130         $this->print_header_and_tabs($cm, $course, $quiz, 'grading');
00131 
00132         // What sort of page to display?
00133         if (!quiz_questions_in_quiz($quiz->questions)) {
00134             echo quiz_no_questions_message($quiz, $cm, $this->context);
00135 
00136         } else if (!$slot) {
00137             $this->display_index($includeauto);
00138 
00139         } else {
00140             $this->display_grading_interface($slot, $questionid, $grade,
00141                     $pagesize, $page, $shownames, $showidnumbers, $order);
00142         }
00143         return true;
00144     }
00145 
00146     protected function get_qubaids_condition() {
00147         global $DB;
00148 
00149         $where = "quiza.quiz = :mangrquizid AND
00150                 quiza.preview = 0 AND
00151                 quiza.timefinish <> 0";
00152         $params = array('mangrquizid' => $this->cm->instance);
00153 
00154         if ($this->currentgroup) {
00155             list($usql, $uparam) = $DB->get_in_or_equal(array_keys($this->users),
00156                     SQL_PARAMS_NAMED, 'mangru');
00157             $where .= ' AND quiza.userid ' . $usql;
00158             $params += $uparam;
00159         }
00160 
00161         return new qubaid_join('{quiz_attempts} quiza', 'quiza.uniqueid', $where, $params);
00162     }
00163 
00164     protected function load_attempts_by_usage_ids($qubaids) {
00165         global $DB;
00166 
00167         list($asql, $params) = $DB->get_in_or_equal($qubaids);
00168         $params[] = $this->quiz->id;
00169 
00170         $attemptsbyid = $DB->get_records_sql("
00171                 SELECT quiza.*, u.firstname, u.lastname, u.idnumber
00172                 FROM {quiz_attempts} quiza
00173                 JOIN {user} u ON u.id = quiza.userid
00174                 WHERE quiza.uniqueid $asql AND quiza.timefinish <> 0 AND quiza.quiz = ?",
00175                 $params);
00176 
00177         $attempts = array();
00178         foreach ($attemptsbyid as $attempt) {
00179             $attempts[$attempt->uniqueid] = $attempt;
00180         }
00181         return $attempts;
00182     }
00183 
00190     protected function base_url() {
00191         return new moodle_url('/mod/quiz/report.php',
00192                 array('id' => $this->cm->id, 'mode' => 'grading'));
00193     }
00194 
00201     protected function list_questions_url($includeauto = null) {
00202         $url = $this->base_url();
00203 
00204         $url->params($this->viewoptions);
00205 
00206         if (!is_null($includeauto)) {
00207             $url->param('includeauto', $includeauto);
00208         }
00209 
00210         return $url;
00211     }
00212 
00220     protected function grade_question_url($slot, $questionid, $grade, $page = true) {
00221         $url = $this->base_url();
00222         $url->params(array('slot' => $slot, 'qid' => $questionid, 'grade' => $grade));
00223         $url->params($this->viewoptions);
00224 
00225         $options = $this->viewoptions;
00226         if (!$page) {
00227             $url->remove_params('page');
00228         } else if (is_integer($page)) {
00229             $url->param('page', $page);
00230         }
00231 
00232         return $url;
00233     }
00234 
00235     protected function format_count_for_table($counts, $type, $gradestring) {
00236         $result = $counts->$type;
00237         if ($counts->$type > 0) {
00238             $result .= ' ' . html_writer::link($this->grade_question_url(
00239                     $counts->slot, $counts->questionid, $type),
00240                     get_string($gradestring, 'quiz_grading'),
00241                     array('class' => 'gradetheselink'));
00242         }
00243         return $result;
00244     }
00245 
00246     protected function display_index($includeauto) {
00247         global $OUTPUT;
00248 
00249         if ($groupmode = groups_get_activity_groupmode($this->cm)) {
00250             // Groups are being used
00251             groups_print_activity_menu($this->cm, $this->list_questions_url());
00252         }
00253 
00254         echo $OUTPUT->heading(get_string('questionsthatneedgrading', 'quiz_grading'));
00255         if ($includeauto) {
00256             $linktext = get_string('hideautomaticallygraded', 'quiz_grading');
00257         } else {
00258             $linktext = get_string('alsoshowautomaticallygraded', 'quiz_grading');
00259         }
00260         echo html_writer::tag('p', html_writer::link($this->list_questions_url(!$includeauto),
00261                 $linktext), array('class' => 'toggleincludeauto'));
00262 
00263         $statecounts = $this->get_question_state_summary(array_keys($this->questions));
00264 
00265         $data = array();
00266         foreach ($statecounts as $counts) {
00267             if ($counts->all == 0) {
00268                 continue;
00269             }
00270             if (!$includeauto && $counts->needsgrading == 0 && $counts->manuallygraded == 0) {
00271                 continue;
00272             }
00273 
00274             $row = array();
00275 
00276             $row[] = $this->questions[$counts->slot]->number;
00277 
00278             $row[] = format_string($counts->name);
00279 
00280             $row[] = $this->format_count_for_table($counts, 'needsgrading', 'grade');
00281 
00282             $row[] = $this->format_count_for_table($counts, 'manuallygraded', 'updategrade');
00283 
00284             if ($includeauto) {
00285                 $row[] = $this->format_count_for_table($counts, 'autograded', 'updategrade');
00286             }
00287 
00288             $row[] = $this->format_count_for_table($counts, 'all', 'gradeall');
00289 
00290             $data[] = $row;
00291         }
00292 
00293         if (empty($data)) {
00294             echo $OUTPUT->heading(get_string('noquestionsfound', 'quiz_grading'));
00295             return;
00296         }
00297 
00298         $table = new html_table();
00299         $table->class = 'generaltable';
00300         $table->id = 'questionstograde';
00301 
00302         $table->head[] = get_string('qno', 'quiz_grading');
00303         $table->head[] = get_string('questionname', 'quiz_grading');
00304         $table->head[] = get_string('tograde', 'quiz_grading');
00305         $table->head[] = get_string('alreadygraded', 'quiz_grading');
00306         if ($includeauto) {
00307             $table->head[] = get_string('automaticallygraded', 'quiz_grading');
00308         }
00309         $table->head[] = get_string('total', 'quiz_grading');
00310 
00311         $table->data = $data;
00312         echo html_writer::table($table);
00313     }
00314 
00315     protected function display_grading_interface($slot, $questionid, $grade,
00316             $pagesize, $page, $shownames, $showidnumbers, $order) {
00317         global $OUTPUT;
00318 
00319         // Make sure there is something to do.
00320         $statecounts = $this->get_question_state_summary(array($slot));
00321 
00322         $counts = null;
00323         foreach ($statecounts as $record) {
00324             if ($record->questionid == $questionid) {
00325                 $counts = $record;
00326                 break;
00327             }
00328         }
00329 
00330         // If not, redirect back to the list.
00331         if (!$counts || $counts->$grade == 0) {
00332             redirect($this->list_questions_url(), get_string('alldoneredirecting', 'quiz_grading'));
00333         }
00334 
00335         if ($pagesize * $page >= $counts->$grade) {
00336             $page = 0;
00337         }
00338 
00339         list($qubaids, $count) = $this->get_usage_ids_where_question_in_state(
00340                 $grade, $slot, $questionid, $order, $page, $pagesize);
00341         $attempts = $this->load_attempts_by_usage_ids($qubaids);
00342 
00343         // Prepare the form.
00344         $hidden = array(
00345             'id' => $this->cm->id,
00346             'mode' => 'grading',
00347             'slot' => $slot,
00348             'qid' => $questionid,
00349             'page' => $page,
00350         );
00351         if (array_key_exists('includeauto', $this->viewoptions)) {
00352             $hidden['includeauto'] = $this->viewoptions['includeauto'];
00353         }
00354         $mform = new quiz_grading_settings($hidden, $counts, $shownames, $showidnumbers);
00355 
00356         // Tell the form the current settings.
00357         $settings = new stdClass();
00358         $settings->grade = $grade;
00359         $settings->pagesize = $pagesize;
00360         $settings->order = $order;
00361         $mform->set_data($settings);
00362 
00363         // Print the heading and form.
00364         echo question_engine::initialise_js();
00365 
00366         $a = new stdClass();
00367         $a->number = $this->questions[$slot]->number;
00368         $a->questionname = format_string($counts->name);
00369         echo $OUTPUT->heading(get_string('gradingquestionx', 'quiz_grading', $a));
00370         echo html_writer::tag('p', html_writer::link($this->list_questions_url(),
00371                 get_string('backtothelistofquestions', 'quiz_grading')),
00372                 array('class' => 'mdl-align'));
00373 
00374         $mform->display();
00375 
00376         // Paging info.
00377         $a = new stdClass();
00378         $a->from = $page * $pagesize + 1;
00379         $a->to = min(($page + 1) * $pagesize, $count);
00380         $a->of = $count;
00381         echo $OUTPUT->heading(get_string('gradingattemptsxtoyofz', 'quiz_grading', $a), 3);
00382 
00383         if ($count > $pagesize && $order != 'random') {
00384             echo $OUTPUT->paging_bar($count, $page, $pagesize,
00385                     $this->grade_question_url($slot, $questionid, $grade, false));
00386         }
00387 
00388         // Display the form with one section for each attempt.
00389         $usehtmleditor = can_use_html_editor();
00390         $sesskey = sesskey();
00391         $qubaidlist = implode(',', $qubaids);
00392         echo html_writer::start_tag('form', array('method' => 'post',
00393                 'action' => $this->grade_question_url($slot, $questionid, $grade, $page),
00394                 'class' => 'mform', 'id' => 'manualgradingform')) .
00395                 html_writer::start_tag('div') .
00396                 html_writer::input_hidden_params(new moodle_url('', array(
00397                 'qubaids' => $qubaidlist, 'slots' => $slot, 'sesskey' => $sesskey)));
00398 
00399         foreach ($qubaids as $qubaid) {
00400             $attempt = $attempts[$qubaid];
00401             $quba = question_engine::load_questions_usage_by_activity($qubaid);
00402             $displayoptions = quiz_get_review_options($this->quiz, $attempt, $this->context);
00403             $displayoptions->hide_all_feedback();
00404             $displayoptions->history = question_display_options::HIDDEN;
00405             $displayoptions->manualcomment = question_display_options::EDITABLE;
00406 
00407             $heading = $this->get_question_heading($attempt, $shownames, $showidnumbers);
00408             if ($heading) {
00409                 echo $OUTPUT->heading($heading, 4);
00410             }
00411             echo $quba->render_question($slot, $displayoptions, $this->questions[$slot]->number);
00412         }
00413 
00414         echo html_writer::tag('div', html_writer::empty_tag('input', array(
00415                 'type' => 'submit', 'value' => get_string('saveandnext', 'quiz_grading'))),
00416                 array('class' => 'mdl-align')) .
00417                 html_writer::end_tag('div') . html_writer::end_tag('form');
00418     }
00419 
00420     protected function get_question_heading($attempt, $shownames, $showidnumbers) {
00421         $a = new stdClass();
00422         $a->attempt = $attempt->attempt;
00423         $a->fullname = fullname($attempt);
00424         $a->idnumber = $attempt->idnumber;
00425 
00426         $showidnumbers &= !empty($attempt->idnumber);
00427 
00428         if ($shownames && $showidnumbers) {
00429             return get_string('gradingattemptwithidnumber', 'quiz_grading', $a);
00430         } else if ($shownames) {
00431             return get_string('gradingattempt', 'quiz_grading', $a);
00432         } else if ($showidnumbers) {
00433             $a->fullname = $attempt->idnumber;
00434             return get_string('gradingattempt', 'quiz_grading', $a);
00435         } else {
00436             return '';
00437         }
00438     }
00439 
00440     protected function validate_submitted_marks() {
00441 
00442         $qubaids = optional_param('qubaids', null, PARAM_SEQUENCE);
00443         if (!$qubaids) {
00444             return false;
00445         }
00446         $qubaids = clean_param_array(explode(',', $qubaids), PARAM_INT);
00447 
00448         $slots = optional_param('slots', '', PARAM_SEQUENCE);
00449         if (!$slots) {
00450             $slots = array();
00451         } else {
00452             $slots = explode(',', $slots);
00453         }
00454 
00455         foreach ($qubaids as $qubaid) {
00456             foreach ($slots as $slot) {
00457                 $prefix = 'q' . $qubaid . ':' . $slot . '_';
00458                 $mark = optional_param($prefix . '-mark', null, PARAM_NUMBER);
00459                 $maxmark = optional_param($prefix . '-maxmark', null, PARAM_NUMBER);
00460                 $minfraction = optional_param($prefix . ':minfraction', null, PARAM_NUMBER);
00461                 if (!is_null($mark) && ($mark < $minfraction * $maxmark || $mark > $maxmark)) {
00462                     return false;
00463                 }
00464             }
00465         }
00466 
00467         return true;
00468     }
00469 
00470     protected function process_submitted_data() {
00471         global $DB;
00472 
00473         $qubaids = optional_param('qubaids', null, PARAM_SEQUENCE);
00474         if (!$qubaids) {
00475             return;
00476         }
00477 
00478         $qubaids = clean_param_array(explode(',', $qubaids), PARAM_INT);
00479         $attempts = $this->load_attempts_by_usage_ids($qubaids);
00480 
00481         $transaction = $DB->start_delegated_transaction();
00482         foreach ($qubaids as $qubaid) {
00483             $attempt = $attempts[$qubaid];
00484             $quba = question_engine::load_questions_usage_by_activity($qubaid);
00485             $attemptobj = new quiz_attempt($attempt, $this->quiz, $this->cm, $this->course);
00486             $attemptobj->process_all_actions(time());
00487         }
00488         $transaction->allow_commit();
00489     }
00490 
00502     protected function get_question_state_summary($slots) {
00503         $dm = new question_engine_data_mapper();
00504         return $dm->load_questions_usages_question_state_summary(
00505                 $this->get_qubaids_condition(), $slots);
00506     }
00507 
00525     protected function get_usage_ids_where_question_in_state($summarystate, $slot,
00526             $questionid = null, $orderby = 'random', $page = 0, $pagesize = null) {
00527         global $CFG, $DB;
00528         $dm = new question_engine_data_mapper();
00529 
00530         if ($pagesize && $orderby != 'random') {
00531             $limitfrom = $page * $pagesize;
00532         } else {
00533             $limitfrom = 0;
00534         }
00535 
00536         $qubaids = $this->get_qubaids_condition();
00537 
00538         $params = array();
00539         if ($orderby == 'date') {
00540             list($statetest, $params) = $dm->in_summary_state_test(
00541                     'manuallygraded', false, 'mangrstate');
00542             $orderby = "(
00543                     SELECT MAX(sortqas.timecreated)
00544                     FROM {question_attempt_steps} sortqas
00545                     WHERE sortqas.questionattemptid = qa.id
00546                         AND sortqas.state $statetest
00547                     )";
00548         } else if ($orderby == 'student' || $orderby == 'idnumber') {
00549             $qubaids->from .= " JOIN {user} u ON quiza.userid = u.id ";
00550             if ($orderby == 'student') {
00551                 $orderby = $DB->sql_fullname('u.firstname', 'u.lastname');
00552             }
00553         }
00554 
00555         return $dm->load_questions_usages_where_question_in_state($qubaids, $summarystate,
00556                 $slot, $questionid, $orderby, $params, $limitfrom, $pagesize);
00557     }
00558 }
 All Data Structures Namespaces Files Functions Variables Enumerations