ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
AttemptResultsTable.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
25 use ILIAS\UI\Component\Table\Presentation as PresentationTable;
34 
36 {
37  private const ENV = 'e';
38  private const LNG = 'l';
39  private const URL_NAMESPACE = ['taresult', 'vc'];
40  private const PARAM_MODE = 'm';
41  private const MODE_OPT_ALL = "all";
42  private const MODE_OPT_CORRECT = "ok";
43  private const MODE_OPT_INCORRECT = "fail";
44  private const PARAM_SORT = 's';
45  private const SORT_OPT_ORDEROFAPPEARANCE = 'ooa';
46  private const SORT_OPT_POSSIBLESCORE = 'ms';
47 
48  protected PresentationTable $table;
49 
50  public function __construct(
51  UIFactory $ui_factory,
52  private UIRenderer $ui_renderer,
53  private Refinery $refinery,
54  private HTTPService $http,
55  DataFactory $data_factory,
56  Language $lng,
57  private AttemptResult $test_results,
58  Settings $settings,
59  string $title,
60  bool $for_print
61  ) {
62  list($mode, $sortation) = $this->getViewControlsParameter();
63  $results = $this->applyControls($mode, $sortation, $test_results->getQuestionResults());
64  $target = new URLBuilder($data_factory->uri($http->request()->getUri()->__toString()));
65 
66  $this->table = $ui_factory->table()->presentation(
67  $title,
68  $for_print ? [] : $this->getViewControls($ui_factory, $lng, $target, $mode, $sortation),
69  $this->getMapping()
70  )
71  ->withEnvironment([
72  self::ENV => $settings,
73  self::LNG => $lng
74  ])
75  ->withData($results);
76  }
77 
78  public function render(): string
79  {
80  return $this->ui_renderer->render($this->table);
81  }
82 
83  public function getTableComponent(): PresentationTable
84  {
85  return $this->table;
86  }
87 
91  private function applyControls(
92  string $mode,
93  string $sortation,
94  array $question_results
95  ) {
96  switch ($mode) {
97  case self::MODE_OPT_CORRECT:
98  $filter = static fn($qr) => $qr->getCorrect() === QuestionResult::CORRECT_FULL;
99  break;
100  case self::MODE_OPT_INCORRECT:
101  $filter = static fn($qr) => $qr->getCorrect() !== QuestionResult::CORRECT_FULL;
102  break;
103  case self::MODE_OPT_ALL:
104  default:
105  $filter = static fn($qr) => true;
106  }
107  $question_results = array_filter($question_results, $filter);
108 
109  if ($sortation === self::SORT_OPT_POSSIBLESCORE) {
110  usort(
111  $question_results,
112  static fn(QuestionResult $a, QuestionResult $b) => $a->getQuestionScore() <=> $b->getQuestionScore()
113  );
114  $question_results = array_reverse($question_results);
115  }
116  return $question_results;
117  }
118 
119  private function getViewControlNamespace(): array
120  {
121  $namespace = self::URL_NAMESPACE;
122  $namespace[] = (string) $this->test_results->getActiveId();
123  $namespace[] = (string) $this->test_results->getAttempt();
124  return $namespace;
125  }
126 
127  private function getViewControlsParameter(): array
128  {
129  $request = $this->http->wrapper()->query();
131 
132  $mode = $request->has($pre . self::PARAM_MODE) ?
133  $request->retrieve($pre . self::PARAM_MODE, $this->refinery->kindlyTo()->string()) : self::MODE_OPT_ALL;
134 
135  $sortation = $request->has($pre . self::PARAM_SORT) ?
136  $request->retrieve($pre . self::PARAM_SORT, $this->refinery->kindlyTo()->string()) : self::SORT_OPT_ORDEROFAPPEARANCE;
137 
138  return [$mode, $sortation];
139  }
140 
144  private function getViewControls(
145  UIFactory $ui_factory,
146  Language $lng,
147  URLBuilder $target,
148  string $mode,
149  string $sortation
150  ): array {
151  $builder = $target->acquireParameter($this->getViewControlNamespace(), self::PARAM_MODE);
152  [$target, $token] = $builder;
153 
154  $modes = [
155  $lng->txt('resulttable_all') => $target->withParameter($token, self::MODE_OPT_ALL)->buildURI()->__toString(),
156  $lng->txt('resulttable_correct') => $target->withParameter($token, self::MODE_OPT_CORRECT)->buildURI()->__toString(),
157  $lng->txt('resulttable_incorrect') => $target->withParameter($token, self::MODE_OPT_INCORRECT)->buildURI()->__toString(),
158  ];
159  $check = [self::MODE_OPT_ALL, self::MODE_OPT_CORRECT, self::MODE_OPT_INCORRECT];
160  $active = array_search($mode, $check);
161 
162  $vc_mode = $ui_factory->viewControl()->mode($modes, $lng->txt('ta_resulttable_vc_mode_aria'))
163  ->withActive(array_keys($modes)[$active]);
164 
165  $options = [
166  self::SORT_OPT_ORDEROFAPPEARANCE => $lng->txt('resulttable_vc_sort_iooa'),
167  self::SORT_OPT_POSSIBLESCORE => $lng->txt('resulttable_vc_sort_posscore')
168  ];
169 
171  $vc_sort = $ui_factory->viewControl()->sortation($options, $sortation)->withTargetURL(
172  $target->buildURI()->__toString(),
173  $pre . self::PARAM_SORT
174  );
175 
176  return [
177  $vc_mode,
178  $vc_sort
179  ];
180  }
181 
182  private function getMapping(): \Closure
183  {
184  return function (PresentationRow $row, QuestionResult $question, UIFactory $ui_factory, array $environment) {
185  $env = $environment[self::ENV];
186  $lng = $environment[self::LNG];
187 
188  $title = $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform(
189  $question->getTitle()
190  );
191 
192  $important_fields = [
193  $lng->txt('position') => (string) ($question->getPosition() + 1),
194  $lng->txt('question_id') => (string) $question->getId(),
195  $lng->txt('question_type') => $lng->txt($question->getType()),
196  $lng->txt('points') => sprintf(
197  '%s/%s (%s%%)',
198  (string) $question->getUserScore(),
199  (string) $question->getQuestionScore(),
200  (string) $question->getUserScorePercent()
201  )
202  ];
203 
204  $stats_fields = $important_fields;
205  $stats_fields[$lng->txt('tst_question_hints_requested_hint_count_header')] = (string) $question->getNumberOfRequestedHints();
206  $stats = $ui_factory->listing()->characteristicValue()->text($stats_fields);
207 
208 
209  $feedback = $ui_factory->listing()->descriptive([
210  $lng->txt('tst_feedback') => $question->getFeedback()
211  ]);
212 
213  $contents = [];
214 
215  $contents[] = $stats;
216  if ($env->getShowFeedback()) {
217  $contents[] = $feedback;
218  }
219 
220  if ($recap = $question->getContentForRecapitulation()) {
221  $contents[] = $ui_factory->listing()->descriptive([
222  $lng->txt('suggested_solution') => $recap
223  ]);
224  }
225 
226  $listing = [
227  $lng->txt('tst_header_participant') => $question->getUserAnswer()
228  ];
229  if ($autosave_content = $question->getAutosavedAnswer()) {
230  $listing[$lng->txt('autosavecontent')] = $autosave_content;
231  }
232 
233  $answer_contents = [
234  $ui_factory->listing()->descriptive($listing)
235  ];
236  if ($env->getShowBestSolution()) {
237  $answer_contents[] = $ui_factory->listing()->descriptive([
238  $lng->txt('tst_header_solution') => $question->getBestSolution()
239  ]);
240  }
241 
242  $answers = $ui_factory->layout()->alignment()->horizontal()->evenlyDistributed(...$answer_contents);
243  $contents[] = $answers;
244 
245  $content = $ui_factory->layout()->alignment()->vertical(...$contents);
246 
247  switch ($question->getCorrect()) {
249  $icon_name = 'icon_ok.svg';
250  $label = $lng->txt("answer_is_right");
251  break;
253  $icon_name = 'icon_mostly_ok.svg';
254  $label = $lng->txt("answer_is_not_correct_but_positive");
255  break;
257  $icon_name = 'icon_not_ok.svg';
258  $label = $lng->txt("answer_is_wrong");
259  break;
260  }
261  $path = \ilUtil::getImagePath('standard/' . $icon_name);
262  $correct_icon = $ui_factory->symbol()->icon()->custom(
263  $path,
264  $label
265  );
266 
267  return $row
268  ->withHeadline($title)
269  ->withLeadingSymbol($correct_icon)
270  ->withImportantFields($important_fields)
271  ->withContent($content);
272  };
273  }
274 }
if($err=$client->getError()) $namespace
buildURI()
Get a URI representation of the full URL including query string and fragment/hash.
Definition: URLBuilder.php:213
__construct(UIFactory $ui_factory, private UIRenderer $ui_renderer, private Refinery $refinery, private HTTPService $http, DataFactory $data_factory, Language $lng, private AttemptResult $test_results, Settings $settings, string $title, bool $for_print)
const SEPARATOR
Separator for parts of a parameter&#39;s namespace.
Definition: URLBuilder.php:49
$http
Definition: deliver.php:14
$path
Definition: ltiservices.php:30
txt(string $a_topic, string $a_default_lang_fallback_mod="")
applyControls(string $mode, string $sortation, array $question_results)
static http()
Fetches the global http state from ILIAS.
$token
Definition: xapitoken.php:67
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
withHeadline(string $headline)
Get a row like this with the given headline.
$results
This describes a Row used in Presentation Table.
getViewControls(UIFactory $ui_factory, Language $lng, URLBuilder $target, string $mode, string $sortation)
return array<>
This describes a Presentation Table.
withParameter(URLBuilderToken $token, string|array $value)
Change an acquired parameter&#39;s value if the supplied token is valid.
Definition: URLBuilder.php:165
global $lng
Definition: privfeed.php:32
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
$check
Definition: buildRTE.php:81
acquireParameter(array $namespace, string $name, ?string $initial_value=null)
Add a new parameter with a namespace and get its token for subsequent changes.
Definition: URLBuilder.php:118
URLBuilder.
Definition: URLBuilder.php:39