/**
 * Load the question data necessary in the reports.
 * - Remove description questions.
 * - Order questions in order that they are in the quiz
 * - Add question numbers.
 * - Add grade from quiz_questions_instance
 */
function quiz_report_load_questions($quiz)
{
    global $CFG;
    $questionlist = quiz_questions_in_quiz($quiz->questions);
    //In fact in most cases the id IN $questionlist below is redundant
    //since we are also doing a JOIN on the qqi table. But will leave it in
    //since this double check will probably do no harm.
    if (!($questions = get_records_sql("SELECT q.*, qqi.grade " . "FROM {$CFG->prefix}question q, " . "{$CFG->prefix}quiz_question_instances qqi " . "WHERE q.id IN ({$questionlist}) AND " . "qqi.question = q.id AND " . "qqi.quiz =" . $quiz->id))) {
        print_error('No questions found');
    }
    //Now we have an array of questions from a quiz we work out there question nos and remove
    //questions with zero length ie. description questions etc.
    //also put questions in order.
    $number = 1;
    $realquestions = array();
    $questionids = explode(',', $questionlist);
    foreach ($questionids as $id) {
        if ($questions[$id]->length) {
            // Ignore questions of zero length
            $realquestions[$id] = $questions[$id];
            $realquestions[$id]->number = $number;
            $number += $questions[$id]->length;
        }
    }
    return $realquestions;
}
/**
 * Get the slots of real questions (not descriptions) in this quiz, in order.
 * @param object $quiz the quiz.
 * @return array of slot => $question object with fields
 *      ->slot, ->id, ->maxmark, ->number, ->length.
 */
function quiz_report_get_significant_questions($quiz)
{
    global $DB;
    $questionids = quiz_questions_in_quiz($quiz->questions);
    if (empty($questionids)) {
        return array();
    }
    list($usql, $params) = $DB->get_in_or_equal(explode(',', $questionids));
    $params[] = $quiz->id;
    $questions = $DB->get_records_sql("\nSELECT\n    q.id,\n    q.length,\n    qqi.grade AS maxmark\n\nFROM {question} q\nJOIN {quiz_question_instances} qqi ON qqi.question = q.id\n\nWHERE\n    q.id {$usql} AND\n    qqi.quiz = ? AND\n    length > 0", $params);
    $qsbyslot = array();
    $number = 1;
    foreach (explode(',', $questionids) as $key => $id) {
        if (!array_key_exists($id, $questions)) {
            continue;
        }
        $slot = $key + 1;
        $question = $questions[$id];
        $question->slot = $slot;
        $question->number = $number;
        $qsbyslot[$slot] = $question;
        $number += $question->length;
    }
    return $qsbyslot;
}
Exemple #3
0
 public function test_quiz_questions_in_quiz() {
     $this->assertEquals(quiz_questions_in_quiz(''), '');
     $this->assertEquals(quiz_questions_in_quiz('0'), '');
     $this->assertEquals(quiz_questions_in_quiz('0,0'), '');
     $this->assertEquals(quiz_questions_in_quiz('0,0,0'), '');
     $this->assertEquals(quiz_questions_in_quiz('1'), '1');
     $this->assertEquals(quiz_questions_in_quiz('1,2'), '1,2');
     $this->assertEquals(quiz_questions_in_quiz('1,0,2'), '1,2');
     $this->assertEquals(quiz_questions_in_quiz('0,1,0,0,2,0'), '1,2');
 }
 public function display($quiz, $cm, $course)
 {
     global $CFG, $DB, $PAGE;
     $this->quiz = $quiz;
     $this->cm = $cm;
     $this->course = $course;
     // Get the URL options.
     $slot = optional_param('slot', null, PARAM_INT);
     $questionid = optional_param('qid', null, PARAM_INT);
     $grade = optional_param('grade', null, PARAM_ALPHA);
     $includeauto = optional_param('includeauto', false, PARAM_BOOL);
     if (!in_array($grade, array('all', 'needsgrading', 'autograded', 'manuallygraded'))) {
         $grade = null;
     }
     $pagesize = optional_param('pagesize', self::DEFAULT_PAGE_SIZE, PARAM_INT);
     $page = optional_param('page', 0, PARAM_INT);
     $order = optional_param('order', self::DEFAULT_ORDER, PARAM_ALPHA);
     // Assemble the options requried to reload this page.
     $optparams = array('includeauto', 'page');
     foreach ($optparams as $param) {
         if (${$param}) {
             $this->viewoptions[$param] = ${$param};
         }
     }
     if ($pagesize != self::DEFAULT_PAGE_SIZE) {
         $this->viewoptions['pagesize'] = $pagesize;
     }
     if ($order != self::DEFAULT_ORDER) {
         $this->viewoptions['order'] = $order;
     }
     // Check permissions.
     $this->context = context_module::instance($cm->id);
     require_capability('mod/quiz:grade', $this->context);
     $shownames = has_capability('quiz/grading:viewstudentnames', $this->context);
     $showidnumbers = has_capability('quiz/grading:viewidnumber', $this->context);
     // Validate order.
     if (!in_array($order, array('random', 'date', 'studentfirstname', 'studentlastname', 'idnumber'))) {
         $order = self::DEFAULT_ORDER;
     } else {
         if (!$shownames && ($order == 'studentfirstname' || $order == 'studentlastname')) {
             $order = self::DEFAULT_ORDER;
         } else {
             if (!$showidnumbers && $order == 'idnumber') {
                 $order = self::DEFAULT_ORDER;
             }
         }
     }
     if ($order == 'random') {
         $page = 0;
     }
     // Get the list of questions in this quiz.
     $this->questions = quiz_report_get_significant_questions($quiz);
     if ($slot && !array_key_exists($slot, $this->questions)) {
         throw new moodle_exception('unknownquestion', 'quiz_grading');
     }
     // Process any submitted data.
     if ($data = data_submitted() && confirm_sesskey() && $this->validate_submitted_marks()) {
         $this->process_submitted_data();
         redirect($this->grade_question_url($slot, $questionid, $grade, $page + 1));
     }
     // Get the group, and the list of significant users.
     $this->currentgroup = $this->get_current_group($cm, $course, $this->context);
     if ($this->currentgroup == self::NO_GROUPS_ALLOWED) {
         $this->users = array();
     } else {
         $this->users = get_users_by_capability($this->context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'), '', '', '', '', $this->currentgroup, '', false);
     }
     $questionsinquiz = quiz_questions_in_quiz($quiz->questions);
     $counts = null;
     if ($slot && $questionsinquiz) {
         // Make sure there is something to do.
         $statecounts = $this->get_question_state_summary(array($slot));
         foreach ($statecounts as $record) {
             if ($record->questionid == $questionid) {
                 $counts = $record;
                 break;
             }
         }
         // If not, redirect back to the list.
         if (!$counts || $counts->{$grade} == 0) {
             redirect($this->list_questions_url(), get_string('alldoneredirecting', 'quiz_grading'));
         }
     }
     // Start output.
     $this->print_header_and_tabs($cm, $course, $quiz, 'grading');
     // What sort of page to display?
     if (!$questionsinquiz) {
         echo quiz_no_questions_message($quiz, $cm, $this->context);
     } else {
         if (!$slot) {
             $this->display_index($includeauto);
         } else {
             $this->display_grading_interface($slot, $questionid, $grade, $pagesize, $page, $shownames, $showidnumbers, $order, $counts);
         }
     }
     return true;
 }
Exemple #5
0
/// Print heading and tabs if this is part of a preview
if (has_capability('mod/quiz:preview', $context)) {
    if ($attempt->userid == $USER->id) {
        // this is the report on a preview
        $currenttab = 'preview';
    } else {
        $currenttab = 'reports';
        $mode = '';
    }
    include 'tabs.php';
} else {
    print_heading(format_string($quiz->name));
}
/// Load all the questions and states needed by this script
// load the questions needed by page
$pagelist = $showall ? quiz_questions_in_quiz($attempt->layout) : quiz_questions_on_page($attempt->layout, $page);
$sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . "  FROM {$CFG->prefix}question q," . "       {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . "   AND q.id IN ({$pagelist})";
if (!($questions = get_records_sql($sql))) {
    error('No questions found');
}
// Load the question type specific information
if (!get_question_options($questions)) {
    error('Could not load question options');
}
// Restore the question sessions to their most recent states
// creating new sessions where required
if (!($states = get_question_states($questions, $quiz, $attempt))) {
    error('Could not restore question sessions');
}
/// Print infobox
$timelimit = (int) $quiz->timelimit * 60;
Exemple #6
0
/**
 * Upgrade states for an attempt to Moodle 1.5 model
 *
 * Any state that does not yet have its timestamp set to nonzero has not yet been upgraded from Moodle 1.4
 * The reason these are still around is that for large sites it would have taken too long to
 * upgrade all states at once. This function sets the timestamp field and creates an entry in the
 * question_sessions table.
 * @param object $attempt  The attempt whose states need upgrading
 */
function quiz_upgrade_states($attempt)
{
    global $CFG;
    // The old quiz model only allowed a single response per quiz attempt so that there will be
    // only one state record per question for this attempt.
    // We set the timestamp of all states to the timemodified field of the attempt.
    execute_sql("UPDATE {$CFG->prefix}question_states SET timestamp = '{$attempt->timemodified}' WHERE attempt = '{$attempt->uniqueid}'", false);
    // For each state we create an entry in the question_sessions table, with both newest and
    // newgraded pointing to this state.
    // Actually we only do this for states whose question is actually listed in $attempt->layout.
    // We do not do it for states associated to wrapped questions like for example the questions
    // used by a RANDOM question
    $session = new stdClass();
    $session->attemptid = $attempt->uniqueid;
    $questionlist = quiz_questions_in_quiz($attempt->layout);
    if ($questionlist and $states = get_records_select('question_states', "attempt = '{$attempt->uniqueid}' AND question IN ({$questionlist})")) {
        foreach ($states as $state) {
            $session->newgraded = $state->id;
            $session->newest = $state->id;
            $session->questionid = $state->question;
            insert_record('question_sessions', $session, false);
        }
    }
}
    if (!$success) {
        $pagebit = '';
        if ($page) {
            $pagebit = '&page=' . $page;
        }
        print_error('errorprocessingresponses', 'question', $CFG->wwwroot . '/mod/quiz/attempt.php?q=' . $quiz->id . $pagebit);
    }
    $attempt->timemodified = $timestamp;
    // We have now finished processing form data
}
/// Finish attempt if requested
if ($finishattempt) {
    // Set the attempt to be finished
    $attempt->timefinish = $timestamp;
    // load all the questions
    $closequestionlist = quiz_questions_in_quiz($attempt->layout);
    $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . "  FROM {$CFG->prefix}question q," . "       {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . "   AND q.id IN ({$closequestionlist})";
    if (!($closequestions = get_records_sql($sql))) {
        error('Questions missing');
    }
    // Load the question type specific information
    if (!get_question_options($closequestions)) {
        error('Could not load question options');
    }
    // Restore the question sessions
    if (!($closestates = get_question_states($closequestions, $quiz, $attempt))) {
        error('Could not restore question sessions');
    }
    $success = true;
    foreach ($closequestions as $key => $question) {
        $action->event = QUESTION_EVENTCLOSE;
Exemple #8
0
    /**
     * Display the report.
     */
    public function display($quiz, $cm, $course) {
        global $CFG, $DB, $OUTPUT, $PAGE;

        $this->context = context_module::instance($cm->id);

        // Work out the display options.
        $download = optional_param('download', '', PARAM_ALPHA);
        $everything = optional_param('everything', 0, PARAM_BOOL);
        $recalculate = optional_param('recalculate', 0, PARAM_BOOL);
        // A qid paramter indicates we should display the detailed analysis of a question.
        $qid = optional_param('qid', 0, PARAM_INT);
        $slot = optional_param('slot', 0, PARAM_INT);

        $pageoptions = array();
        $pageoptions['id'] = $cm->id;
        $pageoptions['mode'] = 'statistics';

        $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions);

        $mform = new quiz_statistics_settings_form($reporturl);
        if ($fromform = $mform->get_data()) {
            $useallattempts = $fromform->useallattempts;
            if ($fromform->useallattempts) {
                set_user_preference('quiz_report_statistics_useallattempts',
                        $fromform->useallattempts);
            } else {
                unset_user_preference('quiz_report_statistics_useallattempts');
            }

        } else {
            $useallattempts = get_user_preferences('quiz_report_statistics_useallattempts', 0);
        }

        // Find out current groups mode.
        $currentgroup = $this->get_current_group($cm, $course, $this->context);
        $nostudentsingroup = false; // True if a group is selected and there is no one in it.
        if (empty($currentgroup)) {
            $currentgroup = 0;
            $groupstudents = array();

        } else if ($currentgroup == self::NO_GROUPS_ALLOWED) {
            $groupstudents = array();
            $nostudentsingroup = true;

        } else {
            // All users who can attempt quizzes and who are in the currently selected group.
            $groupstudents = get_users_by_capability($this->context,
                    array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'),
                    '', '', '', '', $currentgroup, '', false);
            if (!$groupstudents) {
                $nostudentsingroup = true;
            }
        }

        // If recalculate was requested, handle that.
        if ($recalculate && confirm_sesskey()) {
            $this->clear_cached_data($quiz->id, $currentgroup, $useallattempts);
            redirect($reporturl);
        }

        // Set up the main table.
        $this->table = new quiz_statistics_table();
        if ($everything) {
            $report = get_string('completestatsfilename', 'quiz_statistics');
        } else {
            $report = get_string('questionstatsfilename', 'quiz_statistics');
        }
        $courseshortname = format_string($course->shortname, true,
                array('context' => context_course::instance($course->id)));
        $filename = quiz_report_download_filename($report, $courseshortname, $quiz->name);
        $this->table->is_downloading($download, $filename,
                get_string('quizstructureanalysis', 'quiz_statistics'));

        // Load the questions.
        $questions = quiz_report_get_significant_questions($quiz);
        $questionids = array();
        foreach ($questions as $question) {
            $questionids[] = $question->id;
        }
        $fullquestions = question_load_questions($questionids);
        foreach ($questions as $qno => $question) {
            $q = $fullquestions[$question->id];
            $q->maxmark = $question->maxmark;
            $q->slot = $qno;
            $q->number = $question->number;
            $questions[$qno] = $q;
        }

        // Get the data to be displayed.
        list($quizstats, $questions, $subquestions, $s) =
                $this->get_quiz_and_questions_stats($quiz, $currentgroup,
                        $nostudentsingroup, $useallattempts, $groupstudents, $questions);
        $quizinfo = $this->get_formatted_quiz_info_data($course, $cm, $quiz, $quizstats);

        // Set up the table, if there is data.
        if ($s) {
            $this->table->statistics_setup($quiz, $cm->id, $reporturl, $s);
        }

        // Print the page header stuff (if not downloading.
        if (!$this->table->is_downloading()) {
            $this->print_header_and_tabs($cm, $course, $quiz, 'statistics');

            if (groups_get_activity_groupmode($cm)) {
                groups_print_activity_menu($cm, $reporturl->out());
                if ($currentgroup && !$groupstudents) {
                    $OUTPUT->notification(get_string('nostudentsingroup', 'quiz_statistics'));
                }
            }

            if (!quiz_questions_in_quiz($quiz->questions)) {
                echo quiz_no_questions_message($quiz, $cm, $this->context);
            } else if (!$this->table->is_downloading() && $s == 0) {
                echo $OUTPUT->notification(get_string('noattempts', 'quiz'));
            }

            // Print display options form.
            $mform->set_data(array('useallattempts' => $useallattempts));
            $mform->display();
        }

        if ($everything) { // Implies is downloading.
            // Overall report, then the analysis of each question.
            $this->download_quiz_info_table($quizinfo);

            if ($s) {
                $this->output_quiz_structure_analysis_table($s, $questions, $subquestions);

                if ($this->table->is_downloading() == 'xhtml') {
                    $this->output_statistics_graph($quizstats->id, $s);
                }

                foreach ($questions as $question) {
                    if (question_bank::get_qtype(
                            $question->qtype, false)->can_analyse_responses()) {
                        $this->output_individual_question_response_analysis(
                                $question, $reporturl, $quizstats);

                    } else if (!empty($question->_stats->subquestions)) {
                        $subitemstodisplay = explode(',', $question->_stats->subquestions);
                        foreach ($subitemstodisplay as $subitemid) {
                            $this->output_individual_question_response_analysis(
                                    $subquestions[$subitemid], $reporturl, $quizstats);
                        }
                    }
                }
            }

            $this->table->export_class_instance()->finish_document();

        } else if ($slot) {
            // Report on an individual question indexed by position.
            if (!isset($questions[$slot])) {
                print_error('questiondoesnotexist', 'question');
            }

            $this->output_individual_question_data($quiz, $questions[$slot]);
            $this->output_individual_question_response_analysis(
                    $questions[$slot], $reporturl, $quizstats);

            // Back to overview link.
            echo $OUTPUT->box('<a href="' . $reporturl->out() . '">' .
                    get_string('backtoquizreport', 'quiz_statistics') . '</a>',
                    'backtomainstats boxaligncenter generalbox boxwidthnormal mdl-align');

        } else if ($qid) {
            // Report on an individual sub-question indexed questionid.
            if (!isset($subquestions[$qid])) {
                print_error('questiondoesnotexist', 'question');
            }

            $this->output_individual_question_data($quiz, $subquestions[$qid]);
            $this->output_individual_question_response_analysis(
                    $subquestions[$qid], $reporturl, $quizstats);

            // Back to overview link.
            echo $OUTPUT->box('<a href="' . $reporturl->out() . '">' .
                    get_string('backtoquizreport', 'quiz_statistics') . '</a>',
                    'boxaligncenter generalbox boxwidthnormal mdl-align');

        } else if ($this->table->is_downloading()) {
            // Downloading overview report.
            $this->download_quiz_info_table($quizinfo);
            $this->output_quiz_structure_analysis_table($s, $questions, $subquestions);
            $this->table->finish_output();

        } else {
            // On-screen display of overview report.
            echo $OUTPUT->heading(get_string('quizinformation', 'quiz_statistics'));
            echo $this->output_caching_info($quizstats, $quiz->id, $currentgroup,
                    $groupstudents, $useallattempts, $reporturl);
            echo $this->everything_download_options();
            echo $this->output_quiz_info_table($quizinfo);
            if ($s) {
                echo $OUTPUT->heading(get_string('quizstructureanalysis', 'quiz_statistics'));
                $this->output_quiz_structure_analysis_table($s, $questions, $subquestions);
                $this->output_statistics_graph($quizstats->id, $s);
            }
        }

        return true;
    }
Exemple #9
0
    function regrade_selected_attempts($quiz, $attemptids, $groupstudents) {
        global $DB;
        require_capability('mod/quiz:regrade', $this->context);
        if ($groupstudents) {
            list($usql, $params) = $DB->get_in_or_equal($groupstudents);
            $where = "qa.userid $usql AND ";
        } else {
            $params = array();
            $where = '';
        }
        list($asql, $aparams) = $DB->get_in_or_equal($attemptids);
        $where = "qa.id $asql AND ";
        $params = array_merge($params, $aparams);

        $where .= "qa.quiz = ? AND qa.preview = 0";
        $params[] = $quiz->id;
        if (!$attempts = $DB->get_records_sql('SELECT qa.* FROM {quiz_attempts} qa WHERE '. $where, $params)) {
            print_error('noattemptstoregrade', 'quiz_overview');
        }

        // Fetch all questions
        $questions = question_load_questions(explode(',',quiz_questions_in_quiz($quiz->questions)), 'qqi.grade AS maxgrade, qqi.id AS instance',
            '{quiz_question_instances} qqi ON qqi.quiz = ' . $quiz->id . ' AND q.id = qqi.question');
        $updateoverallgrades = array();
        foreach($attempts as $attempt) {
            foreach ($questions as $question) {
                $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
            }
            $updateoverallgrades[] = $attempt->uniqueid;
        }
        $this->check_overall_grades($quiz, array(), $updateoverallgrades);
    }
Exemple #10
0
 /**
  * Prints a table containing all manually graded questions
  *
  * @param object $quiz Quiz object of the currrent quiz
  * @param object $course Course object of the current course
  * @param string $userids Comma-separated list of userids in this course
  * @return boolean
  * @todo Look for the TODO in this code to see what still needs to be done
  **/
 function view_questions($quiz)
 {
     global $CFG, $QTYPE_MANUAL;
     $users = get_course_students($quiz->course);
     if (empty($users)) {
         print_heading(get_string("noattempts", "quiz"));
         return true;
     }
     // setup the table
     $table = new stdClass();
     $table->head = array(get_string("essayquestions", "quiz"), get_string("ungraded", "quiz"));
     $table->align = array("left", "left");
     $table->wrap = array("wrap", "wrap");
     $table->width = "20%";
     $table->size = array("*", "*");
     $table->data = array();
     // get the essay questions
     $questionlist = quiz_questions_in_quiz($quiz->questions);
     $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . "  FROM {$CFG->prefix}question q," . "       {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . "   AND q.id IN ({$questionlist})" . "   AND q.qtype IN ({$QTYPE_MANUAL})" . "   ORDER BY q.name";
     if (empty($questionlist) or !($questions = get_records_sql($sql))) {
         print_heading(get_string('noessayquestionsfound', 'quiz'));
         return false;
     }
     notify(get_string('essayonly', 'quiz_grading'));
     // get all the finished attempts by the users
     $userids = implode(', ', array_keys($users));
     if ($attempts = get_records_select('quiz_attempts', "quiz = {$quiz->id} and timefinish > 0 AND userid IN ({$userids}) AND preview = 0", 'userid, attempt')) {
         foreach ($questions as $question) {
             $link = "<a href=\"report.php?mode=grading&amp;q={$quiz->id}&amp;action=viewquestion&amp;questionid={$question->id}\">" . $question->name . "</a>";
             // determine the number of ungraded attempts
             $ungraded = 0;
             foreach ($attempts as $attempt) {
                 if (!$this->is_graded($question, $attempt)) {
                     $ungraded++;
                 }
             }
             $table->data[] = array($link, $ungraded);
         }
         print_table($table);
     } else {
         print_heading(get_string('noattempts', 'quiz'));
     }
     return true;
 }
Exemple #11
0
    /**
     * Display the report.
     */
    function display($quiz, $cm, $course)
    {
        global $CFG, $db;
        // Define some strings
        $strreallydel = addslashes(get_string('deleteattemptcheck', 'quiz'));
        $strtimeformat = get_string('strftimedatetime');
        $strreviewquestion = get_string('reviewresponse', 'quiz');
        $context = get_context_instance(CONTEXT_MODULE, $cm->id);
        // Only print headers if not asked to download data
        if (!($download = optional_param('download', NULL))) {
            $this->print_header_and_tabs($cm, $course, $quiz, $reportmode = "overview");
        }
        // Deal with actions
        $action = optional_param('action', '', PARAM_ACTION);
        switch ($action) {
            case 'delete':
                // Some attempts need to be deleted
                require_capability('mod/quiz:deleteattempts', $context);
                $attemptids = optional_param('attemptid', array(), PARAM_INT);
                foreach ($attemptids as $attemptid) {
                    add_to_log($course->id, 'quiz', 'delete attempt', 'report.php?id=' . $cm->id, $attemptid, $cm->id);
                    quiz_delete_attempt($attemptid, $quiz);
                }
                break;
        }
        // Set of format options for teacher-created content, for example overall feedback.
        $nocleanformatoptions = new stdClass();
        $nocleanformatoptions->noclean = true;
        // Prepare list of available actions to perform on attempts - we only want to show the checkbox.
        // Column on the table if there are options.
        $attemptactions = array();
        if (has_capability('mod/quiz:deleteattempts', $context)) {
            $attemptactions['delete'] = get_string('delete');
        }
        // Work out some display options - whether there is feedback, and whether scores should be shown.
        $hasfeedback = quiz_has_feedback($quiz->id) && $quiz->grade > 1.0E-7 && $quiz->sumgrades > 1.0E-7;
        $fakeattempt = new stdClass();
        $fakeattempt->preview = false;
        $fakeattempt->timefinish = $quiz->timeopen;
        $reviewoptions = quiz_get_reviewoptions($quiz, $fakeattempt, $context);
        $showgrades = $quiz->grade && $quiz->sumgrades && $reviewoptions->scores;
        // Set table options
        $noattempts = optional_param('noattempts', 0, PARAM_INT);
        $detailedmarks = optional_param('detailedmarks', 0, PARAM_INT);
        $pagesize = optional_param('pagesize', 10, PARAM_INT);
        $reporturl = $CFG->wwwroot . '/mod/quiz/report.php?mode=overview';
        if ($pagesize < 1) {
            $pagesize = 10;
        }
        if (!$reviewoptions->scores) {
            $detailedmarks = 0;
        }
        $reporturlwithoptions = $reporturl . '&amp;id=' . $cm->id . '&amp;noattempts=' . $noattempts . '&amp;detailedmarks=' . $detailedmarks . '&amp;pagesize=' . $pagesize;
        /// find out current groups mode
        $currentgroup = groups_get_activity_group($cm, true);
        if ($groupmode = groups_get_activity_groupmode($cm)) {
            // Groups are being used
            if (!$download) {
                groups_print_activity_menu($cm, $reporturlwithoptions);
            }
        }
        // Print information on the number of existing attempts
        if (!$download) {
            //do not print notices when downloading
            if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, false, $currentgroup)) {
                echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
            }
        }
        // Now check if asked download of data
        if ($download) {
            $filename = clean_filename("{$course->shortname} " . format_string($quiz->name, true));
            $sort = '';
        }
        // Define table columns
        $tablecolumns = array('picture', 'fullname', 'timestart', 'timefinish', 'duration');
        $tableheaders = array('', get_string('name'), get_string('startedon', 'quiz'), get_string('timecompleted', 'quiz'), get_string('attemptduration', 'quiz'));
        if (!empty($attemptactions)) {
            array_unshift($tablecolumns, 'checkbox');
            array_unshift($tableheaders, NULL);
        }
        if ($showgrades) {
            $tablecolumns[] = 'sumgrades';
            $tableheaders[] = get_string('grade', 'quiz') . '/' . $quiz->grade;
        }
        if ($detailedmarks) {
            // we want to display marks for all questions
            // Start by getting all questions
            $questionlist = quiz_questions_in_quiz($quiz->questions);
            $questionids = explode(',', $questionlist);
            $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . "  FROM {$CFG->prefix}question q," . "       {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . "   AND q.id IN ({$questionlist})";
            if (!($questions = get_records_sql($sql))) {
                error('No questions found');
            }
            $number = 1;
            foreach ($questionids as $key => $id) {
                if ($questions[$id]->length) {
                    // Only print questions of non-zero length
                    $tablecolumns[] = '$' . $id;
                    $tableheaders[] = '#' . $number;
                    $questions[$id]->number = $number;
                    $number += $questions[$id]->length;
                } else {
                    // get rid of zero length questions
                    unset($questions[$id]);
                    unset($questionids[$key]);
                }
            }
        }
        if ($hasfeedback) {
            $tablecolumns[] = 'feedbacktext';
            $tableheaders[] = get_string('feedback', 'quiz');
        }
        if (!$download) {
            // Set up the table
            $table = new flexible_table('mod-quiz-report-overview-report');
            $table->define_columns($tablecolumns);
            $table->define_headers($tableheaders);
            $table->define_baseurl($reporturlwithoptions);
            $table->sortable(true);
            $table->collapsible(true);
            $table->column_suppress('picture');
            $table->column_suppress('fullname');
            $table->column_class('picture', 'picture');
            $table->set_attribute('cellspacing', '0');
            $table->set_attribute('id', 'attempts');
            $table->set_attribute('class', 'generaltable generalbox');
            // Start working -- this is necessary as soon as the niceties are over
            $table->setup();
        } else {
            if ($download == 'ODS') {
                require_once "{$CFG->libdir}/odslib.class.php";
                $filename .= ".ods";
                // Creating a workbook
                $workbook = new MoodleODSWorkbook("-");
                // Sending HTTP headers
                $workbook->send($filename);
                // Creating the first worksheet
                $sheettitle = get_string('reportoverview', 'quiz');
                $myxls =& $workbook->add_worksheet($sheettitle);
                // format types
                $format =& $workbook->add_format();
                $format->set_bold(0);
                $formatbc =& $workbook->add_format();
                $formatbc->set_bold(1);
                $formatbc->set_align('center');
                $formatb =& $workbook->add_format();
                $formatb->set_bold(1);
                $formaty =& $workbook->add_format();
                $formaty->set_bg_color('yellow');
                $formatc =& $workbook->add_format();
                $formatc->set_align('center');
                $formatr =& $workbook->add_format();
                $formatr->set_bold(1);
                $formatr->set_color('red');
                $formatr->set_align('center');
                $formatg =& $workbook->add_format();
                $formatg->set_bold(1);
                $formatg->set_color('green');
                $formatg->set_align('center');
                // Here starts workshhet headers
                $headers = array(get_string('name'), get_string('startedon', 'quiz'), get_string('timecompleted', 'quiz'), get_string('attemptduration', 'quiz'));
                if ($showgrades) {
                    $headers[] = get_string('grade', 'quiz') . '/' . $quiz->grade;
                }
                if ($detailedmarks) {
                    foreach ($questionids as $id) {
                        $headers[] = '#' . $questions[$id]->number;
                    }
                }
                if ($hasfeedback) {
                    $headers[] = get_string('feedback', 'quiz');
                }
                $colnum = 0;
                foreach ($headers as $item) {
                    $myxls->write(0, $colnum, $item, $formatbc);
                    $colnum++;
                }
                $rownum = 1;
            } else {
                if ($download == 'Excel') {
                    require_once "{$CFG->libdir}/excellib.class.php";
                    $filename .= ".xls";
                    // Creating a workbook
                    $workbook = new MoodleExcelWorkbook("-");
                    // Sending HTTP headers
                    $workbook->send($filename);
                    // Creating the first worksheet
                    $sheettitle = get_string('reportoverview', 'quiz');
                    $myxls =& $workbook->add_worksheet($sheettitle);
                    // format types
                    $format =& $workbook->add_format();
                    $format->set_bold(0);
                    $formatbc =& $workbook->add_format();
                    $formatbc->set_bold(1);
                    $formatbc->set_align('center');
                    $formatb =& $workbook->add_format();
                    $formatb->set_bold(1);
                    $formaty =& $workbook->add_format();
                    $formaty->set_bg_color('yellow');
                    $formatc =& $workbook->add_format();
                    $formatc->set_align('center');
                    $formatr =& $workbook->add_format();
                    $formatr->set_bold(1);
                    $formatr->set_color('red');
                    $formatr->set_align('center');
                    $formatg =& $workbook->add_format();
                    $formatg->set_bold(1);
                    $formatg->set_color('green');
                    $formatg->set_align('center');
                    // Here starts workshhet headers
                    $headers = array(get_string('name'), get_string('startedon', 'quiz'), get_string('timecompleted', 'quiz'), get_string('attemptduration', 'quiz'));
                    if ($showgrades) {
                        $headers[] = get_string('grade', 'quiz') . '/' . $quiz->grade;
                    }
                    if ($detailedmarks) {
                        foreach ($questionids as $id) {
                            $headers[] = '#' . $questions[$id]->number;
                        }
                    }
                    if ($hasfeedback) {
                        $headers[] = get_string('feedback', 'quiz');
                    }
                    $colnum = 0;
                    foreach ($headers as $item) {
                        $myxls->write(0, $colnum, $item, $formatbc);
                        $colnum++;
                    }
                    $rownum = 1;
                } else {
                    if ($download == 'CSV') {
                        $filename .= ".txt";
                        header("Content-Type: application/download\n");
                        header("Content-Disposition: attachment; filename=\"{$filename}\"");
                        header("Expires: 0");
                        header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
                        header("Pragma: public");
                        $headers = get_string('name') . "\t" . get_string('startedon', 'quiz') . "\t" . get_string('timecompleted', 'quiz') . "\t" . get_string('attemptduration', 'quiz');
                        if ($showgrades) {
                            $headers .= "\t" . get_string('grade', 'quiz') . "/" . $quiz->grade;
                        }
                        if ($detailedmarks) {
                            foreach ($questionids as $id) {
                                $headers .= "\t#" . $questions[$id]->number;
                            }
                        }
                        if ($hasfeedback) {
                            $headers .= "\t" . get_string('feedback', 'quiz');
                        }
                        echo $headers . " \n";
                    }
                }
            }
        }
        $contextlists = get_related_contexts_string(get_context_instance(CONTEXT_COURSE, $course->id));
        // Construct the SQL
        $select = 'SELECT ' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ' AS uniqueid, ' . 'qa.uniqueid as attemptuniqueid, qa.id AS attempt, u.id AS userid, u.firstname, u.lastname, u.picture, ' . 'qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration ';
        if ($course->id != SITEID) {
            // this is too complicated, so just do it for each of the four cases.
            if (!empty($currentgroup) && empty($noattempts)) {
                // we want a particular group and we only want to see students WITH attempts.
                // So join on groups_members and do an inner join on attempts.
                $from = 'FROM ' . $CFG->prefix . 'user u JOIN ' . $CFG->prefix . 'role_assignments ra ON ra.userid = u.id ' . 'JOIN ' . $CFG->prefix . 'groups_members gm ON u.id = gm.userid ' . 'JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid AND qa.quiz = ' . $quiz->id;
                $where = ' WHERE ra.contextid ' . $contextlists . ' AND gm.groupid = ' . $currentgroup . ' AND qa.preview = 0';
            } else {
                if (!empty($currentgroup) && !empty($noattempts)) {
                    // We want a particular group and we want to do something funky with attempts
                    // So join on groups_members and left join on attempts...
                    $from = 'FROM ' . $CFG->prefix . 'user u JOIN ' . $CFG->prefix . 'role_assignments ra ON ra.userid = u.id ' . 'JOIN ' . $CFG->prefix . 'groups_members gm ON u.id = gm.userid ' . 'LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid AND qa.quiz = ' . $quiz->id;
                    $where = ' WHERE ra.contextid ' . $contextlists . ' AND gm.groupid = ' . $currentgroup;
                    if ($noattempts == 1) {
                        // noattempts = 1 means only no attempts, so make the left join ask for only records where the right is null (no attempts)
                        $where .= ' AND qa.userid IS NULL';
                        // show ONLY no attempts;
                    } else {
                        // We are including attempts, so exclude previews.
                        $where .= ' AND qa.preview = 0';
                    }
                } else {
                    if (empty($currentgroup)) {
                        // We don't care about group, and we to do something funky with attempts
                        // So do a left join on attempts
                        $from = 'FROM ' . $CFG->prefix . 'user u JOIN ' . $CFG->prefix . 'role_assignments ra ON ra.userid = u.id LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid AND qa.quiz = ' . $quiz->id;
                        $where = " WHERE ra.contextid {$contextlists}";
                        if (empty($noattempts)) {
                            $where .= ' AND qa.userid IS NOT NULL AND qa.preview = 0';
                            // show ONLY students with attempts;
                        } else {
                            if ($noattempts == 1) {
                                // noattempts = 1 means only no attempts, so make the left join ask for only records where the right is null (no attempts)
                                $where .= ' AND qa.userid IS NULL';
                                // show ONLY students without attempts;
                            } else {
                                if ($noattempts == 3) {
                                    // we want all attempts
                                    $from = 'FROM ' . $CFG->prefix . 'user u JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid ';
                                    $where = ' WHERE qa.quiz = ' . $quiz->id . ' AND qa.preview = 0';
                                }
                            }
                        }
                        // noattempts = 2 means we want all students, with or without attempts
                    }
                }
            }
            $countsql = 'SELECT COUNT(DISTINCT(' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ')) ' . $from . $where;
        } else {
            if (empty($noattempts)) {
                $from = 'FROM ' . $CFG->prefix . 'user u JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid ';
                $where = ' WHERE qa.quiz = ' . $quiz->id . ' AND qa.preview = 0';
                $countsql = 'SELECT COUNT(DISTINCT(' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ')) ' . $from . $where;
            }
        }
        if (!$download) {
            // Add extra limits due to initials bar
            if ($table->get_sql_where()) {
                $where .= ' AND ' . $table->get_sql_where();
            }
            // Count the records NOW, before funky question grade sorting messes up $from
            if (!empty($countsql)) {
                $totalinitials = count_records_sql($countsql);
                if ($table->get_sql_where()) {
                    $countsql .= ' AND ' . $table->get_sql_where();
                }
                $total = count_records_sql($countsql);
            }
            // Add extra limits due to sorting by question grade
            if ($sort = $table->get_sql_sort()) {
                $sortparts = explode(',', $sort);
                $newsort = array();
                $questionsort = false;
                foreach ($sortparts as $sortpart) {
                    $sortpart = trim($sortpart);
                    if (substr($sortpart, 0, 1) == '$') {
                        if (!$questionsort) {
                            $qid = intval(substr($sortpart, 1));
                            $select .= ', grade ';
                            $from .= ' LEFT JOIN ' . $CFG->prefix . 'question_sessions qns ON qns.attemptid = qa.id ' . 'LEFT JOIN ' . $CFG->prefix . 'question_states qs ON qs.id = qns.newgraded ';
                            $where .= ' AND (' . sql_isnull('qns.questionid') . ' OR qns.questionid = ' . $qid . ')';
                            $newsort[] = 'grade ' . (strpos($sortpart, 'ASC') ? 'ASC' : 'DESC');
                            $questionsort = true;
                        }
                    } else {
                        $newsort[] = $sortpart;
                    }
                }
                // Reconstruct the sort string
                $sort = ' ORDER BY ' . implode(', ', $newsort);
            }
            // Fix some wired sorting
            if (empty($sort)) {
                $sort = ' ORDER BY uniqueid';
            }
            $table->pagesize($pagesize, $total);
        }
        // If there is feedback, include it in the query.
        if ($hasfeedback) {
            $factor = $quiz->grade / $quiz->sumgrades;
            $select .= ', qf.feedbacktext ';
            $from .= " JOIN {$CFG->prefix}quiz_feedback qf ON " . "qf.quizid = {$quiz->id} AND qf.mingrade <= qa.sumgrades * {$factor} AND qa.sumgrades * {$factor} < qf.maxgrade";
        }
        // Fetch the attempts
        if (!empty($from)) {
            // if we're in the site course and displaying no attempts, it makes no sense to do the query.
            if (!$download) {
                $attempts = get_records_sql($select . $from . $where . $sort, $table->get_page_start(), $table->get_page_size());
            } else {
                $attempts = get_records_sql($select . $from . $where . $sort);
            }
        } else {
            $attempts = array();
        }
        // Build table rows
        if (!$download) {
            $table->initialbars($totalinitials > 20);
        }
        if (!empty($attempts) || !empty($noattempts)) {
            if ($attempts) {
                foreach ($attempts as $attempt) {
                    $picture = print_user_picture($attempt->userid, $course->id, $attempt->picture, false, true);
                    // uncomment the commented lines below if you are choosing to show unenrolled users and
                    // have uncommented the corresponding lines earlier in this script
                    //if (in_array($attempt->userid, $unenrolledusers)) {
                    //    $userlink = '<a class="dimmed" href="'.$CFG->wwwroot.'/user/view.php?id='.
                    //            $attempt->userid.'&amp;course='.$course->id.'">'.fullname($attempt).'</a>';
                    //}
                    //else {
                    $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $attempt->userid . '&amp;course=' . $course->id . '">' . fullname($attempt) . '</a>';
                    //}
                    // Username columns.
                    $row = array();
                    if (!$download) {
                        if (!empty($attemptactions)) {
                            $row[] = '<input type="checkbox" name="attemptid[]" value="' . $attempt->attempt . '" />';
                        }
                        $row[] = $picture;
                        $row[] = $userlink;
                    } else {
                        $row[] = fullname($attempt);
                    }
                    // Timing columns.
                    if ($attempt->attempt) {
                        $startdate = userdate($attempt->timestart, $strtimeformat);
                        if (!$download) {
                            $row[] = '<a href="review.php?q=' . $quiz->id . '&amp;attempt=' . $attempt->attempt . '">' . $startdate . '</a>';
                        } else {
                            $row[] = $startdate;
                        }
                        if ($attempt->timefinish) {
                            $timefinish = userdate($attempt->timefinish, $strtimeformat);
                            $duration = format_time($attempt->duration);
                            if (!$download) {
                                $row[] = '<a href="review.php?q=' . $quiz->id . '&amp;attempt=' . $attempt->attempt . '">' . $startdate . '</a>';
                            } else {
                                $row[] = '<a href="review.php?q=' . $quiz->id . '&amp;attempt=' . $attempt->attempt . '">' . $timefinish . '</a>';
                            }
                            $row[] = $duration;
                        } else {
                            $row[] = '-';
                            $row[] = get_string('unfinished', 'quiz');
                        }
                    } else {
                        $row[] = '-';
                        $row[] = '-';
                        $row[] = '-';
                    }
                    // Grades columns.
                    if ($showgrades) {
                        if ($attempt->timefinish) {
                            $grade = quiz_rescale_grade($attempt->sumgrades, $quiz);
                            if (!$download) {
                                $row[] = '<a href="review.php?q=' . $quiz->id . '&amp;attempt=' . $attempt->attempt . '">' . $grade . '</a>';
                            } else {
                                $row[] = $grade;
                            }
                        } else {
                            $row[] = '-';
                        }
                    }
                    if ($detailedmarks) {
                        if (empty($attempt->attempt)) {
                            foreach ($questionids as $questionid) {
                                $row[] = '-';
                            }
                        } else {
                            foreach ($questionids as $questionid) {
                                $gradedstateid = get_field('question_sessions', 'newgraded', 'attemptid', $attempt->attemptuniqueid, 'questionid', $questionid);
                                if ($gradedstateid) {
                                    $grade = round(get_field('question_states', 'grade', 'id', $gradedstateid), $quiz->decimalpoints);
                                } else {
                                    $grade = '--';
                                }
                                if (!$download) {
                                    $row[] = link_to_popup_window('/mod/quiz/reviewquestion.php?state=' . $gradedstateid . '&amp;number=' . $questions[$questionid]->number, 'reviewquestion', $grade, 450, 650, $strreviewquestion, 'none', true);
                                } else {
                                    $row[] = $grade;
                                }
                            }
                        }
                    }
                    // Feedback column.
                    if ($hasfeedback) {
                        if ($attempt->timefinish) {
                            $row[] = format_text($attempt->feedbacktext, FORMAT_MOODLE, $nocleanformatoptions);
                        } else {
                            $row[] = '-';
                        }
                    }
                    if (!$download) {
                        $table->add_data($row);
                    } else {
                        if ($download == 'Excel' or $download == 'ODS') {
                            $colnum = 0;
                            foreach ($row as $item) {
                                $myxls->write($rownum, $colnum, $item, $format);
                                $colnum++;
                            }
                            $rownum++;
                        } else {
                            if ($download == 'CSV') {
                                $text = implode("\t", $row);
                                echo $text . " \n";
                            }
                        }
                    }
                }
            }
            if (!$download) {
                // Start form
                echo '<div id="tablecontainer">';
                echo '<form id="attemptsform" method="post" action="' . $reporturlwithoptions . '" onsubmit="var menu = document.getElementById(\'menuaction\'); ' . 'return (menu.options[menu.selectedIndex].value == \'delete\' ? confirm(\'' . $strreallydel . '\') : true);">';
                echo '<div>';
                // Print table
                $table->print_html();
                // Print "Select all" etc.
                if (!empty($attempts) && !empty($attemptactions)) {
                    echo '<table id="commands">';
                    echo '<tr><td>';
                    echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectall', 'quiz') . '</a> / ';
                    echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectnone', 'quiz') . '</a> ';
                    echo '&nbsp;&nbsp;';
                    choose_from_menu($attemptactions, 'action', '', get_string('withselected', 'quiz'), 'if(this.selectedIndex > 0) submitFormById(\'attemptsform\');');
                    echo '<noscript id="noscriptmenuaction" style="display: inline;"><div>';
                    echo '<input type="submit" value="' . get_string('go') . '" /></div></noscript>';
                    echo '<script type="text/javascript">
<!--
document.getElementById("noscriptmenuaction").style.display = "none";
-->
</script>';
                    echo '</td></tr></table>';
                }
                // Close form
                echo '</div>';
                echo '</form></div>';
                if (!empty($attempts)) {
                    echo '<table class="boxaligncenter"><tr>';
                    $options = array();
                    $options["id"] = $cm->id;
                    $options["q"] = $quiz->id;
                    $options['sesskey'] = sesskey();
                    $options["noheader"] = "yes";
                    $options['noattempts'] = $noattempts;
                    $options['detailedmarks'] = $detailedmarks;
                    echo '<td>';
                    $options["download"] = "ODS";
                    print_single_button($reporturl, $options, get_string("downloadods"));
                    echo "</td>\n";
                    echo '<td>';
                    $options["download"] = "Excel";
                    print_single_button($reporturl, $options, get_string("downloadexcel"));
                    echo "</td>\n";
                    echo '<td>';
                    $options["download"] = "CSV";
                    print_single_button($reporturl, $options, get_string("downloadtext"));
                    echo "</td>\n";
                    echo "<td>";
                    helpbutton('overviewdownload', get_string('overviewdownload', 'quiz_overview'), 'quiz');
                    echo "</td>\n";
                    echo '</tr></table>';
                }
            } else {
                if ($download == 'Excel' or $download == 'ODS') {
                    $workbook->close();
                    exit;
                } else {
                    if ($download == 'CSV') {
                        exit;
                    }
                }
            }
        } else {
            if (!$download) {
                $table->print_html();
            }
        }
        // Print display options
        echo '<div class="controls">';
        echo '<form id="options" action="' . $reporturl . '" method="get">';
        echo '<div>';
        echo '<p>' . get_string('displayoptions', 'quiz') . ': </p>';
        echo '<input type="hidden" name="id" value="' . $cm->id . '" />';
        echo '<input type="hidden" name="q" value="' . $quiz->id . '" />';
        echo '<input type="hidden" name="noattempts" value="0" />';
        echo '<input type="hidden" name="detailedmarks" value="0" />';
        echo '<table id="overview-options" class="boxaligncenter">';
        echo '<tr align="left">';
        echo '<td><label for="pagesize">' . get_string('pagesize', 'quiz') . '</label></td>';
        echo '<td><input type="text" id="pagesize" name="pagesize" size="3" value="' . $pagesize . '" /></td>';
        echo '</tr>';
        echo '<tr align="left">';
        echo '<td colspan="2">';
        $options = array(0 => get_string('attemptsonly', 'quiz_overview', $course->students));
        if ($course->id != SITEID) {
            $options[1] = get_string('noattemptsonly', 'quiz_overview', $course->students);
            $options[2] = get_string('allstudents', 'quiz_overview', $course->students);
            $options[3] = get_string('allattempts', 'quiz_overview');
        }
        choose_from_menu($options, 'noattempts', $noattempts, '');
        echo '</td></tr>';
        echo '<tr align="left">';
        echo '<td colspan="2">';
        echo '<input type="checkbox" id="checkdetailedmarks" name="detailedmarks" ' . ($detailedmarks ? 'checked="checked" ' : '') . 'value="1" /> ';
        echo '<label for="checkdetailedmarks">' . get_string('showdetailedmarks', 'quiz') . '</label> ';
        echo '</td></tr>';
        echo '<tr><td colspan="2" align="center">';
        echo '<input type="submit" value="' . get_string('go') . '" />';
        echo '</td></tr></table>';
        echo '</div>';
        echo '</form>';
        echo '</div>';
        echo "\n";
        return true;
    }
 /**
  * Constructor, assuming we already have the necessary data loaded.
  *
  * @param object $quiz the row from the quiz table.
  * @param object $cm the course_module object for this quiz.
  * @param object $course the row from the course table for the course we belong to.
  * @param bool $getcontext intended for testing - stops the constructor getting the context.
  */
 public function __construct($quiz, $cm, $course, $getcontext = true)
 {
     $this->quiz = $quiz;
     $this->cm = $cm;
     $this->quiz->cmid = $this->cm->id;
     $this->course = $course;
     if ($getcontext && !empty($cm->id)) {
         $this->context = get_context_instance(CONTEXT_MODULE, $cm->id);
     }
     $this->questionids = explode(',', quiz_questions_in_quiz($this->quiz->questions));
 }
Exemple #13
0
/**
 * Load the question data necessary in the reports.
 * - Remove description questions.
 * - Order questions in order that they are in the quiz
 * - Add question numbers.
 * - Add grade from quiz_questions_instance
 */
function quiz_report_load_questions($quiz)
{
    global $CFG, $DB;
    $questionlist = quiz_questions_in_quiz($quiz->questions);
    //In fact in most cases the id IN $questionlist below is redundant
    //since we are also doing a JOIN on the qqi table. But will leave it in
    //since this double check will probably do no harm.
    list($usql, $params) = $DB->get_in_or_equal(explode(',', $questionlist));
    $params[] = $quiz->id;
    if (!($questions = $DB->get_records_sql("SELECT q.*, qqi.grade AS maxgrade\n            FROM {question} q,\n            {quiz_question_instances} qqi\n            WHERE q.id {$usql} AND\n            qqi.question = q.id AND\n            qqi.quiz = ?", $params))) {
        print_error('noquestionsfound', 'quiz');
    }
    //Now we have an array of questions from a quiz we work out there question nos and remove
    //questions with zero length ie. description questions etc.
    //also put questions in order.
    $number = 1;
    $realquestions = array();
    $questionids = explode(',', $questionlist);
    foreach ($questionids as $id) {
        if ($questions[$id]->length) {
            // Ignore questions of zero length
            $realquestions[$id] = $questions[$id];
            $realquestions[$id]->number = $number;
            $number += $questions[$id]->length;
        }
    }
    return $realquestions;
}
Exemple #14
0
/**
 * Get the slot for a question with a particular id.
 * @param object $quiz the quiz settings.
 * @param int $questionid the of a question in the quiz.
 * @return int the corresponding slot. Null if the question is not in the quiz.
 */
function quiz_get_slot_for_question($quiz, $questionid) {
    $questionids = quiz_questions_in_quiz($quiz->questions);
    foreach (explode(',', $questionids) as $key => $id) {
        if ($id == $questionid) {
            return $key + 1;
        }
    }
    return null;
}
Exemple #15
0
/**
 * Upgrade states for an attempt to Moodle 1.5 model
 *
 * Any state that does not yet have its timestamp set to nonzero has not yet been upgraded from Moodle 1.4
 * The reason these are still around is that for large sites it would have taken too long to
 * upgrade all states at once. This function sets the timestamp field and creates an entry in the
 * question_sessions table.
 * @param object $attempt  The attempt whose states need upgrading
 */
function quiz_upgrade_states($attempt)
{
    global $DB;
    global $CFG;
    // The old quiz model only allowed a single response per quiz attempt so that there will be
    // only one state record per question for this attempt.
    // We set the timestamp of all states to the timemodified field of the attempt.
    $DB->execute("UPDATE {question_states} SET timestamp = ? WHERE attempt = ?", array($attempt->timemodified, $attempt->uniqueid));
    // For each state we create an entry in the question_sessions table, with both newest and
    // newgraded pointing to this state.
    // Actually we only do this for states whose question is actually listed in $attempt->layout.
    // We do not do it for states associated to wrapped questions like for example the questions
    // used by a RANDOM question
    $session = new stdClass();
    $session->attemptid = $attempt->uniqueid;
    $questionlist = quiz_questions_in_quiz($attempt->layout);
    $params = array($attempt->uniqueid);
    list($usql, $question_params) = $DB->get_in_or_equal(explode(',', $questionlist));
    $params = array_merge($params, $question_params);
    if ($questionlist and $states = $DB->get_records_select('question_states', "attempt = ? AND question {$usql}", $params)) {
        foreach ($states as $state) {
            $session->newgraded = $state->id;
            $session->newest = $state->id;
            $session->questionid = $state->question;
            $DB->insert_record('question_sessions', $session, false);
        }
    }
}
 /**
  * Constructor, assuming we already have the necessary data loaded.
  *
  * @param object $quiz the row from the quiz table.
  * @param object $cm the course_module object for this quiz.
  * @param object $course the row from the course table for the course we belong to.
  * @param bool $getcontext intended for testing - stops the constructor getting the context.
  */
 public function __construct($quiz, $cm, $course, $getcontext = true)
 {
     $this->quiz = $quiz;
     $this->cm = $cm;
     $this->quiz->cmid = $this->cm->id;
     $this->course = $course;
     if ($getcontext && !empty($cm->id)) {
         $this->context = context_module::instance($cm->id);
     }
     $questionids = quiz_questions_in_quiz($this->quiz->questions);
     if ($questionids) {
         $this->questionids = explode(',', quiz_questions_in_quiz($this->quiz->questions));
     } else {
         $this->questionids = array();
         // Which idiot made explode(',', '') = array('')?
     }
 }
Exemple #17
0
 public function display($quiz, $cm, $course)
 {
     global $CFG, $COURSE, $DB, $PAGE, $OUTPUT;
     $this->context = get_context_instance(CONTEXT_MODULE, $cm->id);
     $download = optional_param('download', '', PARAM_ALPHA);
     list($currentgroup, $students, $groupstudents, $allowed) = $this->load_relevant_students($cm);
     $pageoptions = array();
     $pageoptions['id'] = $cm->id;
     $pageoptions['mode'] = 'responses';
     $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions);
     $qmsubselect = quiz_report_qm_filter_select($quiz);
     $mform = new mod_quiz_report_responses_settings($reporturl, array('qmsubselect' => $qmsubselect, 'quiz' => $quiz, 'currentgroup' => $currentgroup, 'context' => $this->context));
     if ($fromform = $mform->get_data()) {
         $attemptsmode = $fromform->attemptsmode;
         if ($qmsubselect) {
             $qmfilter = $fromform->qmfilter;
         } else {
             $qmfilter = 0;
         }
         set_user_preference('quiz_report_responses_qtext', $fromform->qtext);
         set_user_preference('quiz_report_responses_resp', $fromform->resp);
         set_user_preference('quiz_report_responses_right', $fromform->right);
         set_user_preference('quiz_report_pagesize', $fromform->pagesize);
         $includeqtext = $fromform->qtext;
         $includeresp = $fromform->resp;
         $includeright = $fromform->right;
         $pagesize = $fromform->pagesize;
     } else {
         $attemptsmode = optional_param('attemptsmode', null, PARAM_INT);
         if ($qmsubselect) {
             $qmfilter = optional_param('qmfilter', 0, PARAM_INT);
         } else {
             $qmfilter = 0;
         }
         $includeqtext = get_user_preferences('quiz_report_responses_qtext', 0);
         $includeresp = get_user_preferences('quiz_report_responses_resp', 1);
         $includeright = get_user_preferences('quiz_report_responses_right', 0);
         $pagesize = get_user_preferences('quiz_report_pagesize', 0);
     }
     $this->validate_common_options($attemptsmode, $pagesize, $course, $currentgroup);
     if (!$includeqtext && !$includeresp && !$includeright) {
         $includeresp = 1;
         set_user_preference('quiz_report_responses_resp', 1);
     }
     // We only want to show the checkbox to delete attempts
     // if the user has permissions and if the report mode is showing attempts.
     $candelete = has_capability('mod/quiz:deleteattempts', $this->context) && $attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO;
     $displayoptions = array();
     $displayoptions['attemptsmode'] = $attemptsmode;
     $displayoptions['qmfilter'] = $qmfilter;
     $displayoptions['qtext'] = $includeqtext;
     $displayoptions['resp'] = $includeresp;
     $displayoptions['right'] = $includeright;
     $mform->set_data($displayoptions + array('pagesize' => $pagesize));
     if ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) {
         // This option is only available to users who can access all groups in
         // groups mode, so setting allowed to empty (which means all quiz attempts
         // are accessible, is not a security porblem.
         $allowed = array();
     }
     $attemptids = optional_param_array('attemptid', array(), PARAM_INT);
     if ($attemptids && confirm_sesskey()) {
         require_capability('mod/quiz:deleteattempts', $this->context);
         $this->delete_selected_attempts($quiz, $cm, $attemptids, $allowed);
         redirect($reporturl->out(false, $displayoptions));
     }
     // Load the required questions.
     $questions = quiz_report_get_significant_questions($quiz);
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
     $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
     $displaycoursecontext = get_context_instance(CONTEXT_COURSE, $COURSE->id);
     $displaycourseshortname = format_string($COURSE->shortname, true, array('context' => $displaycoursecontext));
     $table = new quiz_report_responses_table($quiz, $this->context, $qmsubselect, $groupstudents, $students, $questions, $candelete, $reporturl, $displayoptions);
     $filename = quiz_report_download_filename(get_string('responsesfilename', 'quiz_responses'), $courseshortname, $quiz->name);
     $table->is_downloading($download, $filename, $displaycourseshortname . ' ' . format_string($quiz->name, true));
     if ($table->is_downloading()) {
         raise_memory_limit(MEMORY_EXTRA);
     }
     if (!$table->is_downloading()) {
         // Only print headers if not asked to download data
         $this->print_header_and_tabs($cm, $course, $quiz, 'responses');
     }
     if ($groupmode = groups_get_activity_groupmode($cm)) {
         // Groups are being used
         if (!$table->is_downloading()) {
             groups_print_activity_menu($cm, $reporturl->out(true, $displayoptions));
         }
     }
     // Print information on the number of existing attempts
     if (!$table->is_downloading()) {
         //do not print notices when downloading
         if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) {
             echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
         }
     }
     $hasquestions = quiz_questions_in_quiz($quiz->questions);
     if (!$table->is_downloading()) {
         if (!$hasquestions) {
             echo quiz_no_questions_message($quiz, $cm, $this->context);
         } else {
             if (!$students) {
                 echo $OUTPUT->notification(get_string('nostudentsyet'));
             } else {
                 if ($currentgroup && !$groupstudents) {
                     echo $OUTPUT->notification(get_string('nostudentsingroup'));
                 }
             }
         }
         // Print display options
         $mform->display();
     }
     $hasstudents = $students && (!$currentgroup || $groupstudents);
     if ($hasquestions && ($hasstudents || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL)) {
         // Print information on the grading method and whether we are displaying
         if (!$table->is_downloading()) {
             //do not print notices when downloading
             if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) {
                 echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
             }
         }
         list($fields, $from, $where, $params) = $this->base_sql($quiz, $qmsubselect, $qmfilter, $attemptsmode, $allowed);
         $table->set_count_sql("SELECT COUNT(1) FROM {$from} WHERE {$where}", $params);
         $table->set_sql($fields, $from, $where, $params);
         // Define table columns
         $columns = array();
         $headers = array();
         if (!$table->is_downloading() && $candelete) {
             $columns[] = 'checkbox';
             $headers[] = null;
         }
         $this->add_user_columns($table, $columns, $headers);
         if ($table->is_downloading()) {
             $this->add_time_columns($columns, $headers);
         }
         $this->add_grade_columns($quiz, $columns, $headers);
         foreach ($questions as $id => $question) {
             if ($displayoptions['qtext']) {
                 $columns[] = 'question' . $id;
                 $headers[] = get_string('questionx', 'question', $question->number);
             }
             if ($displayoptions['resp']) {
                 $columns[] = 'response' . $id;
                 $headers[] = get_string('responsex', 'quiz_responses', $question->number);
             }
             if ($displayoptions['right']) {
                 $columns[] = 'right' . $id;
                 $headers[] = get_string('rightanswerx', 'quiz_responses', $question->number);
             }
         }
         $table->define_columns($columns);
         $table->define_headers($headers);
         $table->sortable(true, 'uniqueid');
         // Set up the table
         $table->define_baseurl($reporturl->out(true, $displayoptions));
         $this->configure_user_columns($table);
         $table->no_sorting('feedbacktext');
         $table->column_class('sumgrades', 'bold');
         $table->set_attribute('id', 'attempts');
         $table->collapsible(true);
         $table->out($pagesize, true);
     }
     return true;
 }
Exemple #18
0
    public function display($quiz, $cm, $course) {
        global $CFG, $DB, $OUTPUT;

        list($currentgroup, $students, $groupstudents, $allowed) =
                $this->init('responses', 'quiz_responses_settings_form', $quiz, $cm, $course);
        $options = new quiz_responses_options('responses', $quiz, $cm, $course);

        if ($fromform = $this->form->get_data()) {
            $options->process_settings_from_form($fromform);

        } else {
            $options->process_settings_from_params();
        }

        $this->form->set_data($options->get_initial_form_data());

        if ($options->attempts == self::ALL_WITH) {
            // This option is only available to users who can access all groups in
            // groups mode, so setting allowed to empty (which means all quiz attempts
            // are accessible, is not a security porblem.
            $allowed = array();
        }

        // Load the required questions.
        $questions = quiz_report_get_significant_questions($quiz);

        // Prepare for downloading, if applicable.
        $courseshortname = format_string($course->shortname, true,
                array('context' => context_course::instance($course->id)));
        $table = new quiz_responses_table($quiz, $this->context, $this->qmsubselect,
                $options, $groupstudents, $students, $questions, $this->get_base_url());
        $filename = quiz_report_download_filename(get_string('responsesfilename', 'quiz_responses'),
                $courseshortname, $quiz->name);
        $table->is_downloading($options->download, $filename,
                $courseshortname . ' ' . format_string($quiz->name, true));
        if ($table->is_downloading()) {
            raise_memory_limit(MEMORY_EXTRA);
        }

        $this->process_actions($quiz, $cm, $currentgroup, $groupstudents, $allowed, $options->get_url());

        // Start output.
        if (!$table->is_downloading()) {
            // Only print headers if not asked to download data.
            $this->print_header_and_tabs($cm, $course, $quiz, $this->mode);
        }

        if ($groupmode = groups_get_activity_groupmode($cm)) {
            // Groups are being used, so output the group selector if we are not downloading.
            if (!$table->is_downloading()) {
                groups_print_activity_menu($cm, $options->get_url());
            }
        }

        // Print information on the number of existing attempts.
        if (!$table->is_downloading()) {
            // Do not print notices when downloading.
            if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) {
                echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
            }
        }

        $hasquestions = quiz_questions_in_quiz($quiz->questions);
        if (!$table->is_downloading()) {
            if (!$hasquestions) {
                echo quiz_no_questions_message($quiz, $cm, $this->context);
            } else if (!$students) {
                echo $OUTPUT->notification(get_string('nostudentsyet'));
            } else if ($currentgroup && !$groupstudents) {
                echo $OUTPUT->notification(get_string('nostudentsingroup'));
            }

            // Print the display options.
            $this->form->display();
        }

        $hasstudents = $students && (!$currentgroup || $groupstudents);
        if ($hasquestions && ($hasstudents || $options->attempts == self::ALL_WITH)) {

            list($fields, $from, $where, $params) = $table->base_sql($allowed);

            $table->set_count_sql("SELECT COUNT(1) FROM $from WHERE $where", $params);

            $table->set_sql($fields, $from, $where, $params);

            if (!$table->is_downloading()) {
                // Print information on the grading method.
                if ($strattempthighlight = quiz_report_highlighting_grading_method(
                        $quiz, $this->qmsubselect, $options->onlygraded)) {
                    echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
                }
            }

            // Define table columns.
            $columns = array();
            $headers = array();

            if (!$table->is_downloading() && $options->checkboxcolumn) {
                $columns[] = 'checkbox';
                $headers[] = null;
            }

            $this->add_user_columns($table, $columns, $headers);
            $this->add_state_column($columns, $headers);

            if ($table->is_downloading()) {
                $this->add_time_columns($columns, $headers);
            }

            $this->add_grade_columns($quiz, $options->usercanseegrades, $columns, $headers);

            foreach ($questions as $id => $question) {
                if ($options->showqtext) {
                    $columns[] = 'question' . $id;
                    $headers[] = get_string('questionx', 'question', $question->number);
                }
                if ($options->showresponses) {
                    $columns[] = 'response' . $id;
                    $headers[] = get_string('responsex', 'quiz_responses', $question->number);
                }
                if ($options->showright) {
                    $columns[] = 'right' . $id;
                    $headers[] = get_string('rightanswerx', 'quiz_responses', $question->number);
                }
            }

            $table->define_columns($columns);
            $table->define_headers($headers);
            $table->sortable(true, 'uniqueid');

            // Set up the table.
            $table->define_baseurl($options->get_url());

            $this->configure_user_columns($table);

            $table->no_sorting('feedbacktext');
            $table->column_class('sumgrades', 'bold');

            $table->set_attribute('id', 'attempts');

            $table->collapsible(true);

            $table->out($options->pagesize, true);
        }
        return true;
    }
Exemple #19
0
 function display($quiz, $cm, $course)
 {
     global $CFG;
     // Print header
     $this->print_header_and_tabs($cm, $course, $quiz, $reportmode = "regrade");
     // Check permissions
     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
     if (!has_capability('mod/quiz:grade', $context)) {
         notify(get_string('regradenotallowed', 'quiz'));
         return true;
     }
     // Fetch all attempts
     if (!($attempts = get_records_select('quiz_attempts', "quiz = '{$quiz->id}' AND preview = 0"))) {
         print_heading(get_string('noattempts', 'quiz'));
         return true;
     }
     // Fetch all questions
     $sql = "SELECT q.*, i.grade AS maxgrade FROM {$CFG->prefix}question q,\n                                         {$CFG->prefix}quiz_question_instances i\n                WHERE i.quiz = {$quiz->id}\n                AND i.question = q.id";
     if (!($questions = get_records_sql($sql))) {
         error("Failed to get questions for regrading!");
     }
     get_question_options($questions);
     // Print heading
     print_heading(get_string('regradingquiz', 'quiz', format_string($quiz->name)));
     echo '<div class="boxaligncenter">';
     print_string('regradedisplayexplanation', 'quiz');
     echo '</div>';
     // Loop through all questions and all attempts and regrade while printing progress info
     foreach ($questions as $question) {
         echo '<strong>' . get_string('regradingquestion', 'quiz', $question->name) . '</strong> ' . get_string('attempts', 'quiz') . ": \n";
         foreach ($attempts as $attempt) {
             set_time_limit(30);
             $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
             if ($changed) {
                 link_to_popup_window('/mod/quiz/reviewquestion.php?attempt=' . $attempt->id . '&amp;question=' . $question->id, 'reviewquestion', ' #' . $attempt->id, 450, 550, get_string('reviewresponse', 'quiz'));
             } else {
                 echo ' #' . $attempt->id;
             }
         }
         echo '<br />';
         // the following makes sure that the output is sent immediately.
         @flush();
         @ob_flush();
     }
     // Loop through all questions and recalculate $attempt->sumgrade
     $attemptschanged = 0;
     foreach ($attempts as $attempt) {
         $sumgrades = 0;
         $questionids = explode(',', quiz_questions_in_quiz($attempt->layout));
         foreach ($questionids as $questionid) {
             $lastgradedid = get_field('question_sessions', 'newgraded', 'attemptid', $attempt->uniqueid, 'questionid', $questionid);
             $sumgrades += get_field('question_states', 'grade', 'id', $lastgradedid);
         }
         if ($attempt->sumgrades != $sumgrades) {
             $attemptschanged++;
             set_field('quiz_attempts', 'sumgrades', $sumgrades, 'id', $attempt->id);
         }
     }
     // Update the overall quiz grades
     if ($grades = get_records('quiz_grades', 'quiz', $quiz->id)) {
         foreach ($grades as $grade) {
             quiz_save_best_grade($quiz, $grade->userid);
         }
     }
     return true;
 }
Exemple #20
0
 function display($quiz, $cm, $course)
 {
     /// This function just displays the report
     global $CFG, $SESSION, $db, $QTYPES;
     $strnoquiz = get_string('noquiz', 'quiz');
     $strnoattempts = get_string('noattempts', 'quiz');
     /// Only print headers if not asked to download data
     $download = optional_param('download', NULL);
     if (!$download) {
         $this->print_header_and_tabs($cm, $course, $quiz, $reportmode = "analysis");
     }
     /// Construct the table for this particular report
     if (!$quiz->questions) {
         print_heading($strnoattempts);
         return true;
     }
     /// Check to see if groups are being used in this quiz
     if ($groupmode = groupmode($course, $cm)) {
         // Groups are being used
         if (!$download) {
             $currentgroup = setup_and_print_groups($course, $groupmode, "report.php?id={$cm->id}&amp;mode=analysis");
         } else {
             $currentgroup = get_and_set_current_group($course, $groupmode);
         }
     } else {
         $currentgroup = get_and_set_current_group($course, $groupmode);
     }
     // set Table and Analysis stats options
     if (!isset($SESSION->quiz_analysis_table)) {
         $SESSION->quiz_analysis_table = array('attemptselection' => 0, 'lowmarklimit' => 0, 'pagesize' => 10);
     }
     foreach ($SESSION->quiz_analysis_table as $option => $value) {
         $urlparam = optional_param($option, NULL);
         if ($urlparam === NULL) {
             ${$option} = $value;
         } else {
             ${$option} = $SESSION->quiz_analysis_table[$option] = $urlparam;
         }
     }
     $scorelimit = $quiz->sumgrades * $lowmarklimit / 100;
     // ULPGC ecastro DEBUG this is here to allow for different SQL to select attempts
     switch ($attemptselection) {
         case QUIZ_ALLATTEMPTS:
             $limit = '';
             $group = '';
             break;
         case QUIZ_HIGHESTATTEMPT:
             $limit = ', max(qa.sumgrades) ';
             $group = ' GROUP BY qa.userid ';
             break;
         case QUIZ_FIRSTATTEMPT:
             $limit = ', min(qa.timemodified) ';
             $group = ' GROUP BY qa.userid ';
             break;
         case QUIZ_LASTATTEMPT:
             $limit = ', max(qa.timemodified) ';
             $group = ' GROUP BY qa.userid ';
             break;
     }
     if ($attemptselection != QUIZ_ALLATTEMPTS) {
         $sql = 'SELECT qa.userid ' . $limit . 'FROM ' . $CFG->prefix . 'user u LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid ' . 'WHERE qa.quiz = ' . $quiz->id . ' AND qa.preview = 0 ' . $group;
         $usermax = get_records_sql_menu($sql);
     }
     $groupmembers = '';
     $groupwhere = '';
     //Add this to the SQL to show only group users
     if ($currentgroup) {
         $groupmembers = ', ' . groups_members_from_sql();
         $groupwhere = ' AND ' . groups_members_where_sql($currentgroup, 'u.id');
     }
     $sql = 'SELECT  qa.* FROM ' . $CFG->prefix . 'quiz_attempts qa, ' . $CFG->prefix . 'user u ' . $groupmembers . 'WHERE u.id = qa.userid AND qa.quiz = ' . $quiz->id . ' AND qa.preview = 0 AND ( qa.sumgrades >= ' . $scorelimit . ' ) ' . $groupwhere;
     // ^^^^^^ es posible seleccionar aqu TODOS los quizzes, como quiere Jussi,
     // pero habra que llevar la cuenta ed cada quiz para restaura las preguntas (quizquestions, states)
     /// Fetch the attempts
     $attempts = get_records_sql($sql);
     if (empty($attempts)) {
         print_heading(get_string('nothingtodisplay'));
         $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
         return true;
     }
     /// Here we rewiew all attempts and record data to construct the table
     $questions = array();
     $statstable = array();
     $questionarray = array();
     foreach ($attempts as $attempt) {
         $questionarray[] = quiz_questions_in_quiz($attempt->layout);
     }
     $questionlist = quiz_questions_in_quiz(implode(",", $questionarray));
     $questionarray = array_unique(explode(",", $questionlist));
     $questionlist = implode(",", $questionarray);
     unset($questionarray);
     foreach ($attempts as $attempt) {
         switch ($attemptselection) {
             case QUIZ_ALLATTEMPTS:
                 $userscore = 0;
                 // can be anything, not used
                 break;
             case QUIZ_HIGHESTATTEMPT:
                 $userscore = $attempt->sumgrades;
                 break;
             case QUIZ_FIRSTATTEMPT:
                 $userscore = $attempt->timemodified;
                 break;
             case QUIZ_LASTATTEMPT:
                 $userscore = $attempt->timemodified;
                 break;
         }
         if ($attemptselection == QUIZ_ALLATTEMPTS || $userscore == $usermax[$attempt->userid]) {
             $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . "  FROM {$CFG->prefix}question q," . "       {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . "   AND q.id IN ({$questionlist})";
             if (!($quizquestions = get_records_sql($sql))) {
                 error('No questions found');
             }
             // Load the question type specific information
             if (!get_question_options($quizquestions)) {
                 error('Could not load question options');
             }
             // Restore the question sessions to their most recent states
             // creating new sessions where required
             if (!($states = get_question_states($quizquestions, $quiz, $attempt))) {
                 error('Could not restore question sessions');
             }
             $numbers = explode(',', $questionlist);
             $statsrow = array();
             foreach ($numbers as $i) {
                 if (!isset($quizquestions[$i]) or !isset($states[$i])) {
                     continue;
                 }
                 $qtype = $quizquestions[$i]->qtype == 'random' ? $states[$i]->options->question->qtype : $quizquestions[$i]->qtype;
                 $q = get_question_responses($quizquestions[$i], $states[$i]);
                 if (empty($q)) {
                     continue;
                 }
                 $qid = $q->id;
                 if (!isset($questions[$qid])) {
                     $questions[$qid]['id'] = $qid;
                     $questions[$qid]['qname'] = $quizquestions[$i]->name;
                     foreach ($q->responses as $answer => $r) {
                         $r->count = 0;
                         $questions[$qid]['responses'][$answer] = $r->answer;
                         $questions[$qid]['rcounts'][$answer] = 0;
                         $questions[$qid]['credits'][$answer] = $r->credit;
                         $statsrow[$qid] = 0;
                     }
                 }
                 $responses = get_question_actual_response($quizquestions[$i], $states[$i]);
                 foreach ($responses as $resp) {
                     if ($resp) {
                         if ($key = array_search($resp, $questions[$qid]['responses'])) {
                             $questions[$qid]['rcounts'][$key]++;
                         } else {
                             $test = new stdClass();
                             $test->responses = $QTYPES[$quizquestions[$i]->qtype]->get_correct_responses($quizquestions[$i], $states[$i]);
                             if ($key = $QTYPES[$quizquestions[$i]->qtype]->check_response($quizquestions[$i], $states[$i], $test)) {
                                 $questions[$qid]['rcounts'][$key]++;
                             } else {
                                 $questions[$qid]['responses'][] = $resp;
                                 $questions[$qid]['rcounts'][] = 1;
                                 $questions[$qid]['credits'][] = 0;
                             }
                         }
                     }
                 }
                 $statsrow[$qid] = get_question_fraction_grade($quizquestions[$i], $states[$i]);
             }
             $attemptscores[$attempt->id] = $attempt->sumgrades;
             $statstable[$attempt->id] = $statsrow;
         }
     }
     // Statistics Data table built
     unset($attempts);
     unset($quizquestions);
     unset($states);
     // now calculate statistics and set the values in the $questions array
     $top = max($attemptscores);
     $bottom = min($attemptscores);
     $gap = ($top - $bottom) / 3;
     $top -= $gap;
     $bottom += $gap;
     foreach ($questions as $qid => $q) {
         $questions[$qid] = $this->report_question_stats($q, $attemptscores, $statstable, $top, $bottom);
     }
     unset($attemptscores);
     unset($statstable);
     /// Now check if asked download of data
     if ($download = optional_param('download', NULL)) {
         $filename = clean_filename("{$course->shortname} " . format_string($quiz->name, true));
         switch ($download) {
             case "Excel":
                 $this->Export_Excel($questions, $filename);
                 break;
             case "ODS":
                 $this->Export_ODS($questions, $filename);
                 break;
             case "CSV":
                 $this->Export_CSV($questions, $filename);
                 break;
         }
     }
     /// Construct the table for this particular report
     $tablecolumns = array('id', 'qname', 'responses', 'credits', 'rcounts', 'rpercent', 'facility', 'qsd', 'disc_index', 'disc_coeff');
     $tableheaders = array(get_string('qidtitle', 'quiz_analysis'), get_string('qtexttitle', 'quiz_analysis'), get_string('responsestitle', 'quiz_analysis'), get_string('rfractiontitle', 'quiz_analysis'), get_string('rcounttitle', 'quiz_analysis'), get_string('rpercenttitle', 'quiz_analysis'), get_string('facilitytitle', 'quiz_analysis'), get_string('stddevtitle', 'quiz_analysis'), get_string('dicsindextitle', 'quiz_analysis'), get_string('disccoefftitle', 'quiz_analysis'));
     $table = new flexible_table('mod-quiz-report-itemanalysis');
     $table->define_columns($tablecolumns);
     $table->define_headers($tableheaders);
     $table->define_baseurl($CFG->wwwroot . '/mod/quiz/report.php?q=' . $quiz->id . '&amp;mode=analysis');
     $table->sortable(true);
     $table->no_sorting('rpercent');
     $table->collapsible(true);
     $table->initialbars(false);
     $table->column_class('id', 'numcol');
     $table->column_class('credits', 'numcol');
     $table->column_class('rcounts', 'numcol');
     $table->column_class('rpercent', 'numcol');
     $table->column_class('facility', 'numcol');
     $table->column_class('qsd', 'numcol');
     $table->column_class('disc_index', 'numcol');
     $table->column_class('disc_coeff', 'numcol');
     $table->column_suppress('id');
     $table->column_suppress('qname');
     $table->column_suppress('facility');
     $table->column_suppress('qsd');
     $table->column_suppress('disc_index');
     $table->column_suppress('disc_coeff');
     $table->set_attribute('cellspacing', '0');
     $table->set_attribute('id', 'itemanalysis');
     $table->set_attribute('class', 'generaltable generalbox');
     // Start working -- this is necessary as soon as the niceties are over
     $table->setup();
     $tablesort = $table->get_sql_sort();
     $sorts = explode(",", trim($tablesort));
     if ($tablesort and is_array($sorts)) {
         $sortindex = array();
         $sortorder = array();
         foreach ($sorts as $sort) {
             $data = explode(" ", trim($sort));
             $sortindex[] = trim($data[0]);
             $s = trim($data[1]);
             if ($s == "ASC") {
                 $sortorder[] = SORT_ASC;
             } else {
                 $sortorder[] = SORT_DESC;
             }
         }
         if (count($sortindex) > 0) {
             $sortindex[] = "id";
             $sortorder[] = SORT_ASC;
             foreach ($questions as $qid => $row) {
                 $index1[$qid] = $row[$sortindex[0]];
                 $index2[$qid] = $row[$sortindex[1]];
             }
             array_multisort($index1, $sortorder[0], $index2, $sortorder[1], $questions);
         }
     }
     $format_options = new stdClass();
     $format_options->para = false;
     $format_options->noclean = true;
     $format_options->newlines = false;
     // Now it is time to page the data, simply slice the keys in the array
     if (!isset($pagesize) || (int) $pagesize < 1) {
         $pagesize = 10;
     }
     $table->pagesize($pagesize, count($questions));
     $start = $table->get_page_start();
     $pagequestions = array_slice(array_keys($questions), $start, $pagesize);
     foreach ($pagequestions as $qnum) {
         $q = $questions[$qnum];
         $qid = $q['id'];
         $question = get_record('question', 'id', $qid);
         if (has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $course->id))) {
             $qnumber = " (" . link_to_popup_window('/question/question.php?id=' . $qid, '&amp;cmid=' . $cm->id . 'editquestion', $qid, 450, 550, get_string('edit'), 'none', true) . ") ";
         } else {
             $qnumber = $qid;
         }
         $qname = '<div class="qname">' . format_text($question->name . " :  ", $question->questiontextformat, $format_options, $quiz->course) . '</div>';
         $qicon = print_question_icon($question, true);
         $qreview = quiz_question_preview_button($quiz, $question);
         $qtext = format_text($question->questiontext, $question->questiontextformat, $format_options, $quiz->course);
         $qquestion = $qname . "\n" . $qtext . "\n";
         $responses = array();
         foreach ($q['responses'] as $aid => $resp) {
             $response = new stdClass();
             if ($q['credits'][$aid] <= 0) {
                 $qclass = 'uncorrect';
             } elseif ($q['credits'][$aid] == 1) {
                 $qclass = 'correct';
             } else {
                 $qclass = 'partialcorrect';
             }
             $response->credit = '<span class="' . $qclass . '">(' . format_float($q['credits'][$aid], 2) . ') </span>';
             $response->text = '<span class="' . $qclass . '">' . format_text($resp, FORMAT_MOODLE, $format_options, $quiz->course) . ' </span>';
             $count = $q['rcounts'][$aid] . '/' . $q['count'];
             $response->rcount = $count;
             $response->rpercent = '(' . format_float($q['rcounts'][$aid] / $q['count'] * 100, 0) . '%)';
             $responses[] = $response;
         }
         $facility = format_float($q['facility'] * 100, 0) . "%";
         $qsd = format_float($q['qsd'], 3);
         $di = format_float($q['disc_index'], 2);
         $dc = format_float($q['disc_coeff'], 2);
         $response = array_shift($responses);
         $table->add_data(array($qnumber . "\n<br />" . $qicon . "\n " . $qreview, $qquestion, $response->text, $response->credit, $response->rcount, $response->rpercent, $facility, $qsd, $di, $dc));
         foreach ($responses as $response) {
             $table->add_data(array('', '', $response->text, $response->credit, $response->rcount, $response->rpercent, '', '', '', ''));
         }
     }
     print_heading_with_help(get_string("analysistitle", "quiz_analysis"), "itemanalysis", "quiz");
     echo '<div id="tablecontainer">';
     $table->print_html();
     echo '</div>';
     $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
     return true;
 }
 public function display($quiz, $cm, $course)
 {
     global $CFG, $DB, $OUTPUT, $PAGE;
     list($currentgroup, $students, $groupstudents, $allowed) = $this->init('overview', 'quiz_overview_settings_form', $quiz, $cm, $course);
     $options = new quiz_overview_options('overview', $quiz, $cm, $course);
     if ($fromform = $this->form->get_data()) {
         $options->process_settings_from_form($fromform);
     } else {
         $options->process_settings_from_params();
     }
     $this->form->set_data($options->get_initial_form_data());
     if ($options->attempts == self::ALL_WITH) {
         // This option is only available to users who can access all groups in
         // groups mode, so setting allowed to empty (which means all quiz attempts
         // are accessible, is not a security porblem.
         $allowed = array();
     }
     // Load the required questions.
     $questions = quiz_report_get_significant_questions($quiz);
     // Prepare for downloading, if applicable.
     $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
     $table = new quiz_overview_table($quiz, $this->context, $this->qmsubselect, $options, $groupstudents, $students, $questions, $options->get_url());
     $filename = quiz_report_download_filename(get_string('overviewfilename', 'quiz_overview'), $courseshortname, $quiz->name);
     $table->is_downloading($options->download, $filename, $courseshortname . ' ' . format_string($quiz->name, true));
     if ($table->is_downloading()) {
         raise_memory_limit(MEMORY_EXTRA);
     }
     $this->course = $course;
     // Hack to make this available in process_actions.
     $this->process_actions($quiz, $cm, $currentgroup, $groupstudents, $allowed, $options->get_url());
     // Start output.
     if (!$table->is_downloading()) {
         // Only print headers if not asked to download data.
         $this->print_header_and_tabs($cm, $course, $quiz, $this->mode);
     }
     if ($groupmode = groups_get_activity_groupmode($cm)) {
         // Groups are being used, so output the group selector if we are not downloading.
         if (!$table->is_downloading()) {
             groups_print_activity_menu($cm, $options->get_url());
         }
     }
     // Print information on the number of existing attempts.
     if (!$table->is_downloading()) {
         // Do not print notices when downloading.
         if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) {
             echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
         }
     }
     $hasquestions = quiz_questions_in_quiz($quiz->questions);
     if (!$table->is_downloading()) {
         if (!$hasquestions) {
             echo quiz_no_questions_message($quiz, $cm, $this->context);
         } else {
             if (!$students) {
                 echo $OUTPUT->notification(get_string('nostudentsyet'));
             } else {
                 if ($currentgroup && !$groupstudents) {
                     echo $OUTPUT->notification(get_string('nostudentsingroup'));
                 }
             }
         }
         // Print the display options.
         $this->form->display();
     }
     $hasstudents = $students && (!$currentgroup || $groupstudents);
     if ($hasquestions && ($hasstudents || $options->attempts == self::ALL_WITH)) {
         // Construct the SQL.
         $fields = $DB->sql_concat('u.id', "'#'", 'COALESCE(quiza.attempt, 0)') . ' AS uniqueid, ';
         if ($this->qmsubselect) {
             $fields .= "(CASE " . "   WHEN {$this->qmsubselect} THEN 1" . "   ELSE 0 " . "END) AS gradedattempt, ";
         }
         list($fields, $from, $where, $params) = $table->base_sql($allowed);
         $table->set_count_sql("SELECT COUNT(1) FROM {$from} WHERE {$where}", $params);
         // Test to see if there are any regraded attempts to be listed.
         $fields .= ", COALESCE((\n                                SELECT MAX(qqr.regraded)\n                                  FROM {quiz_overview_regrades} qqr\n                                 WHERE qqr.questionusageid = quiza.uniqueid\n                          ), -1) AS regraded";
         if ($options->onlyregraded) {
             $where .= " AND COALESCE((\n                                    SELECT MAX(qqr.regraded)\n                                      FROM {quiz_overview_regrades} qqr\n                                     WHERE qqr.questionusageid = quiza.uniqueid\n                                ), -1) <> -1";
         }
         $table->set_sql($fields, $from, $where, $params);
         if (!$table->is_downloading()) {
             // Output the regrade buttons.
             if (has_capability('mod/quiz:regrade', $this->context)) {
                 $regradesneeded = $this->count_question_attempts_needing_regrade($quiz, $groupstudents);
                 if ($currentgroup) {
                     $a = new stdClass();
                     $a->groupname = groups_get_group_name($currentgroup);
                     $a->coursestudents = get_string('participants');
                     $a->countregradeneeded = $regradesneeded;
                     $regradealldrydolabel = get_string('regradealldrydogroup', 'quiz_overview', $a);
                     $regradealldrylabel = get_string('regradealldrygroup', 'quiz_overview', $a);
                     $regradealllabel = get_string('regradeallgroup', 'quiz_overview', $a);
                 } else {
                     $regradealldrydolabel = get_string('regradealldrydo', 'quiz_overview', $regradesneeded);
                     $regradealldrylabel = get_string('regradealldry', 'quiz_overview');
                     $regradealllabel = get_string('regradeall', 'quiz_overview');
                 }
                 $displayurl = new moodle_url($options->get_url(), array('sesskey' => sesskey()));
                 echo '<div class="mdl-align">';
                 echo '<form action="' . $displayurl->out_omit_querystring() . '">';
                 echo '<div>';
                 echo html_writer::input_hidden_params($displayurl);
                 echo '<input type="submit" name="regradeall" value="' . $regradealllabel . '"/>';
                 echo '<input type="submit" name="regradealldry" value="' . $regradealldrylabel . '"/>';
                 if ($regradesneeded) {
                     echo '<input type="submit" name="regradealldrydo" value="' . $regradealldrydolabel . '"/>';
                 }
                 echo '</div>';
                 echo '</form>';
                 echo '</div>';
             }
             // Print information on the grading method.
             if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $this->qmsubselect, $options->onlygraded)) {
                 echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
             }
         }
         // Define table columns.
         $columns = array();
         $headers = array();
         if (!$table->is_downloading() && $options->checkboxcolumn) {
             $columns[] = 'checkbox';
             $headers[] = null;
         }
         $this->add_user_columns($table, $columns, $headers);
         $this->add_state_column($columns, $headers);
         $this->add_time_columns($columns, $headers);
         $this->add_grade_columns($quiz, $options->usercanseegrades, $columns, $headers, false);
         if (!$table->is_downloading() && has_capability('mod/quiz:regrade', $this->context) && $this->has_regraded_questions($from, $where, $params)) {
             $columns[] = 'regraded';
             $headers[] = get_string('regrade', 'quiz_overview');
         }
         if ($options->slotmarks) {
             foreach ($questions as $slot => $question) {
                 // Ignore questions of zero length.
                 $columns[] = 'qsgrade' . $slot;
                 $header = get_string('qbrief', 'quiz', $question->number);
                 if (!$table->is_downloading()) {
                     $header .= '<br />';
                 } else {
                     $header .= ' ';
                 }
                 $header .= '/' . quiz_rescale_grade($question->maxmark, $quiz, 'question');
                 $headers[] = $header;
             }
         }
         $this->set_up_table_columns($table, $columns, $headers, $this->get_base_url(), $options, false);
         $table->set_attribute('class', 'generaltable generalbox grades');
         $table->out($options->pagesize, true);
     }
     if (!$table->is_downloading() && $options->usercanseegrades) {
         $output = $PAGE->get_renderer('mod_quiz');
         if ($currentgroup && $groupstudents) {
             list($usql, $params) = $DB->get_in_or_equal($groupstudents);
             $params[] = $quiz->id;
             if ($DB->record_exists_select('quiz_grades', "userid {$usql} AND quiz = ?", $params)) {
                 $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php', array('id' => $quiz->id, 'groupid' => $currentgroup));
                 $graphname = get_string('overviewreportgraphgroup', 'quiz_overview', groups_get_group_name($currentgroup));
                 echo $output->graph($imageurl, $graphname);
             }
         }
         if ($DB->record_exists('quiz_grades', array('quiz' => $quiz->id))) {
             $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php', array('id' => $quiz->id));
             $graphname = get_string('overviewreportgraph', 'quiz_overview');
             echo $output->graph($imageurl, $graphname);
         }
     }
     return true;
 }
Exemple #22
0
 public function display($quiz, $cm, $course)
 {
     global $CFG, $COURSE, $DB, $OUTPUT;
     $this->context = get_context_instance(CONTEXT_MODULE, $cm->id);
     $download = optional_param('download', '', PARAM_ALPHA);
     list($currentgroup, $students, $groupstudents, $allowed) = $this->load_relevant_students($cm);
     $pageoptions = array();
     $pageoptions['id'] = $cm->id;
     $pageoptions['mode'] = 'overview';
     $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions);
     $qmsubselect = quiz_report_qm_filter_select($quiz);
     $mform = new mod_quiz_report_overview_settings($reporturl, array('qmsubselect' => $qmsubselect, 'quiz' => $quiz, 'currentgroup' => $currentgroup, 'context' => $this->context));
     if ($fromform = $mform->get_data()) {
         $regradeall = false;
         $regradealldry = false;
         $regradealldrydo = false;
         $attemptsmode = $fromform->attemptsmode;
         if ($qmsubselect) {
             $qmfilter = $fromform->qmfilter;
         } else {
             $qmfilter = 0;
         }
         $regradefilter = !empty($fromform->regradefilter);
         set_user_preference('quiz_report_overview_detailedmarks', $fromform->detailedmarks);
         set_user_preference('quiz_report_pagesize', $fromform->pagesize);
         $detailedmarks = $fromform->detailedmarks;
         $pagesize = $fromform->pagesize;
     } else {
         $regradeall = optional_param('regradeall', 0, PARAM_BOOL);
         $regradealldry = optional_param('regradealldry', 0, PARAM_BOOL);
         $regradealldrydo = optional_param('regradealldrydo', 0, PARAM_BOOL);
         $attemptsmode = optional_param('attemptsmode', null, PARAM_INT);
         if ($qmsubselect) {
             $qmfilter = optional_param('qmfilter', 0, PARAM_INT);
         } else {
             $qmfilter = 0;
         }
         $regradefilter = optional_param('regradefilter', 0, PARAM_INT);
         $detailedmarks = get_user_preferences('quiz_report_overview_detailedmarks', 1);
         $pagesize = get_user_preferences('quiz_report_pagesize', 0);
     }
     $this->validate_common_options($attemptsmode, $pagesize, $course, $currentgroup);
     $displayoptions = array();
     $displayoptions['attemptsmode'] = $attemptsmode;
     $displayoptions['qmfilter'] = $qmfilter;
     $displayoptions['regradefilter'] = $regradefilter;
     $mform->set_data($displayoptions + array('detailedmarks' => $detailedmarks, 'pagesize' => $pagesize));
     if (!$this->should_show_grades($quiz)) {
         $detailedmarks = 0;
     }
     // We only want to show the checkbox to delete attempts
     // if the user has permissions and if the report mode is showing attempts.
     $candelete = has_capability('mod/quiz:deleteattempts', $this->context) && $attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO;
     if ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) {
         // This option is only available to users who can access all groups in
         // groups mode, so setting allowed to empty (which means all quiz attempts
         // are accessible, is not a security porblem.
         $allowed = array();
     }
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
     $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
     $displaycoursecontext = get_context_instance(CONTEXT_COURSE, $COURSE->id);
     $displaycourseshortname = format_string($COURSE->shortname, true, array('context' => $displaycoursecontext));
     // Load the required questions.
     $questions = quiz_report_get_significant_questions($quiz);
     $table = new quiz_report_overview_table($quiz, $this->context, $qmsubselect, $groupstudents, $students, $detailedmarks, $questions, $candelete, $reporturl, $displayoptions);
     $filename = quiz_report_download_filename(get_string('overviewfilename', 'quiz_overview'), $courseshortname, $quiz->name);
     $table->is_downloading($download, $filename, $displaycourseshortname . ' ' . format_string($quiz->name, true));
     if ($table->is_downloading()) {
         raise_memory_limit(MEMORY_EXTRA);
     }
     // Process actions.
     if (empty($currentgroup) || $groupstudents) {
         if (optional_param('delete', 0, PARAM_BOOL) && confirm_sesskey()) {
             if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) {
                 require_capability('mod/quiz:deleteattempts', $this->context);
                 $this->delete_selected_attempts($quiz, $cm, $attemptids, $allowed);
                 redirect($reporturl->out(false, $displayoptions));
             }
         } else {
             if (optional_param('regrade', 0, PARAM_BOOL) && confirm_sesskey()) {
                 if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) {
                     require_capability('mod/quiz:regrade', $this->context);
                     $this->regrade_attempts($quiz, false, $groupstudents, $attemptids);
                     redirect($reporturl->out(false, $displayoptions));
                 }
             }
         }
     }
     if ($regradeall && confirm_sesskey()) {
         require_capability('mod/quiz:regrade', $this->context);
         $this->regrade_attempts($quiz, false, $groupstudents);
         redirect($reporturl->out(false, $displayoptions), '', 5);
     } else {
         if ($regradealldry && confirm_sesskey()) {
             require_capability('mod/quiz:regrade', $this->context);
             $this->regrade_attempts($quiz, true, $groupstudents);
             redirect($reporturl->out(false, $displayoptions), '', 5);
         } else {
             if ($regradealldrydo && confirm_sesskey()) {
                 require_capability('mod/quiz:regrade', $this->context);
                 $this->regrade_attempts_needing_it($quiz, $groupstudents);
                 redirect($reporturl->out(false, $displayoptions), '', 5);
             }
         }
     }
     // Start output.
     if (!$table->is_downloading()) {
         // Only print headers if not asked to download data
         $this->print_header_and_tabs($cm, $course, $quiz, 'overview');
     }
     if ($groupmode = groups_get_activity_groupmode($cm)) {
         // Groups are being used
         if (!$table->is_downloading()) {
             groups_print_activity_menu($cm, $reporturl->out(true, $displayoptions));
         }
     }
     // Print information on the number of existing attempts
     if (!$table->is_downloading()) {
         //do not print notices when downloading
         if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) {
             echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
         }
     }
     $hasquestions = quiz_questions_in_quiz($quiz->questions);
     if (!$table->is_downloading()) {
         if (!$hasquestions) {
             echo quiz_no_questions_message($quiz, $cm, $this->context);
         } else {
             if (!$students) {
                 echo $OUTPUT->notification(get_string('nostudentsyet'));
             } else {
                 if ($currentgroup && !$groupstudents) {
                     echo $OUTPUT->notification(get_string('nostudentsingroup'));
                 }
             }
         }
         // Print display options
         $mform->display();
     }
     $hasstudents = $students && (!$currentgroup || $groupstudents);
     if ($hasquestions && ($hasstudents || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL)) {
         // Construct the SQL
         $fields = $DB->sql_concat('u.id', "'#'", 'COALESCE(quiza.attempt, 0)') . ' AS uniqueid, ';
         if ($qmsubselect) {
             $fields .= "(CASE " . "   WHEN {$qmsubselect} THEN 1" . "   ELSE 0 " . "END) AS gradedattempt, ";
         }
         list($fields, $from, $where, $params) = $this->base_sql($quiz, $qmsubselect, $qmfilter, $attemptsmode, $allowed);
         $table->set_count_sql("SELECT COUNT(1) FROM {$from} WHERE {$where}", $params);
         // Test to see if there are any regraded attempts to be listed.
         $fields .= ", COALESCE((\n                                SELECT MAX(qqr.regraded)\n                                  FROM {quiz_overview_regrades} qqr\n                                 WHERE qqr.questionusageid = quiza.uniqueid\n                          ), -1) AS regraded";
         if ($regradefilter) {
             $where .= " AND COALESCE((\n                                    SELECT MAX(qqr.regraded)\n                                      FROM {quiz_overview_regrades} qqr\n                                     WHERE qqr.questionusageid = quiza.uniqueid\n                                ), -1) <> -1";
         }
         $table->set_sql($fields, $from, $where, $params);
         if (!$table->is_downloading()) {
             // Regrade buttons
             if (has_capability('mod/quiz:regrade', $this->context)) {
                 $regradesneeded = $this->count_question_attempts_needing_regrade($quiz, $groupstudents);
                 if ($currentgroup) {
                     $a = new stdClass();
                     $a->groupname = groups_get_group_name($currentgroup);
                     $a->coursestudents = get_string('participants');
                     $a->countregradeneeded = $regradesneeded;
                     $regradealldrydolabel = get_string('regradealldrydogroup', 'quiz_overview', $a);
                     $regradealldrylabel = get_string('regradealldrygroup', 'quiz_overview', $a);
                     $regradealllabel = get_string('regradeallgroup', 'quiz_overview', $a);
                 } else {
                     $regradealldrydolabel = get_string('regradealldrydo', 'quiz_overview', $regradesneeded);
                     $regradealldrylabel = get_string('regradealldry', 'quiz_overview');
                     $regradealllabel = get_string('regradeall', 'quiz_overview');
                 }
                 $displayurl = new moodle_url($reporturl, $displayoptions + array('sesskey' => sesskey()));
                 echo '<div class="mdl-align">';
                 echo '<form action="' . $displayurl->out_omit_querystring() . '">';
                 echo '<div>';
                 echo html_writer::input_hidden_params($displayurl);
                 echo '<input type="submit" name="regradeall" value="' . $regradealllabel . '"/>';
                 echo '<input type="submit" name="regradealldry" value="' . $regradealldrylabel . '"/>';
                 if ($regradesneeded) {
                     echo '<input type="submit" name="regradealldrydo" value="' . $regradealldrydolabel . '"/>';
                 }
                 echo '</div>';
                 echo '</form>';
                 echo '</div>';
             }
             // Print information on the grading method
             if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) {
                 echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
             }
         }
         // Define table columns
         $columns = array();
         $headers = array();
         if (!$table->is_downloading() && $candelete) {
             $columns[] = 'checkbox';
             $headers[] = null;
         }
         $this->add_user_columns($table, $columns, $headers);
         $this->add_time_columns($columns, $headers);
         if ($detailedmarks) {
             foreach ($questions as $slot => $question) {
                 // Ignore questions of zero length
                 $columns[] = 'qsgrade' . $slot;
                 $header = get_string('qbrief', 'quiz', $question->number);
                 if (!$table->is_downloading()) {
                     $header .= '<br />';
                 } else {
                     $header .= ' ';
                 }
                 $header .= '/' . quiz_rescale_grade($question->maxmark, $quiz, 'question');
                 $headers[] = $header;
             }
         }
         if (!$table->is_downloading() && has_capability('mod/quiz:regrade', $this->context) && $this->has_regraded_questions($from, $where, $params)) {
             $columns[] = 'regraded';
             $headers[] = get_string('regrade', 'quiz_overview');
         }
         $this->add_grade_columns($quiz, $columns, $headers);
         $this->set_up_table_columns($table, $columns, $headers, $reporturl, $displayoptions, false);
         $table->set_attribute('class', 'generaltable generalbox grades');
         $table->out($pagesize, true);
     }
     if (!$table->is_downloading() && $this->should_show_grades($quiz)) {
         if ($currentgroup && $groupstudents) {
             list($usql, $params) = $DB->get_in_or_equal($groupstudents);
             $params[] = $quiz->id;
             if ($DB->record_exists_select('quiz_grades', "userid {$usql} AND quiz = ?", $params)) {
                 $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php', array('id' => $quiz->id, 'groupid' => $currentgroup));
                 $graphname = get_string('overviewreportgraphgroup', 'quiz_overview', groups_get_group_name($currentgroup));
                 echo $OUTPUT->heading($graphname);
                 echo html_writer::tag('div', html_writer::empty_tag('img', array('src' => $imageurl, 'alt' => $graphname)), array('class' => 'graph'));
             }
         }
         if ($DB->record_exists('quiz_grades', array('quiz' => $quiz->id))) {
             $graphname = get_string('overviewreportgraph', 'quiz_overview');
             $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php', array('id' => $quiz->id));
             echo $OUTPUT->heading($graphname);
             echo html_writer::tag('div', html_writer::empty_tag('img', array('src' => $imageurl, 'alt' => $graphname)), array('class' => 'graph'));
         }
     }
     return true;
 }
Exemple #23
0
/**
 * 
 * Creates a new PDF with the questions of a quiz's attempt.
 * 
 * @param unknown_type $attempt record with the attempt info
 * @param unknown_type $quiz
 * @param unknown_type $pdf1
 * @param unknown_type $blended
 * @param unknown_type $options array with formatting options
 * @param unknown_type $pdfFile
 * @throws PDFError
 */
function blended_generate_quiz($attempt, $quiz, $pdf1, $blended, $options, $pdfFile)
{
    global $QTYPES;
    global $CFG;
    global $COURSE;
    $uniqueid = $attempt->id;
    $activity_code = $uniqueid;
    $identifyLabel = $options['identifyLabel'];
    /*
     	switch($identifyLabel)
    	{
    		case 'id':
    			$idText= $activity_code;
    			break;
    		case 'none': $idText='';
    		break;
    	}
    */
    $markSize = 3;
    $quizname = $quiz->name;
    $images->ok_marks = '<img src="' . $CFG->wwwroot . '/mod/blended/images/ok_marks.png" height="10" />';
    $images->ko_marks = '<img src="' . $CFG->wwwroot . '/mod/blended/images/ko_marks.png" height="10" />';
    //	$images->ok_marks='<img src="mod/blended/images/ok_marks.png" height="10" />';
    //	$images->ko_marks='<img src="mod/blended/images/ko_marks.png"  height="10"/>';
    $howToMark = get_string('howToMarkInstructions', 'blended', $images);
    $instructions = $quiz->intro . ' ' . $howToMark;
    $fullname = "nombre persona";
    $style = array('position' => 'S', 'border' => false, 'padding' => 1, 'fgcolor' => array(0, 0, 0), 'bgcolor' => false, 'text' => true, 'font' => 'courier', 'fontsize' => $options['fontsize'], 'stretchtext' => 4);
    $headeroptions = new stdClass();
    $headeroptions->rowHeight = 6;
    $headeroptions->logoWidth = 30;
    $headeroptions->codebarWidth = 40;
    $headeroptions->textStyle = $style;
    if (isset($options['logourl'])) {
        $headeroptions->logo_url = $options['logourl'];
    } else {
        $headeroptions->logo_url = $CFG->dirroot . '/mod/blended/pix/UVa_logo.jpg';
    }
    $headeroptions->cellHtmlText = get_string('modulename', 'quiz') . ':' . $quizname;
    //Nombre:
    $headeroptions->cellHtmlDate = '';
    $headeroptions->cellHtmlUser = get_string('Student', 'blended') . ':';
    // Alumno:
    $headeroptions->cellCourseName = $COURSE->fullname;
    $headeroptions->evaluationmarksize = 3;
    // if null evaluation marks are not included in header
    $headeroptions->marksName = 'EVAL';
    $headeroptions->codebarType = $blended->codebartype;
    $headeroptions->identifyLabel = $identifyLabel;
    // show readable text for codebars 'none' if not to be shown
    $headeroptions->instructions = $instructions;
    /**
     * Give precedence to the selected number of columns in the $options
     */
    if (isset($options['columns'])) {
        $numcols = $options['columns'];
    } else {
        if (!isset($blended->numcols) || $blended->numcols == 0) {
            $numcols = 2;
        } else {
            $numcols = $blended->numcols;
        }
    }
    unset($quiz->questionsinuse);
    unset($QTYPES["random"]->catrandoms);
    $pagelist = quiz_questions_on_page($attempt->layout, 0);
    $pagequestions = explode(',', $pagelist);
    $questionlist = quiz_questions_in_quiz($attempt->layout);
    if (!$questionlist) {
        throw new PDFError("Quiz layout is empty", PDFError::QUIZ_IS_EMPTY);
    }
    $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . "  FROM {$CFG->prefix}question q," . "       {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . "   AND q.id IN ({$questionlist})";
    if (!($questions = get_records_sql($sql))) {
        throw new PDFError("Questions not found. ", PDFError::QUESTIONS_NOT_FOUND);
    }
    //Carga las preguntas con sus opciones
    if (!get_question_options($questions)) {
        throw new PDFError("Could not load question options", PDFError::COULD_NOT_LOAD_QUESTION_OPTIONS);
    }
    $quiz_userid = 4;
    $acode = $attempt->id;
    if (!($attemptnumber = (int) get_field_sql('SELECT MAX(attempt)+1 FROM ' . "{$CFG->prefix}quiz_attempts WHERE quiz = '{$quiz->id}' AND " . "userid = '{$quiz_userid}' AND timefinish > 0 AND preview != 1"))) {
        $attemptnumber = 1;
    }
    $quiz_uniqueid = $attempt->attempt;
    $timenow = time();
    $quiz_attempt = create_new_attempt($quiz, $attemptnumber, $quiz_userid, $acode, $quiz_uniqueid, $timenow);
    // Save the attempt
    // if (!insert_record('quiz_attempts', $quiz_attempt)) {
    //     error('Could not create new attempt');
    //}
    if (!($states = get_question_states($questions, $quiz, $quiz_attempt, false))) {
        throw new PDFError("Could not restore question sessions", PDFError::COULD_NOT_RESTORE_QUESTION_SESSIONS);
    }
    // TODO save question states someway in question_states
    foreach ($questions as $i => $question) {
        save_question_session($questions[$i], $states[$i]);
    }
    //	global $QTYPES;
    //$question = reset($questions);
    //print("state answer question $question->id: ".$QTYPES[$question->qtype]->get_question_options($question));
    $quests = new stdClass();
    $quests = array();
    foreach ($pagequestions as $i) {
        $options = quiz_get_renderoptions($quiz->review, $states[$i]);
        $quest = blended_get_question_formulation_and_controls($questions[$i], $states[$i], $quiz, $options);
        if (isset($quest->answers)) {
            foreach ($quest->answers as $c => $v) {
                $text = $v->answer;
                $quest->answers[$c]->answer = blended_image_path($text);
            }
        }
        $quests[] = $quest;
    }
    $idText = '';
    $original = new stdClass();
    $original->question = array();
    $question = $quests;
    $num = 0;
    $a = 0;
    //foreach ($questions as $m)//esto es redundante: crea un array igual
    foreach ($pagequestions as $i) {
        $questions[$i]->questiontext = $quests[$a]->questiontext;
        if (isset($questions[$i]->questiontext)) {
            $questions[$i]->questiontext = blended_image_path($questions[$i]->questiontext);
        }
        $question[$a] = $questions[$i];
        if ($question[$a]->qtype == "multichoice") {
            $question[$a]->anss = array();
            foreach ($states[$questions[$i]->id]->options->order as $j => $aid) {
                $question[$a]->anss[$j] = $questions[$i]->options->answers[$aid];
                $num++;
            }
        }
        $question[$a]->id = "q" . $question[$a]->id;
        $a++;
    }
    foreach ($question as $quest) {
        $original->question[] = $quest;
    }
    /**
     * Start PDF printing
     */
    // create new PDF document
    $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
    blended_new_page($pdf);
    $margins = $pdf->getMargins();
    $columnsWidth = ($pdf->getPageWidth() - $margins['left'] - $margins['right']) / $numcols;
    /**
     * Print all questions with TPDF to calculate exact dimensions of each block
     */
    $pdf->SetFont($headeroptions->textStyle['font'], '', $headeroptions->textStyle['fontsize']);
    for ($key = 0; $key < count($original->question); $key++) {
        $dims_borrador = new stdClass();
        $dims_borrador->coords = array();
        $original->question[$key]->height = blended_print_draft($pdf, $key, $original, $dims_borrador, $columnsWidth, $markSize, $headeroptions);
    }
    /**
     * Print final PDF
     */
    // Array to hold sizes of elements
    $dimsn = array();
    // Print content starting at abscisa $y
    $pdf1 = blended_print_quiz($pdf1, $numcols, $columnsWidth, $margins, $original, $dimsn, $markSize, $headeroptions, $uniqueid, $pdfFile);
    unset($pdf);
    return $pdf1;
}