[ Index ] |
|
Code source de Claroline 188 |
1 <?php // $Id: qti2_classes.php,v 1.15.2.2 2007/09/25 08:41:47 seb Exp $ 2 if ( count( get_included_files() ) == 1 ) die( '---' ); 3 /** 4 * CLAROLINE 5 * 6 * @version 1.8 $Revision: 1.15.2.2 $ 7 * 8 * @copyright (c) 2001-2006 Universite catholique de Louvain (UCL) 9 * 10 * @license http://www.gnu.org/copyleft/gpl.html (GPL) GENERAL PUBLIC LICENSE 11 * 12 * @author Claro Team <cvs@claroline.net> 13 * 14 */ 15 $path = dirname(__FILE__); 16 include_once $path . '/../../lib/answer_multiplechoice.class.php'; 17 include_once $path . '/../../lib/answer_truefalse.class.php'; 18 include_once $path . '/../../lib/answer_fib.class.php'; 19 include_once $path . '/../../lib/answer_matching.class.php'; 20 21 include_once get_path('incRepositorySys') . '/lib/xml.lib.php'; 22 23 class Qti2Question extends Question 24 { 25 /** 26 * Include the correct answer class and create answer 27 */ 28 function setAnswer() 29 { 30 switch($this->type) 31 { 32 case 'MCUA' : 33 $this->answer = new Qti2AnswerMultipleChoice($this->id, false); 34 break; 35 case 'MCMA' : 36 $this->answer = new Qti2AnswerMultipleChoice($this->id, true); 37 break; 38 case 'TF' : 39 $this->answer = new Qti2AnswerTrueFalse($this->id, false); 40 break; 41 case 'FIB' : 42 $this->answer = new Qti2AnswerFillInBlanks($this->id); 43 break; 44 case 'MATCHING' : 45 $this->answer = new Qti2AnswerMatching($this->id); 46 break; 47 default : 48 $this->answer = null; 49 break; 50 } 51 52 return true; 53 } 54 /** 55 * allow to import the question 56 * 57 * @param questionArray is an array that must contain all the information needed to build the question 58 */ 59 60 function import($questionInfo) 61 { 62 if( is_array($questionInfo) ) 63 { 64 if( isset($questionInfo['title']) ) $this->setTitle($questionInfo['title']); 65 if( isset($questionInfo['statement']) ) $this->setDescription($questionInfo['statement']."\n".'<!-- content: imsqti -->'); 66 $this->setType($questionInfo['type']); 67 68 if( !empty($questionInfo['attached_file_url']) ) 69 { 70 $this->importAttachment($questionInfo['tempdir'].$questionInfo['attached_file_url']); 71 } 72 } 73 else 74 { 75 return false; 76 } 77 } 78 79 function importAttachment($importedFilePath) 80 { 81 // copy file in a tmp directory known by object, 82 // attached file will be copied to its final destination when saving question 83 $dir = $this->tmpQuestionDirSys; 84 $filename = basename($importedFilePath); 85 86 if( !is_dir( $dir ) ) 87 { 88 // create it 89 if( !claro_mkdir($dir, CLARO_FILE_PERMISSIONS) ) 90 { 91 claro_failure::set_failure('cannot_create_tmp_dir'); 92 return false; 93 } 94 } 95 96 if( claro_move_file($importedFilePath, $dir.$filename) ) 97 { 98 $this->attachment = $filename; 99 return true; 100 } 101 else 102 { 103 return false; 104 } 105 } 106 } 107 108 class Qti2AnswerMultipleChoice extends answerMultipleChoice 109 { 110 /** 111 * Return the XML flow for the possible answers. 112 * 113 */ 114 function qti2ExportResponses($questionIdent, $questionStatment) 115 { 116 $out = "\n" . ' <![CDATA[' . $questionStatment . ']]>' . "\n"; 117 $out .= ' <choiceInteraction responseIdentifier="' . $questionIdent . '" >' . "\n"; 118 119 foreach ($this->answerList as $current_answer) 120 { 121 $out .= ' <simpleChoice identifier="answer_' . $current_answer['id'] . '" fixed="false"><![CDATA[' . $current_answer['answer'] . ']]>'; 122 if (isset($current_answer['comment']) && $current_answer['comment'] != '') 123 { 124 $out .= '<feedbackInline identifier="answer_' . $current_answer['id'] . '"><![CDATA[' . $current_answer['comment'] . ']]></feedbackInline>'; 125 } 126 $out .= '</simpleChoice>'. "\n"; 127 } 128 129 $out .= ' </choiceInteraction>'. "\n"; 130 131 return $out; 132 } 133 134 /** 135 * Return the XML flow of answer ResponsesDeclaration 136 * 137 */ 138 function qti2ExportResponsesDeclaration($questionIdent) 139 { 140 141 if ($this->multipleAnswer == 'MCMA') $cardinality = 'multiple'; else $cardinality = 'single'; 142 143 $out = ' <responseDeclaration identifier="' . $questionIdent . '" cardinality="' . $cardinality . '" baseType="identifier">' . "\n"; 144 145 //Match the correct answers 146 147 $out .= ' <correctResponse>'. "\n"; 148 149 foreach($this->answerList as $current_answer) 150 { 151 if ($current_answer['correct']) 152 { 153 $out .= ' <value>answer_'. $current_answer['id'] .'</value>'. "\n"; 154 } 155 } 156 $out .= ' </correctResponse>'. "\n"; 157 158 //Add the grading 159 160 $out .= ' <mapping>'. "\n"; 161 162 foreach($this->answerList as $current_answer) 163 { 164 if (isset($current_answer['grade'])) 165 { 166 $out .= ' <mapEntry mapKey="answer_'. $current_answer['id'] .'" mappedValue="'.$current_answer['grade'].'" />'. "\n"; 167 } 168 } 169 $out .= ' </mapping>'. "\n"; 170 171 $out .= ' </responseDeclaration>'. "\n"; 172 173 return $out; 174 } 175 176 /** 177 * allow to import the answers, feedbacks, and grades of a question 178 * @param questionArray is an array that must contain all the information needed to build the question 179 180 */ 181 182 function import($questionArray) 183 { 184 $answerArray = $questionArray['answer']; 185 186 $this->answerList = array(); //re-initialize answer object content 187 188 foreach ($answerArray as $key => $answer) 189 { 190 if (!isset($answer['feedback'])) $answer['feedback'] = ""; 191 192 if (!isset($questionArray['weighting'][$key])) 193 { 194 if (isset($questionArray['default_weighting'])) 195 { 196 $grade = castToFloat($questionArray['default_weighting']); 197 } 198 else 199 { 200 $grade = 0; 201 } 202 } 203 else 204 { 205 $grade = castToFloat($questionArray['weighting'][$key]); 206 } 207 208 if (in_array($key,$questionArray['correct_answers'])) $is_correct = 1; else $is_correct = 0; 209 210 $addedAnswer = array( 211 'answer' => $answer['value'], 212 'correct' => $is_correct, 213 'grade' => $grade, 214 'comment' => $answer['feedback'], 215 ); 216 217 $this->answerList[] = $addedAnswer; 218 } 219 } 220 } 221 222 class Qti2AnswerTrueFalse extends AnswerTrueFalse 223 { 224 /** 225 * Return the XML flow for the possible answers. 226 * 227 */ 228 function qti2ExportResponses($questionIdent, $questionStatment) 229 { 230 $out = "\n" . ' <![CDATA[' . $questionStatment . ']]>'. "\n"; 231 $out .= ' <choiceInteraction responseIdentifier="' . $questionIdent . '" >' . "\n"; 232 233 //set true answer 234 235 $out .= ' <simpleChoice identifier="answer_true" fixed="false"><![CDATA[' . get_lang('True') . ']]>' . "\n"; 236 if (isset($this->trueFeedback) && $this->trueFeedback != '') 237 { 238 $out .= '<feedbackInline identifier="answer_true"><![CDATA[' . $this->trueFeedback . ']]></feedbackInline>'. "\n"; 239 } 240 $out .= '</simpleChoice>'. "\n"; 241 242 //set false answer 243 244 $out .= ' <simpleChoice identifier="answer_false" fixed="false"><![CDATA[' . get_lang('False') . ']]>' . "\n"; 245 if (isset($this->falseFeedback) && $this->falseFeedback != '') 246 { 247 $out .= '<feedbackInline identifier="answer_false"><![CDATA[' . $this->falseFeedback . ']]></feedbackInline>'. "\n"; 248 } 249 $out .= '</simpleChoice>'. "\n"; 250 251 252 $out .= ' </choiceInteraction>'. "\n"; 253 return $out; 254 } 255 256 function qti2ExportResponsesDeclaration($questionIdent) 257 { 258 $out = ' <responseDeclaration identifier="' . $questionIdent . '" cardinality="single" baseType="identifier">' . "\n"; 259 260 //Match the correct answers 261 262 $out .= ' <correctResponse>'. "\n"; 263 264 265 if ($this->correctAnswer=='TRUE') 266 { 267 $out .= ' <value>answer_true</value>'. "\n"; 268 } 269 else 270 { 271 $out .= ' <value>answer_false</value>'. "\n"; 272 } 273 274 $out .= ' </correctResponse>'. "\n"; 275 276 //Add the grading 277 278 $out .= ' <mapping>'. "\n"; 279 280 if (isset($this->trueGrade)) 281 { 282 $out .= ' <mapEntry mapKey="answer_true" mappedValue="'.$this->trueGrade.'" />'. "\n"; 283 } 284 285 if (isset($this->falseGrade)) 286 { 287 $out .= ' <mapEntry mapKey="answer_false" mappedValue="'.$this->falseGrade.'" />'. "\n"; 288 } 289 290 $out .= ' </mapping>'. "\n"; 291 292 $out .= ' </responseDeclaration>'. "\n"; 293 294 return $out; 295 296 } 297 } 298 299 300 301 class Qti2AnswerFillInBlanks extends answerFillInBlanks 302 { 303 /** 304 * Export the text with missing words. 305 * 306 * 307 */ 308 function qti2ExportResponses($questionIdent, $questionStatment) 309 { 310 $out = ''; 311 312 $out .= '<prompt><![CDATA[' . $questionStatment . ']]></prompt>'. "\n"; 313 314 switch ($this->type) 315 { 316 case TEXTFIELD_FILL : 317 { 318 $text = $this->answerText; 319 320 foreach ($this->answerList as $key=>$answer) 321 { 322 $text = str_replace('['.$answer.']','<textEntryInteraction responseIdentifier="fill_'.$key.'" expectedLength="'.strlen($answer).'"/>', $text); 323 } 324 $out .= $text; 325 } 326 break; 327 328 case LISTBOX_FILL : 329 { 330 $replacementList = array(); 331 332 foreach ($this->answerList as $answerKey => $answer) 333 { 334 //build inlinechoice list 335 336 $inlineChoiceList = ''; 337 338 //1-start interaction tag 339 340 $inlineChoiceList .= '<inlineChoiceInteraction responseIdentifier="fill_'.$answerKey.'" >'. "\n"; 341 342 //2- add wrong answer array 343 344 foreach ($this->wrongAnswerList as $choiceKey => $wrongAnswer) 345 { 346 $inlineChoiceList .= ' <inlineChoice identifier="choice_w_'.$answerKey.'_'.$choiceKey.'"><![CDATA['.$wrongAnswer.']]></inlineChoice>'. "\n"; 347 } 348 349 //3- add correct answers array 350 foreach ($this->answerList as $choiceKey => $correctAnswer) 351 { 352 $inlineChoiceList .= ' <inlineChoice identifier="choice_c_'.$answerKey.'_'.$choiceKey.'"><![CDATA['.$correctAnswer.']]></inlineChoice>'. "\n"; 353 } 354 355 //4- finish interaction tag 356 357 $inlineChoiceList .= '</inlineChoiceInteraction>'; 358 359 $replacementList['['.$answer.']'] = $inlineChoiceList; 360 } 361 362 $out .= strtr($this->answerText, $replacementList); 363 } 364 break; 365 } 366 367 return $out; 368 369 } 370 371 /** 372 * 373 */ 374 function qti2ExportResponsesDeclaration($questionIdent) 375 { 376 377 $out = ''; 378 379 foreach ($this->answerList as $answerKey=>$answer) 380 { 381 $out .= ' <responseDeclaration identifier="fill_' . $answerKey . '" cardinality="single" baseType="identifier">' . "\n"; 382 $out .= ' <correctResponse>'. "\n"; 383 384 if ($this->type == TEXTFIELD_FILL) 385 { 386 $out .= ' <value><![CDATA['.$answer.']]></value>'. "\n"; 387 } 388 else 389 { 390 //find correct answer key to apply in manifest and output it 391 392 foreach ($this->answerList as $choiceKey=>$correctAnswer) 393 { 394 if ($correctAnswer==$answer) 395 { 396 $out .= ' <value>choice_c_'.$answerKey.'_'.$choiceKey.'</value>'. "\n"; 397 } 398 } 399 } 400 401 $out .= ' </correctResponse>'. "\n"; 402 403 if (isset($this->gradeList[$answerKey])) 404 { 405 $out .= ' <mapping>'. "\n"; 406 $out .= ' <mapEntry mapKey="'.$answer.'" mappedValue="'.$this->gradeList[$answerKey].'"/>'. "\n"; 407 $out .= ' </mapping>'. "\n"; 408 } 409 410 $out .= ' </responseDeclaration>'. "\n"; 411 } 412 413 return $out; 414 } 415 416 /** 417 * allow to import the answers, feedbacks, and grades of a question 418 * 419 * @param questionArray is an array that must contain all the information needed to build the question 420 421 */ 422 423 function import($questionArray) 424 { 425 // $questionArray['answer'] should be empty for this question type 426 $this->answerText = $questionArray['response_text']; 427 428 if ($questionArray['subtype'] == "TEXTFIELD_FILL") 429 { 430 $this->type = TEXTFIELD_FILL; 431 } 432 if ($questionArray['subtype'] == "LISTBOX_FILL") 433 { 434 $this->wrongAnswerList = $questionArray['wrong_answers']; 435 $this->type = LISTBOX_FILL; 436 } 437 438 //build correct_answsers array 439 if( isset($questionArray['weighting']) && is_array($questionArray['weighting']) ) 440 { 441 $this->gradeList = array(); 442 foreach( $questionArray['weighting'] as $key => $value ) 443 { 444 $this->gradeList[$key] = castToFloat($value); 445 } 446 } 447 } 448 } 449 450 class Qti2AnswerMatching extends answerMatching 451 { 452 /** 453 * Export the question part as a matrix-choice, with only one possible answer per line. 454 */ 455 function qti2ExportResponses($questionIdent, $questionStatment) 456 { 457 $maxAssociation = max(count($this->leftList), count($this->rightList)); 458 459 $out = ""; 460 461 $out .= '<matchInteraction responseIdentifier="' . $questionIdent . '" maxAssociations="'. $maxAssociation .'">'. "\n"; 462 $out .= '<prompt><![CDATA[' . $questionStatment . ']]></prompt>'. "\n"; 463 464 //add left column 465 466 $out .= ' <simpleMatchSet>'. "\n"; 467 468 foreach ($this->leftList as $leftKey=>$leftElement) 469 { 470 $out .= ' <simpleAssociableChoice identifier="left_'.$leftKey.'" ><![CDATA['. $leftElement['answer'] .']]></simpleAssociableChoice>'. "\n"; 471 } 472 473 $out .= ' </simpleMatchSet>'. "\n"; 474 475 //add right column 476 477 $out .= ' <simpleMatchSet>'. "\n"; 478 479 $i = 0; 480 481 foreach($this->rightList as $rightKey=>$rightElement) 482 { 483 $out .= ' <simpleAssociableChoice identifier="right_'.$i.'" ><![CDATA['. $rightElement['answer'] .']]></simpleAssociableChoice>'. "\n"; 484 $i++; 485 } 486 487 $out .= ' </simpleMatchSet>'. "\n"; 488 489 $out .= '</matchInteraction>'. "\n"; 490 491 return $out; 492 } 493 494 /** 495 * 496 */ 497 function qti2ExportResponsesDeclaration($questionIdent) 498 { 499 $out = ' <responseDeclaration identifier="' . $questionIdent . '" cardinality="multiple" baseType="identifier">' . "\n"; 500 $out .= ' <correctResponse>' . "\n"; 501 502 $gradeArray = array(); 503 504 foreach ($this->leftList as $leftKey=>$leftElement) 505 { 506 $i=0; 507 foreach ($this->rightList as $rightKey=>$rightElement) 508 { 509 if( ($leftElement['match'] == $rightElement['code'])) 510 { 511 $out .= ' <value>left_' . $leftKey . ' right_'.$i.'</value>'. "\n"; 512 513 $gradeArray['left_' . $leftKey . ' right_'.$i] = $leftElement['grade']; 514 } 515 $i++; 516 } 517 } 518 $out .= ' </correctResponse>'. "\n"; 519 $out .= ' <mapping>' . "\n"; 520 foreach ($gradeArray as $gradeKey=>$grade) 521 { 522 $out .= ' <mapEntry mapKey="'.$gradeKey.'" mappedValue="'.$grade.'"/>' . "\n"; 523 } 524 $out .= ' </mapping>' . "\n"; 525 $out .= ' </responseDeclaration>'. "\n"; 526 527 return $out; 528 } 529 530 /** 531 * allow to import the answers, feedbacks, and grades of a question 532 * 533 * @param questionArray is an array that must contain all the information needed to build the question 534 535 */ 536 537 function import($questionArray) 538 { 539 $answerArray = $questionArray['answer']; 540 541 //This tick to remove examples in the answers!!!! 542 $this->leftList = array(); 543 $this->rightList = array(); 544 545 //find right and left column 546 $right_column = array_pop($answerArray); 547 $left_column = array_pop($answerArray); 548 549 //1- build answers 550 551 foreach ($right_column as $right_key => $right_element) 552 { 553 $code = $this->addRight($right_element); 554 555 foreach ($left_column as $left_key => $left_element) 556 { 557 $matched_pattern = $left_key." ".$right_key; 558 $matched_pattern_inverted = $right_key." ".$left_key; 559 560 if (in_array($matched_pattern, $questionArray['correct_answers']) || in_array($matched_pattern_inverted, $questionArray['correct_answers'])) 561 { 562 if (isset($questionArray['weighting'][$matched_pattern])) 563 { 564 $grade = castToFloat($questionArray['weighting'][$matched_pattern]); 565 } 566 else 567 { 568 $grade = 0; 569 } 570 $this->addLeft($left_element, $code, $grade); 571 } 572 } 573 } 574 575 $this->save(); 576 } 577 } 578 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 14:38:42 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |