ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.assNumeric.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
8require_once './Modules/TestQuestionPool/interfaces/interface.iQuestionCondition.php';
9require_once './Modules/TestQuestionPool/classes/class.ilUserQuestionResult.php';
10
27{
28 protected $lower_limit;
29 protected $upper_limit;
30
33
45 function __construct(
46 $title = "",
47 $comment = "",
48 $author = "",
49 $owner = -1,
50 $question = ""
51 )
52 {
53 parent::__construct($title, $comment, $author, $owner, $question);
54 $this->maxchars = 6;
55 }
56
62 public function isComplete()
63 {
64 if (
65 strlen($this->title)
66 && $this->author
67 && $this->question
68 && $this->getMaximumPoints() > 0
69 )
70 {
71 return true;
72 }
73 return false;
74 }
75
81 public function saveToDb($original_id = "")
82 {
86 parent::saveToDb($original_id);
87 }
88
94 public function loadFromDb($question_id)
95 {
97 global $ilDB;
98
99 $result = $ilDB->queryF("SELECT qpl_questions.*, " . $this->getAdditionalTableName() . ".* FROM qpl_questions LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s",
100 array("integer"),
101 array($question_id)
102 );
103 if ($result->numRows() == 1)
104 {
105 $data = $ilDB->fetchAssoc($result);
106 $this->setId($question_id);
107 $this->setObjId($data["obj_fi"]);
108 $this->setTitle($data["title"]);
109 $this->setComment($data["description"]);
110 $this->setNrOfTries($data['nr_of_tries']);
111 $this->setOriginalId($data["original_id"]);
112 $this->setAuthor($data["author"]);
113 $this->setPoints($data["points"]);
114 $this->setOwner($data["owner"]);
115 require_once './Services/RTE/classes/class.ilRTE.php';
116 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
117 $this->setMaxChars($data["maxnumofchars"]);
118 $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
119
120 try
121 {
122 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
123 }
125 {
126 }
127 }
128
129 $result = $ilDB->queryF("SELECT * FROM qpl_num_range WHERE question_fi = %s ORDER BY aorder ASC",
130 array('integer'),
131 array($question_id)
132 );
133
134 require_once './Modules/TestQuestionPool/classes/class.assNumericRange.php';
135 if ($result->numRows() > 0)
136 {
138 while ($data = $ilDB->fetchAssoc($result))
139 {
140 $this->setPoints($data['points']);
141 $this->setLowerLimit($data['lowerlimit']);
142 $this->setUpperLimit($data['upperlimit']);
143 }
144 }
145
146 parent::loadFromDb($question_id);
147 }
148
160 public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
161 {
162 if ($this->id <= 0)
163 {
164 // The question has not been saved. It cannot be duplicated
165 return;
166 }
167 // duplicate the question in database
168 $this_id = $this->getId();
169 $thisObjId = $this->getObjId();
170
171 $clone = $this;
172 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
174 $clone->id = -1;
175
176 if( (int)$testObjId > 0 )
177 {
178 $clone->setObjId($testObjId);
179 }
180
181 if ($title)
182 {
183 $clone->setTitle($title);
184 }
185
186 if ($author)
187 {
188 $clone->setAuthor($author);
189 }
190 if ($owner)
191 {
192 $clone->setOwner($owner);
193 }
194
195 if ($for_test)
196 {
197 $clone->saveToDb($original_id);
198 }
199 else
200 {
201 $clone->saveToDb();
202 }
203
204 // copy question page content
205 $clone->copyPageOfQuestion($this_id);
206 // copy XHTML media objects
207 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
208
209 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
210
211 return $clone->id;
212 }
213
222 public function copyObject($target_questionpool_id, $title = "")
223 {
224 if ($this->id <= 0)
225 {
226 // The question has not been saved. It cannot be duplicated
227 return;
228 }
229 // duplicate the question in database
230 $clone = $this;
231 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
233 $clone->id = -1;
234 $source_questionpool_id = $this->getObjId();
235 $clone->setObjId($target_questionpool_id);
236 if ($title)
237 {
238 $clone->setTitle($title);
239 }
240 $clone->saveToDb();
241
242 // copy question page content
243 $clone->copyPageOfQuestion($original_id);
244 // copy XHTML media objects
245 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
246
247 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
248
249 return $clone->id;
250 }
251
252 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
253 {
254 if ($this->id <= 0)
255 {
256 // The question has not been saved. It cannot be duplicated
257 return;
258 }
259
260 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
261
262 $sourceQuestionId = $this->id;
263 $sourceParentId = $this->getObjId();
264
265 // duplicate the question in database
266 $clone = $this;
267 $clone->id = -1;
268
269 $clone->setObjId($targetParentId);
270
271 if ($targetQuestionTitle)
272 {
273 $clone->setTitle($targetQuestionTitle);
274 }
275
276 $clone->saveToDb();
277 // copy question page content
278 $clone->copyPageOfQuestion($sourceQuestionId);
279 // copy XHTML media objects
280 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
281
282 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
283
284 return $clone->id;
285 }
286
287 public function getLowerLimit()
288 {
289 return $this->lower_limit;
290 }
291
292 public function getUpperLimit()
293 {
294 return $this->upper_limit;
295 }
296
297 public function setLowerLimit($a_limit)
298 {
299 $a_limit = str_replace(',', '.', $a_limit);
300 $this->lower_limit = $a_limit;
301 }
302
303 public function setUpperLimit($a_limit)
304 {
305 $a_limit = str_replace(',', '.', $a_limit);
306 $this->upper_limit = $a_limit;
307 }
308
314 public function getMaximumPoints()
315 {
316 return $this->getPoints();
317 }
318
320 {
321 $points = 0;
322 if ($this->contains($previewSession->getParticipantsSolution()))
323 {
324 $points = $this->getPoints();
325 }
326
327 return $points;
328 }
329
342 public function calculateReachedPoints($active_id, $pass = NULL, $authorizedSolution = true, $returndetails = FALSE)
343 {
344 if( $returndetails )
345 {
346 throw new ilTestException('return details not implemented for '.__METHOD__);
347 }
348
350 global $ilDB;
351
352 $found_values = array();
353 if (is_null($pass))
354 {
355 $pass = $this->getSolutionMaxPass($active_id);
356 }
357 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
358 $data = $ilDB->fetchAssoc($result);
359
360 $enteredvalue = $data["value1"];
361
362 $points = 0;
363 if ($this->contains($enteredvalue))
364 {
365 $points = $this->getPoints();
366 }
367
368 return $points;
369 }
370
381 public function contains($value)
382 {
383 require_once './Services/Math/classes/class.EvalMath.php';
384 $eval = new EvalMath();
385 $eval->suppress_errors = TRUE;
386 $result = $eval->e($value);
387 if (($result === FALSE) || ($result === TRUE))
388 {
389 return FALSE;
390 }
391
392 if (($result >= $eval->e($this->getLowerLimit())) && ($result <= $eval->e($this->getUpperLimit())))
393 {
394 return TRUE;
395 }
396 return FALSE;
397 }
398
399 protected function isValidNumericSubmitValue($submittedValue)
400 {
401 if( is_numeric($submittedValue) )
402 {
403 return true;
404 }
405
406 if( preg_match('/^[-+]{0,1}\d+\/\d+$/', $submittedValue) )
407 {
408 return true;
409 }
410
411 return false;
412 }
413
414 public function validateSolutionSubmit()
415 {
416 if( !$this->isValidNumericSubmitValue($this->getSolutionSubmit()) )
417 {
418 ilUtil::sendFailure($this->lng->txt("err_no_numeric_value"), true);
419 return false;
420 }
421
422 return true;
423 }
424
425 public function getSolutionSubmit()
426 {
427 return trim(str_replace(",",".",$_POST["numeric_result"]));
428 }
429
430 public function isValidSolutionSubmit($numeric_solution)
431 {
432 require_once './Services/Math/classes/class.EvalMath.php';
433 $math = new EvalMath();
434 $math->suppress_errors = TRUE;
435 $result = $math->evaluate($numeric_solution);
436
437 return !(
438 ($result === FALSE || $result === TRUE) && strlen($numeric_solution) > 0
439 );
440 }
441
450 public function saveWorkingData($active_id, $pass = NULL, $authorized = true)
451 {
453 global $ilDB;
454
455 if (is_null($pass))
456 {
457 require_once './Modules/Test/classes/class.ilObjTest.php';
458 $pass = ilObjTest::_getPass($active_id);
459 }
460
461 $entered_values = 0;
462
463 $returnvalue = true;
464
465 $numeric_result = $this->getSolutionSubmit();
466
467 $this->getProcessLocker()->requestUserSolutionUpdateLock();
468
469 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized);
470
471 $row = $ilDB->fetchAssoc($result);
472 $update = $row["solution_id"];
473 if ($update)
474 {
475 if (strlen($numeric_result))
476 {
477 $this->updateCurrentSolution($update, trim($numeric_result), null, $authorized);
478 $entered_values++;
479 }
480 else
481 {
482 $this->removeSolutionRecordById($update);
483 }
484 }
485 else
486 {
487 if (strlen($numeric_result))
488 {
489 $this->saveCurrentSolution($active_id, $pass, trim($numeric_result), null, $authorized);
490 $entered_values++;
491 }
492 }
493
494 $this->getProcessLocker()->releaseUserSolutionUpdateLock();
495
496 if ($entered_values)
497 {
498 require_once './Modules/Test/classes/class.ilObjAssessmentFolder.php';
500 {
501 $this->logAction($this->lng->txtlng(
502 "assessment",
503 "log_user_entered_values",
505 ),
506 $active_id,
507 $this->getId()
508 );
509 }
510 }
511 else
512 {
513 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
515 {
516 $this->logAction($this->lng->txtlng(
517 "assessment",
518 "log_user_not_entered_values",
520 ),
521 $active_id,
522 $this->getId()
523 );
524 }
525 }
526
527 return $returnvalue;
528 }
529
530 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
531 {
532 $numericSolution = $this->getSolutionSubmit();
533 $previewSession->setParticipantsSolution($numericSolution);
534 }
535
536 public function saveAdditionalQuestionDataToDb()
537 {
539 global $ilDB;
540
541 // save additional data
542 $ilDB->manipulateF( "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
543 array( "integer" ),
544 array( $this->getId() )
545 );
546
547 $ilDB->manipulateF( "INSERT INTO " . $this->getAdditionalTableName(
548 ) . " (question_fi, maxnumofchars) VALUES (%s, %s)",
549 array( "integer", "integer" ),
550 array(
551 $this->getId(),
552 ($this->getMaxChars()) ? $this->getMaxChars() : 0
553 )
554 );
555 }
556
557 public function saveAnswerSpecificDataToDb()
558 {
560 global $ilDB;
561
562 // Write range to the database
563 $ilDB->manipulateF( "DELETE FROM qpl_num_range WHERE question_fi = %s",
564 array( 'integer' ),
565 array( $this->getId() )
566 );
567
568 $next_id = $ilDB->nextId( 'qpl_num_range' );
569 $ilDB->manipulateF( "INSERT INTO qpl_num_range (range_id, question_fi, lowerlimit, upperlimit, points, aorder, tstamp)
570 VALUES (%s, %s, %s, %s, %s, %s, %s)",
571 array( 'integer', 'integer', 'text', 'text', 'float', 'integer', 'integer' ),
572 array( $next_id, $this->id, $this->getLowerLimit(), $this->getUpperLimit(
573 ), $this->getPoints(), 0, time() )
574 );
575 }
576
584 protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
585 {
586 // nothing to rework!
587 }
588
594 public function getQuestionType()
595 {
596 return "assNumeric";
597 }
598
604 public function getMaxChars()
605 {
606 return $this->maxchars;
607 }
608
614 public function setMaxChars($maxchars)
615 {
616 $this->maxchars = $maxchars;
617 }
618
625 {
626 return "qpl_qst_numeric";
627 }
628
634 {
635 return parent::getRTETextWithMediaObjects();
636 }
637
650 public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
651 {
652 include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
653 $solutions = $this->getSolutionValues($active_id, $pass);
654 $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
655 $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
656 $i = 1;
657 $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($this->lng->txt("result")), $format_bold);
658 if (strlen($solutions[0]["value1"]))
659 {
660 $worksheet->write($startrow + $i, 1, ilExcelUtils::_convert_text($solutions[0]["value1"]));
661 }
662 $i++;
663 return $startrow + $i + 1;
664 }
665
674 public function getOperators($expression)
675 {
676 require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
678 }
679
684 public function getExpressionTypes()
685 {
686 return array(
690 );
691 }
692
701 public function getUserQuestionResult($active_id, $pass)
702 {
704 global $ilDB;
705 $result = new ilUserQuestionResult($this, $active_id, $pass);
706
707 $maxStep = $this->lookupMaxStep($active_id, $pass);
708
709 if( $maxStep !== null )
710 {
711 $data = $ilDB->queryF(
712 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
713 array("integer", "integer", "integer","integer"),
714 array($active_id, $pass, $this->getId(), $maxStep)
715 );
716 }
717 else
718 {
719 $data = $ilDB->queryF(
720 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
721 array("integer", "integer", "integer"),
722 array($active_id, $pass, $this->getId())
723 );
724 }
725
726 while($row = $ilDB->fetchAssoc($data))
727 {
728 $result->addKeyValue(1, $row["value1"]);
729 }
730
731 $points = $this->calculateReachedPoints($active_id, $pass);
732 $max_points = $this->getMaximumPoints();
733
734 $result->setReachedPercentage(($points/$max_points) * 100);
735
736 return $result;
737 }
738
747 public function getAvailableAnswerOptions($index = null)
748 {
749 return array(
750 "lower" => $this->getLowerLimit(),
751 "upper" => $this->getUpperLimit()
752 );
753 }
754}
$result
Class for numeric questions.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assNumericQuestion.
getExpressionTypes()
Get all available expression types for a specific question.
copyObject($target_questionpool_id, $title="")
Copies an assNumeric object.
contains($value)
Checks for a given value within the range.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
setMaxChars($maxchars)
Sets the maximum number of characters for the numeric input field.
setLowerLimit($a_limit)
isValidNumericSubmitValue($submittedValue)
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
Creates an Excel worksheet for the detailed cumulated results of this question.
saveToDb($original_id="")
Saves a assNumeric object to a database.
setUpperLimit($a_limit)
getQuestionType()
Returns the question type of the question.
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assNumeric constructor
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
Reworks the allready saved working data if neccessary.
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
getMaxChars()
Returns the maximum number of characters for the numeric input field.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
getOperators($expression)
Get all available operations for a specific question.
isValidSolutionSubmit($numeric_solution)
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
isComplete()
Returns true, if a numeric question is complete for use.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
Abstract basic class which is to be extended by the concrete assessment question type classes.
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass.
static _getOriginalId($question_id)
Returns the original id of a question.
setId($id=-1)
Sets the id of the assQuestion object.
setOriginalId($original_id)
setObjId($obj_id=0)
Set the object id of the container object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
saveQuestionDataToDb($original_id="")
getId()
Gets the id of the assQuestion object.
getObjId()
Get the object id of the container object.
setTitle($title="")
Sets the title string of the assQuestion object.
calculateReachedPoints($active_id, $pass=NULL, $authorizedSolution=true, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second.
updateCurrentSolution($solutionId, $value1, $value2, $authorized=true)
removeSolutionRecordById($solutionId)
setAuthor($author="")
Sets the authors name of the assQuestion object.
getPoints()
Returns the maximum available points for the question.
saveWorkingData($active_id, $pass=NULL, $authorized=true)
Saves the learners input of the question to the database.
getSolutionValues($active_id, $pass=NULL, $authorized=true)
Loads solutions of a given user from the database an returns it.
logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getTitle()
Gets the title string of the assQuestion object.
setPoints($a_points)
Sets the maximum available points for the question.
setComment($comment="")
Sets the comment string of the assQuestion object.
setNrOfTries($a_nr_of_tries)
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true)
setQuestion($question="")
Sets the question string of the question object.
loadFromDb($question_id)
Loads the question from the database.
_convert_text($a_text, $a_target="has been removed")
_getLogLanguage()
retrieve the log language for assessment logging
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
_getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
Base Exception for all Exceptions relating to Modules/Test.
Class ilUserQuestionResult.
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
$_POST['username']
Definition: cron.php:12
$data
Class iQuestionCondition.
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
Interface ilObjAnswerScoringAdjustable.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
Interface ilObjQuestionScoringAdjustable.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
global $ilDB