From 83a15d025cb163509dcff124ed914058c826966f Mon Sep 17 00:00:00 2001
From: pichetp ";print_r($QTYPES);echo"
session
";print_r($SESSION);echo""; + // echo "
question
";print_r($question);echo""; + $this->regenerate = true; + $this->question = $question; + $this->qtypeobj =& $QTYPES[$this->question->qtype]; + //get the dataset definitions for this question + //coming here everytime even when using a NoSubmitButton + //so this will only set the values to the actual question database content which is not what we want + //so this should be removed from here + // get priority to paramdatasets + + // question->id == 0 so no stored datasets + // else get datasets + if ( "1" == optional_param('reload','', PARAM_INT )) { + // echo "
optional reload exist
"; + $this->reload = true ; + }else { + $this->reload = false ; + } + if(!$this->reload ){ // use database data as this is first pass + if ( !empty($question->id)) { + if (empty($question->options)) { + $this->get_question_options($question); + } + $this->datasetdefs = $this->qtypeobj->get_dataset_definitions($question->id, array()); + + if(!empty($this->datasetdefs)){ + foreach ($this->datasetdefs as $datasetdef) { + // Get maxnumber + if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) { + $this->maxnumber = $datasetdef->itemcount; + } + } + foreach ($this->datasetdefs as $defid => $datasetdef) { + if (isset($datasetdef->id)) { + $this->datasetdefs[$defid]->items = $DB->get_records_sql( // Use number as key!! + " SELECT itemnumber, definition, id, value + FROM {question_dataset_items} + WHERE definition = ? ", array($datasetdef->id)); + } + } + } + $i = 0 ; + foreach($this->question->options->answers as $answer){ + $this->answer[$i] = $answer ; + $i++; + } + $this->nonemptyanswer = $this->answer ; + } + $datasettoremove = false; + $newdatasetvalues = false ; + $newdataset = false ; + }else { + // handle reload to get values from the form-elements + // answers, datasetdefs and data_items + // verify for the specific dataset values as the other parameters + // unints, feeedback etc are handled elsewhere + // handle request buttons : + // 'analyzequestion' (Identify the wild cards {x..} present in answers) + // 'addbutton' (create new set of datatitems) + // 'updatedatasets' is handled automatically on each reload + // The analyzequestion is done every time on reload + // to detect any new wild cards so that the current display reflects + // the mandatory (i.e. in answers) datasets + // to implement : don't do any changes if the question is used in a quiz. + // If new datadef, new properties should erase items. + $dummyform = new stdClass(); + $mandatorydatasets = array(); + + if ( $dummyform->answer =optional_param('answer')) { // there is always at least one answer... + $fraction = optional_param('fraction') ; + $feedback = optional_param('feedback') ; + $tolerance = optional_param('tolerance') ; + $tolerancetype = optional_param('tolerancetype') ; + $correctanswerlength = optional_param('correctanswerlength') ; + $correctanswerformat = optional_param('correctanswerformat') ; + + foreach( $dummyform->answer as $key => $answer ) { + if(trim($answer) != ''){ // just look for non-empty + $this->answer[$key]=new stdClass(); + $this->answer[$key]->answer = $answer; + $this->answer[$key]->fraction = $fraction[$key]; + $this->answer[$key]->feedback = $feedback[$key]; + $this->answer[$key]->tolerance = $tolerance[$key]; + $this->answer[$key]->tolerancetype = $tolerancetype[$key]; + $this->answer[$key]->correctanswerlength = $correctanswerlength[$key]; + $this->answer[$key]->correctanswerformat = $correctanswerformat[$key]; + $this->nonemptyanswer[]= $this->answer[$key]; + $mandatorydatasets +=$this->qtypeobj->find_dataset_names($answer); + } + } + } + // echo "this->answer
";print_r($this->answer);echo""; + // echo "
this->answer
";print_r($this->nonemptyanswer);echo""; + $this->datasetdefs = array(); + // rebuild datasetdefs from old values + $olddef = optional_param('datasetdef'); + $oldoptions = optional_param('defoptions'); + $calcmin = optional_param('calcmin') ; + $calclength = optional_param('calclength') ; + $calcmax = optional_param('calcmax') ; + /* echo "
calcmin
";print_r(optional_param('calcmin'));echo""; + echo "
calcmax
";print_r(optional_param('calcmax'));echo""; + echo "
calclength
";print_r(optional_param('calclength'));echo"";*/ + $newdatasetvalues = false ; + // echo "
olddef
";print_r(optional_param('datasetdef'));echo""; + + for($key = 1 ; $key <= sizeof($olddef) ; $key++) { + $def = $olddef[$key] ; + $this->datasetdefs[$def]= new stdClass ; + $this->datasetdefs[$def]->type = 1; + $this->datasetdefs[$def]->category = 0; + // $this->datasets[$key]->name = $datasetname; + $this->datasetdefs[$def]->options = $oldoptions[$key] ; + $this->datasetdefs[$def]->calcmin = $calcmin[$key] ; + $this->datasetdefs[$def]->calcmax = $calcmax[$key] ; + $this->datasetdefs[$def]->calclength = $calclength[$key] ; + //then compare with new values + if (ereg('^(uniform|loguniform):([^:]*):([^:]*):([0-9]*)$', $this->datasetdefs[$def]->options, $regs)) { + if( $this->datasetdefs[$def]->calcmin != $regs[2]|| + $this->datasetdefs[$def]->calcmax != $regs[3] || + $this->datasetdefs[$def]->calclength != $regs[4]){ + $newdatasetvalues = true ; + // echo "
new datasetdefs values ".$regs[2]."xx". $regs[3]."xx".$regs[4]."
"; + } + + } + $this->datasetdefs[$def]->options="uniform:".$this->datasetdefs[$def]->calcmin.":".$this->datasetdefs[$def]->calcmax.":".$this->datasetdefs[$def]->calclength; + } + + // echo "this datasetdefs
";print_r($this->datasetdefs);echo""; + // detect new datasets + $newdataset = false ; + foreach ($mandatorydatasets as $datasetname) { + if (!isset($this->datasetdefs["1-0-$datasetname"])) { + // list($options, $selected) = + // $this->dataset_options($form, $datasetname); + $key = "1-0-$datasetname"; + $this->datasetdefs[$key]=new stdClass ;//"1-0-$datasetname"; + $this->datasetdefs[$key]->type = 1; + $this->datasetdefs[$key]->category = 0; + $this->datasetdefs[$key]->name = $datasetname; + $this->datasetdefs[$key]->options = "uniform:1.0:10.0:1"; + $newdataset = true ; + // echo "
new datasetdefs $datasetname
"; + // $form->dataset[$key]=$selected ; + //$key++; + }else { + $this->datasetdefs["1-0-$datasetname"]->name = $datasetname ; + } + } + // remove obsolete datasets + $datasettoremove = false; + foreach ($this->datasetdefs as $defkey => $datasetdef){ + if(!isset($datasetdef->name )){ + // echo "dataset $defkey to remove
"; + $datasettoremove = true; + unset($this->datasetdefs[$defkey]); + } + } + + + } // handle reload + // create items if $newdataset and noofitems > 0 and !$newdatasetvalues + // eliminate any items if $newdatasetvalues + // eliminate any items if $datasettoremove, $newdataset, $newdatasetvalues + if ($datasettoremove ||$newdataset ||$newdatasetvalues ) { + foreach ($this->datasetdefs as $defkey => $datasetdef){ + $datasetdef->itemcount = 0; + unset($datasetdef->items); + } + } + $maxnumber = -1 ; + if ( "" !=optional_param('addbutton')){ + $maxnumber = optional_param('selectadd') ; + foreach ($this->datasetdefs as $defid => $datasetdef) { + $datasetdef->itemcount = $maxnumber; + unset($datasetdef->items); + for ($numberadded =1 ; $numberadded <= $maxnumber; $numberadded++){ + $datasetitem = new stdClass; + // $datasetitem->definition = $datasetdef->id ; + $datasetitem->itemnumber = $numberadded; + $datasetitem->id = 0; + $datasetitem->value = $this->qtypeobj->generate_dataset_item($datasetdef->options); + $this->datasetdefs[$defid]->items[$numberadded]=$datasetitem ; + /* if (!$DB->insert_record('question_dataset_items', $datasetitem)) { + print_error('cannotinsert', 'question'); + }*/ + }//for number added + }// datasetsdefs end + $this->maxnumber = $maxnumber ; + // echo"using create new items $this->maxnumber
"; + }else { + // Handle reload dataset items + // echo"using optional to build
"; + if ( "" !=optional_param('definition')&& !($datasettoremove ||$newdataset ||$newdatasetvalues )){ + $i = 1; + $fromformdefinition = optional_param('definition'); + $fromformnumber = optional_param('number'); + $fromformitemid = optional_param('itemid'); + ksort($fromformdefinition); + // echo "fromformdefinition
";print_r($fromformdefinition);echo""; + // echo "
fromformnumber
";print_r($fromformnumber);echo""; + + foreach($fromformdefinition as $key => $defid) { + $addeditem = new stdClass(); + $addeditem->id = $fromformitemid[$i] ; + $addeditem->value = $fromformnumber[$i]; + $addeditem->itemnumber = ceil($i / count($this->datasetdefs)); + $this->datasetdefs[$defid]->items[$addeditem->itemnumber]=$addeditem ; + $this->datasetdefs[$defid]->itemcount = $i ; + $i++; + } + } + if (isset($addeditem->itemnumber) && $this->maxnumber < $addeditem->itemnumber){ + $this->maxnumber = $addeditem->itemnumber; + if(!empty($this->datasetdefs)){ + foreach ($this->datasetdefs as $datasetdef) { + $datasetdef->itemcount = $this->maxnumber ; + } + } + } + } + + // echo "
line 443 datasetdefs
";print_r($this->datasetdefs);echo""; + //$key = 0 ; + // if ( "" !=optional_param('answer')) echo "
optional answer exist
"; + // if ( "" !=optional_param('answer['.$key.']','', PARAM_NOTAGS)) echo "optional $key exist
"; + // if ( "" !=optional_param('noanswer','', PARAM_INT )) echo "optional noanswer exist
"; + + parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable); + } + + function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) { + $repeated = parent::get_per_answer_fields(&$mform, $label, $gradeoptions, $repeatedoptions, $answersoption); + $mform->setType('answer', PARAM_NOTAGS); + $addrepeated = array(); + $addrepeated[] =& $mform->createElement('text', 'tolerance', get_string('tolerance', 'qtype_calculated')); + $repeatedoptions['tolerance']['type'] = PARAM_NUMBER; + $repeatedoptions['tolerance']['default'] = 0.01; + $addrepeated[] =& $mform->createElement('select', 'tolerancetype', get_string('tolerancetype', 'quiz'), $this->qtypeobj->tolerance_types()); + $addrepeated[] =& $mform->createElement('select', 'correctanswerlength', get_string('correctanswershows', 'qtype_calculated'), range(0, 9)); + $repeatedoptions['correctanswerlength']['default'] = 2; + + $answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz')); + $addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats); + array_splice($repeated, 3, 0, $addrepeated); + $repeated[1]->setLabel(get_string('correctanswerformula', 'quiz').'='); + + return $repeated; + } + + /** + * Add question-type specific form fields. + * + * @param MoodleQuickForm $mform the form being built. + */ + function definition_inner(&$mform) { + global $QTYPES; + $this->qtypeobj =& $QTYPES[$this->qtype()]; + $strquestionlabel = $this->qtypeobj->comment_header($this->nonemptyanswer); + $label = get_string("sharedwildcards", "qtype_datasetdependent"); + $mform->addElement('hidden', 'initialcategory', 1); + $mform->addElement('hidden', 'reload', 1); +// $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question); +// $mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name'); + $addfieldsname='updatecategory'; + $addstring=get_string("updatecategory", "qtype_calculated"); + $mform->registerNoSubmitButton($addfieldsname); + +// $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory'); + + $creategrades = get_grade_options(); + $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'), + $creategrades->gradeoptions, 1, 1); + + $repeated = array(); + $repeated[] =& $mform->createElement('header', 'unithdr', get_string('unithdr', 'qtype_numerical', '{no}')); + + $repeated[] =& $mform->createElement('text', 'unit', get_string('unit', 'quiz')); + $mform->setType('unit', PARAM_NOTAGS); + + $repeated[] =& $mform->createElement('text', 'multiplier', get_string('multiplier', 'quiz')); + $mform->setType('multiplier', PARAM_NUMBER); + + if (isset($this->question->options)){ + $countunits = count($this->question->options->units); + } else { + $countunits = 0; + } + if ($this->question->formoptions->repeatelements){ + $repeatsatstart = $countunits + 1; + } else { + $repeatsatstart = $countunits; + } + $this->repeat_elements($repeated, $repeatsatstart, array(), 'nounits', 'addunits', 2, get_string('addmoreunitblanks', 'qtype_calculated', '{no}')); + + if ($mform->elementExists('multiplier[0]')){ + $firstunit =& $mform->getElement('multiplier[0]'); + $firstunit->freeze(); + $firstunit->setValue('1.0'); + $firstunit->setPersistantFreeze(true); + } + //hidden elements + // $mform->addElement('hidden', 'wizard', 'datasetdefinitions'); + // $mform->setType('wizard', PARAM_ALPHA); + // $mform->addElement('header', '', ''); + $label = "session answer
";print_r($SESSION);echo""; + // echo "
session answer
";print_r($SESSION->calculated->questionform->answers);echo""; + + + }else { + $this->wizwarddisplay = false; + } + if ($this->maxnumber != -1){ + $this->noofitems = $this->maxnumber; + } else { + $this->noofitems = 0; + } + if(!empty($this->datasetdefs)){ + + $key = 0; + $mform->addElement('header', 'additemhdr', get_string('wildcardparam', 'qtype_calculatedsimple')); + $idx = 1; + if(!empty($this->datasetdefs)){ + $j = (($this->noofitems) * count($this->datasetdefs))+1;// + foreach ($this->datasetdefs as $defkey => $datasetdef){ + $mform->addElement('static', "na[$j]", get_string('param', 'qtype_datasetdependent', $datasetdef->name)); + $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j); + $mform->addElement('hidden', "datasetdef[$idx]"); + $mform->setType("datasetdef[$idx]", PARAM_RAW); + $idx++; + $mform->addElement('static', "divider[$j]", '', '
mandatorydatasets $key xx".optional_param("answer[0]",'', PARAM_NOTAGS)."YY".$this->_form->getElementValue('answer['.$key.']')."xx
"; + + $formdata = array(); + $fromform = new stdClass(); + //fill out all data sets and also the fields for the next item to add. + if(!empty($this->datasetdefs)){ + $j = $this->noofitems * count($this->datasetdefs); + for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){ + $data = array(); + foreach ($this->datasetdefs as $defid => $datasetdef){ + if (isset($datasetdef->items[$itemnumber])){ + $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value; + $formdata["definition[$j]"] = $defid; + $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id; + $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value; + } + $j--; + } + // echo "
answers avant comment
";print_r($answer);echo""; + // echo "
data avant comment
";print_r($data);echo""; + + if($this->noofitems != 0 ) { + if(!isset($question->id)) $question->id = 0 ; + $comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this-> + if ($comment->outsidelimit) { + $this->outsidelimit=$comment->outsidelimit ; + } + $totalcomment=''; + // echo "
comment
";print_r($comment);echo""; + + foreach ($this->nonemptyanswer as $key => $answer) { + $totalcomment .= $comment->stranswers[$key].'
question data
";print_r($question);echo""; + + parent::set_data($question); + } + + function qtype() { + return 'calculatedsimple'; + } + + function validation($data, $files) { + $errors = parent::validation($data, $files); + //verifying for errors in {=...} in question text; + $qtext = ""; + $qtextremaining = $data['questiontext'] ; + $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']); + foreach ($possibledatasets as $name => $value) { + $qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining); + } + // echo "numericalquestion qtextremaining
";print_r($possibledatasets); + while (ereg('\{=([^[:space:]}]*)}', $qtextremaining, $regs1)) { + $qtextsplits = explode($regs1[0], $qtextremaining, 2); + $qtext =$qtext.$qtextsplits[0]; + $qtextremaining = $qtextsplits[1]; + if (!empty($regs1[1]) && $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) { + if(!isset($errors['questiontext'])){ + $errors['questiontext'] = $formulaerrors.':'.$regs1[1] ; + }else { + $errors['questiontext'] .= '
'.$formulaerrors.':'.$regs1[1]; + } + } + } + $answers = $data['answer']; + $answercount = 0; + $maxgrade = false; + $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']); + $mandatorydatasets = array(); + foreach ($answers as $key => $answer){ + $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer); + } + if ( count($mandatorydatasets )==0){ + // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent'); + foreach ($answers as $key => $answer){ + $errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent'); + } + } + foreach ($answers as $key => $answer){ + //check no of choices + // the * for everykind of answer not actually implemented + $trimmedanswer = trim($answer); + if (($trimmedanswer!='')||$answercount==0){ + $eqerror = qtype_calculated_find_formula_errors($trimmedanswer); + if (FALSE !== $eqerror){ + $errors['answer['.$key.']'] = $eqerror; + } + } + if ($trimmedanswer!=''){ + if ('2' == $data['correctanswerformat'][$key] + && '0' == $data['correctanswerlength'][$key]) { + $errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz'); + } + if (!is_numeric($data['tolerance'][$key])){ + $errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated'); + } + if ($data['fraction'][$key] == 1) { + $maxgrade = true; + } + + $answercount++; + } + //check grades + + //TODO how should grade checking work here?? + /*if ($answer != '') { + if ($data['fraction'][$key] > 0) { + $totalfraction += $data['fraction'][$key]; + } + if ($data['fraction'][$key] > $maxfraction) { + $maxfraction = $data['fraction'][$key]; + } + }*/ + } + //grade checking : + /// Perform sanity checks on fractional grades + /*if ( ) { + if ($maxfraction != 1) { + $maxfraction = $maxfraction * 100; + $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction); + } + } else { + $totalfraction = round($totalfraction,2); + if ($totalfraction != 1) { + $totalfraction = $totalfraction * 100; + $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction); + } + }*/ + $units = $data['unit']; + if (count($units)) { + foreach ($units as $key => $unit){ + if (is_numeric($unit)){ + $errors['unit['.$key.']'] = get_string('mustnotbenumeric', 'qtype_calculated'); + } + $trimmedunit = trim($unit); + $trimmedmultiplier = trim($data['multiplier'][$key]); + if (!empty($trimmedunit)){ + if (empty($trimmedmultiplier)){ + $errors['multiplier['.$key.']'] = get_string('youmustenteramultiplierhere', 'qtype_calculated'); + } + if (!is_numeric($trimmedmultiplier)){ + $errors['multiplier['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated'); + } + + } + } + } + if ($answercount==0){ + $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated'); + } + if ($maxgrade == false) { + $errors['fraction[0]'] = get_string('fractionsnomax', 'question'); + } + if (isset($data['backtoquiz']) && ($this->noofitems==0) ){ + $errors['warning'] = get_string('warning', 'mnet'); + } + if ($this->outsidelimit){ + // if(!isset($errors['warning'])) $errors['warning']=' '; + $errors['outsidelimits'] = get_string('oneanswertrueansweroutsidelimits','qtype_calculated'); + } + $numbers = $data['number']; + foreach ($numbers as $key => $number){ + if(! is_numeric($number)){ + if (stristr($number,',')){ + $errors['number['.$key.']'] = get_string('The , cannot be used, use . as in 0.013 or 1.3e-2', 'qtype_datasetdependent'); + }else { + $errors['number['.$key.']'] = get_string('This is not a valid number', 'qtype_datasetdependent'); + } + }else if( stristr($number,'x')){ + $errors['number['.$key.']'] = get_string('Hexadecimal format (i.e. 0X12d) is not allowed', 'qtype_datasetdependent'); + } else if( is_nan($number)){ + $errors['number['.$key.']'] = get_string('is a NAN number', 'qtype_datasetdependent'); + } + } + if ( $this->noofitems==0 ){ + $errors['warning'] = get_string('warning', 'mnet'); + } + + return $errors; + } +} +?> \ No newline at end of file diff --git a/question/type/calculatedsimple/icon.gif b/question/type/calculatedsimple/icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..e3d60dffbb3ff299080c6c90168e8322377f1a8e GIT binary patch literal 78 zcmZ?wbhEHb6krfw_`t{j0g69aSQ!`?8FWBgkPHKpYEOSA!;Rz9<~-cHD`Ls?M|*0g bE}QbK)9G%e=B-_uo^mhUCVAhDk--`O>5mzv literal 0 HcmV?d00001 diff --git a/question/type/calculatedsimple/questiontype.php b/question/type/calculatedsimple/questiontype.php new file mode 100644 index 0000000000..7eedba4d5b --- /dev/null +++ b/question/type/calculatedsimple/questiontype.php @@ -0,0 +1,434 @@ +subtypeoptions; + // Get old answers: + global $CFG, $DB; + + if (isset($question->answer) && !isset($question->answers)) { + $question->answers = $question->answer; + } + + // Get old versions of the objects + if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { + $oldanswers = array(); + } + + if (!$oldoptions = $DB->get_records('question_calculated', array('question' => $question->id), 'answer ASC')) { + $oldoptions = array(); + } + + // Save the units. + $virtualqtype = $this->get_virtual_qtype(); + $result = $virtualqtype->save_numerical_units($question); + if (isset($result->error)) { + return $result; + } else { + $units = &$result->units; + } + // Insert all the new answers + if (isset($question->answer) && !isset($question->answers)) { + $question->answers=$question->answer; + } + foreach ($question->answers as $key => $dataanswer) { + if ( trim($dataanswer) != '' ) { + $answer = new stdClass; + $answer->question = $question->id; + $answer->answer = trim($dataanswer); + $answer->fraction = $question->fraction[$key]; + $answer->feedback = trim($question->feedback[$key]); + + if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it + $answer->id = $oldanswer->id; + if (! $DB->update_record("question_answers", $answer)) { + $result->error = get_string('errorupdatinganswer','question',$answer->id); + return $result; + } + } else { // This is a completely new answer + if (! $answer->id = $DB->insert_record("question_answers", $answer)) { + $result->error = get_string('errorinsertinganswer','question'); + return $result; + } + } + + // Set up the options object + if (!$options = array_shift($oldoptions)) { + $options = new stdClass; + } + $options->question = $question->id; + $options->answer = $answer->id; + $options->tolerance = trim($question->tolerance[$key]); + $options->tolerancetype = trim($question->tolerancetype[$key]); + $options->correctanswerlength = trim($question->correctanswerlength[$key]); + $options->correctanswerformat = trim($question->correctanswerformat[$key]); + + // Save options + if (isset($options->id)) { // reusing existing record + if (! $DB->update_record('question_calculated', $options)) { + $mess->name = $this->name(); + $mess->id = $options->id ; + $result->error = get_string('errorupdatingoptions','question',$mess); + // $result->error = "Could not update question calculated options! (id=$options->id)"; + return $result; + } + } else { // new options + if (! $DB->insert_record('question_calculated', $options)) { + $result->error = "Could not insert question calculated options!"; + return $result; + } + } + } + } + // delete old answer records + if (!empty($oldanswers)) { + foreach($oldanswers as $oa) { + $DB->delete_records('question_answers', array('id' => $oa->id)); + } + } + + // delete old answer records + if (!empty($oldoptions)) { + foreach($oldoptions as $oo) { + $DB->delete_records('question_calculated', array('id' => $oo->id)); + } + } + + + if( isset($question->import_process)&&$question->import_process){ + $this->import_datasets($question); + }else { + //save datasets and datatitems from form i.e in question + // $datasetdefs = $this->get_dataset_definitions($question->id, array()); + $question->dataset = $question->datasetdef ; + // $this->save_dataset_definitions($question); + // Save datasets + $datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset); + $tmpdatasets = array_flip($question->dataset); + $defids = array_keys($datasetdefinitions); + $datasetdefs = array(); + foreach ($defids as $defid) { + $datasetdef = &$datasetdefinitions[$defid]; + if (isset($datasetdef->id)) { + if (!isset($tmpdatasets[$defid])) { + // This dataset is not used any more, delete it + $DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $datasetdef->id)); + // if ($datasetdef->category == 0) { // Question local dataset + $DB->delete_records('question_dataset_definitions', array('id' => $datasetdef->id)); + $DB->delete_records('question_dataset_items', array('definition' => $datasetdef->id)); + // } + } + // This has already been saved or just got deleted + unset($datasetdefinitions[$defid]); + continue; + } + if (!$datasetdef->id = $DB->insert_record('question_dataset_definitions', $datasetdef)) { + print_error("cannotcreatedataset", 'question', '', $defid); + } + $datasetdefs[]= clone($datasetdef); + $questiondataset = new stdClass; + $questiondataset->question = $question->id; + $questiondataset->datasetdefinition = $datasetdef->id; + if (!$DB->insert_record('question_datasets', $questiondataset)) { + print_error('cannotcreaterelation', 'question', '', $name); + } + unset($datasetdefinitions[$defid]); + } + // Remove local obsolete datasets as well as relations + // to datasets in other categories: + if (!empty($datasetdefinitions)) { + foreach ($datasetdefinitions as $def) { + $DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $def->id)); + if ($def->category == 0) { // Question local dataset + $DB->delete_records('question_dataset_definitions', array('id' => $def->id)); + $DB->delete_records('question_dataset_items', array('definition' => $def->id)); + } + } + } + $datasetdefs = $this->get_dataset_definitions($question->id, $question->dataset); + // echo "datasetdefs save
";print_r($datasetdefs);echo""; + // Handle adding and removing of dataset items + $i = 1; + ksort($question->definition); + foreach ($question->definition as $key => $defid) { + $addeditem = new stdClass(); + $addeditem->definition = $datasetdefs[$defid]->id; + $addeditem->value = $question->number[$i]; + $addeditem->itemnumber = ceil($i / count($datasetdefs)); + if (empty($question->makecopy) && $question->itemid[$i]) { + // Reuse any previously used record + $addeditem->id = $question->itemid[$i]; + if (!$DB->update_record('question_dataset_items', $addeditem)) { + print_error('cannotupdateitem', 'question'); + } + } else { + if (!$DB->insert_record('question_dataset_items', $addeditem)) { + print_error('cannotinsert', 'question'); + } + } + $i++; + } + if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber){ + $maxnumber = $addeditem->itemnumber; + foreach ($datasetdefs as $key => $newdef) { + if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) { + $newdef->itemcount = $maxnumber; + // Save the new value for options + $DB->update_record('question_dataset_definitions', $newdef); + } + } + } + } + // Report any problems. + //convert to calculated + if(!empty($question->makecopy) && !empty($question->convert) ){ + // echo "question save
";print_r($question);echo""; + if (!$DB->set_field('question', 'qtype', 'calculated', array('id'=> $question->id))) { + print_error('cannotupdateitem', 'question'); + } + } + if (!empty($result->notice)) { + return $result; + } + return true; + } + function finished_edit_wizard(&$form) { + return true ; //isset($form->backtoquiz); + } + + + + + /** + * this version save the available data at the different steps of the question editing process + * without using global $SESSION as storage between steps + * at the first step $wizardnow = 'question' + * when creating a new question + * when modifying a question + * when copying as a new question + * the general parameters and answers are saved using parent::save_question + * then the datasets are prepared and saved + * at the second step $wizardnow = 'datasetdefinitions' + * the datadefs final type are defined as private, category or not a datadef + * at the third step $wizardnow = 'datasetitems' + * the datadefs parameters and the data items are created or defined + * + * @param object question + * @param object $form + * @param int $course + * @param PARAM_ALPHA $wizardnow should be added as we are coming from question2.php + */ + function save_question($question, $form, $course) { + + $question = default_questiontype::save_question($question, $form, $course); + return $question; + } + + + function response_summary($question, $state, $length=80, $formatting=true) { + // The actual response is the bit after the hyphen + return substr($state->answer, strpos($state->answer, '-')+1, $length); + } + + function custom_generator_tools_part(&$mform, $idx, $j){ + + $minmaxgrp = array(); + $minmaxgrp[] =& $mform->createElement('text', "calcmin[$idx]", get_string('calcmin', 'qtype_datasetdependent')); + $minmaxgrp[] =& $mform->createElement('text', "calcmax[$idx]", get_string('calcmax', 'qtype_datasetdependent')); + $mform->addGroup($minmaxgrp, 'minmaxgrp', get_string('minmax', 'qtype_datasetdependent'), ' - ', false); + $mform->setType("calcmin[$idx]", PARAM_NUMBER); + $mform->setType("calcmax[$idx]", PARAM_NUMBER); + + $precisionoptions = range(0, 10); + $mform->addElement('select', "calclength[$idx]", get_string('calclength', 'qtype_datasetdependent'), $precisionoptions); + + $distriboptions = array('uniform' => get_string('uniform', 'qtype_datasetdependent'), 'loguniform' => get_string('loguniform', 'qtype_datasetdependent')); + $mform->addElement('hidden', "calcdistribution[$idx]", 'uniform'); + + + } + + function comment_header($answers) { + //$this->get_question_options($question); + $strheader = ""; + $delimiter = ''; + + // $answers = $question->options->answers; + // echo "comments header answers
";print_r($answers);echo""; + + foreach ($answers as $key => $answer) { + /* if (is_string($answer)) { + $strheader .= $delimiter.$answer; + } else {*/ + $strheader .= $delimiter.$answer->answer; + // } + $delimiter = '
'; + } + return $strheader; + } + + function comment_on_datasetitems($questionid, $answers,$data, $number) { + global $DB; + $comment = new stdClass; + $comment->stranswers = array(); + $comment->outsidelimit = false ; + $comment->answers = array(); + /// Find a default unit: + if (!empty($questionid) && $unit = $DB->get_record('question_numerical_units', array('question'=> $questionid, 'multiplier' => 1.0))) { + $unit = $unit->unit; + } else { + $unit = ''; + } + + $answers = fullclone($answers); + $strmin = get_string('min', 'quiz'); + $strmax = get_string('max', 'quiz'); + $errors = ''; + $delimiter = ': '; + $virtualqtype = $this->get_virtual_qtype(); + foreach ($answers as $key => $answer) { + $formula = $this->substitute_variables($answer->answer,$data); + $formattedanswer = qtype_calculated_calculate_answer( + $answer->answer, $data, $answer->tolerance, + $answer->tolerancetype, $answer->correctanswerlength, + $answer->correctanswerformat, $unit); + if ( $formula === '*'){ + $answer->min = ' '; + $formattedanswer->answer = $answer->answer ; + }else { + eval('$answer->answer = '.$formula.';') ; + $virtualqtype->get_tolerance_interval($answer); + } + if ($answer->min === '') { + // This should mean that something is wrong + $comment->stranswers[$key] = " $formattedanswer->answer".'
'; + } else if ($formula === '*'){ + $comment->stranswers[$key] = $formula.' = '.get_string('anyvalue','qtype_calculated').'
'; + }else{ + $comment->stranswers[$key]= $formula.' = '.$formattedanswer->answer.'' ; + $comment->stranswers[$key] .= "
".$strmin. $delimiter.$answer->min.'---'; + $comment->stranswers[$key] .= $strmax.$delimiter.$answer->max; + $comment->stranswers[$key] .='
'; + $correcttrue->correct = $formattedanswer->answer ; + $correcttrue->true = $answer->answer ; + if ($formattedanswer->answer < $answer->min || $formattedanswer->answer > $answer->max){ + $comment->outsidelimit = true ; + $comment->answers[$key] = $key; + $comment->stranswers[$key] .=get_string('trueansweroutsidelimits','qtype_calculated',$correcttrue);//ERROR True answer '..' outside limits'; + }else { + $comment->stranswers[$key] .=get_string('trueanswerinsidelimits','qtype_calculated',$correcttrue);//' True answer :'.$calculated->trueanswer.' inside limits'; + } + $comment->stranswers[$key] .=''; + } + } + return fullclone($comment); + } + + function tolerance_types() { + return array('1' => get_string('relative', 'quiz'), + '2' => get_string('nominal', 'quiz'), + // '3' => get_string('geometric', 'quiz') + ); + } + + function dataset_options($form, $name, $mandatory=true,$renameabledatasets=false) { + // Takes datasets from the parent implementation but + // filters options that are currently not accepted by calculated + // It also determines a default selection... + //$renameabledatasets not implemented anmywhere + list($options, $selected) = $this->dataset_options_from_database($form, $name,'','qtype_calculated'); + // list($options, $selected) = $this->dataset_optionsa($form, $name); + + foreach ($options as $key => $whatever) { + if (!ereg('^1-', $key) && $key != '0') { + unset($options[$key]); + } + } + if (!$selected) { + if ($mandatory){ + $selected = "1-0-$name"; // Default + }else { + $selected = "0"; // Default + } + } + return array($options, $selected); + } + + +/** + * Runs all the code required to set up and save an essay question for testing purposes. + * Alternate DB table prefix may be used to facilitate data deletion. + */ + function generate_test($name, $courseid = null) { + global $DB; + list($form, $question) = parent::generate_test($name, $courseid); + $form->feedback = 1; + $form->multiplier = array(1, 1); + $form->shuffleanswers = 1; + $form->noanswers = 1; + $form->qtype ='calculatedsimple'; + $question->qtype ='calculatedsimple'; + $form->answers = array('{a} + {b}'); + $form->fraction = array(1); + $form->tolerance = array(0.01); + $form->tolerancetype = array(1); + $form->correctanswerlength = array(2); + $form->correctanswerformat = array(1); + $form->questiontext = "What is {a} + {b}?"; + + if ($courseid) { + $course = $DB->get_record('course', array('id'=> $courseid)); + } + + $new_question = $this->save_question($question, $form, $course); + + $dataset_form = new stdClass(); + $dataset_form->nextpageparam["forceregeneration"]= 1; + $dataset_form->calcmin = array(1 => 1.0, 2 => 1.0); + $dataset_form->calcmax = array(1 => 10.0, 2 => 10.0); + $dataset_form->calclength = array(1 => 1, 2 => 1); + $dataset_form->number = array(1 => 5.4 , 2 => 4.9); + $dataset_form->itemid = array(1 => '' , 2 => ''); + $dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform'); + $dataset_form->definition = array(1 => "1-0-a", + 2 => "1-0-b"); + $dataset_form->nextpageparam = array('forceregeneration' => false); + $dataset_form->addbutton = 1; + $dataset_form->selectadd = 1; + $dataset_form->courseid = $courseid; + $dataset_form->cmid = 0; + $dataset_form->id = $new_question->id; + $this->save_dataset_items($new_question, $dataset_form); + + return $new_question; + } +} +//// END OF CLASS //// + +////////////////////////////////////////////////////////////////////////// +//// INITIATION - Without this line the question type is not in use... /// +////////////////////////////////////////////////////////////////////////// +question_register_questiontype(new question_calculatedsimple_qtype()); + + +?> -- 2.39.5