ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.assNumeric.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
23
40{
41 protected $lower_limit;
42 protected $upper_limit;
43 public $maxchars = 6;
44
45 public function isComplete(): bool
46 {
47 if (
48 strlen($this->title)
49 && $this->author
50 && $this->question
51 && $this->getMaximumPoints() > 0
52 ) {
53 return true;
54 }
55 return false;
56 }
57
58 public function saveToDb(?int $original_id = null): void
59 {
63 parent::saveToDb($original_id);
64 }
65
66 public function loadFromDb(int $question_id): void
67 {
68 $result = $this->db->queryF(
69 "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",
70 ["integer"],
71 [$question_id]
72 );
73 if ($result->numRows() == 1) {
74 $data = $this->db->fetchAssoc($result);
75 $this->setId($question_id);
76 $this->setObjId($data["obj_fi"]);
77 $this->setTitle((string) $data["title"]);
78 $this->setComment((string) $data["description"]);
79 $this->setNrOfTries($data['nr_of_tries']);
80 $this->setOriginalId($data["original_id"]);
81 $this->setAuthor($data["author"]);
82 $this->setPoints($data["points"]);
83 $this->setOwner($data["owner"]);
84 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
85 $this->setMaxChars($data["maxnumofchars"]);
86
87 try {
88 $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
91 }
92
93 try {
94 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
96 }
97 }
98
99 $result = $this->db->queryF(
100 "SELECT * FROM qpl_num_range WHERE question_fi = %s ORDER BY aorder ASC",
101 ['integer'],
102 [$question_id]
103 );
104
105 if ($result->numRows() > 0) {
107 while ($data = $this->db->fetchAssoc($result)) {
108 $this->setPoints($data['points']);
109 $this->setLowerLimit($data['lowerlimit']);
110 $this->setUpperLimit($data['upperlimit']);
111 }
112 }
113
114 parent::loadFromDb($question_id);
115 }
116
117 public function getLowerLimit()
118 {
119 return $this->lower_limit;
120 }
121
122 public function getUpperLimit()
123 {
124 return $this->upper_limit;
125 }
126
127 public function setLowerLimit(string $limit): void
128 {
129 $this->lower_limit = str_replace(',', '.', $limit);
130 }
131
132 public function setUpperLimit(string $limit): void
133 {
134 $this->upper_limit = str_replace(',', '.', $limit);
135 }
136
137 public function getMaximumPoints(): float
138 {
139 return $this->getPoints();
140 }
141
143 {
144 $points = 0;
145 if ($this->contains($previewSession->getParticipantsSolution())) {
146 $points = $this->getPoints();
147 }
148
149 return $this->ensureNonNegativePoints($points);
150 }
151
152 public function calculateReachedPoints(
153 int $active_id,
154 ?int $pass = null,
155 bool $authorized_solution = true
156 ): float {
157 if ($pass === null) {
158 $pass = $this->getSolutionMaxPass($active_id);
159 }
160 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized_solution);
161 $data = $this->db->fetchAssoc($result);
162 $enteredvalue = '';
163 if (is_array($data) && array_key_exists('value1', $data)) {
164 $enteredvalue = $data["value1"];
165 }
166
167 $points = 0.0;
168 if ($this->contains($enteredvalue)) {
169 $points = $this->getPoints();
170 }
171
172 return $points;
173 }
174
185 public function contains($value): bool
186 {
187 $eval = new EvalMath();
188 $eval->suppress_errors = true;
189 $result = $eval->e((string) $value);
190 if (($result === false) || ($result === true)) {
191 return false;
192 }
193
194 if (($result >= $eval->e($this->getLowerLimit())) && ($result <= $eval->e($this->getUpperLimit()))) {
195 return true;
196 }
197 return false;
198 }
199
200 public function validateSolutionSubmit(): bool
201 {
202 if ($this->getSolutionSubmit() === null) {
203 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("err_no_numeric_value"), true);
204 return false;
205 }
206
207 return true;
208 }
209
210 protected function getSolutionSubmit(): ?float
211 {
212 return $this->questionpool_request->float('numeric_result') ?? null;
213 }
214
215 public function isValidSolutionSubmit($numeric_solution): bool
216 {
217 $math = new EvalMath();
218 $math->suppress_errors = true;
219 $result = $math->evaluate($numeric_solution);
220
221 return !(
222 ($result === false || $result === true) && strlen($numeric_solution) > 0
223 );
224 }
225
226 public function saveWorkingData(
227 int $active_id,
228 ?int $pass = null,
229 bool $authorized = true
230 ): bool {
231 if (is_null($pass)) {
232 $pass = ilObjTest::_getPass($active_id);
233 }
234
235 $answer = $this->getSolutionSubmit();
236 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
237 function () use ($answer, $active_id, $pass, $authorized) {
238 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized);
239 $update = -1;
240 if ($this->db->numRows($result) !== 0) {
241 $row = $this->db->fetchAssoc($result);
242 $update = $row['solution_id'];
243 }
244
245 if ($update !== -1
246 && $answer === '') {
247 $this->removeSolutionRecordById($update);
248 return;
249 }
250 if ($update !== -1) {
251 $this->updateCurrentSolution($update, $answer, null, $authorized);
252 return;
253 }
254
255 if ($answer !== '') {
256 $this->saveCurrentSolution($active_id, $pass, $answer, null, $authorized);
257 }
258 }
259 );
260
261 return true;
262 }
263
264 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
265 {
266 $numericSolution = $this->getSolutionSubmit();
267 $previewSession->setParticipantsSolution($numericSolution);
268 }
269
271 {
272 // save additional data
273 $this->db->manipulateF(
274 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
275 [ "integer" ],
276 [ $this->getId() ]
277 );
278
279 $this->db->manipulateF(
280 "INSERT INTO " . $this->getAdditionalTableName(
281 ) . " (question_fi, maxnumofchars) VALUES (%s, %s)",
282 [ "integer", "integer" ],
283 [
284 $this->getId(),
285 ($this->getMaxChars()) ? $this->getMaxChars() : 0
286 ]
287 );
288 }
289
291 {
292 // Write range to the database
293 $this->db->manipulateF(
294 "DELETE FROM qpl_num_range WHERE question_fi = %s",
295 [ 'integer' ],
296 [ $this->getId() ]
297 );
298
299 $next_id = $this->db->nextId('qpl_num_range');
300 $this->db->manipulateF(
301 "INSERT INTO qpl_num_range (range_id, question_fi, lowerlimit, upperlimit, points, aorder, tstamp)
302 VALUES (%s, %s, %s, %s, %s, %s, %s)",
303 [ 'integer', 'integer', 'text', 'text', 'float', 'integer', 'integer' ],
304 [ $next_id, $this->id, $this->getLowerLimit(), $this->getUpperLimit(
305 ), $this->getPoints(), 0, time() ]
306 );
307 }
308
314 public function getQuestionType(): string
315 {
316 return "assNumeric";
317 }
318
324 public function getMaxChars()
325 {
326 return $this->maxchars;
327 }
328
334 public function setMaxChars($maxchars): void
335 {
336 $this->maxchars = $maxchars;
337 }
338
344 public function getAdditionalTableName(): string
345 {
346 return "qpl_qst_numeric";
347 }
348
353 public function getRTETextWithMediaObjects(): string
354 {
355 return parent::getRTETextWithMediaObjects();
356 }
357
358 public function getOperators(string $expression): array
359 {
361 }
362
363 public function getExpressionTypes(): array
364 {
365 return [
369 ];
370 }
371
372 public function getUserQuestionResult(
373 int $active_id,
374 int $pass
376 $result = new ilUserQuestionResult($this, $active_id, $pass);
377
378 $maxStep = $this->lookupMaxStep($active_id, $pass);
379 if ($maxStep > 0) {
380 $data = $this->db->queryF(
381 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
382 ["integer", "integer", "integer","integer"],
383 [$active_id, $pass, $this->getId(), $maxStep]
384 );
385 } else {
386 $data = $this->db->queryF(
387 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
388 ["integer", "integer", "integer"],
389 [$active_id, $pass, $this->getId()]
390 );
391 }
392
393 while ($row = $this->db->fetchAssoc($data)) {
394 $result->addKeyValue(1, $row["value1"]);
395 }
396
397 $points = $this->calculateReachedPoints($active_id, $pass);
398 $max_points = $this->getMaximumPoints();
399
400 $result->setReachedPercentage(($points / $max_points) * 100);
401
402 return $result;
403 }
404
405 public function getAvailableAnswerOptions(?int $index = null): array
406 {
407 return [
408 "lower" => $this->getLowerLimit(),
409 "upper" => $this->getUpperLimit()
410 ];
411 }
412
413 public function getAnswerTableName(): string
414 {
415 return '';
416 }
417
418 public function toLog(AdditionalInformationGenerator $additional_info): array
419 {
420 return [
421 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->getQuestionType(),
422 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $this->getTitleForHTMLOutput(),
423 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $this->formatSAQuestion($this->getQuestion()),
424 AdditionalInformationGenerator::KEY_QUESTION_SHUFFLE_ANSWER_OPTIONS => $additional_info
425 ->getTrueFalseTagForBool($this->getShuffle()),
426 AdditionalInformationGenerator::KEY_QUESTION_MAXCHARS => $this->getMaxChars(),
427 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $this->getPoints(),
428 AdditionalInformationGenerator::KEY_QUESTION_LOWER_LIMIT => $this->getLowerLimit(),
429 AdditionalInformationGenerator::KEY_QUESTION_UPPER_LIMIT => $this->getUpperLimit(),
430 AdditionalInformationGenerator::KEY_FEEDBACK => [
431 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
432 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
433 ]
434 ];
435 }
436
437 protected function solutionValuesToLog(
438 AdditionalInformationGenerator $additional_info,
439 array $solution_values
440 ): string {
441 if (!array_key_exists(0, $solution_values) ||
442 !array_key_exists('value1', $solution_values[0])) {
443 return '';
444 }
445 return $solution_values[0]['value1'];
446 }
447
448 public function solutionValuesToText(array $solution_values): string
449 {
450 if (!array_key_exists(0, $solution_values) ||
451 !array_key_exists('value1', $solution_values[0])) {
452 return '';
453 }
454 return $solution_values[0]['value1'];
455 }
456
457 public function getCorrectSolutionForTextOutput(int $active_id, int $pass): string
458 {
459 return "{$this->getLowerLimit()}-{$this->getUpperLimit()}";
460 }
461}
Class for numeric questions.
getExpressionTypes()
Get all available expression types for a specific question.
contains($value)
Checks for a given value within the range.
solutionValuesToText(array $solution_values)
MUST convert the given solution values into text.
setMaxChars($maxchars)
Sets the maximum number of characters for the numeric input field.
getOperators(string $expression)
Get all available operations for a specific question.
toLog(AdditionalInformationGenerator $additional_info)
MUST return an array of the question settings that can be stored in the log.
getUserQuestionResult(int $active_id, int $pass)
Get the user solution for a question by active_id and the test pass.
getQuestionType()
Returns the question type of the question.
getCorrectSolutionForTextOutput(int $active_id, int $pass)
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 ...
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
setLowerLimit(string $limit)
isValidSolutionSubmit($numeric_solution)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
setUpperLimit(string $limit)
calculateReachedPoints(int $active_id, ?int $pass=null, bool $authorized_solution=true)
getAvailableAnswerOptions(?int $index=null)
If index is null, the function returns an array with all anwser options else it returns the specific ...
saveToDb(?int $original_id=null)
loadFromDb(int $question_id)
saveWorkingData(int $active_id, ?int $pass=null, bool $authorized=true)
solutionValuesToLog(AdditionalInformationGenerator $additional_info, array $solution_values)
MUST convert the given solution values into an array or a string that can be stored in the log.
setOriginalId(?int $original_id)
ensureNonNegativePoints(float $points)
setId(int $id=-1)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
setQuestion(string $question="")
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
setAuthor(string $author="")
setComment(string $comment="")
setObjId(int $obj_id=0)
getSolutionMaxPass(int $active_id)
setOwner(int $owner=-1)
setNrOfTries(int $a_nr_of_tries)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
setTitle(string $title="")
saveQuestionDataToDb(?int $original_id=null)
setPoints(float $points)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static getOperatorsByExpression(string $expression)
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
if(!file_exists('../ilias.ini.php'))