]> git.mjollnir.org Git - moodle.git/commitdiff
Improved handling of event types so that now graded states can always be distinguishe...
authorgustav_delius <gustav_delius>
Sun, 19 Mar 2006 18:28:29 +0000 (18:28 +0000)
committergustav_delius <gustav_delius>
Sun, 19 Mar 2006 18:28:29 +0000 (18:28 +0000)
lang/en_utf8/quiz.php
lib/questionlib.php
question/questiontypes/essay/questiontype.php
question/questiontypes/match/questiontype.php
question/questiontypes/multianswer/questiontype.php
question/questiontypes/multichoice/questiontype.php
question/questiontypes/numerical/questiontype.php
question/questiontypes/questiontype.php
question/questiontypes/rqp/questiontype.php
question/questiontypes/shortanswer/questiontype.php
question/questiontypes/truefalse/questiontype.php

index af6e8254aa54f9ad06dd2d2746573db25fc6fb93..e62c3cc2e6e46d2b364d54789e3b7a7eee702650 100644 (file)
@@ -159,6 +159,8 @@ $string['event2'] = 'Save';
 $string['event3'] = 'Grade';
 $string['event5'] = 'Validate';
 $string['event6'] = 'Close';
+$string['event7'] = 'Submit';
+$string['event8'] = 'Close';
 $string['examview'] = 'Examview';
 $string['existingcategory1'] = 'a literal from an already existing set of literals that are also used by other questions in this category';
 $string['existingcategory2'] = 'a file from an already existing set of files that are also used by other questions in this category';
index 7532245cf743242f4f82f6c57eebc53b5528fddc..3e22162d7ec89432520b9834103c0e57bf0f6e50 100644 (file)
 /**#@+
 * The different types of events that can create question states
 */
-define('QUESTION_EVENTOPEN', '0');
-define('QUESTION_EVENTNAVIGATE', '1');
-define('QUESTION_EVENTSAVE', '2');
-define('QUESTION_EVENTGRADE', '3');
-define('QUESTION_EVENTDUPLICATEGRADE', '4');
-define('QUESTION_EVENTVALIDATE', '5');
-define('QUESTION_EVENTCLOSE', '6');
-define('QUESTION_EVENTSUBMIT', '7');
+define('QUESTION_EVENTOPEN', '0');      // The state was created by Moodle
+define('QUESTION_EVENTNAVIGATE', '1');  // The responses were saved because the student navigated to another page (this is not currently used)
+define('QUESTION_EVENTSAVE', '2');      // The student has requested that the responses should be saved but not submitted or validated
+define('QUESTION_EVENTGRADE', '3');     // Moodle has graded the responses. A SUBMIT event can be changed to a GRADE event by Moodle.
+define('QUESTION_EVENTDUPLICATE', '4'); // The responses submitted were the same as previously
+define('QUESTION_EVENTVALIDATE', '5');  // The student has requested a validation. This causes the responses to be saved as well, but not graded.
+define('QUESTION_EVENTCLOSEANDGRADE', '6'); // Moodle has graded the responses. A CLOSE event can be changed to a CLOSEANDGRADE event by Moodle.
+define('QUESTION_EVENTSUBMIT', '7');    // The student response has been submitted but it has not yet been marked
+define('QUESTION_EVENTCLOSE', '8');     // The response has been submitted and the session has been closed, either because the student requested it or because Moodle did it (e.g. because of a timelimit). The responses have not been graded.
 /**#@-*/
 
 /**#@+
@@ -275,7 +276,6 @@ function get_question_states(&$questions, $cmoptions, $attempt) {
                 $states[$i]->last_graded = $gradedstates[$i];
             } else {
                 $states[$i]->last_graded = clone($states[$i]);
-                $states[$i]->last_graded->responses = array('' => '');
             }
         } else {
             // Create a new state object
@@ -445,7 +445,17 @@ function save_question_session(&$question, &$state) {
 * @param object $state
 */
 function question_state_is_graded($state) {
-    return ($state->event == QUESTION_EVENTGRADE or $state->event == QUESTION_EVENTCLOSE);
+    return ($state->event == QUESTION_EVENTGRADE or $state->event == QUESTION_EVENTCLOSEANDGRADE);
+}
+
+/**
+* Determines whether a state has been closed by looking at the event field
+*
+* @return boolean         true if the state has been closed
+* @param object $state
+*/
+function question_state_is_closed($state) {
+    return ($state->event == QUESTION_EVENTCLOSE or $state->event == QUESTION_EVENTCLOSEANDGRADE);
 }
 
 
@@ -479,7 +489,7 @@ function question_extract_responses($questions, $responses, $defaultevent) {
             if ($key === 'validate') {
                 $actions[$quid]->event = QUESTION_EVENTVALIDATE;
             } else if ($key === 'mark') {
-                $actions[$quid]->event = QUESTION_EVENTGRADE;
+                $actions[$quid]->event = QUESTION_EVENTSUBMIT;
             } else {
                 $actions[$quid]->event = $defaultevent;
             }
@@ -537,10 +547,11 @@ function regrade_question_in_attempt($question, $attempt, $cmoptions, $verbose=f
             if (((count($states) - 1) === $j) && ($attempt->timefinish > 0)) {
                 $action->event = QUESTION_EVENTCLOSE;
 
-            // Grade instead of closing, question_process_responses will then
-            // work out whether to close it
-            } else if (QUESTION_EVENTCLOSE == $states[$j]->event) {
-                $action->event = QUESTION_EVENTGRADE;
+            // Change event to submit so that it will be reprocessed
+            } else if (QUESTION_EVENTCLOSE == $states[$j]->event
+                       or QUESTION_EVENTGRADE == $states[$j]->event
+                       or QUESTION_EVENTCLOSEANDGRADE == $states[$j]->event) {
+                $action->event = QUESTION_EVENTSUBMIT;
 
             // By default take the event that was saved in the database
             } else {
@@ -605,14 +616,15 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
     unset($action->responses['mark'], $action->responses['validate']);
 
     // Check the question session is still open
-    if (QUESTION_EVENTCLOSE == $state->event) {
+    if (question_state_is_closed($state)) {
         return true;
     }
+
     // If $action->event is not set that implies saving
     if (! isset($action->event)) {
         $action->event = QUESTION_EVENTSAVE;
     }
-    // Check if we are grading the question; compare against last graded
+    // If submitted then compare against last graded
     // responses, not last given responses in this case
     if (question_isgradingevent($action->event)) {
         $state->responses = $state->last_graded->responses;
@@ -622,6 +634,8 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
     $sameresponses = (($state->responses == $action->responses) or
      ($state->responses == array(''=>'') && array_keys(array_count_values($action->responses))===array('')));
 
+    // If the response has not been changed then we do not have to process it again
+    // unless the attempt is closing or validation is requested
     if ($sameresponses and QUESTION_EVENTCLOSE != $action->event
      and QUESTION_EVENTVALIDATE != $action->event) {
         return true;
@@ -646,11 +660,10 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
         // Grade the response but don't update the overall grade
         $QTYPES[$question->qtype]->grade_responses(
          $question, $state, $cmoptions);
-        // Force the event to save or validate (even if the grading caused the
-        // state to close)
+        // Don't allow the processing to change the event type
         $state->event = $action->event;
 
-    } else if (QUESTION_EVENTGRADE == $action->event) {
+    } else if (QUESTION_EVENTSUBMIT == $action->event) {
 
         // Work out if the current responses (or equivalent responses) were
         // already given in
@@ -658,33 +671,35 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
         // b. any other graded attempt
         if($QTYPES[$question->qtype]->compare_responses(
          $question, $state, $state->last_graded)) {
-            $state->event = QUESTION_EVENTDUPLICATEGRADE;
+            $state->event = QUESTION_EVENTDUPLICATE;
         } else {
             if ($cmoptions->optionflags & QUIZ_IGNORE_DUPRESP) {
                 /* Walk back through the previous graded states looking for
                 one where the responses are equivalent to the current
                 responses. If such a state is found, set the current grading
                 details to those of that state and set the event to
-                QUESTION_EVENTDUPLICATEGRADE */
+                QUESTION_EVENTDUPLICATE */
                 question_search_for_duplicate_responses($question, $state);
             }
-            // If we did not find a duplicate, perform grading
-            if (QUESTION_EVENTDUPLICATEGRADE != $state->event) {
-                // Decrease sumgrades by previous grade and then later add new grade
-                $attempt->sumgrades -= (float)$state->last_graded->grade;
-
-                $QTYPES[$question->qtype]->grade_responses(
-                 $question, $state, $cmoptions);
-                // Calculate overall grade using correct penalty method
-                question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions);
-                // Update the last graded state (don't simplify!)
-                unset($state->last_graded);
-                $state->last_graded = clone($state);
-                unset($state->last_graded->changed);
-
-                $attempt->sumgrades += (float)$state->last_graded->grade;
-            }
         }
+
+        // If we did not find a duplicate, perform grading
+        if (QUESTION_EVENTDUPLICATE != $state->event) {
+            // Decrease sumgrades by previous grade and then later add new grade
+            $attempt->sumgrades -= (float)$state->last_graded->grade;
+
+            $QTYPES[$question->qtype]->grade_responses(
+             $question, $state, $cmoptions);
+            // Calculate overall grade using correct penalty method
+            question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions);
+            // Update the last graded state (don't simplify!)
+            unset($state->last_graded);
+            $state->last_graded = clone($state);
+            unset($state->last_graded->changed);
+
+            $attempt->sumgrades += (float)$state->last_graded->grade;
+        }
+
     } else if (QUESTION_EVENTCLOSE == $action->event) {
         // decrease sumgrades by previous grade and then later add new grade
         $attempt->sumgrades -= (float)$state->last_graded->grade;
@@ -696,8 +711,6 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
             // Calculate overall grade using correct penalty method
             question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions);
         }
-        // Force the state to close (as the attempt is closing)
-        $state->event = QUESTION_EVENTCLOSE;
         
         // Update the last graded state (don't simplify!)
         unset($state->last_graded);
@@ -715,7 +728,7 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
 * Determine if event requires grading
 */
 function question_isgradingevent($event) {
-    return (QUESTION_EVENTGRADE == $event || QUESTION_EVENTCLOSE == $event);
+    return (QUESTION_EVENTSUBMIT == $event || QUESTION_EVENTCLOSE == $event);
 }
 
 /**
@@ -725,6 +738,8 @@ function question_isgradingevent($event) {
 * to ignore the marking request for the current response. However this
 * check against all previous graded responses is only performed if
 * the QUIZ_IGNORE_DUPRESP bit in $cmoptions->optionflags is set
+* If the current response is a duplicate of a previously graded response then
+* $STATE->event is set to QUESTION_EVENTDUPLICATE.
 * @return boolean         Indicates if a state with duplicate responses was
 *                         found.
 * @param object $question
@@ -743,12 +758,12 @@ function question_search_for_duplicate_responses(&$question, &$state) {
          $question, $oldstate)) {
             if(!$QTYPES[$question->qtype]->compare_responses(
              $question, $state, $oldstate)) {
-                $state->event = QUESTION_EVENTDUPLICATEGRADE;
+                $state->event = QUESTION_EVENTDUPLICATE;
                 break;
             }
         }
     }
-    return (QUESTION_EVENTDUPLICATEGRADE == $state->event);
+    return (QUESTION_EVENTDUPLICATE == $state->event);
 }
 
 /**
@@ -771,7 +786,7 @@ function question_search_for_duplicate_responses(&$question, &$state) {
 *                           for incorrect earlier responses are subtracted.
 */
 function question_apply_penalty_and_timelimit(&$question, &$state, $attempt, $cmoptions) {
-    // deal with penaly
+    // deal with penalty
     if ($cmoptions->penaltyscheme) {
             $state->grade = $state->raw_grade - $state->sumpenalty;
             $state->sumpenalty += (float) $state->penalty;
index c0777688d75047cecb0078db5c445a6ded0cccde..a571073e5b171a2d81dd5901a5a9f4b4b5ac1dc2 100644 (file)
@@ -173,12 +173,13 @@ class question_essay_qtype extends quiz_default_questiontype {
     function grade_responses(&$question, &$state, $cmoptions) {
         $state->raw_grade = 0;
         // if a fraction is submitted, then we use it, otherwise the raw grade is 0
-        if (isset($state->responses['fraction'])) {
+        if ($state->responses['fraction']) {
             $state->raw_grade = $state->responses['fraction'];
             $state->options->graded = 1;
+            // mark the state as graded
+            $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
         } else {
             $state->raw_grade = 0;
-            $state->event = QUESTION_EVENTSUBMIT;
         }
 
         // Make sure we don't assign negative or too high marks
index baca52726721f847ccbfa124d08978c96430f176..623c12068380a4cdc8c30267d3b492719c851128 100644 (file)
@@ -294,6 +294,9 @@ class question_match_qtype extends quiz_default_questiontype {
                             0.0), 1.0) * $question->maxgrade;
         $state->penalty = $question->penalty * $question->maxgrade;
 
+        // mark the state as graded
+        $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
+
         return true;
     }
 
index e8c8460323ae1a20dcbcc1582ccc91e4c7ad0f40..2f9d572d780588e97724ca5c0e1cda834bc14049 100644 (file)
@@ -356,6 +356,9 @@ class quiz_embedded_cloze_qtype extends quiz_default_questiontype {
         }
         $state->penalty = $question->penalty * $question->maxgrade;
 
+        // mark the state as graded
+        $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
+
         return true;
     }
 
index 7f3ca8708b1d8b9c7f99c952fa8eab9d44fd0714..43a964171e3e47ca0970c7855685a92ea7d12623 100644 (file)
@@ -350,6 +350,9 @@ class question_multichoice_qtype extends quiz_default_questiontype {
         // Apply the penalty for this attempt
         $state->penalty = $question->penalty * $question->maxgrade;
 
+        // mark the state as graded
+        $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
+
         return true;
     }
 
index a3919f7739f128bf156a490b98c166ab7755db43..1675fac934f64c2b38360866e74ac1ba6d8d0d1e 100644 (file)
@@ -292,6 +292,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
                             0.0), 1.0) * $question->maxgrade;
         $state->penalty = $question->penalty * $question->maxgrade;
 
+        // mark the state as graded
+        $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
+
         return true;
     }
 
index 7702da4e239e754ed0c72e966db04fb9a2708bf6..1aa9e5831900a16972c50dfe909308dbbdb0fcd7 100644 (file)
@@ -458,7 +458,7 @@ class quiz_default_questiontype {
         $grade = '';
         if ($question->maxgrade and $options->scores) {
             if ($cmoptions->optionflags & QUIZ_ADAPTIVE) {
-                $grade = (!($state->last_graded->event == QUESTION_EVENTGRADE)) ? '--/' : round($state->last_graded->grade, $cmoptions->decimalpoints).'/';
+                $grade = (!question_state_is_graded($state->last_graded)) ? '--/' : round($state->last_graded->grade, $cmoptions->decimalpoints).'/';
             }
             $grade .= $question->maxgrade;
         }
@@ -470,7 +470,7 @@ class quiz_default_questiontype {
                 $states = get_records_select('question_states', "attempt = '$state->attempt' AND question = '$question->id' AND event > '0'", 'seq_number DESC');
             } else {
                 // show only graded states
-                $states = get_records_select('question_states', "attempt = '$state->attempt' AND question = '$question->id' AND event = '".QUESTION_EVENTGRADE."'", 'seq_number DESC');
+                $states = get_records_select('question_states', "attempt = '$state->attempt' AND question = '$question->id' AND event IN (".QUESTION_EVENTGRADE.','.QUESTION_EVENTCLOSEANDGRADE.")", 'seq_number DESC');
             }
             if (count($states) > 1) {
                 $strreviewquestion = get_string('reviewresponse', 'quiz');
@@ -531,12 +531,12 @@ class quiz_default_questiontype {
         attempt and displays the overall grade obtained counting all previous
         responses (and penalties) */
 
-        if (QUESTION_EVENTDUPLICATEGRADE == $state->event) {
+        if (QUESTION_EVENTDUPLICATE == $state->event) {
             echo ' ';
             print_string('duplicateresponse', 'quiz');
         }
         if (!empty($question->maxgrade) && $options->scores) {
-            if ($state->last_graded->event == QUESTION_EVENTGRADE) {
+            if (question_state_is_graded($state->last_graded)) {
                 // Display the grading details from the last graded state
                 $grade->cur = round($state->last_graded->grade, $cmoptions->decimalpoints);
                 $grade->max = $question->maxgrade;
@@ -566,7 +566,7 @@ class quiz_default_questiontype {
                     }
                     // print info about new penalty
                     // penalty is relevant only if the answer is not correct and further attempts are possible
-                    if (($state->last_graded->raw_grade < $question->maxgrade) and (QUESTION_EVENTCLOSE !== $state->event)) {
+                    if (($state->last_graded->raw_grade < $question->maxgrade) and (QUESTION_EVENTCLOSEANDGRADE !== $state->event)) {
                         if ('' !== $state->last_graded->penalty && ((float)$state->last_graded->penalty) > 0.0) {
                             // A penalty was applied so display it
                             print_string('gradingdetailspenalty', 'quiz', $state->last_graded->penalty);
@@ -718,6 +718,7 @@ class quiz_default_questiontype {
         // arrays. The ordering of the arrays does not matter.
         // Question types may wish to override this (eg. to ignore trailing
         // white space or to make "7.0" and "7" compare equal).
+        if ($question->qtype = MATCH) {var_dump($state->responses);echo '<br>Teststate:';var_dump($teststate->responses);}
         return $state->responses == $teststate->responses;
     }
 
@@ -750,7 +751,7 @@ class quiz_default_questiontype {
     *                         must be updated. The method is able to
     *                         close the question session (preventing any further
     *                         attempts at this question) by setting
-    *                         $state->event to QUESTION_EVENTCLOSE.
+    *                         $state->event to QUESTION_EVENTCLOSEANDGRADE
     * @param object $cmoptions
     */
     function grade_responses(&$question, &$state, $cmoptions) {
@@ -776,6 +777,9 @@ class quiz_default_questiontype {
         // Only allow one attempt at the question
         $state->penalty = 1;
 
+        // mark the state as graded
+        $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
+
         return true;
     }
 
index 119e58c552e379f98b5db6150b6aeece10a1f258..0d46a0099a08430c603d3560527f99fb4e7ef46f 100644 (file)
@@ -360,6 +360,7 @@ class question_rqp_qtype extends quiz_default_questiontype {
     * This function calls RQP_Render to perform response processing and grading
     * and updates the state accordingly. It also caches the rendering output in case
     * it is needed later.
+    * TODO: set $state->event appropriately
     * @return boolean         Indicates success or failure.
     * @param object $question The question to be graded.
     * @param object $state    The state of the question to grade. The current
index f96300559e1044fdc4bfa3458252220e6dffc47a..d8d9f83dc0936a405ff8a2eaa8ab5dad2e502988 100644 (file)
@@ -198,6 +198,9 @@ class question_shortanswer_qtype extends quiz_default_questiontype {
                             0.0), 1.0) * $question->maxgrade;
         $state->penalty = $question->penalty * $question->maxgrade;
 
+        // mark the state as graded
+        $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
+
         return true;
     }
 
index 5b9076cb9dbb081a305e7864b5e1ecc02d233afe..e7cc30671fa97c0ebdcfb560ed3c76bba00eb492 100644 (file)
@@ -194,6 +194,9 @@ class question_truefalse_qtype extends quiz_default_questiontype {
         // Only allow one attempt at the question
         $state->penalty = 1;
 
+        // mark the state as graded
+        $state->event = ($state->event ==  QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
+
         return true;
     }