ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
AdditionalInformationGenerator.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
27 
29 {
30  public const DATE_STORAGE_FORMAT = \DateTimeInterface::ISO8601;
31  public const KEY_USER = 'user';
32  public const KEY_USERS = 'users';
33  public const KEY_QUESTION_ID = 'id';
34  public const KEY_QUESTION_ORDER = 'order';
35  public const KEY_QUESTIONS = 'questions';
36  public const KEY_ANON_IDS = 'anonymous';
37 
38  public const KEY_EVAL_FINALIZED = 'finalized_evaluation';
39  public const KEY_FEEDBACK = 'tst_feedback';
40  public const KEY_QUESTION_TITLE = 'question_title';
41  public const KEY_QUESTION_TEXT = 'tst_question';
42  public const KEY_QUESTION_TYPE = 'tst_question_type';
43  public const KEY_HOMOGENEOUS_SCORING = 'tst_inp_all_quest_points_equal_per_pool_desc';
44  public const KEY_QUESTION_AMOUNT_TYPE = 'tst_inp_quest_amount_cfg_mode';
45  public const KEY_QUESTION_AMOUNT_PER_TEST = 'tst_inp_quest_amount_per_test';
46  public const KEY_QUESTION_AMOUNT_PER_POOL = 'tst_inp_quest_amount_per_source_pool';
47  public const KEY_SOURCE_POOL = 'obj_qpl';
48  public const KEY_SOURCE_TAXONOMY_FILTER = 'tst_inp_source_pool_filter_tax';
49  public const KEY_SOURCE_TYPE_FILTER = 'tst_filter_question_type';
50  public const KEY_SOURCE_LIFECYCLE_FILTER = 'qst_lifecycle';
51  public const KEY_REACHED_POINTS = 'tst_reached_points';
52  public const KEY_MARK_SHORT_NAME = 'tst_mark_short_form';
53  public const KEY_MARK_OFFICIAL_NAME = 'tst_mark_official_form';
54  public const KEY_MARK_MINIMUM_LEVEL = 'tst_mark_minimum_level';
55  public const KEY_MARK_IS_PASSING = 'tst_mark_passed';
56 
57  public const KEY_TEST_TITLE = 'title';
58  public const KEY_TEST_DESCRIPTION = 'description';
59  public const KEY_TEST_ONLINE = 'online';
60  public const KEY_TEST_VISIBILITY_PERIOD = 'crs_visibility_until';
61  public const KEY_TEST_VISIBILITY_PERIOD_FROM = 'from';
62  public const KEY_TEST_VISIBILITY_PERIOD_UNTIL = 'to';
63  public const KEY_TEST_VISIBLE_OUTSIDE_PERIOD = 'activation_visible_when_disabled';
64  public const KEY_TEST_QUESTION_SET_TYPE = 'test_question_set_type';
65  public const KEY_TEST_ANONYMITY = 'tst_anonymity';
66  public const KEY_TEST_INTRODUCTION_ENABLED = 'tst_introduction';
67  public const KEY_TEST_CONDITIONS_ENABLED = 'tst_conditions_checkbox_enabled';
68  public const KEY_TEST_START_TIME = 'tst_starting_time';
69  public const KEY_TEST_END_TIME = 'tst_ending_time';
70  public const KEY_TEST_PASSWORD = 'tst_password';
71  public const KEY_TEST_IP_RANGE = 'ip_range_label';
72  public const KEY_TEST_FIXED_PARTICIPANTS = 'participants_invitation';
73  public const KEY_TEST_LIMIT_NR_OF_TRIES = 'tst_limit_nr_of_tries';
74  public const KEY_TEST_BLOCK_AFTER_PASSED = 'tst_block_passes_after_passed';
75  public const KEY_TEST_PASSWAITING_ENABLED = 'tst_pass_waiting_enabled';
76  public const KEY_TEST_PROCESSING_TIME_ENABLED = 'tst_processing_time_duration';
77  public const KEY_TEST_RESET_PROCESSING_TIME = 'tst_reset_processing_time';
78  public const KEY_TEST_ADDED_PROCESSING_TIME = 'minutes';
79  public const KEY_TEST_KIOSK_ENABLED = 'kiosk';
80  public const KEY_TEST_KIOSK_SHOW_TITLE = 'kiosk_show_title';
81  public const KEY_TEST_KIOSK_SHOW_PARTICIPANT_NAME = 'kiosk_show_participant';
82  public const KEY_TEST_SHOW_EXAM_ID = 'examid_in_test_pass';
83  public const KEY_TEST_TITLE_PRESENTATION = 'tst_title_output';
84  public const KEY_TEST_AUTOSAVE_ENABLED = 'autosave';
85  public const KEY_TEST_SHUFFLE_QUESTIONS = 'tst_shuffle_questions';
86  public const KEY_TEST_FEEDBACK_ENABLED = 'tst_instant_feedback';
87  public const KEY_TEST_FEEDBACK_SHOW_POINTS = 'tst_instant_feedback_results';
88  public const KEY_TEST_FEEDBACK_SHOW_GENERIC = 'tst_instant_feedback_answer_generic';
89  public const KEY_TEST_FEEDBACK_SHOW_SPECIFIC = 'tst_instant_feedback_answer_specific';
90  public const KEY_TEST_FEEDBACK_SHOW_SOLUTION = 'tst_instant_feedback_solution';
91  public const KEY_TEST_FEEDBACK_TRIGGER = 'tst_instant_feedback_trigger';
92  public const KEY_TEST_LOCK_ANSWERS_MODE = 'tst_answer_fixation_handling';
93  public const KEY_TEST_USE_PREVIOUS_ANSWERS_ENABELD = 'tst_use_previous_answers';
94  public const KEY_TEST_SUSPEND_ALLOWED = 'tst_show_cancel';
95  public const KEY_TEST_POSTPONED_MOVE_TO_END = 'tst_postpone';
96  public const KEY_TEST_OVERVIEW_ENABLED = 'tst_show_summary';
97  public const KEY_TEST_OVERVIEW_SHOW_START = 'tst_list_of_questions_start';
98  public const KEY_TEST_OVERVIEW_SHOW_END = 'tst_list_of_questions_end';
99  public const KEY_TEST_OVERVIEW_SHOW_DESCRIPTION = 'tst_list_of_questions_with_description';
100  public const KEY_TEST_QUESTION_MARKING_ENABLED = 'question_marking';
101  public const KEY_TEST_QUESTION_LIST_ENABLED = 'tst_enable_questionlist';
102  public const KEY_TEST_ANSWER_OVERVIEW_ENABLED = 'enable_examview';
103  public const KEY_TEST_CONCLUDING_REMARKS_ENABLED = 'final_statement';
104  public const KEY_TEST_REDIRECT_MODE = 'redirect_after_finishing_tst';
105  public const KEY_TEST_REDIRECT_URL = 'redirection_url';
106  public const KEY_TEST_MAIL_NOTIFICATION_CONTENT_TYPE = 'tst_finish_notification';
107  public const KEY_TEST_ALWAYS_SEND_NOTIFICATION = 'tst_finish_notification_content_type';
108  public const KEY_TEST_TAXONOMIES_ENABLED = 'tst_activate_skill_service';
109  public const KEY_TEST_HIDE_INFO_TAB = 'tst_hide_info_tab';
110 
111  public const KEY_SCORING_COUNT_SYSTEM = 'tst_text_count_system';
112  public const KEY_SCORING_SCORE_CUTTING = 'tst_score_cutting';
113  public const KEY_SCORING_PASS_SCORING = 'tst_pass_scoring';
114  public const KEY_SCORING_REPORTING = 'tst_results_access_setting';
115  public const KEY_SCORING_REPORTING_SHOW_STATUS = 'tst_results_grading_opt_show_status';
116  public const KEY_SCORING_REPORTING_SHOW_MARK = 'tst_results_grading_opt_show_mark';
117  public const KEY_SCORING_REPORTING_SHOW_DETAILS = 'tst_results_grading_opt_show_details';
118  public const KEY_SCORING_DELETION_ALLOWED = 'tst_pass_deletion';
119  public const KEY_SCORING_SOLUTION_SHOW_BEST_SOLUTION = 'tst_results_print_best_solution';
120  public const KEY_SCORING_SOLUTION_SHOW_FEEDBACK = 'tst_show_solution_feedback';
121  public const KEY_SCORING_SOLUTION_SHOW_SUGGESTED = 'tst_show_solution_suggested';
122  public const KEY_SCORING_SOLUTION_SHOW_PRINTVIEW = 'tst_show_solution_printview';
123  public const KEY_SCORING_SOLUTION_SHOW_ANSWERS_ONLY = 'tst_hide_pagecontents';
124  public const KEY_SCORING_SOLUTION_SHOW_SIGNATRUE = 'tst_show_solution_signature';
125  public const KEY_SCORING_SOLUTION_SHOW_EXAM_ID = 'examid_in_test_res';
126  public const KEY_SCORING_HIGHSCORE_ENABLED = 'tst_highscore_enabled';
127  public const KEY_SCORING_HIGHSCORE_MODE = 'tst_highscore_mode';
128  public const KEY_SCORING_HIGHSCORE_SHOW_TOP_NUM = 'tst_highscore_top_num';
129  public const KEY_SCORING_HIGHSCORE_SHOW_ANON = 'tst_highscore_anon';
130  public const KEY_SCORING_HIGHSCORE_SHOW_ACHIEVED_TS = 'tst_highscore_achieved_ts';
131  public const KEY_SCORING_HIGHSCORE_SHOW_SCORE = 'tst_highscore_score';
132  public const KEY_SCORING_HIGHSCORE_SHOW_PERCENTAGE = 'tst_highscore_percentage';
133  public const KEY_SCORING_HIGHSCORE_SHOW_WTIME = 'tst_highscore_wtime';
134 
135  public const KEY_PASS = 'pass';
136  public const KEY_PAX_ANSWER = 'answer';
137 
138  public const KEY_QUESTION_SHUFFLE_ANSWER_OPTIONS = 'shuffle_answers';
139  public const KEY_QUESTION_FEEDBACK_ON_INCOMPLETE = 'feedback_incomplete_solution';
140  public const KEY_QUESTION_FEEDBACK_ON_COMPLETE = 'feedback_complete_solution';
141  public const KEY_QUESTION_ANSWER_OPTION = 'answer';
142  public const KEY_QUESTION_ANSWER_OPTIONS = 'answers';
143  public const KEY_QUESTION_CORRECT_ANSWER_OPTIONS = 'correct_answers';
144  public const KEY_QUESTION_LONGMENU_TEXT = 'lmtext';
145  public const KEY_QUESTION_KPRIM_OPTION_LABEL = 'option_label';
146  public const KEY_QUESTION_REACHABLE_POINTS = 'points';
147  public const KEY_QUESTION_TEXT_MATCHING_METHOD = 'matching_method';
148  public const KEY_QUESTION_FORMULA_VARIABLES = 'variables';
149  public const KEY_QUESTION_FORMULA_RESULTS = 'results';
150  public const KEY_QUESTION_FORMULA_VARIABLE = 'variable';
151  public const KEY_QUESTION_FORMULA_RESULT = 'result';
152  public const KEY_QUESTION_FORMULA_PRECISION = 'precision';
153  public const KEY_QUESTION_FORMULA_INTPRECISION = 'intprecision';
154  public const KEY_QUESTION_FORMULA_TOLERANCE = 'tolerance';
155  public const KEY_QUESTION_FORMULA_UNIT = 'unit';
156  public const KEY_QUESTION_FORMULA_RESULT_TYPE = 'result_type_selection';
157  public const KEY_QUESTION_FORMULA_FORMULA = 'formula';
158  public const KEY_QUESTION_ORDERING_NESTING_TYPE = 'qst_use_nested_answers';
159  public const KEY_QUESTION_ANSWER_OPTION_IMAGE = 'image';
160  public const KEY_QUESTION_ANSWER_OPTION_ORDER = 'order';
161  public const KEY_QUESTION_ANSWER_OPTION_CORRECTNESS = 'correctness';
162  public const KEY_QUESTION_POINTS_CHECKED = 'points_checked';
163  public const KEY_QUESTION_POINTS_UNCHECKED = 'points_unchecked';
164  public const KEY_QUESTION_IMAGEMAP_IMAGE = 'image';
165  public const KEY_QUESTION_IMAGEMAP_MODE = 'tst_imap_qst_mode';
166  public const KEY_QUESTION_IMAGEMAP_ANSWER_OPTION_COORDS = 'coordinates';
168  public const KEY_QUESTION_TEXTSIZE = 'textsize';
169  public const KEY_QUESTION_UPLOAD_MAXSIZE = 'maxsize';
170  public const KEY_QUESTION_UPLOAD_ALLOWED_EXTENSIONS = 'allowedextensions';
171  public const KEY_QUESTION_UPLOAD_COMPLETION_BY_SUBMISSION = 'ass_completion_by_submission';
172  public const KEY_QUESTION_ERRORTEXT_ERRORTEXT = 'assErrorText';
173  public const KEY_QUESTION_MAXCHARS = 'maxchars';
174  public const KEY_QUESTION_LOWER_LIMIT = 'range_lower_limit';
175  public const KEY_QUESTION_UPPER_LIMIT = 'range_upper_limit';
176  public const KEY_QUESTION_MATCHING_TERM = 'term';
177  public const KEY_QUESTION_MATCHING_TERMS = 'terms';
178  public const KEY_QUESTION_MATCHING_DEFINITION = 'definition';
179  public const KEY_QUESTION_MATCHING_DEFINITIONS = 'definitions';
180  public const KEY_QUESTION_CLOZE_CLOZETEXT = 'cloze_text';
181  public const KEY_QUESTION_CLOZE_GAPS = 'gaps';
182  public const KEY_QUESTION_CLOZE_GAP_TYPE = 'type';
183  public const KEY_QUESTION_KPRIM_SCORE_PARTIAL_SOLUTION_ENABLED = 'score_partsol_enabled';
184  public const KEY_QUESTION_TEXT_WORDCOUNT_ENABLED = 'qst_essay_wordcounter_enabled';
185  public const KEY_QUESTION_TEXT_SCORING_MODE = 'essay_scoring_mode';
186 
187  private const TAG_NONE = '{{ none }}';
188  private const TAG_TRUE = '{{ true }}';
189  private const TAG_FALSE = '{{ false }}';
190  private const TAG_ENABLED = '{{ enabled }}';
191  private const TAG_DISABLED = '{{ disabled }}';
192  private const TAG_CHECKED = '{{ checked }}';
193  private const TAG_UNCHECKED = '{{ unchecked }}';
194 
195  private const VALID_TAGS = [
196  'none',
197  'enabled',
198  'disabled',
199  'true',
200  'false',
201  'checked',
202  'unchecked',
203  'seconds',
204  'redirect_always',
205  'gap',
206  'points',
207  'type',
208  'answers_select',
209  'answers_text_box',
210  'tst_finish_notification_simple',
211  'tst_finish_notification_advanced',
212  'test_question_set_type_fixed',
213  'tst_title_output_full',
214  'tst_title_output_hide_points',
215  'tst_title_output_no_title',
216  'tst_title_output_only_points',
217  'tst_instant_feedback_trigger_forced',
218  'tst_instant_feedback_trigger_manual',
219  'tst_answer_fixation_none',
220  'tst_answer_fixation_on_instantfb_or_followupqst',
221  'tst_answer_fixation_on_instant_feedback',
222  'tst_answer_fixation_on_followup_question',
223  'tst_highscore_own_table',
224  'tst_highscore_top_table',
225  'tst_highscore_all_tables',
226  'tst_results_access_setting',
227  'tst_results_access_finished',
228  'tst_results_access_always',
229  'tst_results_access_setting',
230  'tst_results_access_passed',
231  'tst_count_partial_solutions',
232  'tst_count_correct_solutions',
233  'tst_score_cut_question',
234  'tst_score_cut_test',
235  'tst_pass_last_pass',
236  'tst_pass_best_pass',
237  'tst_inp_quest_amount_cfg_mode_pool',
238  'tst_imap_qst_mode_mc',
239  'tst_imap_qst_mode_sc',
240  'option_label_right_wrong',
241  'option_label_plus_minus',
242  'option_label_applicable_or_not',
243  'option_label_adequate_or_not',
244  'option_label_custom',
245  'qpl_qst_inp_matching_mode_one_on_one',
246  'qpl_qst_inp_matching_mode_all_on_all',
247  'essay_scoring_mode_without_keywords',
248  'essay_scoring_mode_keyword_relation_any',
249  'essay_scoring_mode_keyword_relation_all',
250  'essay_scoring_mode_keyword_relation_one',
251  'qst_nested_nested_answers_off',
252  'qst_nested_nested_answers_on',
253  'oq_btn_use_order_pictures',
254  'oq_btn_use_order_terms',
255  ];
256 
261  private const LEGACY_TAGS = [];
262 
263  private array $tags;
264 
265  public function __construct(
266  private readonly \Mustache_Engine $mustache,
267  private readonly \ilLanguage $lng,
268  private readonly UIFactory $ui_factory,
269  private readonly Refinery $refinery,
270  private readonly GeneralQuestionPropertiesRepository $questions_repo
271  ) {
272  $lng->loadLanguageModule('assessment');
273  $lng->loadLanguageModule('crs');
274  $this->tags = $this->buildTags();
275  }
276 
277  public function parseForTable(
278  array $additional_info,
279  array $environment
280  ): DescriptiveListing {
288  return $this->ui_factory->listing()->descriptive(
289  array_combine(
290  array_map(
291  fn(string $k): string => $this->getCorrectedTranslationForKey($k) . ' ',
292  array_keys($additional_info)
293  ),
294  array_map(
295  fn(string $k): string => $this->parseValue($k, $additional_info[$k], $environment),
296  array_keys($additional_info)
297  )
298  )
299  );
300  }
301 
302  public function parseForExport(
303  array $additional_info,
304  array $environment
305  ): string {
306  return implode(
307  '; ',
308  array_map(
309  fn(string $k) => "{$this->getCorrectedTranslationForKey($k)}: {$this->parseValue($k, $additional_info[$k] ?? '', $environment)}",
310  array_keys($additional_info)
311  )
312  );
313  }
314 
315  public function getTrueFalseTagForBool(bool $bool): string
316  {
317  return $bool ? self::TAG_TRUE : self::TAG_FALSE;
318  }
319 
320  public function getEnabledDisabledTagForBool(bool $bool): string
321  {
322  return $bool ? self::TAG_ENABLED : self::TAG_DISABLED;
323  }
324 
325  public function getCheckedUncheckedTagForBool(bool $bool): string
326  {
327  return $bool ? self::TAG_CHECKED : self::TAG_UNCHECKED;
328  }
329 
330  public function getNoneTag(): string
331  {
332  return self::TAG_NONE;
333  }
334 
335  public function getTagForLangVar(string $lang_var): string
336  {
337  return "{{ {$lang_var} }}";
338  }
339 
340  private function getCorrectedTranslationForKey(string $key): string
341  {
342  $lang_var = $key;
343  if (array_key_exists($key, self::LEGACY_TAGS)) {
344  $lang_var = self::LEGACY_TAGS[$key];
345  }
346 
347  return $this->lng->exists($lang_var) ? $this->lng->txt($lang_var) : $key;
348  }
349 
350  private function parseValue(
351  int|string $key,
352  string|int|float|array $value,
353  array $environment
354  ): string {
355  switch ($key) {
356  case self::KEY_USER:
357  return \ilUserUtil::getNamePresentation(
358  $value,
359  false,
360  false,
361  '',
362  true
363  );
364  case self::KEY_USERS:
365  return $this->buildListOfUsers($value);
366  case self::KEY_QUESTION_TYPE:
367  return $this->lng->txt($value);
368  case self::KEY_QUESTIONS:
369  return implode(
370  ', ',
371  array_map(
372  fn(int $usr): string => $this->questions_repo
373  ->getForQuestionId($usr)?->getTitle() ?? $this->lng->txt('deleted'),
374  $value
375  )
376  );
377  case self::KEY_QUESTION_ID:
378  if (is_int($value)) {
379  return $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform(
380  $this->questions_repo->getForQuestionId($value)?->getTitle() ?? $this->lng->txt('deleted')
381  );
382  }
383  //no break
384  default:
385  return $this->buildDefaultValueString($value, $environment);
386  }
387  }
388 
389  private function buildListOfUsers(array $user_ids): string
390  {
391  return implode(
392  ', ',
393  array_map(
394  static fn(int $usr): string => \ilUserUtil::getNamePresentation(
395  $usr,
396  false,
397  false,
398  '',
399  true
400  ),
401  $user_ids
402  )
403  );
404  }
405 
406  private function buildDefaultValueString(
407  string|int|float|array $value,
408  array $environment
409  ): string {
410  if (is_int($value)
411  || is_float($value)) {
412  return (string) $value;
413  }
414  if (is_array($value)) {
415  return $this->buildValueStringFromArray($value, $environment);
416  }
417  if ($value === '') {
418  return $this->lng->txt('none');
419  }
420  if (strpos($value, '+0000') !== false
421  && ($date = \DateTimeImmutable::createFromFormat(self::DATE_STORAGE_FORMAT, $value)) !== false) {
422  return $date
423  ->setTimezone($environment['timezone'])
424  ->format($environment['date_format']);
425  }
426  return $this->mustache->render(
427  $this->refinery->string()->stripTags()->transform($value),
429  );
430  }
431 
432  private function buildValueStringFromArray(array $value, array $environment): string
433  {
434  return array_reduce(
435  array_keys($value),
436  function ($c, $k) use ($value, $environment): string {
437  $label = $k;
438  if (is_string($k)) {
439  $label = $this->getCorrectedTranslationForKey($k);
440  }
441  if ($c !== '') {
442  $c .= ', ';
443  }
444  return "{$c}{$label}: {$this->parseValue($k, $value[$k], $environment)}";
445  },
446  ''
447  );
448  }
449 
450  private function buildTags(): array
451  {
452  return array_combine(
453  self::VALID_TAGS,
454  array_map(
455  fn(string $v): string => $this->lng->txt($v),
456  self::VALID_TAGS
457  )
458  ) + array_reduce(
459  array_keys(self::LEGACY_TAGS),
460  function (array $c, string $k): array {
461  $c[$k] = $this->lng->txt(self::LEGACY_TAGS[$k]);
462  return $c;
463  },
464  []
465  );
466  }
467 }
parseValue(int|string $key, string|int|float|array $value, array $environment)
$c
Definition: deliver.php:25
parseForExport(array $additional_info, array $environment)
static getNamePresentation( $a_user_id, bool $a_user_image=false, bool $a_profile_link=false, string $a_profile_back_link='', bool $a_force_first_lastname=false, bool $a_omit_login=false, bool $a_sortable=true, bool $a_return_data_array=false, $a_ctrl_path='ilpublicuserprofilegui')
Default behaviour is:
__construct(private readonly \Mustache_Engine $mustache, private readonly \ilLanguage $lng, private readonly UIFactory $ui_factory, private readonly Refinery $refinery, private readonly GeneralQuestionPropertiesRepository $questions_repo)
buildDefaultValueString(string|int|float|array $value, array $environment)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
global $lng
Definition: privfeed.php:31
parseForTable(array $additional_info, array $environment)