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 
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  var $maxchars;
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 }
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.
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
Creates an Excel worksheet for the detailed cumulated results of this question.
static _getOriginalId($question_id)
Returns the original id of a question.
Class iQuestionCondition.
$_POST['username']
Definition: cron.php:12
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assNumeric constructor
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...
_getPass($active_id)
Retrieves the actual pass of a given user for a given test.
_convert_text($a_text, $a_target="has been removed")
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. ...
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true)
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)
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
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.
setMaxChars($maxchars)
Sets the maximum number of characters for the numeric input field.
removeSolutionRecordById($solutionId)
setAuthor($author="")
Sets the authors name of the assQuestion object.
$data
Class ilUserQuestionResult.
Interface ilObjAnswerScoringAdjustable.
saveWorkingData($active_id, $pass=NULL, $authorized=true)
Saves the learners input of the question to the database.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assNumericQuestion.
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
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)
_getLogLanguage()
retrieve the log language for assessment logging
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.
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.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
global $ilDB
setOriginalId($original_id)
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass...
calculateReachedPoints($active_id, $pass=NULL, $authorizedSolution=true, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
getSolutionValues($active_id, $pass=NULL, $authorized=true)
Loads solutions of a given user from the database an returns it.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getTitle()
Gets the title string of the assQuestion object.
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.
contains($value)
Checks for a given value within the range.
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.