diff --git a/question/type/calculated/editquestion.html b/question/type/calculated/editquestion.html index 71b9c0b26d1..9901f961fd0 100644 --- a/question/type/calculated/editquestion.html +++ b/question/type/calculated/editquestion.html @@ -80,24 +80,31 @@ + : - " />   - + " />   + fraction,""); ?> : - " />± + " />± : tolerance_types(), - 'tolerancetype[]', $answers[0]->tolerancetype, false); ?> + 'tolerancetype[]', $answer->tolerancetype, false); ?> @@ -108,17 +115,27 @@ '4' => ' 4 ', '5' => ' 5 ', '6' => ' 6 ', '7' => ' 7 ', '8' => ' 8 ', '9' => ' 9 '), 'correctanswerlength[]', - $answers[0]->correctanswerlength, false); ?> + $answer->correctanswerlength, false); ?> get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz')), 'correctanswerformat[]', - $answers[0]->correctanswerformat, false); ?> + $answer->correctanswerformat, false); ?> : - + + + + + + + @@ -157,40 +174,40 @@ for ($i=1; $i + + + + + + + + + id) { + ?> + + + " /> + + + + + + + + + - - - - -" /> + + - diff --git a/question/type/calculated/editquestion.php b/question/type/calculated/editquestion.php index c8fbb93dd86..1781ab0ee81 100644 --- a/question/type/calculated/editquestion.php +++ b/question/type/calculated/editquestion.php @@ -3,7 +3,7 @@ // Get a handle to the question type we are dealing with here $qtypeobj = $QTYPES['calculated']; -if (empty($form)) { +if (empty($form)|| isset($form->addanswers) || isset($form->addunits)) { /****************************************************************/ /***** First page in question wizard - editquestion.html.html! **/ /****************************************************************/ @@ -14,7 +14,7 @@ if (empty($form)) { // However, the code behind supports up to six formulas // and the database store and attempt/review framework // does not have any limit. - $answers= array(); +/* $answers= array(); for ($i=0; $i<6; $i++) { // Make answer slots with default values $answers[$i]->answer = ""; @@ -38,15 +38,52 @@ if (empty($form)) { } } } + */ + $emptyanswer = new stdClass; + $emptyanswer->answer = ''; + $emptyanswer->feedback = ""; + $emptyanswer->fraction = "1.0"; + $emptyanswer->tolerance = "0.01"; + $emptyanswer->tolerancetype = "1"; + $emptyanswer->correctanswerlength = "2"; // Defaults to two ... + $emptyanswer->correctanswerformat = "1"; // ... decimals + + if (!empty($question->id) && isset($question->qtype) && + $QTYPES[$question->qtype]->get_question_options($question)) { + + $answers = array_values($question->options->answers); + /* $units = array_values($question->options->units); + usort($units, create_function('$a, $b', // make sure the default unit is at index 0 + 'if (1.0 === (float)$a->multiplier) { return -1; } else '. + 'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }')); + */ + } else { + $answers = array(); + $answers[] = $emptyanswer; + // $units = array(); + } + + // Add blank answers to make the number up to QUESTION_NUMANS + // or one more than current, if there are already lots. + $emptyanswer = new stdClass; + $emptyanswer->answer = ''; + $emptyanswer->feedback = ""; + $emptyanswer->fraction = "1.0"; + $emptyanswer->tolerance = "0.01"; + $emptyanswer->tolerancetype = "1"; + $emptyanswer->correctanswerlength = "2"; // Defaults to two ... + $emptyanswer->correctanswerformat = "1"; // ... decimals + // $i = count($answers); + // $limit = QUESTION_NUMANS; +// $limit = $limit <= $i ? $i+1 : $limit; +// for (; $i < $limit; $i++) { + $answers[] = $emptyanswer; + // } // Units are handled the same way // as for numerical questions $units = array(); - for ($i=0 ; $i<6 ; $i++) { - // Make unit slots, default as blank... - $units[$i]->multiplier = ''; - $units[$i]->unit = ''; - } + if (!empty($question->id) and $unitsraw = get_records( 'question_numerical_units', 'question', $question->id)) { /// Find default unit and have it put in the zero slot @@ -70,8 +107,9 @@ if (empty($form)) { } } else { $units[0]->multiplier = 1.0; + $units[0]->unit= ''; } - + // Strip trailing zeros from multipliers foreach ($units as $i => $unit) { if (ereg('^(.*\\..(.*[^0])?)0+$', $unit->multiplier, $regs1)) { @@ -82,6 +120,13 @@ if (empty($form)) { } } } + if (isset($form->addunits)){ + $emptyunit = new stdClass; + $emptyunit->multiplier = ''; + $emptyunit->unit = ''; + $units[]=$emptyunit; + $units[]=$emptyunit; + } print_heading_with_help(get_string("editingcalculated", "quiz"), "calculated", "quiz"); require("$CFG->dirroot/question/type/calculated/editquestion.html"); } else { // $form is not empty diff --git a/question/type/calculated/questiontype.php b/question/type/calculated/questiontype.php index 790806ae4b1..24690e6a782 100644 --- a/question/type/calculated/questiontype.php +++ b/question/type/calculated/questiontype.php @@ -195,11 +195,136 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype delete_records('question_calculated', 'id', $oo->id); } } + // validating data but not on import + if( !isset($question->import_process)){ + $mandatorydatasets = array(); + foreach ($question->answers as $answer) { + $mandatorydatasets += $this->find_dataset_names($answer); + } + // do not proceed further if no mandatorydataset + if (count($mandatorydatasets) < 1) { // check there are at lest 2 answers for multiple choice + $result->notice = get_string('atleastonewildcard', 'qtype_datasetdependent');//get_string("notenoughanswers", "qtype_multichoice", "2"); + return $result; + } + $calculatedmessages = array(); + //evaluate the equations i.e {=5+4) eval( + $qtext = ""; + $qtextremaining = $question->questiontext ; + $possibledatasets = $this->find_dataset_names($question->questiontext); + foreach ($possibledatasets as $name => $value) { + $qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining); + } + // echo "numericalquestion qtextremaining
";print_r($possibledatasets); 
 
+//         echo "test
";print_r($numericalquestion);
+           while  (ereg('\{=([^[:space:]}]*)}', $qtextremaining, $regs1)) {
+             $qtextsplits = explode($regs1[0], $qtextremaining, 2);
+            $qtext =$qtext.$qtextsplits[0];
+            $qtextremaining = $qtextsplits[1];
+             // echo "testsplit0".$qtextsplits[0]."
"; + // echo "test".$regs1[0]."
"; + // echo "qtext".$qtext."
"; + // echo "test
";print_r($regs1);
+            if (empty($regs1[1])) {
+                    $str = '';
+                } else {
+                    // could put here an equation verification
+                     if ($formulaerrors =
+                     qtype_calculated_find_formula_errors($regs1[1])) {
+                        $calculatedmessages[] = $formulaerrors;
+                        $str = '';
+                    }                  
+                }
+            } 
+            // import from 1.8 to be tested
+            $answercount=0 ;
+        $maxgrade = false;
+        $mandatorydatasets = array();
+        foreach ($question->answers as $key => $answer){
+            $mandatorydatasets += $this->find_dataset_names($answer);
+        }      
+        if ( count($mandatorydatasets )==0){
+          //  $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
+ //           foreach ($answers as $key => $answer){
+               $calculatedmessages[] = get_string('atleastonewildcard', 'qtype_datasetdependent');
+//            }      
+        }  
+        foreach ($question->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){
+                    $calculatedmessages[] = $eqerror.":".$answer;
+                }
+            }
+            
+            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++;
+            }
+        } 
+        if ($answercount == 0) {
+            $calculatedmessages[]=get_string('atleastoneanswer', 'qtype_calculated');
+        }
+          /*              $calculatedmessages = array();
+                if (empty($form->name)) {
+                    $calculatedmessages[] = get_string('missingname', 'quiz');
+                }
+                if (empty($form->questiontext)) {
+                    $calculatedmessages[] = get_string('missingquestiontext', 'quiz');
+                }
+                // Verify formulas
+                foreach ($form->answers as $key => $answer) {
+                    if ('' === trim($answer)) {
+                        $calculatedmessages[] =
+                            get_string('missingformula', 'quiz');
+                    }
+                    if ($formulaerrors =
+                     qtype_calculated_find_formula_errors($answer)) {
+                        $calculatedmessages[] = $formulaerrors;
+                    }
+                    if (! isset($form->tolerance[$key])) {
+                        $form->tolerance[$key] = 0.0;
+                    }
+                    if (! is_numeric($form->tolerance[$key])) {
+                        $calculatedmessages[] =
+                            get_string('tolerancemustbenumeric', 'quiz');
+                    }
+                }
 
+                if (!empty($calculatedmessages)) {
+                    $errorstring = "The following errors were found:
"; + foreach ($calculatedmessages as $msg) { + $errorstring .= $msg . '
'; + } + error($errorstring); + } + */ + + } if( isset($question->import_process)&&$question->import_process){ $this->import_datasets($question); } + if (!empty($calculatedmessages)) { + $errorstring = "The following errors were found:
"; + foreach ($calculatedmessages as $msg) { + $errorstring .= $msg . '
'; + } + $result->notice=$errorstring; + } + // Report any problems. if (!empty($result->notice)) { return $result; @@ -261,7 +386,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype $datasetitem->number = $dataitem->itemnumber ; $datasetitem->value = $dataitem->value ; if (!insert_record('question_dataset_items', $datasetitem)) { - error("Unable to insert dataset item $item->itemnumber with $item->value for $datasetdef->name"); + error("Unable to insert dataset item $datasetitem->number with $item->value for $datasetdef->name"); } } } @@ -273,6 +398,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype $question->options->answers = array(); foreach ($form->answers as $key => $answer) { $a->answer = trim($form->answer[$key]); + $a->fraction = $form->fraction[$key];//new $a->tolerance = $form->tolerance[$key]; $a->tolerancetype = $form->tolerancetype[$key]; $a->correctanswerlength = $form->correctanswerlength[$key]; @@ -365,6 +491,25 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype } $numericalquestion->questiontext = parent::substitute_variables( $numericalquestion->questiontext, $state->options->dataset); + //evaluate the equations i.e {=5+4) + $qtext = ""; + $qtextremaining = $numericalquestion->questiontext ; + while (ereg('\{=([^[:space:]}]*)}', $qtextremaining, $regs1)) { + $qtextsplits = explode($regs1[0], $qtextremaining, 2); + $qtext =$qtext.$qtextsplits[0]; + $qtextremaining = $qtextsplits[1]; + if (empty($regs1[1])) { + $str = ''; + } else { + if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){ + $str=$formulaerrors ; + }else { + eval('$str = '.$regs1[1].';'); + } + } + $qtext = $qtext.$str ; + } + $numericalquestion->questiontext = $qtext.$qtextremaining ; // end replace equations $virtualqtype->print_question_formulation_and_controls($numericalquestion, $state, $cmoptions, $options); } @@ -590,7 +735,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype function comment_header($question) { //$this->get_question_options($question); global $SESSION; - $strheader = ''; + $strheader = Array(); $delimiter = ''; if (empty($question->id)) { $answers = $SESSION->datasetdependent->questionform->answers; @@ -599,9 +744,9 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype } foreach ($answers as $answer) { if (is_string($answer)) { - $strheader .= $delimiter.$answer; + $strheader[] = $answer; } else { - $strheader .= $delimiter.$answer->answer; + $strheader[]= $answer->answer; } $delimiter = ','; } @@ -624,6 +769,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype $errors = ''; $delimiter = ': '; $virtualqtype = $this->get_virtual_qtype(); + $column =Array(); foreach ($answers as $answer) { $calculated = qtype_calculated_calculate_answer( $answer->answer, $data, $answer->tolerance, @@ -639,12 +785,13 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype $errors .= " -$calculated->answer"; $stranswers .= $delimiter; } else { - $stranswers .= $delimiter.$calculated->answer; - $strmin .= $delimiter.$calculated->min; - $strmax .= $delimiter.$calculated->max; + // $stranswers .= $delimiter.$calculated->answer; + // $strmin .= $delimiter.$calculated->min; + // $strmax .= $delimiter.$calculated->max; + $column[]=$stranswers.$delimiter.$calculated->answer.'
'.$strmin.$delimiter.$calculated->min.'
'.$strmax.$delimiter.$calculated->max ; } } - return "$stranswers
$strmin
$strmax
$errors"; + return $column; } function tolerance_types() { @@ -653,18 +800,25 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype '3' => get_string('geometric', 'quiz')); } - function dataset_options($form, $name, $renameabledatasets=false) { + 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... - list($options, $selected) = parent::dataset_options($form, $name); + //$renameabledatasets not implemented anmywhere + list($options, $selected) = parent::dataset_options($form, $name,'','qtype_calculated'); + // list($options, $selected) = $this->dataset_optionsa($form, $name); + foreach ($options as $key => $whatever) { if (!ereg('^'.LITERAL.'-', $key) && $key != '0') { unset($options[$key]); } } if (!$selected) { + if ($mandatory){ $selected = LITERAL . "-0-$name"; // Default + }else { + $selected = "0"; // Default + } } return array($options, $selected); } @@ -721,6 +875,100 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype return $str; } + /** + * This function retrieve the item count of the available category shareable + * wild cards that is added as a comment displayed when a wild card with + * the same name is displayed in datasetdefinitions_form.php + */ + function get_dataset_definitions_category($form) { + global $CFG; + $datasetdefs = array(); + $lnamemax = 30; + if (!empty($form->category)) { + $sql = "SELECT i.*,d.* + FROM {$CFG->prefix}question_datasets d, + {$CFG->prefix}question_dataset_definitions i + WHERE i.id = d.datasetdefinition + AND i.category = '$form->category' + ; + "; + if ($records = get_records_sql($sql)) { + foreach ($records as $r) { + if ( !isset ($datasetdefs["$r->name"])) $datasetdefs["$r->name"] = $r->itemcount; + } + } + } + return $datasetdefs ; + } + + /** + * This function build a table showing the available category shareable + * wild cards, their name, their definition (Min, Max, Decimal) , the item count + * and the name of the question where they are used. + * This table is intended to be add before the question text to help the user use + * these wild cards + */ + + function print_dataset_definitions_category($form) { + global $CFG; + $datasetdefs = array(); + $lnamemax = 22; + $namestr =get_string('name', 'quiz'); + $minstr=get_string('min', 'quiz'); + $maxstr=get_string('max', 'quiz'); + $rangeofvaluestr=get_string('minmax','qtype_datasetdependent'); + $questionusingstr = get_string('usedinquestion','qtype_calculated'); + $wildcardstr = get_string('wildcard', 'qtype_calculated'); + $itemscountstr = get_string('itemscount','qtype_datasetdependent'); + $text =''; + if (!empty($form->category)) { + $sql = "SELECT i.*,d.* + FROM {$CFG->prefix}question_datasets d, + {$CFG->prefix}question_dataset_definitions i + WHERE i.id = d.datasetdefinition + AND i.category = '$form->category'; + " ; + if ($records = get_records_sql($sql)) { + foreach ($records as $r) { + $sql1 = "SELECT q.* + FROM {$CFG->prefix}question q + WHERE q.id = $r->question + "; + if ( !isset ($datasetdefs["$r->type-$r->category-$r->name"])){ + $datasetdefs["$r->type-$r->category-$r->name"]= $r; + } + if ($questionb = get_records_sql($sql1)) { + $datasetdefs["$r->type-$r->category-$r->name"]->questions[$r->question]->name =$questionb[$r->question]->name ; + } + } + } + } + if (!empty ($datasetdefs)){ + + $text =""; + foreach ($datasetdefs as $datasetdef){ + list($distribution, $min, $max,$dec) = explode(':', $datasetdef->options, 4); + $text .=""; + } + $text .="
$namestr$rangeofvaluestr$itemscountstr$questionusingstr
$datasetdef->name $min - $max $datasetdef->itemcount  "; + foreach ($datasetdef->questions as $qu) { + //limit the name length displayed + if (!empty($qu->name)) { + $qu->name = (strlen($qu->name) > $lnamemax) ? + substr($qu->name, 0, $lnamemax).'...' : $qu->name; + } else { + $qu->name = ''; + } + $text .="    $qu->name
"; + } + $text .="
"; + }else{ + $text .=get_string('nosharedwildcard', 'qtype_calculated'); + } + return $text ; + } + + /// BACKUP FUNCTIONS //////////////////////////// /* diff --git a/question/type/datasetdependent/abstractqtype.php b/question/type/datasetdependent/abstractqtype.php index 49c1609ef49..6a4880e8de2 100644 --- a/question/type/datasetdependent/abstractqtype.php +++ b/question/type/datasetdependent/abstractqtype.php @@ -27,7 +27,7 @@ class question_dataset_dependent_questiontype extends default_questiontype { // Find out how many datasets are available global $CFG; if(!$maxnumber = (int)get_field_sql( - "SELECT MAX(a.itemcount) + "SELECT MIN(a.itemcount) FROM {$CFG->prefix}question_dataset_definitions a, {$CFG->prefix}question_datasets b WHERE b.question = $question->id @@ -76,42 +76,6 @@ class question_dataset_dependent_questiontype extends default_questiontype { return true; } - function print_question_formulation_and_controls(&$question, &$state, $cmoptions, - $options) { - // Substitute variables in questiontext before giving the data to the - // virtual type for printing - $virtualqtype = $this->get_virtual_qtype(); - $unit = $virtualqtype->get_default_numerical_unit($question); - foreach ($question->options->answers as $answer) { - $answer->answer = $this->substitute_variables($answer->answer, - $state->options->dataset); - } - $question->questiontext = $this->substitute_variables( - $question->questiontext, $state->options->dataset); - $virtualqtype->print_question_formulation_and_controls($question, - $state, $cmoptions, $options); - } - - function grade_responses(&$question, &$state, $cmoptions) { - // Forward the grading to the virtual qtype - foreach ($question->options->answers as $answer) { - $answer->answer = $this->substitute_variables($answer->answer, - $state->options->dataset); - } - $virtualqtype = $this->get_virtual_qtype(); - return $virtualqtype->grade_responses($question, $state, $cmoptions) ; - } - - // ULPGC ecastro - function check_response(&$question, &$state) { - // Forward the checking to the virtual qtype - foreach ($question->options->answers as $answer) { - $answer->answer = $this->substitute_variables($answer->answer, - $state->options->dataset); - } - $virtualqtype = $this->get_virtual_qtype(); - return $virtualqtype->check_response($question, $state) ; - } function substitute_variables($str, $dataset) { foreach ($dataset as $name => $value) { @@ -156,7 +120,11 @@ class question_dataset_dependent_questiontype extends default_questiontype { // See where we're coming from switch($form->wizardpage) { case 'question': + if (!isset($form->addanswers)) { require("$CFG->dirroot/question/type/datasetdependent/datasetdefinitions.php"); + // require("$CFG->dirroot/question/type/datasetdependent/datasetdefinitions_form.php"); + // $mform =& new question_dataset_dependent_definitions_form("question.php?wizardnow=datasetdefinitions", $question); + } break; case 'datasetdefinitions': case 'datasetitems': @@ -168,6 +136,80 @@ class question_dataset_dependent_questiontype extends default_questiontype { } } + /** + * This method prepare the $datasets in a format similar to dadatesetdefinitions_form.php + * so that they can be saved + * using the function save_dataset_definitions($form) + * when creating a new calculated question or + * whenediting an already existing calculated question + * or by function save_as_new_dataset_definitions($form, $initialid) + * when saving as new an already existing calculated question + * + * @param object $form + * @param int $questionfromid default = '0' + */ + function preparedatasets($form , $questionfromid='0'){ + // the dataset names present in the edit_question_form and edit_calculated_form are retrieved + $possibledatasets = $this->find_dataset_names($form->questiontext); + $mandatorydatasets = array(); + foreach ($form->answers as $answer) { + $mandatorydatasets += $this->find_dataset_names($answer); + } + // if there are identical datasetdefs already saved in the original question. + // either when editing a question or saving as new + // they are retrieved using $questionfromid + if ($questionfromid!='0'){ + $form->id = $questionfromid ; + } + $datasets = array(); + $key = 0 ; + // always prepare the mandatorydatasets present in the answers + // the $options are not used here + foreach ($mandatorydatasets as $datasetname) { + if (!isset($datasets[$datasetname])) { + list($options, $selected) = + $this->dataset_options($form, $datasetname); + $datasets[$datasetname]=''; + $form->dataset[$key]=$selected ; + $key++; + } + } + // do not prepare possibledatasets when creating a question + // they will defined and stored with datasetdefinitions_form.php + // the $options are not used here + if ($questionfromid!='0'){ + + foreach ($possibledatasets as $datasetname) { + if (!isset($datasets[$datasetname])) { + list($options, $selected) = + $this->dataset_options($form, $datasetname,false); + $datasets[$datasetname]=''; + $form->dataset[$key]=$selected ; + $key++; + } + } + } + return $datasets ; + } + /** + * 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) { // For dataset dependent questions a wizard is used for editing // questions. Therefore saving the question is delayed until @@ -181,35 +223,34 @@ class question_dataset_dependent_questiontype extends default_questiontype { // See where we're coming from switch($form->wizardpage) { + case '' : case 'question': // coming from the first page, creating the second - if (empty($form->id)) { - $SESSION->datasetdependent = new stdClass; - $SESSION->datasetdependent->questionform = $form; - } else { + if (empty($form->id)) { // for a new question $form->id is empty $question = parent::save_question($question, $form, $course); - } - break; - case 'datasetdefinitions': - if (empty($form->id)) { - if (isset($SESSION->datasetdependent->questionform)) { - $SESSION->datasetdependent->definitionform = $form; - } else { - // Something went wrong, go back to the first page - redirect("question.php?category={$question->category}" . - "&qtype={$question->qtype}"); - } - } else { + //prepare the datasets using default $questionfromid + $form->datasets = $this->preparedatasets($form); + $form->id = $question->id; + $this->save_dataset_definitions($form); + } else if (!empty($form->makecopy)){ + $questionfromid = $form->id ; + $question = parent::save_question($question, $form, $course); + //prepare the datasets + $form->datasets = $this->preparedatasets($form,$questionfromid); + $form->id = $question->id; + $this->save_as_new_dataset_definitions($form,$questionfromid ); + } else {// editing a question + $question = parent::save_question($question, $form, $course); + //prepare the datasets + $form->datasets = $this->preparedatasets($form,$question->id); + $form->id = $question->id; $this->save_dataset_definitions($form); } break; + case 'datasetdefinitions': + $this->save_dataset_definitions($form); + break; case 'datasetitems': - if (empty($form->id) && isset($form->addbutton)) { - $question = parent::save_question($question, - $SESSION->datasetdependent->questionform, $course); - $SESSION->datasetdependent->definitionform->id = $form->id = $question->id; - $this->save_dataset_definitions($SESSION->datasetdependent->definitionform); - unset($SESSION->datasetdependent); - } + $this->save_dataset_items($question, $form); break; default: error('Incorrect or no wizard page specified!'); @@ -218,14 +259,19 @@ class question_dataset_dependent_questiontype extends default_questiontype { return $question; } - function get_dataset_definitions($form) { + function save_dataset_items($question, $fromform){ + //overridden in child classes + } + + function get_dataset_definitions($questionid, $newdatasets) { + //get the existing datasets for this question $datasetdefs = array(); - if (!empty($form->id)) { + if (!empty($questionid)) { global $CFG; $sql = "SELECT i.* FROM {$CFG->prefix}question_datasets d, {$CFG->prefix}question_dataset_definitions i - WHERE d.question = '$form->id' + WHERE d.question = '$questionid' AND d.datasetdefinition = i.id "; if ($records = get_records_sql($sql)) { @@ -235,20 +281,20 @@ class question_dataset_dependent_questiontype extends default_questiontype { } } - $datasets = empty($form->dataset) ? $form->definition : $form->dataset; - foreach ($datasets as $dataset) { + foreach ($newdatasets as $dataset) { if (!$dataset) { continue; // The no dataset case... } if (!isset($datasetdefs[$dataset])) { + //make new datasetdef list($type, $category, $name) = explode('-', $dataset, 3); $datasetdef = new stdClass; $datasetdef->type = $type; $datasetdef->name = $name; $datasetdef->category = $category; $datasetdef->itemcount = 0; - $datasetdef->options = ''; + $datasetdef->options = 'uniform:1.0:10.0:1'; $datasetdefs[$dataset] = clone($datasetdef); } } @@ -257,7 +303,7 @@ class question_dataset_dependent_questiontype extends default_questiontype { function save_dataset_definitions($form) { // Save datasets - $datasetdefinitions = $this->get_dataset_definitions($form); + $datasetdefinitions = $this->get_dataset_definitions($form->id, $form->dataset); $tmpdatasets = array_flip($form->dataset); $defids = array_keys($datasetdefinitions); foreach ($defids as $defid) { @@ -334,7 +380,122 @@ class question_dataset_dependent_questiontype extends default_questiontype { } } } + /** This function create a copy of the datasets ( definition and dataitems) + * from the preceding question if they remain in the new question + * otherwise its create the datasets that have been added as in the + * save_dataset_definitions() + */ + function save_as_new_dataset_definitions($form, $initialid) { + global $CFG ; + // Get the datasets from the intial question + $datasetdefinitions = $this->get_dataset_definitions($initialid, $form->dataset); + // $tmpdatasets contains those of the new question + $tmpdatasets = array_flip($form->dataset); + $defids = array_keys($datasetdefinitions);// new datasets + foreach ($defids as $defid) { + $datasetdef = &$datasetdefinitions[$defid]; + if (isset($datasetdef->id)) { + // This dataset exist in the initial question + if (!isset($tmpdatasets[$defid])) { + // do not exist in the new question so ignore + unset($datasetdefinitions[$defid]); + continue; + } + // create a copy but not for category one + if (0 == $datasetdef->category) { + $olddatasetid = $datasetdef->id ; + $olditemcount = $datasetdef->itemcount ; + $datasetdef->itemcount =0; + if (!$datasetdef->id = insert_record( + 'question_dataset_definitions', $datasetdef)) { + error("Unable to create dataset $defid"); + } + //copy the dataitems + $olditems = get_records_sql( // Use number as key!! + " SELECT number, value + FROM {$CFG->prefix}question_dataset_items + WHERE definition = $olddatasetid "); + if (count($olditems) > 0 ) { + $itemcount = 0; + foreach($olditems as $item ){ + $item->definition = $datasetdef->id; + if (!insert_record('question_dataset_items', $item)) { + error("Unable to insert dataset item $item->number with $item->value for $datasetdef->name"); + } + $itemcount++; + } + //update item count + $datasetdef->itemcount =$itemcount; + update_record('question_dataset_definitions', $datasetdef); + } // end of copy the dataitems + }// end of copy the datasetdef + // Create relation to the new question with this + // copy as new datasetdef from the initial question + $questiondataset = new stdClass; + $questiondataset->question = $form->id; + $questiondataset->datasetdefinition = $datasetdef->id; + if (!insert_record('question_datasets', + $questiondataset)) { + error("Unable to create relation to dataset $name"); + } + unset($datasetdefinitions[$defid]); + continue; + }// end of datasetdefs from the initial question + // really new one code similar to save_dataset_definitions() + if (!$datasetdef->id = insert_record( + 'question_dataset_definitions', $datasetdef)) { + error("Unable to create dataset $defid"); + } + if (0 != $datasetdef->category) { + // We need to look for already existing + // datasets in the category. + // By first creating the datasetdefinition above we + // can manage to automatically take care of + // some possible realtime concurrence + if ($olderdatasetdefs = get_records_select( + 'question_dataset_definitions', + "type = '$datasetdef->type' + AND name = '$datasetdef->name' + AND category = '$datasetdef->category' + AND id < $datasetdef->id + ORDER BY id DESC")) { + + while ($olderdatasetdef = array_shift($olderdatasetdefs)) { + delete_records('question_dataset_definitions', + 'id', $datasetdef->id); + $datasetdef = $olderdatasetdef; + } + } + } + + // Create relation to this dataset: + $questiondataset = new stdClass; + $questiondataset->question = $form->id; + $questiondataset->datasetdefinition = $datasetdef->id; + if (!insert_record('question_datasets', + $questiondataset)) { + error("Unable to create relation to dataset $name"); + } + unset($datasetdefinitions[$defid]); + } + + // Remove local obsolete datasets as well as relations + // to datasets in other categories: + if (!empty($datasetdefinitions)) { + foreach ($datasetdefinitions as $def) { + delete_records('question_datasets', + 'question', $form->id, + 'datasetdefinition', $def->id); + + if ($def->category == 0) { // Question local dataset + delete_records('question_dataset_definitions', 'id', $def->id); + delete_records('question_dataset_items', + 'definition', $def->id); + } + } + } + } /* @@ -395,58 +556,8 @@ class question_dataset_dependent_questiontype extends default_questiontype { */ -/* - function create_runtime_question($question, $form) { - $question->name = trim($form->name); - $question->questiontext = trim($form->questiontext); - $question->questiontextformat = $form->questiontextformat; - $question->parent = isset($form->parent)? $form->parent : 0; - $question->length = $this->actual_number_of_questions($question); - $question->penalty = isset($form->penalty) ? $form->penalty : 0; - if (empty($form->image)) { - $question->image = ""; - } else { - $question->image = $form->image; - } - if (empty($question->name)) { - $question->name = strip_tags($question->questiontext); - if (empty($question->name)) { - $question->name = '-'; - } - } - - if ($question->penalty > 1 or $question->penalty < 0) { - $question->errors['penalty'] = get_string('invalidpenalty', 'quiz'); - } - - if (isset($form->defaultgrade)) { - $question->defaultgrade = $form->defaultgrade; - } - return $question; - } -*/ - -/* - function validate_form($form) { - switch($form->wizardpage) { - case 'question': - error('Validation for the wizardpage "question" needs to be ' . - 'defined in the inheriting questiontype.'); - case 'datasetdefinitions': - // Nothing to validate - $SESSION->datasetdependent->datasetdefinitions = $form; - break; - case 'datasets': - break; - default: - error('Incorrect or no wizard page specified!'); - break; - } - return true; - } -*/ /// Dataset functionality function pick_question_dataset($question, $datasetitem) { // Select a dataset in the following format: diff --git a/question/type/datasetdependent/datasetitems.php b/question/type/datasetdependent/datasetitems.php index 36cc7d85e48..aaa421d6042 100644 --- a/question/type/datasetdependent/datasetitems.php +++ b/question/type/datasetdependent/datasetitems.php @@ -1,6 +1,7 @@ id)) { $datasetdefs = $this->get_dataset_definitions( $SESSION->datasetdependent->definitionform); @@ -26,7 +29,7 @@ if (empty($question->options)) { $this->get_question_options($question); } - $datasetdefs = $this->get_dataset_definitions($form); + $datasetdefs = $this->get_dataset_definitions($question->id, array()); } // Handle generator options... @@ -55,8 +58,21 @@ $addeditem->definition = $datasetdefs[$defid]->id; $addeditem->value = $form->value[$key]; if ($form->itemid[$key]) { - // Reuse an previously used record $addeditem->id = $form->itemid[$key]; + // Reuse an previously used record + if (empty($form->forceregeneration) && ( + isset($form->regenerateddefid) && + $form->regenerateddefid != $defid || + isset($form->deletebutton))) { + // echo "

Reuse an previously used record un".$addeditem->id."

"; + } else { + if ($this->supports_dataset_item_generation()) { + $addeditem->value = $this->generate_dataset_item($datasetdefs[$defid]->options); + } else { + $addeditem->value = ''; + } + } + //echo "

update le dataset_items".$addeditem->id."

"; if (!update_record('question_dataset_items', $addeditem)) { error("Error: Unable to update dataset item"); } @@ -66,31 +82,79 @@ error("Error: Unable to insert dataset item"); } } - + } + $maxnumber = $addeditem->number; + $numbertoadd =0; + if ($form->selectadd > 1 && $maxnumber < $max100 ) { + $numbertoadd =$form->selectadd-1 ; + if ( $max100 - $maxnumber < $numbertoadd ) { + $numbertoadd = $max100 - $maxnumber ; + } + //add the other items. + // tout d'abord le définit + // Generate a new dataset item (or reuse an old one) + foreach ($datasetdefs as $defid => $datasetdef) { + if (isset($datasetdef->id)) { + $datasetdefs[$defid]->items = get_records_sql( // Use number as key!! + " SELECT number, definition, id, value + FROM {$CFG->prefix}question_dataset_items + WHERE definition = $datasetdef->id ORDER BY number"); + } + // echo "
"; print_r($datasetdefs[$defid]->items);
+    	    for ($numberadded =$maxnumber+1 ; $numberadded <= $maxnumber+$numbertoadd ; $numberadded++){
+                    if (isset($datasetdefs[$defid]->items[$numberadded]) && (
+                      empty($form->forceregeneration) 
+                      // && isset($form->regenerateddefid) &&
+                      // $form->regenerateddefid != $defid || no
+                       || isset($form->deletebutton))) {
+                    //  echo "

Reuse an previously used record".$numberadded."id".$datasetdef->id."

"; + } else { + $datasetitem = new stdClass; + $datasetitem->definition = $datasetdef->id ; + $datasetitem->number = $numberadded; + if ($this->supports_dataset_item_generation()) { + $datasetitem->value = $this->generate_dataset_item($datasetdef->options); + } else { + $datasetitem->value = ''; + } + //pp echo "
"; print_r( $datasetitem );
+                        //insere le nouveau
+                        if (!insert_record('question_dataset_items', $datasetitem)) {
+                            error("Error: Unable to insert new dataset item");
+                        }
+                        $datasetdefs[$defid]->items[$numberadded] = clone($datasetitem);
+                    }
+     		}//for number added   	
+    	    }// datasetsdefs end										
+        }
+	$maxnumber += $numbertoadd ;
             foreach ($datasetdefs as $key => $newdef) {
                 if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) {
-                    $newdef->itemcount = $maxnumber+1;
+                    $newdef->itemcount = $maxnumber;
                     // Save the new value for options
                     update_record('question_dataset_definitions', $newdef);
                 }
             }
-        }
-        // else Success:
-        $maxnumber = $addeditem->number;
+        //}	// if select >
+		
 
     } else if (isset($form->deletebutton)
                && $maxnumber == $form->numbertodelete)  {
         // Simply decrease itemcount where == $maxnumber
+        // selectedelete

+ if(isset($form->selectdelete)) $newmaxnumber = $maxnumber-$form->selectdelete ; + else $newmaxnumber = $maxnumber-1 ; + if ($newmaxnumber < 0 ) $newmaxnumber = 0 ; foreach ($datasetdefs as $datasetdef) { if ($datasetdef->itemcount == $maxnumber) { - $datasetdef->itemcount--; + $datasetdef->itemcount= $newmaxnumber ; //pp--; if (!update_record('question_dataset_definitions', $datasetdef)) { error("Error: Unable to update itemcount"); } } } - --$maxnumber; + $maxnumber= $newmaxnumber; } make_upload_directory("$course->id"); // Just in case @@ -160,13 +224,17 @@ . '
' . $strforceregeneration; } + //pp limit + if ($maxnumber < $max100) { $addline[] = ''.$forceregeneration; + 'value="'.$stradd.'"/>'.'' .$forceregeneration; $addline[] = $maxnumber+1; - - + } else { + $addline[] =''; + $addline[] = ">".$max100; + } foreach ($datasetdefs as $defid => $datasetdef) { if ($datasetdef->name) { $table->head[] = $datasetdef->name; @@ -197,8 +265,10 @@ } if ($strquestionheader) { - $table->head[] = $strquestionheader; - $addtable->head[] = $strquestionheader; + foreach($strquestionheader as $header){ + $table->head[] = $header; + $addtable->head[] = $header; + } if (empty($question->id) && isset($SESSION->datasetdependent->questionform)) { $tmp = &$SESSION->datasetdependent->questionform; @@ -212,7 +282,10 @@ } $question->options->answers = $answers; } - $addline[] = $this->comment_on_datasetitems($question, $data, $maxnumber + 1); + $comment =$this->comment_on_datasetitems($question, $data, $maxnumber + 1); + foreach($comment as $comm){ + $addline[] = $comm ; + } } // Set up the table showing existing datasets @@ -223,7 +296,7 @@ if ($maxnumber == $number) { $columns[] = " - "; + ".''; } else { $columns[] = ''; } @@ -237,7 +310,10 @@ ($data[$datasetdef->name] = $datasetdef->items[$number]->value) ; } if ($strquestionheader) { - $columns[] = $this->comment_on_datasetitems($question, $data, $number); + $comment =$this->comment_on_datasetitems($question, $data, $number); + foreach($comment as $comm){ + $columns[] = $comm ; + } } $table->data[] = $columns; }