ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
ilObjTestSettingsTestBehaviour.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
24 
26 {
27  private const DEFAULT_PROCESSING_TIME_MINUTES = 90;
28 
29  public function __construct(
30  int $test_id,
31  protected int $number_of_tries = 0,
32  protected bool $block_after_passed_enabled = false,
33  protected ?string $pass_waiting = null,
34  protected bool $processing_time_enabled = false,
35  protected ?string $processing_time = null,
36  protected bool $reset_processing_time = false,
37  protected int $kiosk_mode = 0,
38  protected bool $examid_in_test_pass_enabled = false
39  ) {
40  $this->pass_waiting = $this->cleanupPassWaiting($this->pass_waiting);
41  parent::__construct($test_id);
42  }
43 
44  public function toForm(
48  array $environment = null
49  ): FormInput {
50  $inputs['limit_attempts'] = $this->getInputLimitAttempts(
51  $lng,
52  $f,
53  $refinery,
54  $environment
55  );
56  $inputs['force_waiting_between_attempts'] = $this->getInputForceWaitingBetweenAttempts(
57  $lng,
58  $f,
59  $refinery,
60  $environment
61  );
62  $inputs['time_limit_for_completion'] = $this->getInputTimeLimitForCompletion(
63  $lng,
64  $f,
65  $refinery,
66  $environment
67  );
68  $inputs['kiosk_mode'] = $this->getInputKioskMode($lng, $f, $refinery);
69 
70  $inputs['show_exam_id'] = $f->checkbox(
71  $lng->txt('examid_in_test_pass'),
72  $lng->txt('examid_in_test_pass_desc')
74 
75  return $f->section($inputs, $lng->txt('tst_settings_header_test_run'));
76  }
77 
78  private function getInputLimitAttempts(
82  array $environment
83  ): FormInput {
84  $trafo = $refinery->custom()->transformation(
85  static function (?array $vs): array {
86  if ($vs === null) {
87  return [
88  'number_of_available_attempts' => 0,
89  'block_after_passed' => false
90  ];
91  }
92 
93  return $vs;
94  }
95  );
96 
97  $sub_inputs['number_of_available_attempts'] = $f->numeric($lng->txt('tst_nr_of_tries'));
98  $sub_inputs['block_after_passed'] = $f->checkbox(
99  $lng->txt('tst_block_passes_after_passed'),
100  $lng->txt('tst_block_passes_after_passed_info')
101  );
102 
103  if (!$environment['participant_data_exists']) {
104  $sub_inputs['number_of_available_attempts'] =
105  $sub_inputs['number_of_available_attempts']->withRequired(true)
106  ->withAdditionalTransformation($refinery->int()->isGreaterThan(0));
107  }
108 
109  $limit_attempts = $f->optionalGroup(
110  $sub_inputs,
111  $lng->txt('tst_limit_nr_of_tries'),
112  $lng->txt('tst_nr_of_tries_desc')
113  )->withValue(null)
114  ->withAdditionalTransformation($trafo);
115 
116  if ($this->getNumberOfTries() > 0) {
117  $limit_attempts = $limit_attempts->withValue(
118  [
119  'number_of_available_attempts' => $this->getNumberOfTries(),
120  'block_after_passed' => $this->getBlockAfterPassedEnabled()
121  ]
122  );
123  }
124 
125  if (!$environment['participant_data_exists']) {
126  return $limit_attempts;
127  }
128 
129  return $limit_attempts->withDisabled(true);
130  }
131 
133  \ilLanguage $lng,
136  array $environment
137  ): FormInput {
138  $constraint = $refinery->custom()->constraint(
139  static function (?string $vs): bool {
140  if ($vs !== null && $vs === '0:0:0') {
141  return false;
142  }
143 
144  return true;
145  },
146  sprintf($lng->txt('not_greater_than'), $lng->txt('tst_pass_waiting_time'), 0)
147  );
148 
149  $trafo = $refinery->custom()->transformation(
150  static function (?array $vs): ?string {
151  if ($vs === null) {
152  return null;
153  }
154 
155  return implode(':', $vs);
156  }
157  );
158 
159  $force_waiting_between_attempts = $f->optionalGroup(
160  $this->getSubInputsForceWaitingBetweenAttempts($lng, $f, $refinery, ),
161  $lng->txt('tst_pass_waiting_enabled'),
162  $lng->txt('tst_pass_waiting_info')
163  )->withValue(null)
164  ->withAdditionalTransformation($trafo);
165 
166  if ($this->getPassWaitingEnabled()) {
167  list($days, $hours, $minutes) = explode(':', $this->getPassWaiting());
168  $force_waiting_between_attempts = $force_waiting_between_attempts->withValue(
169  [
170  'days' => $days,
171  'hours' => $hours,
172  'minutes' => $minutes
173  ]
174  );
175  }
176 
177  if (!$environment['participant_data_exists']) {
178  return $force_waiting_between_attempts->withAdditionalTransformation($constraint);
179  }
180 
181  return $force_waiting_between_attempts->withDisabled(true);
182  }
183 
185  \ilLanguage $lng,
188  ): array {
189  $sub_inputs_force_waiting_between_attempts['days'] = $f->numeric($lng->txt('days'))
190  ->withAdditionalTransformation($refinery->int()->isGreaterThanOrEqual(0))
191  ->withRequired(true)
192  ->withValue(0);
193  $sub_inputs_force_waiting_between_attempts['hours'] = $f->numeric($lng->txt('hours'))
194  ->withAdditionalTransformation($refinery->int()->isGreaterThanOrEqual(0))
195  ->withAdditionalTransformation($refinery->int()->isLessThanOrEqual(24))
196  ->withRequired(true)
197  ->withValue(0);
198  $sub_inputs_force_waiting_between_attempts['minutes'] = $f->numeric($lng->txt('minutes'))
199  ->withAdditionalTransformation($refinery->int()->isGreaterThanOrEqual(0))
200  ->withAdditionalTransformation($refinery->int()->isLessThanOrEqual(60))
201  ->withRequired(true)
202  ->withValue(0);
203 
204  return $sub_inputs_force_waiting_between_attempts;
205  }
206 
207  private function cleanupPassWaiting(?string $pass_waiting): ?string
208  {
209  if ($pass_waiting === null || $pass_waiting === '') {
210  return null;
211  }
212 
213  $pass_waiting_array = array_map(
214  fn(string $v) => strval((int) $v),
215  explode(':', $pass_waiting)
216  );
217  if (count($pass_waiting_array) === 3) {
218  return implode(':', $pass_waiting_array);
219  }
220 
221  $month = array_shift($pass_waiting_array);
222  $pass_waiting_array[0] = strval((int) $pass_waiting_array[0] + (int) $month * 31);
223  return implode(':', $pass_waiting_array);
224  }
225 
227  \ilLanguage $lng,
230  array $environment
231  ): FormInput {
232  $trafo = $refinery->custom()->transformation(
233  static function (?array $vs): array {
234  if ($vs === null) {
235  return [
236  'processing_time_limit' => false,
237  'time_limit_for_completion_value' => null,
238  'reset_time_limit_for_completion_by_attempt' => false
239  ];
240  }
241 
242  $vs['processing_time_limit'] = true;
243  $vs['time_limit_for_completion_value'] = sprintf(
244  '%02d:%02d:00',
245  floor(
246  $vs['time_limit_for_completion_value'] / 60
247  ),
248  $vs['time_limit_for_completion_value'] % 60
249  );
250  return $vs;
251  }
252  );
253 
254  $sub_inputs_time_limit_for_completion['time_limit_for_completion_value'] = $f
255  ->numeric(
256  $lng->txt('tst_processing_time_duration'),
257  $lng->txt('tst_processing_time_desc')
258  )
259  ->withRequired(true)
260  ->withAdditionalTransformation($refinery->int()->isGreaterThan(0))
261  ->withValue(self::DEFAULT_PROCESSING_TIME_MINUTES);
262  $sub_inputs_time_limit_for_completion['reset_time_limit_for_completion_by_attempt'] = $f->checkbox(
263  $lng->txt('tst_reset_processing_time'),
264  $lng->txt('tst_reset_processing_time_desc')
265  );
266 
267  $time_limit_for_completion = $f->optionalGroup(
268  $sub_inputs_time_limit_for_completion,
269  $lng->txt('tst_processing_time'),
270  $lng->txt('tst_processing_time_desc')
271  )->withValue(null)
272  ->withAdditionalTransformation($trafo);
273 
274  if ($this->getProcessingTimeEnabled()) {
275  $time_limit_for_completion = $time_limit_for_completion->withValue(
276  [
277  'time_limit_for_completion_value' => (int) $this->getProcessingTimeAsMinutes(),
278  'reset_time_limit_for_completion_by_attempt' => (bool) $this->getResetProcessingTime()
279  ]
280  );
281  }
282 
283  if (!$environment['participant_data_exists']) {
284  return $time_limit_for_completion;
285  }
286 
287  return $time_limit_for_completion->withDisabled(true);
288  }
289 
290  private function getInputKioskMode(
291  \ilLanguage $lng,
294  ): FormInput {
295  $trafo = $refinery->custom()->transformation(
296  static function (?array $vs): ?int {
297  if ($vs === null) {
298  return $kiosk_mode = 0;
299  }
300 
301  $kiosk_mode = 1;
302 
303  if ($vs['show_title'] === true) {
304  $kiosk_mode += 2;
305  }
306 
307  if ($vs['show_participant_name'] === true) {
308  $kiosk_mode += 4;
309  }
310 
311  return $kiosk_mode;
312  }
313  );
314 
315  $sub_inputs_kiosk_mode['show_title'] = $f->checkbox(
316  $lng->txt('kiosk_show_title')
317  );
318 
319  $sub_inputs_kiosk_mode['show_participant_name'] = $f->checkbox(
320  $lng->txt('kiosk_show_participant')
321  );
322 
323  $kiosk_mode = $f->optionalGroup(
324  $sub_inputs_kiosk_mode,
325  $lng->txt('kiosk'),
326  $lng->txt('kiosk_description')
327  )->withValue(null)
328  ->withAdditionalTransformation($trafo);
329 
330  if (!$this->getKioskMode()) {
331  return $kiosk_mode;
332  }
333 
334  return $kiosk_mode->withValue(
335  [
336  'show_title' => $this->getShowTitleInKioskMode(),
337  'show_participant_name' => $this->getShowParticipantNameInKioskMode()
338  ]
339  );
340  }
341 
342  public function toStorage(): array
343  {
344  return [
345  'nr_of_tries' => ['integer', $this->getNumberOfTries()],
346  'block_after_passed' => ['integer', (int) $this->getBlockAfterPassedEnabled()],
347  'pass_waiting' => ['string', $this->getPassWaiting()],
348  'enable_processing_time' => ['integer', (int) $this->getProcessingTimeEnabled()],
349  'processing_time' => ['string', $this->getProcessingTime()],
350  'reset_processing_time' => ['integer', (int) $this->getResetProcessingTime()],
351  'kiosk' => ['integer', $this->getKioskMode()],
352  'examid_in_test_pass' => ['integer', (int) $this->getExamIdInTestPassEnabled()]
353  ];
354  }
355 
356  public function getNumberOfTries(): int
357  {
358  return $this->number_of_tries;
359  }
360  public function withNumberOfTries(int $number_of_tries): self
361  {
362  $clone = clone $this;
363  $clone->number_of_tries = $number_of_tries;
364  return $clone;
365  }
366 
367  public function getBlockAfterPassedEnabled(): bool
368  {
369  return $this->block_after_passed_enabled;
370  }
371  public function withBlockAfterPassedEnabled(bool $block_after_passed_enabled): self
372  {
373  $clone = clone $this;
374  $clone->block_after_passed_enabled = $block_after_passed_enabled;
375  return $clone;
376  }
377 
378  public function getPassWaiting(): ?string
379  {
380  return $this->pass_waiting;
381  }
382  public function getPassWaitingEnabled(): bool
383  {
384  if ($this->pass_waiting === null) {
385  return false;
386  }
387  if (array_sum(explode(':', $this->pass_waiting)) > 0) {
388  return true;
389  }
390  return false;
391  }
392  public function withPassWaiting(?string $pass_waiting): self
393  {
394  $clone = clone $this;
395  $clone->pass_waiting = $this->cleanupPassWaiting($pass_waiting);
396  return $clone;
397  }
398 
399  public function getProcessingTimeEnabled(): bool
400  {
401  return $this->processing_time_enabled;
402  }
403  public function withProcessingTimeEnabled(bool $processing_time_enabled): self
404  {
405  $clone = clone $this;
406  $clone->processing_time_enabled = $processing_time_enabled;
407  return $clone;
408  }
409 
410  public function getProcessingTime(): ?string
411  {
412  return $this->processing_time;
413  }
414  public function getProcessingTimeAsMinutes(): int
415  {
416  if ($this->processing_time !== null) {
417  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
418  return ((int) $matches[1] * 60) + (int) $matches[2];
419  }
420  }
421 
422  return self::DEFAULT_PROCESSING_TIME_MINUTES;
423  }
424  public function withProcessingTime(?string $processing_time): self
425  {
426  $clone = clone $this;
427  $clone->processing_time = $processing_time;
428  return $clone;
429  }
430 
431  public function getResetProcessingTime(): bool
432  {
433  return $this->reset_processing_time;
434  }
435  public function withResetProcessingTime(bool $reset_processing_time): self
436  {
437  $clone = clone $this;
438  $clone->reset_processing_time = $reset_processing_time;
439  return $clone;
440  }
441 
442  public function getKioskMode(): int
443  {
444  return $this->kiosk_mode;
445  }
446  public function getKioskModeEnabled(): bool
447  {
448  if (($this->kiosk_mode & 1) > 0) {
449  return true;
450  } else {
451  return false;
452  }
453  }
454  public function getShowTitleInKioskMode(): bool
455  {
456  if (($this->kiosk_mode & 2) > 0) {
457  return true;
458  } else {
459  return false;
460  }
461  }
462  public function getShowParticipantNameInKioskMode(): bool
463  {
464  if (($this->kiosk_mode & 4) > 0) {
465  return true;
466  } else {
467  return false;
468  }
469  }
470  public function withKioskMode(int $kiosk_mode): self
471  {
472  $clone = clone $this;
473  $clone->kiosk_mode = $kiosk_mode;
474  return $clone;
475  }
476 
477  public function getExamIdInTestPassEnabled(): bool
478  {
479  return $this->examid_in_test_pass_enabled;
480  }
481  public function withExamIdInTestPassEnabled(bool $exam_id_in_test_pass_enabled): self
482  {
483  $clone = clone $this;
484  $clone->examid_in_test_pass_enabled = $exam_id_in_test_pass_enabled;
485  return $clone;
486  }
487 }
This is what a factory for input fields looks like.
Definition: Factory.php:28
getSubInputsForceWaitingBetweenAttempts(\ilLanguage $lng, FieldFactory $f, Refinery $refinery)
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
getInputTimeLimitForCompletion(\ilLanguage $lng, FieldFactory $f, Refinery $refinery, array $environment)
withBlockAfterPassedEnabled(bool $block_after_passed_enabled)
withAdditionalTransformation(Transformation $trafo)
Apply a transformation to the content of the input.
withResetProcessingTime(bool $reset_processing_time)
__construct(VocabulariesInterface $vocabularies)
$lng
withProcessingTimeEnabled(bool $processing_time_enabled)
__construct(int $test_id, protected int $number_of_tries=0, protected bool $block_after_passed_enabled=false, protected ?string $pass_waiting=null, protected bool $processing_time_enabled=false, protected ?string $processing_time=null, protected bool $reset_processing_time=false, protected int $kiosk_mode=0, protected bool $examid_in_test_pass_enabled=false)
toForm(\ilLanguage $lng, FieldFactory $f, Refinery $refinery, array $environment=null)
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:58
getInputLimitAttempts(\ilLanguage $lng, FieldFactory $f, Refinery $refinery, array $environment)
getInputKioskMode(\ilLanguage $lng, FieldFactory $f, Refinery $refinery)
withRequired(bool $is_required, ?Constraint $requirement_constraint=null)
Get an input like this, but set the field to be required (or not).
This describes inputs that can be used in forms.
Definition: FormInput.php:31
withExamIdInTestPassEnabled(bool $exam_id_in_test_pass_enabled)
getInputForceWaitingBetweenAttempts(\ilLanguage $lng, FieldFactory $f, Refinery $refinery, array $environment)
Refinery Factory $refinery