ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
All Data Structures Namespaces Files Functions Variables Modules Pages
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 
4 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
8 require_once './Modules/TestQuestionPool/interfaces/interface.iQuestionCondition.php';
9 require_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  ) {
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 {
123  }
124 
125  try {
126  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
127  } catch (ilTestQuestionPoolException $e) {
128  }
129  }
130 
131  $result = $ilDB->queryF(
132  "SELECT * FROM qpl_num_range WHERE question_fi = %s ORDER BY aorder ASC",
133  array('integer'),
134  array($question_id)
135  );
136 
137  require_once './Modules/TestQuestionPool/classes/class.assNumericRange.php';
138  if ($result->numRows() > 0) {
140  while ($data = $ilDB->fetchAssoc($result)) {
141  $this->setPoints($data['points']);
142  $this->setLowerLimit($data['lowerlimit']);
143  $this->setUpperLimit($data['upperlimit']);
144  }
145  }
146 
147  parent::loadFromDb($question_id);
148  }
149 
161  public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
162  {
163  if ($this->id <= 0) {
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  $clone->setObjId($testObjId);
178  }
179 
180  if ($title) {
181  $clone->setTitle($title);
182  }
183 
184  if ($author) {
185  $clone->setAuthor($author);
186  }
187  if ($owner) {
188  $clone->setOwner($owner);
189  }
190 
191  if ($for_test) {
192  $clone->saveToDb($original_id);
193  } else {
194  $clone->saveToDb();
195  }
196 
197  // copy question page content
198  $clone->copyPageOfQuestion($this_id);
199  // copy XHTML media objects
200  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
201 
202  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
203 
204  return $clone->id;
205  }
206 
215  public function copyObject($target_questionpool_id, $title = "")
216  {
217  if ($this->id <= 0) {
218  // The question has not been saved. It cannot be duplicated
219  return;
220  }
221  // duplicate the question in database
222  $clone = $this;
223  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
225  $clone->id = -1;
226  $source_questionpool_id = $this->getObjId();
227  $clone->setObjId($target_questionpool_id);
228  if ($title) {
229  $clone->setTitle($title);
230  }
231  $clone->saveToDb();
232 
233  // copy question page content
234  $clone->copyPageOfQuestion($original_id);
235  // copy XHTML media objects
236  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
237 
238  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
239 
240  return $clone->id;
241  }
242 
243  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
244  {
245  if ($this->id <= 0) {
246  // The question has not been saved. It cannot be duplicated
247  return;
248  }
249 
250  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
251 
252  $sourceQuestionId = $this->id;
253  $sourceParentId = $this->getObjId();
254 
255  // duplicate the question in database
256  $clone = $this;
257  $clone->id = -1;
258 
259  $clone->setObjId($targetParentId);
260 
261  if ($targetQuestionTitle) {
262  $clone->setTitle($targetQuestionTitle);
263  }
264 
265  $clone->saveToDb();
266  // copy question page content
267  $clone->copyPageOfQuestion($sourceQuestionId);
268  // copy XHTML media objects
269  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
270 
271  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
272 
273  return $clone->id;
274  }
275 
276  public function getLowerLimit()
277  {
278  return $this->lower_limit;
279  }
280 
281  public function getUpperLimit()
282  {
283  return $this->upper_limit;
284  }
285 
286  public function setLowerLimit($a_limit)
287  {
288  $a_limit = str_replace(',', '.', $a_limit);
289  $this->lower_limit = $a_limit;
290  }
291 
292  public function setUpperLimit($a_limit)
293  {
294  $a_limit = str_replace(',', '.', $a_limit);
295  $this->upper_limit = $a_limit;
296  }
297 
303  public function getMaximumPoints()
304  {
305  return $this->getPoints();
306  }
307 
309  {
310  $points = 0;
311  if ($this->contains($previewSession->getParticipantsSolution())) {
312  $points = $this->getPoints();
313  }
314 
315  $reachedPoints = $this->deductHintPointsFromReachedPoints($previewSession, $points);
316 
317  return $this->ensureNonNegativePoints($reachedPoints);
318  }
319 
332  public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
333  {
334  if ($returndetails) {
335  throw new ilTestException('return details not implemented for ' . __METHOD__);
336  }
337 
339  global $DIC;
340  $ilDB = $DIC['ilDB'];
341 
342  $found_values = array();
343  if (is_null($pass)) {
344  $pass = $this->getSolutionMaxPass($active_id);
345  }
346  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
347  $data = $ilDB->fetchAssoc($result);
348 
349  $enteredvalue = $data["value1"];
350 
351  $points = 0;
352  if ($this->contains($enteredvalue)) {
353  $points = $this->getPoints();
354  }
355 
356  return $points;
357  }
358 
369  public function contains($value)
370  {
371  require_once './Services/Math/classes/class.EvalMath.php';
372  $eval = new EvalMath();
373  $eval->suppress_errors = true;
374  $result = $eval->e($value);
375  if (($result === false) || ($result === true)) {
376  return false;
377  }
378 
379  if (($result >= $eval->e($this->getLowerLimit())) && ($result <= $eval->e($this->getUpperLimit()))) {
380  return true;
381  }
382  return false;
383  }
384 
385  protected function isValidNumericSubmitValue($submittedValue)
386  {
387  if (is_numeric($submittedValue)) {
388  return true;
389  }
390 
391  if (preg_match('/^[-+]{0,1}\d+\/\d+$/', $submittedValue)) {
392  return true;
393  }
394 
395  return false;
396  }
397 
398  public function validateSolutionSubmit()
399  {
400  if (strlen($this->getSolutionSubmit()) && !$this->isValidNumericSubmitValue($this->getSolutionSubmit())) {
401  ilUtil::sendFailure($this->lng->txt("err_no_numeric_value"), true);
402  return false;
403  }
404 
405  return true;
406  }
407 
408  public function getSolutionSubmit()
409  {
410  return trim(str_replace(",", ".", $_POST["numeric_result"]));
411  }
412 
413  public function isValidSolutionSubmit($numeric_solution)
414  {
415  require_once './Services/Math/classes/class.EvalMath.php';
416  $math = new EvalMath();
417  $math->suppress_errors = true;
418  $result = $math->evaluate($numeric_solution);
419 
420  return !(
421  ($result === false || $result === true) && strlen($numeric_solution) > 0
422  );
423  }
424 
433  public function saveWorkingData($active_id, $pass = null, $authorized = true)
434  {
436  global $DIC;
437  $ilDB = $DIC['ilDB'];
438 
439  if (is_null($pass)) {
440  require_once './Modules/Test/classes/class.ilObjTest.php';
441  $pass = ilObjTest::_getPass($active_id);
442  }
443 
444  $entered_values = 0;
445 
446  $returnvalue = true;
447 
448  $numeric_result = $this->getSolutionSubmit();
449 
450  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $numeric_result, $ilDB, $active_id, $pass, $authorized) {
451  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized);
452 
453  $row = $ilDB->fetchAssoc($result);
454  $update = $row["solution_id"];
455  if ($update) {
456  if (strlen($numeric_result)) {
457  $this->updateCurrentSolution($update, trim($numeric_result), null, $authorized);
458  $entered_values++;
459  } else {
460  $this->removeSolutionRecordById($update);
461  }
462  } else {
463  if (strlen($numeric_result)) {
464  $this->saveCurrentSolution($active_id, $pass, trim($numeric_result), null, $authorized);
465  $entered_values++;
466  }
467  }
468  });
469 
470  if ($entered_values) {
471  require_once './Modules/Test/classes/class.ilObjAssessmentFolder.php';
474  $this->lng->txtlng(
475  "assessment",
476  "log_user_entered_values",
478  ),
479  $active_id,
480  $this->getId()
481  );
482  }
483  } else {
484  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
487  $this->lng->txtlng(
488  "assessment",
489  "log_user_not_entered_values",
491  ),
492  $active_id,
493  $this->getId()
494  );
495  }
496  }
497 
498  return $returnvalue;
499  }
500 
501  protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
502  {
503  $numericSolution = $this->getSolutionSubmit();
504  $previewSession->setParticipantsSolution($numericSolution);
505  }
506 
507  public function saveAdditionalQuestionDataToDb()
508  {
510  global $DIC;
511  $ilDB = $DIC['ilDB'];
512 
513  // save additional data
514  $ilDB->manipulateF(
515  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
516  array( "integer" ),
517  array( $this->getId() )
518  );
519 
520  $ilDB->manipulateF(
521  "INSERT INTO " . $this->getAdditionalTableName(
522  ) . " (question_fi, maxnumofchars) VALUES (%s, %s)",
523  array( "integer", "integer" ),
524  array(
525  $this->getId(),
526  ($this->getMaxChars()) ? $this->getMaxChars() : 0
527  )
528  );
529  }
530 
531  public function saveAnswerSpecificDataToDb()
532  {
534  global $DIC;
535  $ilDB = $DIC['ilDB'];
536 
537  // Write range to the database
538  $ilDB->manipulateF(
539  "DELETE FROM qpl_num_range WHERE question_fi = %s",
540  array( 'integer' ),
541  array( $this->getId() )
542  );
543 
544  $next_id = $ilDB->nextId('qpl_num_range');
545  $ilDB->manipulateF(
546  "INSERT INTO qpl_num_range (range_id, question_fi, lowerlimit, upperlimit, points, aorder, tstamp)
547  VALUES (%s, %s, %s, %s, %s, %s, %s)",
548  array( 'integer', 'integer', 'text', 'text', 'float', 'integer', 'integer' ),
549  array( $next_id, $this->id, $this->getLowerLimit(), $this->getUpperLimit(
550  ), $this->getPoints(), 0, time() )
551  );
552  }
553 
559  public function getQuestionType()
560  {
561  return "assNumeric";
562  }
563 
569  public function getMaxChars()
570  {
571  return $this->maxchars;
572  }
573 
579  public function setMaxChars($maxchars)
580  {
581  $this->maxchars = $maxchars;
582  }
583 
589  public function getAdditionalTableName()
590  {
591  return "qpl_qst_numeric";
592  }
593 
598  public function getRTETextWithMediaObjects()
599  {
600  return parent::getRTETextWithMediaObjects();
601  }
602 
606  public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
607  {
608  parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
609 
610  $solutions = $this->getSolutionValues($active_id, $pass);
611 
612  $i = 1;
613  $worksheet->setCell($startrow + $i, 0, $this->lng->txt("result"));
614  $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
615 
616  $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
617  if (strlen($solutions[0]["value1"])) {
618  $worksheet->setCell($startrow + $i, 1, $solutions[0]["value1"]);
619  }
620  $i++;
621 
622  return $startrow + $i + 1;
623  }
624 
633  public function getOperators($expression)
634  {
635  require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
637  }
638 
643  public function getExpressionTypes()
644  {
645  return array(
649  );
650  }
651 
660  public function getUserQuestionResult($active_id, $pass)
661  {
663  global $DIC;
664  $ilDB = $DIC['ilDB'];
665  $result = new ilUserQuestionResult($this, $active_id, $pass);
666 
667  $maxStep = $this->lookupMaxStep($active_id, $pass);
668 
669  if ($maxStep !== null) {
670  $data = $ilDB->queryF(
671  "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
672  array("integer", "integer", "integer","integer"),
673  array($active_id, $pass, $this->getId(), $maxStep)
674  );
675  } else {
676  $data = $ilDB->queryF(
677  "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
678  array("integer", "integer", "integer"),
679  array($active_id, $pass, $this->getId())
680  );
681  }
682 
683  while ($row = $ilDB->fetchAssoc($data)) {
684  $result->addKeyValue(1, $row["value1"]);
685  }
686 
687  $points = $this->calculateReachedPoints($active_id, $pass);
688  $max_points = $this->getMaximumPoints();
689 
690  $result->setReachedPercentage(($points / $max_points) * 100);
691 
692  return $result;
693  }
694 
703  public function getAvailableAnswerOptions($index = null)
704  {
705  return array(
706  "lower" => $this->getLowerLimit(),
707  "upper" => $this->getUpperLimit()
708  );
709  }
710 }
static logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
getId()
Gets the id of the assQuestion object.
static _getOriginalId($question_id)
Returns the original id of a question.
Class iQuestionCondition.
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assNumeric constructor
$data
Definition: storeScorm.php:23
getExpressionTypes()
Get all available expression types for a specific question.
$result
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
getPoints()
Returns the maximum available points for the question.
getMaxChars()
Returns the maximum number of characters for the numeric input field.
setLowerLimit($a_limit)
Abstract basic class which is to be extended by the concrete assessment question type classes...
ensureNonNegativePoints($points)
getSolutionValues($active_id, $pass=null, $authorized=true)
Loads solutions of a given user from the database an returns it.
setId($id=-1)
Sets the id of the assQuestion object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second. ...
setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
{}
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
setNrOfTries($a_nr_of_tries)
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
getQuestionType()
Returns the question type of the question.
loadFromDb($question_id)
Loads the question from the database.
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...
getObjId()
Get the object id of the container object.
isValidNumericSubmitValue($submittedValue)
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
Base Exception for all Exceptions relating to Modules/Test.
$index
Definition: metadata.php:128
setMaxChars($maxchars)
Sets the maximum number of characters for the numeric input field.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
removeSolutionRecordById($solutionId)
static _getLogLanguage()
retrieve the log language for assessment logging
setAuthor($author="")
Sets the authors name of the assQuestion object.
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
Class ilUserQuestionResult.
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true, $tstamp=null)
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
Interface ilObjAnswerScoringAdjustable.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assNumericQuestion.
saveToDb($original_id="")
Saves a assNumeric object to a database.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
getOperators($expression)
Get all available operations for a specific question.
updateCurrentSolution($solutionId, $value1, $value2, $authorized=true)
setUpperLimit($a_limit)
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
deductHintPointsFromReachedPoints(ilAssQuestionPreviewSession $previewSession, $reachedPoints)
copyObject($target_questionpool_id, $title="")
Copies an assNumeric object.
setPoints($a_points)
Sets the maximum available points for the question.
saveQuestionDataToDb($original_id="")
isValidSolutionSubmit($numeric_solution)
isComplete()
Returns true, if a numeric question is complete for use.
Class for numeric questions.
setQuestion($question="")
Sets the question string of the question object.
Interface ilObjQuestionScoringAdjustable.
__construct(Container $dic, ilPlugin $plugin)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
global $ilDB
setOriginalId($original_id)
$DIC
Definition: xapitoken.php:46
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass...
setLifecycle(ilAssQuestionLifecycle $lifecycle)
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
setTitle($title="")
Sets the title string of the assQuestion object.
setObjId($obj_id=0)
Set the object id of the container object.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
setComment($comment="")
Sets the comment string of the assQuestion object.
$_POST["username"]
contains($value)
Checks for a given value within the range.
$i
Definition: metadata.php:24
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.