ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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
32 public $maxchars;
33
45 public function __construct(
46 $title = "",
47 $comment = "",
48 $author = "",
49 $owner = -1,
50 $question = ""
51 ) {
52 parent::__construct($title, $comment, $author, $owner, $question);
53 $this->maxchars = 6;
54 }
55
61 public function isComplete()
62 {
63 if (
64 strlen($this->title)
65 && $this->author
66 && $this->question
67 && $this->getMaximumPoints() > 0
68 ) {
69 return true;
70 }
71 return false;
72 }
73
79 public function saveToDb($original_id = "")
80 {
84 parent::saveToDb($original_id);
85 }
86
92 public function loadFromDb($question_id)
93 {
95 global $DIC;
96 $ilDB = $DIC['ilDB'];
97
98 $result = $ilDB->queryF(
99 "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 $data = $ilDB->fetchAssoc($result);
105 $this->setId($question_id);
106 $this->setObjId($data["obj_fi"]);
107 $this->setTitle($data["title"]);
108 $this->setComment($data["description"]);
109 $this->setNrOfTries($data['nr_of_tries']);
110 $this->setOriginalId($data["original_id"]);
111 $this->setAuthor($data["author"]);
112 $this->setPoints($data["points"]);
113 $this->setOwner($data["owner"]);
114 require_once './Services/RTE/classes/class.ilRTE.php';
115 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
116 $this->setMaxChars($data["maxnumofchars"]);
117 $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
118
119 try {
120 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
121 } catch (ilTestQuestionPoolException $e) {
122 }
123 }
124
125 $result = $ilDB->queryF(
126 "SELECT * FROM qpl_num_range WHERE question_fi = %s ORDER BY aorder ASC",
127 array('integer'),
128 array($question_id)
129 );
130
131 require_once './Modules/TestQuestionPool/classes/class.assNumericRange.php';
132 if ($result->numRows() > 0) {
134 while ($data = $ilDB->fetchAssoc($result)) {
135 $this->setPoints($data['points']);
136 $this->setLowerLimit($data['lowerlimit']);
137 $this->setUpperLimit($data['upperlimit']);
138 }
139 }
140
141 parent::loadFromDb($question_id);
142 }
143
155 public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
156 {
157 if ($this->id <= 0) {
158 // The question has not been saved. It cannot be duplicated
159 return;
160 }
161 // duplicate the question in database
162 $this_id = $this->getId();
163 $thisObjId = $this->getObjId();
164
165 $clone = $this;
166 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
168 $clone->id = -1;
169
170 if ((int) $testObjId > 0) {
171 $clone->setObjId($testObjId);
172 }
173
174 if ($title) {
175 $clone->setTitle($title);
176 }
177
178 if ($author) {
179 $clone->setAuthor($author);
180 }
181 if ($owner) {
182 $clone->setOwner($owner);
183 }
184
185 if ($for_test) {
186 $clone->saveToDb($original_id);
187 } else {
188 $clone->saveToDb();
189 }
190
191 // copy question page content
192 $clone->copyPageOfQuestion($this_id);
193 // copy XHTML media objects
194 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
195
196 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
197
198 return $clone->id;
199 }
200
209 public function copyObject($target_questionpool_id, $title = "")
210 {
211 if ($this->id <= 0) {
212 // The question has not been saved. It cannot be duplicated
213 return;
214 }
215 // duplicate the question in database
216 $clone = $this;
217 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
219 $clone->id = -1;
220 $source_questionpool_id = $this->getObjId();
221 $clone->setObjId($target_questionpool_id);
222 if ($title) {
223 $clone->setTitle($title);
224 }
225 $clone->saveToDb();
226
227 // copy question page content
228 $clone->copyPageOfQuestion($original_id);
229 // copy XHTML media objects
230 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
231
232 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
233
234 return $clone->id;
235 }
236
237 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
238 {
239 if ($this->id <= 0) {
240 // The question has not been saved. It cannot be duplicated
241 return;
242 }
243
244 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
245
246 $sourceQuestionId = $this->id;
247 $sourceParentId = $this->getObjId();
248
249 // duplicate the question in database
250 $clone = $this;
251 $clone->id = -1;
252
253 $clone->setObjId($targetParentId);
254
255 if ($targetQuestionTitle) {
256 $clone->setTitle($targetQuestionTitle);
257 }
258
259 $clone->saveToDb();
260 // copy question page content
261 $clone->copyPageOfQuestion($sourceQuestionId);
262 // copy XHTML media objects
263 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
264
265 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
266
267 return $clone->id;
268 }
269
270 public function getLowerLimit()
271 {
272 return $this->lower_limit;
273 }
274
275 public function getUpperLimit()
276 {
277 return $this->upper_limit;
278 }
279
280 public function setLowerLimit($a_limit)
281 {
282 $a_limit = str_replace(',', '.', $a_limit);
283 $this->lower_limit = $a_limit;
284 }
285
286 public function setUpperLimit($a_limit)
287 {
288 $a_limit = str_replace(',', '.', $a_limit);
289 $this->upper_limit = $a_limit;
290 }
291
297 public function getMaximumPoints()
298 {
299 return $this->getPoints();
300 }
301
303 {
304 $points = 0;
305 if ($this->contains($previewSession->getParticipantsSolution())) {
306 $points = $this->getPoints();
307 }
308
309 $reachedPoints = $this->deductHintPointsFromReachedPoints($previewSession, $points);
310
311 return $this->ensureNonNegativePoints($reachedPoints);
312 }
313
326 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
327 {
328 if ($returndetails) {
329 throw new ilTestException('return details not implemented for ' . __METHOD__);
330 }
331
333 global $DIC;
334 $ilDB = $DIC['ilDB'];
335
336 $found_values = array();
337 if (is_null($pass)) {
338 $pass = $this->getSolutionMaxPass($active_id);
339 }
340 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
341 $data = $ilDB->fetchAssoc($result);
342
343 $enteredvalue = $data["value1"];
344
345 $points = 0;
346 if ($this->contains($enteredvalue)) {
347 $points = $this->getPoints();
348 }
349
350 return $points;
351 }
352
363 public function contains($value)
364 {
365 require_once './Services/Math/classes/class.EvalMath.php';
366 $eval = new EvalMath();
367 $eval->suppress_errors = true;
368 $result = $eval->e($value);
369 if (($result === false) || ($result === true)) {
370 return false;
371 }
372
373 if (($result >= $eval->e($this->getLowerLimit())) && ($result <= $eval->e($this->getUpperLimit()))) {
374 return true;
375 }
376 return false;
377 }
378
379 protected function isValidNumericSubmitValue($submittedValue)
380 {
381 if (is_numeric($submittedValue)) {
382 return true;
383 }
384
385 if (preg_match('/^[-+]{0,1}\d+\/\d+$/', $submittedValue)) {
386 return true;
387 }
388
389 return false;
390 }
391
392 public function validateSolutionSubmit()
393 {
394 if (strlen($this->getSolutionSubmit()) && !$this->isValidNumericSubmitValue($this->getSolutionSubmit())) {
395 ilUtil::sendFailure($this->lng->txt("err_no_numeric_value"), true);
396 return false;
397 }
398
399 return true;
400 }
401
402 public function getSolutionSubmit()
403 {
404 return trim(str_replace(",", ".", $_POST["numeric_result"]));
405 }
406
407 public function isValidSolutionSubmit($numeric_solution)
408 {
409 require_once './Services/Math/classes/class.EvalMath.php';
410 $math = new EvalMath();
411 $math->suppress_errors = true;
412 $result = $math->evaluate($numeric_solution);
413
414 return !(
415 ($result === false || $result === true) && strlen($numeric_solution) > 0
416 );
417 }
418
427 public function saveWorkingData($active_id, $pass = null, $authorized = true)
428 {
430 global $DIC;
431 $ilDB = $DIC['ilDB'];
432
433 if (is_null($pass)) {
434 require_once './Modules/Test/classes/class.ilObjTest.php';
435 $pass = ilObjTest::_getPass($active_id);
436 }
437
438 $entered_values = 0;
439
440 $returnvalue = true;
441
442 $numeric_result = $this->getSolutionSubmit();
443
444 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $numeric_result, $ilDB, $active_id, $pass, $authorized) {
445 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized);
446
447 $row = $ilDB->fetchAssoc($result);
448 $update = $row["solution_id"];
449 if ($update) {
450 if (strlen($numeric_result)) {
451 $this->updateCurrentSolution($update, trim($numeric_result), null, $authorized);
452 $entered_values++;
453 } else {
454 $this->removeSolutionRecordById($update);
455 }
456 } else {
457 if (strlen($numeric_result)) {
458 $this->saveCurrentSolution($active_id, $pass, trim($numeric_result), null, $authorized);
459 $entered_values++;
460 }
461 }
462 });
463
464 if ($entered_values) {
465 require_once './Modules/Test/classes/class.ilObjAssessmentFolder.php';
468 $this->lng->txtlng(
469 "assessment",
470 "log_user_entered_values",
472 ),
473 $active_id,
474 $this->getId()
475 );
476 }
477 } else {
478 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
481 $this->lng->txtlng(
482 "assessment",
483 "log_user_not_entered_values",
485 ),
486 $active_id,
487 $this->getId()
488 );
489 }
490 }
491
492 return $returnvalue;
493 }
494
495 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
496 {
497 $numericSolution = $this->getSolutionSubmit();
498 $previewSession->setParticipantsSolution($numericSolution);
499 }
500
501 public function saveAdditionalQuestionDataToDb()
502 {
504 global $DIC;
505 $ilDB = $DIC['ilDB'];
506
507 // save additional data
508 $ilDB->manipulateF(
509 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
510 array( "integer" ),
511 array( $this->getId() )
512 );
513
514 $ilDB->manipulateF(
515 "INSERT INTO " . $this->getAdditionalTableName(
516 ) . " (question_fi, maxnumofchars) VALUES (%s, %s)",
517 array( "integer", "integer" ),
518 array(
519 $this->getId(),
520 ($this->getMaxChars()) ? $this->getMaxChars() : 0
521 )
522 );
523 }
524
525 public function saveAnswerSpecificDataToDb()
526 {
528 global $DIC;
529 $ilDB = $DIC['ilDB'];
530
531 // Write range to the database
532 $ilDB->manipulateF(
533 "DELETE FROM qpl_num_range WHERE question_fi = %s",
534 array( 'integer' ),
535 array( $this->getId() )
536 );
537
538 $next_id = $ilDB->nextId('qpl_num_range');
539 $ilDB->manipulateF(
540 "INSERT INTO qpl_num_range (range_id, question_fi, lowerlimit, upperlimit, points, aorder, tstamp)
541 VALUES (%s, %s, %s, %s, %s, %s, %s)",
542 array( 'integer', 'integer', 'text', 'text', 'float', 'integer', 'integer' ),
543 array( $next_id, $this->id, $this->getLowerLimit(), $this->getUpperLimit(
544 ), $this->getPoints(), 0, time() )
545 );
546 }
547
553 public function getQuestionType()
554 {
555 return "assNumeric";
556 }
557
563 public function getMaxChars()
564 {
565 return $this->maxchars;
566 }
567
573 public function setMaxChars($maxchars)
574 {
575 $this->maxchars = $maxchars;
576 }
577
583 public function getAdditionalTableName()
584 {
585 return "qpl_qst_numeric";
586 }
587
593 {
594 return parent::getRTETextWithMediaObjects();
595 }
596
600 public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
601 {
602 parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
603
604 $solutions = $this->getSolutionValues($active_id, $pass);
605
606 $i = 1;
607 $worksheet->setCell($startrow + $i, 0, $this->lng->txt("result"));
608 $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
609
610 $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
611 if (strlen($solutions[0]["value1"])) {
612 $worksheet->setCell($startrow + $i, 1, $solutions[0]["value1"]);
613 }
614 $i++;
615
616 return $startrow + $i + 1;
617 }
618
627 public function getOperators($expression)
628 {
629 require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
631 }
632
637 public function getExpressionTypes()
638 {
639 return array(
643 );
644 }
645
654 public function getUserQuestionResult($active_id, $pass)
655 {
657 global $DIC;
658 $ilDB = $DIC['ilDB'];
659 $result = new ilUserQuestionResult($this, $active_id, $pass);
660
661 $maxStep = $this->lookupMaxStep($active_id, $pass);
662
663 if ($maxStep !== null) {
664 $data = $ilDB->queryF(
665 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
666 array("integer", "integer", "integer","integer"),
667 array($active_id, $pass, $this->getId(), $maxStep)
668 );
669 } else {
670 $data = $ilDB->queryF(
671 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
672 array("integer", "integer", "integer"),
673 array($active_id, $pass, $this->getId())
674 );
675 }
676
677 while ($row = $ilDB->fetchAssoc($data)) {
678 $result->addKeyValue(1, $row["value1"]);
679 }
680
681 $points = $this->calculateReachedPoints($active_id, $pass);
682 $max_points = $this->getMaximumPoints();
683
684 $result->setReachedPercentage(($points / $max_points) * 100);
685
686 return $result;
687 }
688
697 public function getAvailableAnswerOptions($index = null)
698 {
699 return array(
700 "lower" => $this->getLowerLimit(),
701 "upper" => $this->getUpperLimit()
702 );
703 }
704}
$result
$_POST["username"]
An exception for terminatinating execution or to throw for unit testing.
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)
{Creates an Excel worksheet for the detailed cumulated results of this question.object}
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
savePreviewData(ilAssQuestionPreviewSession $previewSession)
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.
getSolutionValues($active_id, $pass=null, $authorized=true)
Loads solutions of a given user from the database an returns it.
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.
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true, $tstamp=null)
getObjId()
Get the object id of the container object.
setTitle($title="")
Sets the title string of the assQuestion object.
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.
deductHintPointsFromReachedPoints(ilAssQuestionPreviewSession $previewSession, $reachedPoints)
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
static logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
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.
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
setQuestion($question="")
Sets the question string of the question object.
loadFromDb($question_id)
Loads the question from the database.
ensureNonNegativePoints($points)
static _getLogLanguage()
retrieve the log language for assessment logging
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
static _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.
$i
Definition: disco.tpl.php:19
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.
$index
Definition: metadata.php:60
$row
global $DIC
Definition: saml.php:7
global $ilDB
$data
Definition: bench.php:6