Note: You are currently viewing documentation for Moodle 2.9. Up-to-date documentation for the latest stable version of Moodle may be available here: question edit QTYPES USEABLE BY MULTIANSWER form functions.

Development:question edit QTYPES USEABLE BY MULTIANSWER form functions

From MoodleDocs

The code flow of question_edit_QTYPES_USEABLE_BY_MULTIANSWER_form functions that will be used by the new multianswer(Cloze) editing interface.

Main question_edit_QTYPES_USEABLE_BY_MULTIANSWER_form()

As described in Development:Cloze question type this function should be created to be able to create the class with or without activating the moodle form.

function question_edit_shortanswer_form($submiturl, $question, $category, $contexts, $formeditable = true,$go=true){
if( $go) parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable );

}

definition_inner(&$mform)

This function can be divided as

  1. Modification of the main question display like removing grade in multianswer
  2. Display usual answer parameters
    1. answer
    2. grade
    3. feedback
    4. others like tolerance in numerical
  3. Display other answer parameters like units in numerical
  4. Display specific feedbacks as in multichoice

For the purpose of multianswer two subfunctions should be added so that

  1. Modification of the main question display like removing grade in multianswer remains in the definition_inner()
  2. Display usual answer parameters is done by definition_inner_answer()
    1. answer
    2. grade
    3. feedback
    4. others like tolerance in numerical
  3. Display other answer parameters like units in numerical is done by definition_inner_other()
  4. Display specific feedbacks as in multichoice is not useable in multianswer so remains in the definition_inner()

So the definition_inner(&$mform) code become (using a mixed example)

    function definition_inner(&$mform) {
       // Remove meaningless defaultgrade field.
       $mform->removeElement('defaultgrade');
      $this->definition_inner_answer($mform,,$this,$this->question,) ;
      $this->definition_inner_other($mform,,$this,$this->question,,) ;
      $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
       $mform->addElement('htmleditor', 'correctfeedback', get_string('correctfeedback', 'qtype_multichoice'),
                               array('course' => $this->coursefilesid));
       $mform->setType('correctfeedback', PARAM_RAW);
       //etc.
     }

The definition_inner_answer() functions should be created only by QTYPES_USEABLE_BY_MULTIANSWER i.e. shortanswer,numerical and multichoice for regular ones. The definition_inner_other() functions should be created only when necessary by QTYPES_USEABLE_BY_MULTIANSWER i.e. numerical for regular ones.


definition_inner_answer()

To ientified the parameters in the edit_multianswer they will be named with a prefix like sub_1_, sub_2_ etc. We need also a Question{#1},Question{#2} prefix to be added to the headers and the add new answer button. We need to access the $question and the object using the definition_inner_answer i.e. $this which become $that inside definition_inner_answer. a $display object will be used (and described elsewhere) to control the display. a typical function (without the display control code for numerical)

       function definition_inner_answer(&$mform,$prefix=,&$that,$question,$prehdr,$displayoptions) {

           $creategrades = get_grade_options();
       $gradeoptions = $creategrades->gradeoptions;
       $repeated = array();
       $repeatedoptions = array();
          $repeated[] =& $mform->createElement('header',$prefix.'answerhdr', $prehdr.get_string('answerno', 'qtype_numerical', '{no}'));
       
       $repeated[] =& $mform->createElement('text', $prefix.'answer', get_string('answer', 'quiz'));
       $mform->setType('answer', PARAM_RAW);

       $repeated[] =& $mform->createElement('text', $prefix.'tolerance', get_string('acceptederror', 'quiz'));
       $mform->setType($prefix.'tolerance', PARAM_NUMBER);

       $repeated[] =& $mform->createElement('select', $prefix.'fraction', get_string('grade'), $gradeoptions);
       $repeatedoptions[$prefix.'fraction']['default'] = 0;
 
       $repeated[] =& $mform->createElement('htmleditor', $prefix.'feedback', get_string('feedback', 'quiz'),
                               array('course' => $that->coursefilesid));
        
       $mform->setType($prefix.'feedback', PARAM_RAW);

 

       if (isset($question->options)){
           $countanswers = count($question->options->answers);
       } else {
           $countanswers = 0;
       }
       if ($question->formoptions->repeatelements){
           $repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + 1))?
                               QUESTION_NUMANS_START : ($countanswers + 1);
       } else {
           $repeatsatstart = $countanswers;
       }
       
       $that->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, $prefix.'noanswers',  

       $prefix.'addanswers', QUESTION_NUMANS_ADD, $prehdr.' '.get_string('addmoreanswerblanks', 'qtype_numerical'));

}

definition_inner_other()

for numerical

   function definition_inner_other(&$mform,$prefix=,&$that,$question,$prehdr,$displayoptions) {


       $repeated = array();
       if($displayoptions->displayothers == 'hide' ){
           $repeated[] =& $mform->createElement('hidden', $prefix.'unit',get_string('unit', 'quiz'));
       } else {
           
       $repeated[] =& $mform->createElement('header',$prefix.'unithdr', $prehdr.' '.get_string('unithdr', 'qtype_numerical', '{no}'));
               $repeated[] =& $mform->createElement('text', $prefix.'unit', get_string('unit', 'quiz'));
       }
       $mform->setType($prefix.'unit', PARAM_NOTAGS);
       if($displayoptions->displayothers == 'hide' ){
           $repeated[] =& $mform->createElement('hidden',$prefix.'multiplier', get_string('multiplier', 'quiz'));
       } else {
           $repeated[] =& $mform->createElement('text',$prefix.'multiplier', get_string('multiplier', 'quiz'));
       }
       $mform->setType($prefix.'multiplier', PARAM_NOTAGS);

       if (isset($question->options)){
           $countunits = count($question->options->units);
       } else {
           $countunits = 0;
       }

       if ($question->formoptions->repeatelements){
           $repeatsatstart = $countunits + 2;
       } else {
           $repeatsatstart = $countunits;
       }
       $that->repeat_elements($repeated, $repeatsatstart, array(), $prefix.'nounits',$prefix.'addunits', 2, $prehdr.' '.get_string('addmoreunitblanks', 'qtype_numerical'));

       $firstunit =& $mform->getElement($prefix.'multiplier[0]');
       $firstunit->freeze();
       $firstunit->setValue('1.0');
       $firstunit->setPersistantFreeze(true);
       
           }

set_data()

This should also be divided with the setting data answer with a $prefix. However as the inner_other are always on the multianswer answer form (hidden or not)for the qtypes that have ones(like numerical) there is no need to create a set_data_other().But for consistency it is preferable to set one if a definition_inner_other exits. As we cannot assured that there are $default values to set (i.e. if there is no $question->options )the $default_values should be merged after testing.

   // numerical as example
         $default_values_answers = $this->set_data_answers($question,);
         $default_values_other = $this->set_data_other($question,);
          if(is_array($default_values_other) && count($default_values_other)){
              if(is_array($default_values_answers)){
                  $default_values = array_merge($default_values_answers,$default_values_other);
              }else $default_values =$default_values_other;
          }

        $question = (object)((array)$question + $default_values));

set_data_answers()

The $prefix i.e sub_1_ is needed to identify the parameters on the edit_multianswer_form

for numerical note the $answer->tolerance which is specific to numerical
   function set_data_answers($question,$prefix=){

      $default_values =array();
       if (isset($question->options)){
           $answers = $question->options->answers;
           if (count($answers)) {
               $key = 0;
               foreach ($answers as $answer){
                   $default_values[$prefix.'answer['.$key.']'] = $answer->answer;
                   $default_values[$prefix.'fraction['.$key.']'] = $answer->fraction;
                   $default_values[$prefix.'tolerance['.$key.']'] = $answer->tolerance;
                   $default_values[$prefix.'feedback['.$key.']'] = $answer->feedback;
                   $key++;
               }
           }
for numerical the following line are added
           $units  = array_values($question->options->units);
           if (!empty($units)) {
               foreach ($units as $key => $unit){
                   $default_values[$prefix.'unit['.$key.']'] = $unit->unit;
                   $default_values[$prefix.'multiplier['.$key.']'] = $unit->multiplier;
               }
           }
}

==