ILIAS  release_8 Revision v8.23
class.SurveyMetricQuestion.php
Go to the documentation of this file.
1 <?php
2 
26 {
27  public const SUBTYPE_NON_RATIO = 3;
28  public const SUBTYPE_RATIO_NON_ABSOLUTE = 4;
29  public const SUBTYPE_RATIO_ABSOLUTE = 5;
30 
31  public int $subtype;
32 
33  public ?float $minimum;
34  public ?float $maximum;
35 
36  public function __construct(
37  string $title = "",
38  string $description = "",
39  string $author = "",
40  string $questiontext = "",
41  int $owner = -1,
42  int $subtype = self::SUBTYPE_NON_RATIO
43  ) {
44  global $DIC;
45 
46  $this->db = $DIC->database();
48 
49  $this->subtype = $subtype;
50  $this->minimum = null;
51  $this->maximum = null;
52  }
53 
54  public function setSubtype(int $a_subtype = self::SUBTYPE_NON_RATIO): void
55  {
56  $this->subtype = $a_subtype;
57  }
58 
59  public function setMinimum(?float $minimum = null): void
60  {
61  $this->minimum = $minimum;
62  }
63 
64  public function setMaximum(?float $maximum = null): void
65  {
66  $this->maximum = $maximum;
67  }
68 
69  public function getSubtype(): ?int
70  {
71  return $this->subtype;
72  }
73 
74  public function getMinimum(): ?float
75  {
76  if (is_null($this->minimum) && $this->getSubtype() > 3) {
77  $this->minimum = 0;
78  }
79  return $this->minimum;
80  }
81 
82  public function getMaximum(): ?float
83  {
84  return $this->maximum;
85  }
86 
87  public function getQuestionDataArray(int $id): array
88  {
89  $ilDB = $this->db;
90 
91  $result = $ilDB->queryF(
92  "SELECT svy_question.*, " . $this->getAdditionalTableName() . ".* FROM svy_question, " . $this->getAdditionalTableName() . " WHERE svy_question.question_id = %s AND svy_question.question_id = " . $this->getAdditionalTableName() . ".question_fi",
93  array('integer'),
94  array($id)
95  );
96  if ($result->numRows() === 1) {
97  return $ilDB->fetchAssoc($result);
98  } else {
99  return array();
100  }
101  }
102 
103  public function loadFromDb(int $question_id): void
104  {
105  $ilDB = $this->db;
106 
107  $result = $ilDB->queryF(
108  "SELECT svy_question.*, " . $this->getAdditionalTableName() . ".* FROM svy_question LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = svy_question.question_id WHERE svy_question.question_id = %s",
109  array('integer'),
110  array($question_id)
111  );
112  if ($result->numRows() === 1) {
113  $data = $ilDB->fetchAssoc($result);
114  $this->setId((int) $data["question_id"]);
115  $this->setTitle((string) $data["title"]);
116  $this->setDescription((string) $data["description"]);
117  $this->setObjId((int) $data["obj_fi"]);
118  $this->setAuthor((string) $data["author"]);
119  $this->setOwner((int) $data["owner_fi"]);
120  $this->label = (string) $data['label'];
121  $this->setQuestiontext(ilRTE::_replaceMediaObjectImageSrc((string) $data["questiontext"], 1));
122  $this->setObligatory((bool) $data["obligatory"]);
123  $this->setComplete((bool) $data["complete"]);
124  $this->setOriginalId((int) $data["original_id"]);
125  $this->setSubtype((int) $data["subtype"]);
126 
127  $result = $ilDB->queryF(
128  "SELECT svy_variable.* FROM svy_variable WHERE svy_variable.question_fi = %s",
129  array('integer'),
130  array($question_id)
131  );
132  if ($result->numRows() > 0) {
133  if ($data = $ilDB->fetchAssoc($result)) {
134  $this->minimum = is_null($data["value1"]) ? null : (float) $data["value1"];
135  if (($data["value2"] < 0) or (strcmp($data["value2"], "") == 0)) {
136  $this->maximum = null;
137  } else {
138  $this->maximum = is_null($data["value2"]) ? null : (float) $data["value2"];
139  }
140  }
141  }
142  }
143  parent::loadFromDb($question_id);
144  }
145 
146  public function isComplete(): bool
147  {
148  return (
149  $this->getTitle() !== '' &&
150  $this->getAuthor() !== '' &&
151  $this->getQuestiontext() !== ''
152  );
153  }
154 
155  public function saveToDb(int $original_id = 0): int
156  {
157  $ilDB = $this->db;
158 
159  $affectedRows = parent::saveToDb($original_id);
160  if ($affectedRows === 1) {
161  $ilDB->manipulateF(
162  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
163  array('integer'),
164  array($this->getId())
165  );
166  $ilDB->manipulateF(
167  "INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, subtype) VALUES (%s, %s)",
168  array('integer', 'text'),
169  array($this->getId(), $this->getSubtype())
170  );
171 
172  // saving material uris in the database
173  $this->saveMaterial();
174 
175  // save categories
176  $ilDB->manipulateF(
177  "DELETE FROM svy_variable WHERE question_fi = %s",
178  array('integer'),
179  array($this->getId())
180  );
181 
182  if (preg_match("/[\D]/", $this->maximum) or (strcmp($this->maximum, "&infin;") == 0)) {
183  $max = -1;
184  } else {
185  $max = $this->getMaximum();
186  }
187  $next_id = $ilDB->nextId('svy_variable');
188  $ilDB->manipulateF(
189  "INSERT INTO svy_variable (variable_id, category_fi, question_fi, value1, value2, sequence, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s)",
190  array('integer','integer','integer','float','float','integer','integer'),
191  array($next_id, 0, $this->getId(), $this->getMinimum(), $max, 0, time())
192  );
193  }
194  return $affectedRows;
195  }
196 
197  public function toXML(
198  bool $a_include_header = true
199  ): string {
200  $a_xml_writer = new ilXmlWriter();
201  $a_xml_writer->xmlHeader();
202  $this->insertXML($a_xml_writer, $a_include_header);
203  $xml = $a_xml_writer->xmlDumpMem(false);
204  if (!$a_include_header) {
205  $pos = strpos($xml, "?>");
206  $xml = substr($xml, $pos + 2);
207  }
208  return $xml;
209  }
210 
211  public function insertXML(
212  ilXmlWriter $a_xml_writer,
213  bool $a_include_header = true
214  ): void {
215  $attrs = array(
216  "id" => $this->getId(),
217  "title" => $this->getTitle(),
218  "type" => $this->getQuestionType(),
219  "subtype" => $this->getSubtype(),
220  "obligatory" => $this->getObligatory()
221  );
222  $a_xml_writer->xmlStartTag("question", $attrs);
223 
224  $a_xml_writer->xmlElement("description", null, $this->getDescription());
225  $a_xml_writer->xmlElement("author", null, $this->getAuthor());
226  $a_xml_writer->xmlStartTag("questiontext");
227  $this->addMaterialTag($a_xml_writer, $this->getQuestiontext());
228  $a_xml_writer->xmlEndTag("questiontext");
229 
230  $a_xml_writer->xmlStartTag("responses");
231  switch ($this->getSubtype()) {
232  case 4:
233  case 3:
234  $attrs = array(
235  "id" => "0",
236  "format" => "double"
237  );
238  if ((string) $this->getMinimum() !== '') {
239  $attrs["min"] = $this->getMinimum();
240  }
241  if ((string) $this->getMaximum() !== '') {
242  $attrs["max"] = $this->getMaximum();
243  }
244  break;
245  case 5:
246  $attrs = array(
247  "id" => "0",
248  "format" => "integer"
249  );
250  if ((string) $this->getMinimum() !== '') {
251  $attrs["min"] = $this->getMinimum();
252  }
253  if ((string) $this->getMaximum() !== '') {
254  $attrs["max"] = $this->getMaximum();
255  }
256  break;
257  }
258  $a_xml_writer->xmlStartTag("response_num", $attrs);
259  $a_xml_writer->xmlEndTag("response_num");
260 
261  $a_xml_writer->xmlEndTag("responses");
262 
263  if (count($this->material) && preg_match(
264  "/il_(\d*?)_(\w+)_(\d+)/",
265  $this->material["internal_link"],
266  $matches
267  )) {
268  $attrs = array(
269  "label" => $this->material["title"]
270  );
271  $a_xml_writer->xmlStartTag("material", $attrs);
272  $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
273  if (strcmp($matches[1], "") !== 0) {
274  $intlink = $this->material["internal_link"];
275  }
276  $a_xml_writer->xmlElement("mattext", null, $intlink);
277  $a_xml_writer->xmlEndTag("material");
278  }
279 
280  $a_xml_writer->xmlEndTag("question");
281  }
282 
283  public function getQuestionTypeID(): int
284  {
285  $ilDB = $this->db;
286  $result = $ilDB->queryF(
287  "SELECT questiontype_id FROM svy_qtype WHERE type_tag = %s",
288  array('text'),
289  array($this->getQuestionType())
290  );
291  $row = $ilDB->fetchAssoc($result);
292  return (int) $row["questiontype_id"];
293  }
294 
295  public function getQuestionType(): string
296  {
297  return "SurveyMetricQuestion";
298  }
299 
300  public function getAdditionalTableName(): string
301  {
302  return "svy_qst_metric";
303  }
304 
305  public function getWorkingDataFromUserInput(array $post_data): array
306  {
307  $entered_value = $post_data[$this->getId() . "_metric_question"] ?? "";
308  $data = array();
309  if (strlen($entered_value)) {
310  $data[] = array("value" => $entered_value);
311  }
312  return $data;
313  }
314 
318  public function checkUserInput(
319  array $post_data,
320  int $survey_id
321  ): string {
322  $entered_value = $post_data[$this->getId() . "_metric_question"];
323  // replace german notation with international notation
324  $entered_value = str_replace(",", ".", $entered_value);
325 
326  if ((!$this->getObligatory()) && (strlen($entered_value) == 0)) {
327  return "";
328  }
329 
330  if (strlen($entered_value) == 0) {
331  return $this->lng->txt("survey_question_obligatory");
332  }
333 
334  if (strlen($this->getMinimum())) {
335  if ($entered_value < $this->getMinimum()) {
336  return $this->lng->txt("metric_question_out_of_bounds");
337  }
338  }
339 
340  if (strlen($this->getMaximum())) {
341  if (($this->getMaximum() == 1) && ($this->getMaximum() < $this->getMinimum())) {
342  // old &infty; values as maximum
343  } elseif ($entered_value > $this->getMaximum()) {
344  return $this->lng->txt("metric_question_out_of_bounds");
345  }
346  }
347 
348  if (!is_numeric($entered_value)) {
349  return $this->lng->txt("metric_question_not_a_value");
350  }
351 
352  if ($this->getSubtype() === self::SUBTYPE_RATIO_ABSOLUTE && ((int) $entered_value != (float) $entered_value)) {
353  return $this->lng->txt("metric_question_floating_point");
354  }
355  return "";
356  }
357 
358  public function saveUserInput(
359  array $post_data,
360  int $active_id,
361  bool $a_return = false
362  ): ?array {
363  $ilDB = $this->db;
364 
365  $entered_value = $post_data[$this->getId() . "_metric_question"];
366 
367  // replace german notation with international notation
368  $entered_value = str_replace(",", ".", $entered_value);
369 
370  if ($a_return) {
371  return array(array("value" => $entered_value, "textanswer" => null));
372  }
373 
374  if ($entered_value === '') {
375  return null;
376  }
377 
378  $next_id = $ilDB->nextId('svy_answer');
379  #20216
380  $fields = array();
381  $fields['answer_id'] = array("integer", $next_id);
382  $fields['question_fi'] = array("integer", $this->getId());
383  $fields['active_fi'] = array("integer", $active_id);
384  $fields['value'] = array("float", $entered_value);
385  $fields['textanswer'] = array("clob", null);
386  $fields['tstamp'] = array("integer", time());
387 
388  $ilDB->insert("svy_answer", $fields);
389 
390  return null;
391  }
392 
393  public function importResponses(array $a_data): void
394  {
395  foreach ($a_data as $id => $data) {
396  $this->setMinimum($data["min"]);
397  $this->setMaximum($data["max"]);
398  }
399  }
400 
401  public function usableForPrecondition(): bool
402  {
403  return true;
404  }
405 
406  public function getAvailableRelations(): array
407  {
408  return array("<", "<=", "=", "<>", ">=", ">");
409  }
410 
411  public function outPreconditionSelectValue(
412  ilTemplate $template
413  ): void {
414  $template->setCurrentBlock("textfield");
415  $template->setVariable("TEXTFIELD_VALUE", "");
416  $template->parseCurrentBlock();
417  }
418 
424  public function getPreconditionSelectValue(
425  string $default,
426  string $title,
427  string $variable
428  ): ?ilFormPropertyGUI {
429  $step3 = new ilNumberInputGUI($title, $variable);
430  $step3->setValue($default);
431  return $step3;
432  }
433 
437  public function getMinMaxText(): string
438  {
439  $min = (string) $this->getMinimum();
440  $max = (string) $this->getMaximum();
441  if ($min !== '' && $max !== '') {
442  return "(" . $min . " " . strtolower($this->lng->txt("to")) . " " . $max . ")";
443  } elseif ($min !== '') {
444  return "(&gt;= " . $min . ")";
445  } elseif ($max !== '') {
446  return "(&lt;= " . $max . ")";
447  } else {
448  return "";
449  }
450  }
451 }
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...
parseCurrentBlock(string $part=ilGlobalTemplateInterface::DEFAULT_BLOCK)
setQuestiontext(string $questiontext="")
toXML(bool $a_include_header=true)
const IL_INST_ID
Definition: constants.php:40
__construct(string $title="", string $description="", string $author="", string $questiontext="", int $owner=-1, int $subtype=self::SUBTYPE_NON_RATIO)
setObligatory(bool $obligatory=true)
setOriginalId(?int $original_id)
setMaximum(?float $maximum=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setComplete(bool $a_complete)
checkUserInput(array $post_data, int $survey_id)
xmlEndTag(string $tag)
Writes an endtag.
global $DIC
Definition: feed.php:28
setAuthor(string $author="")
setVariable($variable, $value='')
Sets a variable value.
Definition: IT.php:514
addMaterialTag(ilXmlWriter $a_xml_writer, string $a_material, bool $close_material_tag=true, bool $add_mobs=true, ?array $a_attrs=null)
Creates an XML material tag from a plain text or xhtml text.
This class represents a number property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$xml
Definition: metadata.php:351
setTitle(string $title="")
setMinimum(?float $minimum=null)
setCurrentBlock(string $part=ilGlobalTemplateInterface::DEFAULT_BLOCK)
saveUserInput(array $post_data, int $active_id, bool $a_return=false)
outPreconditionSelectValue(ilTemplate $template)
setOwner(int $owner=0)
This class represents a property in a property form.
__construct(Container $dic, ilPlugin $plugin)
getMinMaxText()
Creates a text for the input range of the metric question.
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
setSubtype(int $a_subtype=self::SUBTYPE_NON_RATIO)
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
getWorkingDataFromUserInput(array $post_data)
setDescription(string $description="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getPreconditionSelectValue(string $default, string $title, string $variable)
Creates a form property for the precondition value.
setObjId(int $obj_id=0)
Set the reference(?) id of the container object.
insertXML(ilXmlWriter $a_xml_writer, bool $a_include_header=true)