mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 16:36:37 +02:00
MDL-17366 adding the calculatedsimple questiontype
This commit is contained in:
parent
b925fe0a00
commit
83a15d025c
4 changed files with 1164 additions and 0 deletions
15
lang/en_utf8/qtype_calculatedsimple.php
Normal file
15
lang/en_utf8/qtype_calculatedsimple.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
$string['addingcalculatedsimple'] = 'Adding a Simple Calculated question';
|
||||||
|
$string['calculatedsimple'] = 'Calculated Simple ';
|
||||||
|
$string['calculatedsimplesummary'] = 'A simpler version of calculated questions which are like numerical questions but with the numbers used selected randomly from a set when the quiz is taken.';
|
||||||
|
$string['converttocalculated'] = 'Save as a new regular calculated question';
|
||||||
|
$string['editingcalculatedsimple'] = 'Editing a Simple Calculated question';
|
||||||
|
$string['findwildcards']='Find the wild cards {x..} present in the correct answer formulas';
|
||||||
|
$string['generatenewitemsset'] = 'Generate a new set of ';
|
||||||
|
$string['mustbenumeric'] = 'You must enter a number here.';
|
||||||
|
$string['mustnotbenumeric'] = 'This can\'t be a number.';
|
||||||
|
$string['wildcarditems']= 'Items generated';
|
||||||
|
$string['wildcardrole']= ' The wild cards <strong>{x..}</strong> will be substituted by a numerical value from the generated values';
|
||||||
|
$string['wildcardparam']= 'Wild cards parameters used to generate the items ';
|
||||||
|
$string['willconverttocalculated']= 'If set, the <strong>Save as new question</strong> will save as a new calculated question';
|
||||||
|
?>
|
715
question/type/calculatedsimple/edit_calculatedsimple_form.php
Normal file
715
question/type/calculatedsimple/edit_calculatedsimple_form.php
Normal file
|
@ -0,0 +1,715 @@
|
||||||
|
<?php // $Id$
|
||||||
|
/**
|
||||||
|
* Defines the editing form for the calculated simplequestion type.
|
||||||
|
*
|
||||||
|
* @copyright © 2007 Jamie Pratt
|
||||||
|
* @author Jamie Pratt me@jamiep.org
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculatedsimple editing form definition.
|
||||||
|
*/
|
||||||
|
class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
|
/**
|
||||||
|
* Handle to the question type for this question.
|
||||||
|
*
|
||||||
|
* @var question_calculatedsimple_qtype
|
||||||
|
*/
|
||||||
|
var $qtypeobj;
|
||||||
|
var $wildcarddisplay ;
|
||||||
|
// public $qtypeobj;
|
||||||
|
// $questiondisplay will contain the question from the form
|
||||||
|
var $questiondisplay ;
|
||||||
|
|
||||||
|
public $datasetdefs;
|
||||||
|
|
||||||
|
public $reload = false ;
|
||||||
|
|
||||||
|
public $maxnumber = -1;
|
||||||
|
|
||||||
|
public $regenerate = true;
|
||||||
|
|
||||||
|
public $noofitems;
|
||||||
|
|
||||||
|
public $outsidelimit = false ;
|
||||||
|
|
||||||
|
public $commentanswer = array();
|
||||||
|
|
||||||
|
public $answer = array();
|
||||||
|
|
||||||
|
public $nonemptyanswer = array();
|
||||||
|
|
||||||
|
|
||||||
|
function question_edit_calculatedsimple_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
||||||
|
global $QTYPES, $SESSION, $CFG, $DB;
|
||||||
|
// echo "<p> QTYPES <pre>";print_r($QTYPES);echo"</pre></p>";
|
||||||
|
// echo "<p> session <pre>";print_r($SESSION);echo"</pre></p>";
|
||||||
|
// echo "<p> question <pre>";print_r($question);echo"</pre></p>";
|
||||||
|
$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 "<p> optional reload exist </p>";
|
||||||
|
$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 "<p>this->answer <pre>";print_r($this->answer);echo"</pre></p>";
|
||||||
|
// echo "<p>this->answer <pre>";print_r($this->nonemptyanswer);echo"</pre></p>";
|
||||||
|
$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 "<p> calcmin <pre>";print_r(optional_param('calcmin'));echo"</pre></p>";
|
||||||
|
echo "<p> calcmax <pre>";print_r(optional_param('calcmax'));echo"</pre></p>";
|
||||||
|
echo "<p> calclength <pre>";print_r(optional_param('calclength'));echo"</pre></p>";*/
|
||||||
|
$newdatasetvalues = false ;
|
||||||
|
// echo "<p> olddef <pre>";print_r(optional_param('datasetdef'));echo"</pre></p>";
|
||||||
|
|
||||||
|
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 "<p> new datasetdefs values ".$regs[2]."xx". $regs[3]."xx".$regs[4]."</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->datasetdefs[$def]->options="uniform:".$this->datasetdefs[$def]->calcmin.":".$this->datasetdefs[$def]->calcmax.":".$this->datasetdefs[$def]->calclength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// echo "<p>this datasetdefs <pre>";print_r($this->datasetdefs);echo"</pre></p>";
|
||||||
|
// 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 "<p> new datasetdefs $datasetname </p>";
|
||||||
|
// $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 "<p> dataset $defkey to remove </p>";
|
||||||
|
$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"<p> using create new items $this->maxnumber </p>";
|
||||||
|
}else {
|
||||||
|
// Handle reload dataset items
|
||||||
|
// echo"<p> using optional to build </p>";
|
||||||
|
if ( "" !=optional_param('definition')&& !($datasettoremove ||$newdataset ||$newdatasetvalues )){
|
||||||
|
$i = 1;
|
||||||
|
$fromformdefinition = optional_param('definition');
|
||||||
|
$fromformnumber = optional_param('number');
|
||||||
|
$fromformitemid = optional_param('itemid');
|
||||||
|
ksort($fromformdefinition);
|
||||||
|
// echo "<p> fromformdefinition <pre>";print_r($fromformdefinition);echo"</pre></p>";
|
||||||
|
// echo "<p> fromformnumber <pre>";print_r($fromformnumber);echo"</pre></p>";
|
||||||
|
|
||||||
|
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 "<p>line 443 datasetdefs <pre>";print_r($this->datasetdefs);echo"</pre></p>";
|
||||||
|
//$key = 0 ;
|
||||||
|
// if ( "" !=optional_param('answer')) echo "<p> optional answer exist </p>";
|
||||||
|
// if ( "" !=optional_param('answer['.$key.']','', PARAM_NOTAGS)) echo "<p> optional $key exist </p>";
|
||||||
|
// if ( "" !=optional_param('noanswer','', PARAM_INT )) echo "<p> optional noanswer exist </p>";
|
||||||
|
|
||||||
|
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 = "<div class='mdl-align'></div><div class='mdl-align'>".get_string('wildcardrole', 'qtype_calculatedsimple')."</div>";
|
||||||
|
$mform->addElement('html', "<div class='mdl-align'> </div>");
|
||||||
|
$mform->addElement('html', $label);// explaining the role of datasets so other strings can be shortened
|
||||||
|
|
||||||
|
$mform->addElement('submit', 'analyzequestion', get_string('findwildcards','qtype_calculatedsimple'));
|
||||||
|
$mform->registerNoSubmitButton('analyzequestion');
|
||||||
|
$mform->closeHeaderBefore('analyzequestion');
|
||||||
|
if ( "" != optional_param('analyzequestion','', PARAM_RAW)) {
|
||||||
|
|
||||||
|
$this->wizarddisplay = true;
|
||||||
|
// echo "<p> session answer <pre>";print_r($SESSION);echo"</pre></p>";
|
||||||
|
// echo "<p> session answer <pre>";print_r($SESSION->calculated->questionform->answers);echo"</pre></p>";
|
||||||
|
|
||||||
|
|
||||||
|
}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]", '', '<hr />');
|
||||||
|
$j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$addoptions = Array();
|
||||||
|
$addoptions['1']='1';
|
||||||
|
for ($i=10; $i<=100 ; $i+=10){
|
||||||
|
$addoptions["$i"]="$i";
|
||||||
|
}
|
||||||
|
$mform->closeHeaderBefore('additemhdr');
|
||||||
|
$addgrp = array();
|
||||||
|
$addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('generatenewitemsset', 'qtype_calculatedsimple'));
|
||||||
|
$addgrp[] =& $mform->createElement('select', "selectadd", get_string('additem', 'qtype_datasetdependent'), $addoptions);
|
||||||
|
$addgrp[] = & $mform->createElement('static',"stat","Items",get_string('item(s)', 'qtype_datasetdependent'));
|
||||||
|
$mform->addGroup($addgrp, 'addgrp', '', ' ', false);
|
||||||
|
$mform->registerNoSubmitButton('addbutton');
|
||||||
|
$mform->closeHeaderBefore('addgrp');
|
||||||
|
$mform->addElement('static', "divideradd", '', '');
|
||||||
|
if ($this->noofitems == 0) {
|
||||||
|
$mform->addElement('static','warningnoitems','','<span class="error">'.get_string('youmustaddatleastoneitem', 'qtype_datasetdependent').'</span>');
|
||||||
|
$mform->closeHeaderBefore('warningnoitems');
|
||||||
|
}else {
|
||||||
|
$mform->addElement('header', 'additemhdr1', get_string('wildcarditems', 'qtype_calculatedsimple'));
|
||||||
|
$mform->closeHeaderBefore('additemhdr1');
|
||||||
|
// $mform->addElement('header', '', get_string('itemno', 'qtype_datasetdependent', ""));
|
||||||
|
// $mform->addElement('submit', 'updatedatasets', get_string('updatedatasetparam', 'qtype_datasetdependent'));
|
||||||
|
// $mform->registerNoSubmitButton('updatedatasets');
|
||||||
|
// $mform->setAdvanced("updatedatasets",true);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
$j = $this->noofitems * count($this->datasetdefs);
|
||||||
|
for ($i = $this->noofitems; $i >= 1 ; $i--){
|
||||||
|
foreach ($this->datasetdefs as $defkey => $datasetdef){
|
||||||
|
$mform->addElement('text', "number[$j]", get_string('param', 'qtype_datasetdependent', $datasetdef->name));
|
||||||
|
$mform->setType("number[$j]", PARAM_NUMBER);
|
||||||
|
$mform->setAdvanced("number[$j]",true);
|
||||||
|
$mform->addElement('hidden', "itemid[$j]");
|
||||||
|
$mform->setType("itemid[$j]", PARAM_INT);
|
||||||
|
|
||||||
|
$mform->addElement('hidden', "definition[$j]");
|
||||||
|
$mform->setType("definition[$j]", PARAM_NOTAGS);
|
||||||
|
|
||||||
|
$j--;
|
||||||
|
}
|
||||||
|
if (!empty( $strquestionlabel)){
|
||||||
|
$repeated[] =& $mform->addElement('static', "answercomment[$i]", "<b>".get_string('itemno', 'qtype_datasetdependent', $i)."</b> ".$strquestionlabel);
|
||||||
|
}
|
||||||
|
$mform->addElement('static', "divider1[$j]", '', '<hr />');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if ($this->outsidelimit){
|
||||||
|
// $mform->addElement('static','outsidelimit','','');
|
||||||
|
// }
|
||||||
|
}else {
|
||||||
|
$mform->addElement('static','warningnowildcards','','<span class="error">'.get_string('atleastonewildcard', 'qtype_calculatedsimple').'</span>');
|
||||||
|
$mform->closeHeaderBefore('warningnowildcards');
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//non standard name for button element needed so not using add_action_buttons
|
||||||
|
//hidden elements
|
||||||
|
|
||||||
|
$mform->addElement('hidden', 'id');
|
||||||
|
$mform->setType('id', PARAM_INT);
|
||||||
|
|
||||||
|
$mform->addElement('hidden', 'courseid');
|
||||||
|
$mform->setType('courseid', PARAM_INT);
|
||||||
|
$mform->setDefault('courseid', 0);
|
||||||
|
|
||||||
|
$mform->addElement('hidden', 'cmid');
|
||||||
|
$mform->setType('cmid', PARAM_INT);
|
||||||
|
$mform->setDefault('cmid', 0);
|
||||||
|
if (!empty($this->question->id)){
|
||||||
|
if ($this->question->formoptions->cansaveasnew){
|
||||||
|
$mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
|
||||||
|
$mform->closeHeaderBefore('additemhdr');
|
||||||
|
|
||||||
|
$mform->addElement('checkbox', 'convert','' ,get_string('willconverttocalculated', 'qtype_calculatedsimple'));
|
||||||
|
$mform->setDefault('convert', 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// $mform->addElement('hidden', 'wizard', 'edit_calculatedsimple');
|
||||||
|
// $mform->setType('wizard', PARAM_ALPHA);
|
||||||
|
/*
|
||||||
|
$mform->addElement('hidden', 'returnurl');
|
||||||
|
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||||
|
$mform->setDefault('returnurl', 0);
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_data($question) {
|
||||||
|
$answer = $this->answer;
|
||||||
|
$default_values = array();
|
||||||
|
if (count($answer)) {
|
||||||
|
$key = 0;
|
||||||
|
foreach ($answer as $answer){
|
||||||
|
$default_values['answer['.$key.']'] = $answer->answer;
|
||||||
|
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||||
|
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
||||||
|
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
||||||
|
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
||||||
|
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
||||||
|
$default_values['feedback['.$key.']'] = $answer->feedback;
|
||||||
|
$key++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($question->options)){
|
||||||
|
$units = array_values($question->options->units);
|
||||||
|
// make sure the default unit is at index 0
|
||||||
|
usort($units, create_function('$a, $b',
|
||||||
|
'if (1.0 === (float)$a->multiplier) { return -1; } else '.
|
||||||
|
'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
|
||||||
|
if (count($units)) {
|
||||||
|
$key = 0;
|
||||||
|
foreach ($units as $unit){
|
||||||
|
$default_values['unit['.$key.']'] = $unit->unit;
|
||||||
|
$default_values['multiplier['.$key.']'] = $unit->multiplier;
|
||||||
|
$key++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$key = 0 ;
|
||||||
|
// echo "<p> mandatorydatasets $key xx".optional_param("answer[0]",'', PARAM_NOTAGS)."YY".$this->_form->getElementValue('answer['.$key.']')."xx<p>";
|
||||||
|
|
||||||
|
$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 "<p>answers avant comment <pre>";print_r($answer);echo"</pre></p>";
|
||||||
|
// echo "<p>data avant comment <pre>";print_r($data);echo"</pre></p>";
|
||||||
|
|
||||||
|
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 "<p> comment <pre>";print_r($comment);echo"</pre></p>";
|
||||||
|
|
||||||
|
foreach ($this->nonemptyanswer as $key => $answer) {
|
||||||
|
$totalcomment .= $comment->stranswers[$key].'<br/>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// $formdata['reload'] = '1';
|
||||||
|
// $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
|
||||||
|
$formdata['selectdelete'] = '1';
|
||||||
|
$formdata['selectadd'] = '1';
|
||||||
|
$j = $this->noofitems * count($this->datasetdefs)+1;
|
||||||
|
$data = array(); // data for comment_on_datasetitems later
|
||||||
|
$idx =1 ;
|
||||||
|
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||||
|
$formdata["datasetdef[$idx]"] = $defid;
|
||||||
|
$idx++;
|
||||||
|
}
|
||||||
|
$formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
|
||||||
|
}
|
||||||
|
$question = (object)((array)$question + $default_values+$formdata );
|
||||||
|
// echo "<p> question data <pre>";print_r($question);echo"</pre></p>";
|
||||||
|
|
||||||
|
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 <pre>";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'] .= '<br/>'.$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
BIN
question/type/calculatedsimple/icon.gif
Normal file
BIN
question/type/calculatedsimple/icon.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 B |
434
question/type/calculatedsimple/questiontype.php
Normal file
434
question/type/calculatedsimple/questiontype.php
Normal file
|
@ -0,0 +1,434 @@
|
||||||
|
<?php // $Id$
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// CALCULATED ///
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
/// QUESTION TYPE CLASS //////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
|
|
||||||
|
// Used by the function custom_generator_tools:
|
||||||
|
var $calcgenerateidhasbeenadded = false;
|
||||||
|
public $virtualqtype = false;
|
||||||
|
|
||||||
|
function name() {
|
||||||
|
return 'calculatedsimple';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function save_question_options($question) {
|
||||||
|
//$options = $question->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 "<p> datasetdefs save <pre>";print_r($datasetdefs);echo"</pre></p>";
|
||||||
|
// 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 "<p> question save <pre>";print_r($question);echo"</pre></p>";
|
||||||
|
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 "<p>comments header answers <pre>";print_r($answers);echo"</pre></p>";
|
||||||
|
|
||||||
|
foreach ($answers as $key => $answer) {
|
||||||
|
/* if (is_string($answer)) {
|
||||||
|
$strheader .= $delimiter.$answer;
|
||||||
|
} else {*/
|
||||||
|
$strheader .= $delimiter.$answer->answer;
|
||||||
|
// }
|
||||||
|
$delimiter = '<br/><br/><br/>';
|
||||||
|
}
|
||||||
|
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".'<br/><br/>';
|
||||||
|
} else if ($formula === '*'){
|
||||||
|
$comment->stranswers[$key] = $formula.' = '.get_string('anyvalue','qtype_calculated').'<br/><br/>';
|
||||||
|
}else{
|
||||||
|
$comment->stranswers[$key]= $formula.' = '.$formattedanswer->answer.'' ;
|
||||||
|
$comment->stranswers[$key] .= "<br/>".$strmin. $delimiter.$answer->min.'---';
|
||||||
|
$comment->stranswers[$key] .= $strmax.$delimiter.$answer->max;
|
||||||
|
$comment->stranswers[$key] .='<br/>';
|
||||||
|
$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);//<span class="error">ERROR True answer '..' outside limits</span>';
|
||||||
|
}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());
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
Loading…
Add table
Add a link
Reference in a new issue