if (!$quizobj->is_preview_user() && $messages) {
    print_error('attempterror', 'quiz', $quizobj->view_url(), $accessmanager->print_messages($messages, true));
}
$accessmanager->do_password_check($quizobj->is_preview_user());
/// Delete any previous preview attempts belonging to this user.
quiz_delete_previews($quiz, $USER->id);
/// Create the new attempt and initialize the question sessions
$attempt = quiz_create_attempt($quiz, $attemptnumber, $lastattempt, time(), $quizobj->is_preview_user());
/// Save the attempt in the database.
if (!($attempt->id = $DB->insert_record('quiz_attempts', $attempt))) {
    quiz_error($quiz, 'newattemptfail');
}
/// Log the new attempt.
if ($attempt->preview) {
    add_to_log($course->id, 'quiz', 'preview', 'view.php?id=' . $quizobj->get_cmid(), $quizobj->get_quizid(), $quizobj->get_cmid());
} else {
    add_to_log($course->id, 'quiz', 'attempt', 'review.php?attempt=' . $attempt->id, $quizobj->get_quizid(), $quizobj->get_cmid());
}
/// Fully load all the questions in this quiz.
$quizobj->preload_questions();
$quizobj->load_questions();
/// Create initial states for all questions in this quiz.
if (!($states = get_question_states($quizobj->get_questions(), $quizobj->get_quiz(), $attempt, $lastattemptid))) {
    print_error('cannotrestore', 'quiz');
}
/// Save all the newly created states.
foreach ($quizobj->get_questions() as $i => $question) {
    save_question_session($question, $states[$i]);
}
/// Redirect to the attempt page.
redirect($quizobj->attempt_url($attempt->id));
Exemple #2
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}&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 . '&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;
 }
Exemple #3
0
 /**
  * Prints questions with comment and grade form underneath each question
  *
  * @return void
  * @todo Finish documenting this function
  **/
 function print_questions_and_form($quiz, $question, $userid, $attemptid, $gradeungraded, $gradenextungraded, $ungraded)
 {
     global $CFG;
     // TODO get the context, and put in proper roles an permissions checks.
     $context = NULL;
     $questions[$question->id] =& $question;
     $usehtmleditor = can_use_richtext_editor();
     list($select, $from, $where) = $this->attempts_sql($quiz->id, false, $question->id, $userid, $attemptid, $gradeungraded, $gradenextungraded);
     $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
     if ($gradenextungraded) {
         $attempts = get_records_sql($select . $from . $where . $sort, 0, QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE);
     } else {
         $attempts = get_records_sql($select . $from . $where . $sort);
     }
     if ($attempts) {
         $firstattempt = current($attempts);
         $fullname = fullname($firstattempt);
         if ($gradeungraded) {
             // getting all ungraded attempts
             print_heading(get_string('gradingungraded', 'quiz_grading', $ungraded), '', 3);
         } else {
             if ($gradenextungraded) {
                 // getting next ungraded attempts
                 print_heading(get_string('gradingnextungraded', 'quiz_grading', QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE), '', 3);
             } else {
                 if ($userid) {
                     print_heading(get_string('gradinguser', 'quiz_grading', $fullname), '', 3);
                 } else {
                     if ($attemptid) {
                         $a = new object();
                         $a->fullname = $fullname;
                         $a->attempt = $firstattempt->attempt;
                         print_heading(get_string('gradingattempt', 'quiz_grading', $a), '', 3);
                     } else {
                         print_heading(get_string('gradingall', 'quiz_grading', count($attempts)), '', 3);
                     }
                 }
             }
         }
         // Display the form with one part for each selected attempt
         echo '<form method="post" action="report.php">' . '<input type="hidden" name="mode" value="grading" />' . '<input type="hidden" name="q" value="' . $quiz->id . '" />' . '<input type="hidden" name="sesskey" value="' . sesskey() . '" />' . '<input type="hidden" name="questionid" value="' . $question->id . '" />';
         foreach ($attempts as $attempt) {
             // Load the state for this attempt (The questions array was created earlier)
             $states = get_question_states($questions, $quiz, $attempt);
             // The $states array is indexed by question id but because we are dealing
             // with only one question there is only one entry in this array
             $state =& $states[$question->id];
             $options = quiz_get_reviewoptions($quiz, $attempt, $context);
             unset($options->questioncommentlink);
             $options->noeditlink = true;
             $copy = $state->manualcomment;
             $state->manualcomment = '';
             $options->readonly = 1;
             $gradedclass = question_state_is_graded($state) ? ' class="highlightgraded" ' : '';
             $gradedstring = question_state_is_graded($state) ? ' ' . get_string('graded', 'quiz_grading') : '';
             $a = new object();
             $a->fullname = fullname($attempt, true);
             $a->attempt = $attempt->attempt;
             // print the user name, attempt count, the question, and some more hidden fields
             echo '<div class="boxaligncenter" width="80%" style="clear:left;padding:15px;">';
             echo "<span{$gradedclass}>" . get_string('gradingattempt', 'quiz_grading', $a);
             echo $gradedstring . "</span>";
             print_question($question, $state, '', $quiz, $options);
             $prefix = "manualgrades[{$attempt->uniqueid}]";
             if (!question_state_is_graded($state)) {
                 $grade = '';
             } else {
                 $grade = round($state->last_graded->grade, 3);
             }
             $state->manualcomment = $copy;
             include $CFG->dirroot . '/question/comment.html';
             echo '</div>';
         }
         echo '<div class="boxaligncenter"><input type="submit" value="' . get_string('savechanges') . '" /></div>' . '</form>';
         if ($usehtmleditor) {
             use_html_editor();
         }
     } else {
         notify(get_string('noattemptstoshow', 'quiz'));
     }
 }
/// 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;
        $action->responses = $closestates[$key]->responses;
        $action->timestamp = $closestates[$key]->timestamp;
        if (question_process_responses($question, $closestates[$key], $action, $quiz, $attempt)) {
            save_question_session($question, $closestates[$key]);
        } else {
            $success = false;
        }
    }
    if (!$success) {
        $pagebit = '';
require_capability('mod/quiz:grade', $context);
// Load question
if (!($question = get_record('question', 'id', $questionid))) {
    error('Question for this session is missing');
}
$question->maxgrade = get_field('quiz_question_instances', 'grade', 'quiz', $quiz->id, 'question', $question->id);
// Some of the questions code is optimised to work with several questions
// at once so it wants the question to be in an array.
$key = $question->id;
$questions[$key] =& $question;
// Add additional questiontype specific information to the question objects.
if (!get_question_options($questions)) {
    error("Unable to load questiontype specific question information");
}
// Load state
$states = get_question_states($questions, $quiz, $attempt);
// The $states array is indexed by question id but because we are dealing
// with only one question there is only one entry in this array
$state =& $states[$question->id];
print_header();
print_heading(format_string($question->name));
//add_to_log($course->id, 'quiz', 'review', "review.php?id=$cm->id&amp;attempt=$attempt->id", "$quiz->id", "$cm->id");
if ($data = data_submitted() and confirm_sesskey()) {
    // the following will update the state and attempt
    question_process_comment($question, $state, $attempt, $data->response['comment'], $data->response['grade']);
    // If the state has changed save it and update the quiz grade
    if ($state->changed) {
        save_question_session($question, $state);
        quiz_save_best_grade($quiz, $attempt->userid);
    }
    notify(get_string('changessaved'));
Exemple #6
0
// new sessions. Make $states a reference to the states array in the moodle
// session.
if (isset($SESSION->quizpreview->states) and $SESSION->quizpreview->questionid == $id) {
    // Reload the question session history from the moodle session
    $states =& $SESSION->quizpreview->states;
    $historylength = count($states) - 1;
    if ($back && $historylength > 0) {
        // Go back one step in the history
        unset($states[$historylength]);
        $historylength--;
    }
} else {
    // Record the question id in the moodle session
    $SESSION->quizpreview->questionid = $id;
    // Create an empty session for the question
    if (!($newstates = get_question_states($questions, $quiz, $attempt))) {
        print_error('newattemptfail', 'quiz');
    }
    $SESSION->quizpreview->states = array($newstates);
    $states =& $SESSION->quizpreview->states;
    $historylength = 0;
}
if (!$fillcorrect && !$back && ($form = data_submitted())) {
    $form = (array) $form;
    $submitted = true;
    // Create a new item in the history of question states (don't simplify!)
    $states[$historylength + 1] = array();
    $states[$historylength + 1][$id] = clone $states[$historylength][$id];
    $historylength++;
    $curstate =& $states[$historylength][$id];
    $curstate->changed = false;
Exemple #7
0
 /**
  * Prints questions with comment and grade form underneath each question
  *
  * @return void
  * @todo Finish documenting this function
  **/
 function print_questions_and_form($quiz, $question)
 {
     global $CFG, $db;
     // grade question specific parameters
     $gradeall = optional_param('gradeall', 0, PARAM_INT);
     $userid = optional_param('userid', 0, PARAM_INT);
     $attemptid = optional_param('attemptid', 0, PARAM_INT);
     // TODO get the context, and put in proper roles an permissions checks.
     $context = NULL;
     $questions[$question->id] =& $question;
     $usehtmleditor = can_use_richtext_editor();
     $users = get_course_students($quiz->course);
     $userids = implode(',', array_keys($users));
     // this sql joins the attempts table and the user table
     $select = 'SELECT ' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ' AS userattemptid,
                 qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, qa.preview,
                 u.id AS userid, u.firstname, u.lastname, u.picture ';
     $from = 'FROM ' . $CFG->prefix . 'user u LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON (u.id = qa.userid AND qa.quiz = ' . $quiz->id . ') ';
     if ($gradeall) {
         // get all user attempts
         $where = 'WHERE u.id IN (' . $userids . ') ';
     } else {
         if ($userid) {
             // get all the attempts for a specific user
             $where = 'WHERE u.id=' . $userid . ' ';
         } else {
             // get a specific attempt
             $where = 'WHERE qa.id=' . $attemptid . ' ';
         }
     }
     // ignore previews
     $where .= ' AND preview = 0 ';
     $where .= 'AND ' . $db->IfNull('qa.attempt', '0') . ' != 0 ';
     $where .= 'AND ' . $db->IfNull('qa.timefinish', '0') . ' != 0 ';
     $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
     $attempts = get_records_sql($select . $from . $where . $sort);
     // Display the form with one part for each selected attempt
     echo '<form method="post" action="report.php">' . '<input type="hidden" name="mode" value="grading" />' . '<input type="hidden" name="q" value="' . $quiz->id . '" />' . '<input type="hidden" name="sesskey" value="' . sesskey() . '" />' . '<input type="hidden" name="action" value="viewquestion" />' . '<input type="hidden" name="questionid" value="' . $question->id . '" />';
     foreach ($attempts as $attempt) {
         // Load the state for this attempt (The questions array was created earlier)
         $states = get_question_states($questions, $quiz, $attempt);
         // The $states array is indexed by question id but because we are dealing
         // with only one question there is only one entry in this array
         $state =& $states[$question->id];
         $options = quiz_get_reviewoptions($quiz, $attempt, $context);
         unset($options->questioncommentlink);
         $copy = $state->manualcomment;
         $state->manualcomment = '';
         $options->readonly = 1;
         // print the user name, attempt count, the question, and some more hidden fields
         echo '<div class="boxaligncenter" width="80%" style="padding:15px;">' . fullname($attempt, true) . ': ' . get_string('attempt', 'quiz') . $attempt->attempt;
         print_question($question, $state, '', $quiz, $options);
         $prefix = "manualgrades[{$attempt->uniqueid}]";
         $grade = round($state->last_graded->grade, 3);
         $state->manualcomment = $copy;
         include $CFG->dirroot . '/question/comment.html';
         echo '</div>';
     }
     echo '<div class="boxaligncenter"><input type="submit" value="' . get_string('savechanges') . '" /></div>' . '</form>';
     if ($usehtmleditor) {
         use_html_editor();
     }
 }
Exemple #8
0
 /**
  * Prints questions with comment and grade form underneath each question
  *
  * @return void
  * @todo Finish documenting this function
  **/
 function print_questions_and_form($quiz, $question, $userid, $attemptid, $gradeungraded, $gradenextungraded, $ungraded)
 {
     global $CFG, $DB, $OUTPUT;
     $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
     $questions[$question->id] =& $question;
     $usehtmleditor = can_use_html_editor();
     list($select, $from, $where, $params) = $this->attempts_sql($quiz->id, false, $question->id, $userid, $attemptid, $gradeungraded, $gradenextungraded);
     $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
     if ($gradenextungraded) {
         $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params, 0, QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE);
     } else {
         $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params);
     }
     if ($attempts) {
         $firstattempt = current($attempts);
         $fullname = fullname($firstattempt);
         if ($gradeungraded) {
             // getting all ungraded attempts
             echo $OUTPUT->heading(get_string('gradingungraded', 'quiz_grading', $ungraded), 3);
         } else {
             if ($gradenextungraded) {
                 // getting next ungraded attempts
                 echo $OUTPUT->heading(get_string('gradingnextungraded', 'quiz_grading', QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE), 3);
             } else {
                 if ($userid) {
                     echo $OUTPUT->heading(get_string('gradinguser', 'quiz_grading', $fullname), 3);
                 } else {
                     if ($attemptid) {
                         $a = new object();
                         $a->fullname = $fullname;
                         $a->attempt = $firstattempt->attempt;
                         echo $OUTPUT->heading(get_string('gradingattempt', 'quiz_grading', $a), 3);
                     } else {
                         echo $OUTPUT->heading(get_string('gradingall', 'quiz_grading', count($attempts)), 3);
                     }
                 }
             }
         }
         // Display the form with one part for each selected attempt
         echo '<form method="post" action="report.php" class="mform" id="manualgradingform">' . '<input type="hidden" name="mode" value="grading" />' . '<input type="hidden" name="q" value="' . $quiz->id . '" />' . '<input type="hidden" name="sesskey" value="' . sesskey() . '" />' . '<input type="hidden" name="questionid" value="' . $question->id . '" />';
         foreach ($attempts as $attempt) {
             // Load the state for this attempt (The questions array was created earlier)
             $states = get_question_states($questions, $quiz, $attempt);
             // The $states array is indexed by question id but because we are dealing
             // with only one question there is only one entry in this array
             $state =& $states[$question->id];
             $options = quiz_get_reviewoptions($quiz, $attempt, $context);
             unset($options->questioncommentlink);
             $options->readonly = 1;
             if (question_state_is_graded($state)) {
                 $gradedclass = 'main highlightgraded';
                 $gradedstring = ' ' . get_string('graded', 'quiz_grading');
             } else {
                 $gradedclass = 'main';
                 $gradedstring = '';
             }
             $a = new object();
             $a->fullname = fullname($attempt, true);
             $a->attempt = $attempt->attempt;
             // print the user name, attempt count, the question, and some more hidden fields
             echo '<div class="boxaligncenter" width="80%" style="clear:left;padding:15px;">';
             echo $OUTPUT->heading(get_string('gradingattempt', 'quiz_grading', $a) . $gradedstring, 3, $gradedclass);
             // Print the question, without showing any previous comment.
             $copy = $state->manualcomment;
             $state->manualcomment = '';
             $options->noeditlink = true;
             print_question($question, $state, '', $quiz, $options);
             // The print the comment and grade fields, putting back the previous comment.
             $state->manualcomment = $copy;
             question_print_comment_fields($question, $state, 'manualgrades[' . $attempt->uniqueid . ']', $quiz, get_string('manualgrading', 'quiz'));
             echo '</div>';
         }
         echo '<div class="boxaligncenter"><input type="submit" value="' . get_string('savechanges') . '" /></div>' . '</form>';
     } else {
         echo $OUTPUT->notification(get_string('noattemptstoshow', 'quiz'));
     }
 }
$number = quiz_first_questionnumber($attempt->layout, $pagelist);
$quests = new stdClass();
$quests = array();
/// Print all the questions
// LA PAGINACION YA NO LA HACE MOODLE SINO BLENDED ASI QUE EL ARRAY PAGEQUESTIONS NO TIENE SENTIDO
//    foreach ($pagequestions as $i) {
//        $options = quiz_get_renderoptions($quiz->review, $states[$i]);
//        $questions[$i]
//        $quests[$i] = get_question_formulation_and_controls($questions[$i], $states[$i], $quiz, $options);
//        $number += $questions[$i]->length;
//    }
//Carga las preguntas con sus opciones
if (!get_question_options(&$questions)) {
    error('Could not load question options');
}
$states = get_question_states(&$questions, $quiz, $attempt, $lastattemptid);
foreach ($questions as $id => $question) {
    $options = quiz_get_renderoptions($quiz->review, $states[$id]);
    $quest = get_question_formulation_and_controls(&$question, &$states[$id], $quiz, $options);
    //$question->anss=$quest->anss;
    $quests[] = $quest;
    $number += $question->length;
    // NO ENTIENDO QUE ACUMULA ESTO
}
$item = new stdClass();
$descartados = new stdClass();
$descartados->question = array();
$borrado = new stdClass();
$borrado->question = array();
$original = new stdClass();
$original->question = array();
function evaluate_quiz($acode, $jobid, $newattempt, $blended)
{
    global $USER;
    global $CFG;
    mtrace("Evaluation QUIZ Processing..." . "<BR><BR>");
    try {
        print "New Attempt is: " . $newattempt . "<BR/>";
        $detected_userid = find_userid($acode, $jobid);
        if ($detected_userid == null or $detected_userid == '') {
            throw new EvaluationError(get_string('ErrorUserIDEmpty', 'blended'), EvaluationError::USERID_IS_EMPTY);
        }
        $user_reg = blended_get_user($detected_userid, $blended);
        if ($user_reg == null) {
            throw new EvaluationError(get_string('ErrorUserNotInCourse', 'blended'), EvaluationError::USER_NOT_IN_THIS_COURSE);
        }
        $userid = $user_reg->id;
        mtrace('Obtained USERID value: ' . $userid . " OK. <BR/>");
        $quiz = get_quiz($acode);
        $attempts = quiz_get_user_attempts($quiz->id, $userid, 'all', true);
        mtrace("Searching quiz... Success." . "<BR/>");
        $uniqueid = get_uniqueid($acode);
        mtrace('Obtained uniqueid: OK. <BR/>');
        $timestamp = get_timestamp($acode);
        mtrace('Obtained timestamp: OK. <BR/>');
        if (!get_record('quiz_attempts', 'uniqueid', $uniqueid)) {
            $newattempt = true;
        } else {
            $newattempt = false;
            mtrace("User {$userid} had opened this attempt already.");
        }
        $attemptnumber = 1;
        if ($newattempt == false) {
            mtrace('Obtaining user attempt...<BR/>');
            set_attempt_unfinished($uniqueid);
            $attempt = quiz_get_user_attempt_unfinished($quiz->id, $userid);
        } elseif ($newattempt == true) {
            mtrace('Creating new attempt...<BR/>');
            $attempt = create_new_attempt($quiz, $attemptnumber, $userid, $acode, $uniqueid, $timestamp);
            // Save the attempt
            if (!insert_record('quiz_attempts', $attempt)) {
                throw new EvaluationError(get_string('ErrorCouldNotCreateAttempt', 'blended'), EvaluationError::CREATE_QUIZ_ATTEMPT_ERROR);
            }
            // Actualizamos el estado de las imágenes para indicar que ya está creado un nuevo attempt
            update_images_status($acode, $jobid);
        }
        update_question_attempts($uniqueid);
        // /*
        mtrace('<BR>Getting questions and question options... ');
        $questions = get_questions($attempt, $quiz);
        if (!get_question_options($questions)) {
            error('Could not load question options');
        }
        mtrace('Success! <BR>');
        //	print ("<BR>He obtenido questions: ");
        //print_object($questions);
        $lastattemptid = false;
        //	 if ($attempt->attempt > 1 and $quiz->attemptonlast and !$attempt->preview) {
        // Find the previous attempt
        //      if (!$lastattemptid = get_field('quiz_attempts', 'uniqueid', 'quiz', $attempt->quiz, 'userid', $attempt->userid, 'attempt', $attempt->attempt-1)) {
        //        error('Could not find previous attempt to build on');
        //  }
        //}
        //print ('He obtenido lastattemptid');
        mtrace('Getting question states... ');
        if (!($states = get_question_states($questions, $quiz, $attempt, $lastattemptid))) {
            error('Could not restore question sessions');
        }
        mtrace('Success! <BR>');
        mtrace('Getting responses... <BR>');
        $responses = get_responses($acode, $jobid, $attempt);
        //print('Estas son las responses:');
        //print_object($responses);
        //$timestamp=time();
        $event = 8;
        $actions = question_extract_responses($questions, $responses, $event);
        $questionids = get_questionids($acode);
        //	print $questionids;
        $questionidarray = explode(',', $questionids);
        $success = true;
        mtrace('<BR> Processing responses and saving session... ');
        foreach ($questionidarray as $i) {
            if (!isset($actions[$i])) {
                $actions[$i]->responses = array('' => '');
                $actions[$i]->event = QUESTION_EVENTOPEN;
            }
            $actions[$i]->timestamp = $timestamp;
            if (question_process_responses($questions[$i], $states[$i], $actions[$i], $quiz, $attempt)) {
                save_question_session($questions[$i], $states[$i]);
            } else {
                $success = false;
            }
        }
        mtrace('Success! <BR>');
        // Set the attempt to be finished
        $timestamp = time();
        //$attempt->timefinish = $timestamp;
        // Update the quiz attempt and the overall grade for the quiz
        mtrace('<BR> Finishing the attempt... ');
        // print_object ($attempt);
        if (set_field('quiz_attempts', 'timefinish', $timestamp, 'uniqueid', $uniqueid) == false) {
            throw new EvaluationError('Unable to finish the quiz attempt!', EvaluationError::FINISH_QUIZ_ATTEMPT_ERROR);
        }
        mtrace('Success! <BR>');
        if ($attempt->attempt > 1 || $attempt->timefinish > 0 and !$attempt->preview) {
            mtrace('<BR> Saving quiz grade... ');
            quiz_save_best_grade($quiz, $userid);
        }
        mtrace('Success! <BR>');
        // */
        mtrace("Process Done. <BR><BR>");
        mtrace("<center> Your quiz has been succesfully evaluated!! </center>");
    } catch (EvaluationError $e) {
        throw $e;
    }
    return;
}
Exemple #11
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;
}