ILIAS  trunk Revision v12.0_alpha-1540-g00f839d5fa1
class.ConsecutiveScoringGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
23use ILIAS\UI\Factory as UIFactory;
24use ILIAS\UI\Renderer as UIRenderer;
26use Psr\Http\Message\ServerRequestInterface;
41
43{
44 public const CMD_VIEW = 'view';
45 public const DEFAULT_COMMAND = 'view';
46
47 private const ACTION_FORM_STATE = 'fs';
48 private const ACTION_STORE_STATE = 'ss';
49 private const ACTION_STORE = 'store';
50 private const ACTION_SCORING_COMPLETE = 'ucomplete';
51 private const ACTION_SCORING_INCOMPLETE = 'uincomplete';
52
53 private const FILTER_USERS = 'fusers';
54 private const FILTER_QUESTIONS = 'fquestions';
55 private const FILTER_ANSWERED = 'fanswerd';
56 private const FILTER_FINAL = 'ffinal';
57 private const FILTER_USER_FINAL = 'fusrfinal';
58 private const FILTER_ONLY = 'only';
59 private const FILTER_HIDE = 'hide';
60 private const FILTER_SCOREDBY = 'fscrby';
61
62 private ?array $filter_values = null;
63 private Prompt $prompt;
64
65 public function __construct(
66 protected readonly \ilCtrlInterface $ctrl,
67 protected readonly \ilGlobalTemplateInterface $tpl,
68 protected readonly \ilTabsGUI $tabs,
69 protected readonly \ilLanguage $lng,
70 protected readonly \ilObjTest $object,
71 protected readonly \ilTestAccess $test_access,
72 protected readonly UIFactory $ui_factory,
73 protected UIRenderer $ui_renderer,
74 protected readonly Refinery $refinery,
75 protected readonly ServerRequestInterface $request,
76 protected readonly ResponseHandler $test_response,
77 protected readonly ConsecutiveScoring $scoring,
78 protected readonly ConsecutiveScoringURLs $scoring_url_builder,
79 protected readonly \ilUIFilterService $filter_service,
80 ) {
81 $this->prompt = $this->ui_factory->prompt()->standard($this->scoring_url_builder->buildURI());
82 }
83 public function executeCommand(): void
84 {
85 if (!$this->test_access->checkScoreParticipantsAccess()
86 && !$this->test_access->checkScoreParticipantsAccessAnon()
87 ) {
88 \ilObjTestGUI::accessViolationRedirect();
89 }
90
91 if (!$this->object->getGlobalSettings()->isManualScoringEnabled()) {
92 // allow only if at least one question type is marked for manual scoring
93 $this->tpl->setOnScreenMessage('failure', $this->lng->txt('manscoring_not_allowed'), true);
94 $this->ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
95 }
96
97 $this->tabs->activateTab(TabsManager::TAB_ID_MANUAL_SCORING);
98
99 $act = $this->scoring_url_builder->getAction() ?? self::DEFAULT_COMMAND;
100 [$question_id, $user_id, $attempt_id] = $this->scoring_url_builder->getIdParameters();
101
102 switch ($act) {
104 $answer_section =
105 $this->ui_renderer->render([
106 $this->getUserRepresentation($user_id, $attempt_id),
107 $this->getUserAnswer($question_id, $user_id, $attempt_id, false, false),
108 ]);
109 $response = $this->ui_factory->prompt()->state()->show(
110 $this->getScoringForm(self::ACTION_STORE_STATE, $question_id, $user_id, $attempt_id)
111 )->withTitle( //TODO: should not be on state, but on form
112 $answer_section
113 );
114 $this->test_response->sendAsync(
115 $this->ui_renderer->renderAsync($response)
116 );
117 break;
118
120 $form = $this->getScoringForm(self::ACTION_STORE_STATE, $question_id, $user_id, $attempt_id)
121 ->withRequest($this->request);
122 $formdata = $form->getData();
123 if ($formdata !== null) {
124 $this->store($formdata);
125 $msg = sprintf(
126 $this->lng->txt('tst_saved_manscoring_successfully'),
127 $attempt_id + 1,
128 $this->scoring->getUserFullName($user_id, (string) $attempt_id)
129 );
130 $this->tpl->setOnScreenMessage('success', $msg, true);
131
132 $anchor = sprintf('anchor_%s_%s', $question_id, $user_id);
133 $url = $this->scoring_url_builder
134 ->withAction(self::CMD_VIEW)
135 ->withFragment($anchor)
136 ->withForceRedirect()
137 ->buildURI();
138 $response = $this->ui_factory->prompt()->state()->redirect($url);
139 } else {
140 $response = $this->ui_factory->prompt()->state()->show($form);
141 }
142
143 $this->test_response->sendAsync(
144 $this->ui_renderer->renderAsync($response)
145 );
146 break;
147
149 $form = $this->getScoringForm(self::ACTION_STORE, $question_id, $user_id, $attempt_id)
150 ->withRequest($this->request);
151 $formdata = $form->getData();
152 if ($formdata === null) {
153 $this->tpl->setContent($this->view());
154 } else {
155 $this->store($formdata);
156 $msg = sprintf(
157 $this->lng->txt('tst_saved_manscoring_successfully'),
158 $attempt_id + 1,
159 $this->scoring->getUserFullName($user_id, (string) $attempt_id)
160 );
161 $this->tpl->setOnScreenMessage('success', $msg, true);
162 $this->scoring_url_builder->withAction(self::CMD_VIEW)->redirect();
163 }
164 break;
165
167 $this->scoring->completeScoring($user_id, true);
168 $msg = $this->lng->txt('manscoring_finalized');
169 $this->tpl->setOnScreenMessage('success', $msg, true);
170 $this->scoring_url_builder->withAction(self::CMD_VIEW)->redirect();
171 break;
172
174 $this->scoring->completeScoring($user_id, false);
175 $msg = $this->lng->txt('manscoring_finalized_removed');
176 $this->tpl->setOnScreenMessage('success', $msg, true);
177 $this->scoring_url_builder->withAction(self::CMD_VIEW)->redirect();
178 break;
179
181 $this->tpl->setContent($this->view());
182 break;
183
184 default:
185 throw new \Exception('no such command/action: ' . $act);
186 }
187 }
188
189 protected function view(): string
190 {
191 $filter = $this->getFilterInputs();
192 $this->filter_values = $this->filter_service->getData($filter);
193
194 $sequence = $this->ui_factory->navigation()->sequence(
195 $this,
197 )
198 ->withId('cs_' . (string) $this->object->getRefId())
199 ->withViewControls($this->getViewControls())
200 ->withRequest($this->request);
201
202 return $this->ui_renderer->render([
203 $filter,
204 $sequence
205 ]);
206 }
207
211 public function getAllPositions(
212 ServerRequestInterface $request,
213 mixed $viewcontrol_values,
214 mixed $filter_values
215 ): array {
216 $filter_values = $this->filter_values;
217 return $this->scoring->getPositions()
218 ->applyFilters(...$this->getFilters($filter_values))
219 ->get($viewcontrol_values);
220 }
221
222 public function getSegment(
223 ServerRequestInterface $request,
224 mixed $position_data,
225 mixed $viewcontrol_values,
226 mixed $filter_values
227 ): Segment {
228 if ($position_data === null) {
229 return $this->ui_factory->legacy()->segment(
230 '',
231 $this->lng->txt('ui_table_no_records')
232 );
233 }
234
235 [$usr_active_ids, $question_ids] = $position_data;
236 $usr_active_id = current($usr_active_ids);
237 $question_id = current($question_ids);
238
239 $attempt_id = $this->scoring->getAttemptUsedForEvaluation($usr_active_id);
240 $question_representation = $this->getQuestionRepresentation($question_id, true);
241 $user_representation = $this->getUserRepresentation($usr_active_id, $attempt_id);
242
243 return $this->ui_factory->legacy()->segment(
244 $this->ui_renderer->render(
245 $viewcontrol_values->isUserCentric() ? $user_representation : $question_representation
246 ),
247 $this->ui_renderer->render(
248 $viewcontrol_values->isSingle()
249 ? [
250 $viewcontrol_values->isUserCentric() ? $question_representation : $user_representation,
251 $this->singleSegmentContent($question_id, $usr_active_id, $attempt_id, $request)
252 ]
253 : [
254 $viewcontrol_values->isUserCentric()
255 ? $this->collectForUser($usr_active_id, $question_ids)
256 : $this->collectForQuestion($question_id, $usr_active_ids),
257 $this->prompt
258 ]
259 )
260 )
261 ->withSegmentActions(
262 ...
263 $viewcontrol_values->isUserCentric()
264 ? $this->getSegmentActionsForUser($usr_active_id)
265 : []
266 );
267 }
268
269 protected function getViewControls(): ViewControlContainer
270 {
271 $vcs = [
272 $this->ui_factory->input()->viewControl()->mode(
273 [
274 ConsecutiveScoringMode::ORIENTATION_USER => $this->lng->txt('mode_user'),
275 ConsecutiveScoringMode::ORIENTATION_QUESTION => $this->lng->txt('mode_question'),
276 ]
277 ),
278 $this->ui_factory->input()->viewControl()->mode(
279 [
280 ConsecutiveScoringMode::MODE_ALL_AT_ONCE => $this->lng->txt('mode_allatonce'),
281 ConsecutiveScoringMode::MODE_ONE_BY_ONE => $this->lng->txt('mode_onebyone'),
282 ]
283 )
284 ];
285
286 return $this->ui_factory->input()->container()->viewControl()->standard($vcs)
287 ->withAdditionalTransformation(
288 $this->refinery->custom()->transformation(
289 fn($v) => new ConsecutiveScoringMode(...$v)
290 )
291 );
292 }
293
294 protected function getFilterInputs(): FilterContainer
295 {
296 $filter = [
297 self::FILTER_USERS => $this->ui_factory->input()->field()->multiselect(
298 $this->lng->txt('tst_man_scoring_userselection'),
299 $this->scoring->getParticipantNames()
300 ),
301 self::FILTER_QUESTIONS => $this->ui_factory->input()->field()->multiselect(
302 $this->lng->txt('tst_man_scoring_questionselection'),
303 $this->scoring->getQuestionTitles($this->lng)
304 ),
305 self::FILTER_ANSWERED => $this->ui_factory->input()->field()->select(
306 $this->lng->txt('tst_man_scoring_only_answered'),
307 [
308 self::FILTER_ONLY => $this->lng->txt('tst_man_scoring_answered_only'),
309 self::FILTER_HIDE => $this->lng->txt('tst_man_scoring_answered_hide'),
310 ]
311 )->withValue(null),
312 self::FILTER_FINAL => $this->ui_factory->input()->field()->select(
313 $this->lng->txt('tst_man_scoring_finalized'),
314 [
315 self::FILTER_ONLY => $this->lng->txt('tst_man_scoring_finalized_only'),
316 self::FILTER_HIDE => $this->lng->txt('tst_man_scoring_finalized_hide'),
317 ]
318 )->withValue(null),
319 self::FILTER_USER_FINAL => $this->ui_factory->input()->field()->select(
320 $this->lng->txt('finalized_evaluation'),
321 [
322 self::FILTER_ONLY => $this->lng->txt('evaluated_users'),
323 self::FILTER_HIDE => $this->lng->txt('not_evaluated_users')
324 ]
325 )->withValue(null),
326 self::FILTER_SCOREDBY => $this->ui_factory->input()->field()->multiselect(
327 $this->lng->txt('scored_by'),
328 $this->scoring->getAllFinalizingUserNames()
329 )->withValue(null),
330
331 ];
332 return $this->filter_service->standard(
333 'csfilter_' . (string) $this->object->getRefId(),
334 $this->ctrl->getLinkTarget($this, self::CMD_VIEW),
335 $filter,
336 array_map(fn() => true, $filter),
337 true,
338 true
339 );
340 }
344 protected function getFilters(
345 ?array $values_from_filter
346 ): array {
347 if ($values_from_filter === null) {
348 return [];
349 }
350 $filter_values = array_map(
351 fn($v) => $v === '' ? null : $v,
352 $values_from_filter
353 );
354
355 $ret = [];
356 if ($filter_values[self::FILTER_USERS] !== null) {
357 $ret[] = static fn(array $uids, array $qids): array => [
358 array_intersect($uids, $filter_values[self::FILTER_USERS]),
359 $qids
360 ];
361 }
362
363 if ($filter_values[self::FILTER_QUESTIONS] !== null) {
364 $ret[] = static fn(array $uids, array $qids): array => [
365 $uids,
366 array_intersect($qids, $filter_values[self::FILTER_QUESTIONS])
367 ];
368 }
369
370 if ($filter_values[self::FILTER_USER_FINAL] !== null) {
371 $ret[] = fn(array $uids, array $qids): array => [
372 array_filter(
373 $uids,
374 function ($uid) use ($filter_values) {
375 $complete = $this->scoring->isScoringComplete($uid);
376 $filter = $filter_values[self::FILTER_USER_FINAL];
377 return ($complete && $filter === self::FILTER_ONLY)
378 || (!$complete && $filter === self::FILTER_HIDE);
379 }
380 ),
381 $qids
382 ];
383 }
384
385 if ($filter_values[self::FILTER_ANSWERED] !== null) {
386 $answered = $this->scoring->getAnsweredQuestionIds();
387 $ret[] = function (array $uids, array $qids) use ($filter_values, $answered): array {
388 $qids = ($filter_values[self::FILTER_ANSWERED] === self::FILTER_ONLY)
389 ? array_intersect($qids, $answered[current($uids)])
390 : array_diff($qids, $answered[current($uids)]);
391 return [$uids, $qids];
392 };
393 }
394
395 if ($filter_values[self::FILTER_FINAL] !== null) {
396 $finalized = $this->scoring->getFinalizedFeedbackIds();
397 $ret[] = function (array $uids, array $qids) use ($filter_values, $finalized): array {
398 $qids = ($filter_values[self::FILTER_FINAL] === self::FILTER_ONLY)
399 ? array_intersect($qids, $finalized[current($uids)])
400 : array_diff($qids, $finalized[current($uids)]);
401 return [$uids, $qids];
402 };
403 }
404
405 if ($filter_values[self::FILTER_SCOREDBY] !== null) {
406 $scored_by = $this->scoring->getQidsFinalizedBy($filter_values[self::FILTER_SCOREDBY]);
407 $ret[] = static fn(array $uids, array $qids): array => [
408 $uids,
409 array_intersect($qids, $scored_by),
410 ];
411 }
412
413 return $ret;
414 }
415
416 protected function getUserRepresentation(int $usr_active_id, int $attempt_id): Entity
417 {
418 $usr_fullname = $this->scoring->getUserFullName($usr_active_id, (string) $attempt_id);
419 $usr_avatar = (new \ilUserAvatarResolver((int) $this->scoring->getUserId($usr_active_id, (string) $attempt_id)))->getAvatar();
420 $scored_participant_entity =
421 $this->ui_factory->entity()->standard(
422 $usr_fullname,
423 $usr_avatar
424 )->withDetails(
425 $this->ui_factory->listing()->property()->withProperty(
426 $this->lng->txt('scored_pass'),
427 (string) ($attempt_id + 1)
428 )->withProperty(
429 $this->lng->txt('usr_manscoring_complete'),
430 $this->scoring->isScoringComplete($usr_active_id) ?
431 $this->lng->txt('yes') : $this->lng->txt('no')
432 )->withProperty(
433 $this->lng->txt('exam_id'),
434 \ilObjTest::buildExamId($usr_active_id, $attempt_id, $this->object->getId())
435 )
436 );
437 return $scored_participant_entity;
438 }
439
440 protected function getQuestionRepresentation(int $question_id, bool $show_title = false): LegacyContent
441 {
442 $tpl = new \ilTemplate('tpl.il_as_tst_manual_scoring_consecutive_question.html', true, true, 'components/ILIAS/Test');
443 $question = $this->scoring->getQuestionObject($question_id);
444 $question_text = $question->getQuestion();
445
446 if ($show_title) {
447 $tpl->setCurrentBlock('expandable_title');
448 $question_title = $question->getTitle();
449 $tpl->setVariable('TITLE', $question_title);
450 } else {
451 $tpl->setCurrentBlock('question_only');
452 $tpl->setVariable('EXPAND_COLLAPSE', $this->lng->txt('expand') . '/' . $this->lng->txt('collapse'));
453 }
454 $tpl->setVariable('QUESTION', $question_text);
455 $tpl->parseCurrentBlock();
456
457 return $this->ui_factory->legacy()->content($tpl->get());
458 }
459
460 protected function getUserAnswer(
461 int $question_id,
462 int $usr_active_id,
463 int $attempt_id,
464 bool $show_feedback_html = false,
465 bool $show_grade_btn = false,
466 bool $show_properties = false
467 ): LegacyContent {
468 $question_gui = $this->scoring->getUserQuestionGUI($question_id, $usr_active_id, $attempt_id);
469 $question_solution = $question_gui->getSolutionOutput(
470 $usr_active_id,
471 $attempt_id,
472 $graphical_output = true,
473 $result_output = true,
474 $show_question_only = true,
475 $show_feedback = false,
476 $show_correct_solution = false,
477 $show_manual_scoring = true,
478 $show_question_text = false,
479 $show_inline_feedback = false
480 );
481 $tpl = new \ilTemplate('tpl.il_as_tst_manual_scoring_consecutive_answer.html', true, true, 'components/ILIAS/Test');
482
483 $usr_question = $question_gui->getObject();
484 $feedback = $this->scoring->getSingleManualFeedback($question_id, $usr_active_id, $attempt_id);
485
486 if ($show_properties) {
487 $info =
488 $this->ui_factory->listing()->property()
489 ->withProperty(
490 $this->lng->txt('tst_highscore_score'),
491 implode(' ', [
492 (string) $usr_question->getReachedPoints($usr_active_id, $attempt_id),
493 $this->lng->txt('tst_manscoring_input_of_max'),
494 (string) $usr_question->getMaximumPoints()
495 ])
496 )
497 ->withProperty(
498 $this->lng->txt('finalized_evaluation'),
499 (bool) ($feedback['finalized_evaluation'] ?? false) ?
500 $this->lng->txt('yes') : $this->lng->txt('no')
501 );
502 $info = $this->getWithFinalizedProperties($feedback, $info);
503 $tpl->setVariable('PROPERTIES', $this->ui_renderer->render($info));
504 }
505
506 $tpl->setVariable('ANSWER', $question_solution);
507 if (array_key_exists('feedback', $feedback) && $show_feedback_html) {
508 $tpl->setVariable(
509 'FEEDBACK',
510 $this->refinery->string()->markdown()->toHTML()->transform($feedback['feedback'])
511 );
512 } elseif ($show_feedback_html) {
513 $tpl->setVariable('FEEDBACK', $this->lng->txt('tst_manscoring_no_feedback'));
514 }
515 if ($show_grade_btn) {
516 $tpl->setVariable(
517 'GRADEBTN',
518 $this->ui_renderer->render(
519 $this->getSingleFormButton($question_id, $usr_active_id, $attempt_id)
520 )
521 );
522 }
523
524 return $this->ui_factory->legacy()->content($tpl->get());
525 }
526
527 protected function getScoringForm(string $action, int $question_id, int $usr_active_id, int $attempt_id): Form
528 {
529 $action = $this->scoring_url_builder
530 ->withAction($action)
531 ->withIdParameters($question_id, $usr_active_id, $attempt_id)
532 ->buildURI()->__toString();
533
534 $question = $this->scoring->getQuestionObject($question_id);
535 $max_points = $question->getMaximumPoints();
536 $score = $question->getReachedPoints($usr_active_id, $attempt_id);
537 $feedback = $this->scoring->getSingleManualFeedback($question_id, $usr_active_id, $attempt_id);
538 $feedback_final = (bool) ($feedback['finalized_evaluation'] ?? false);
539 $feedback_txt = $feedback['feedback'] ?? '';
540
541 $inputs = [];
542 $inputs[] = $this->ui_factory->input()->field()->numeric(
543 $this->lng->txt('tst_change_points_for_question')
544 )
545 ->withByline($this->lng->txt('tst_manscoring_input_of_max') . ' ' . $max_points)
547 $this->refinery->custom()->constraint(
548 fn($v) => (float) $v <= $max_points,
549 fn() => sprintf(
550 $this->lng->txt('tst_manscoring_maxpoints_exceeded_input_alert'),
551 $max_points
552 )
553 )
554 )
555 ->withAdditionalTransformation($this->refinery->kindlyTo()->float())
556 ->withValue($score);
557
558 $inputs[] = $this->ui_factory->input()->field()->markdown(
560 $this->lng->txt('set_manual_feedback')
561 )
562 ->withAdditionalTransformation($this->refinery->to()->string())
563 ->withValue($feedback_txt);
564
565 $inputs[] = $this->ui_factory->input()->field()->checkbox(
566 $this->lng->txt('finalized_evaluation')
567 )
568 ->withAdditionalTransformation($this->refinery->kindlyTo()->bool())
569 ->withValue($feedback_final);
570
571 $to_int = $this->refinery->kindlyTo()->int();
572 $inputs[] = $this->ui_factory->input()->field()->group(
573 [
574 $this->ui_factory->input()->field()->hidden()
575 ->withAdditionalTransformation($to_int)
576 ->withValue($question_id),
577 $this->ui_factory->input()->field()->hidden()
578 ->withAdditionalTransformation($to_int)
579 ->withValue($usr_active_id),
580 $this->ui_factory->input()->field()->hidden()
581 ->withAdditionalTransformation($to_int)
582 ->withValue($attempt_id)
583 ]
584 )
586 $this->refinery->custom()->transformation(
587 fn($values) => [
588 'qid' => $values[0],
589 'usr_active_id' => $values[1],
590 'attempt_id' => $values[2],
591 ]
592 )
593 );
594
595 return $this->ui_factory->input()->container()->form()->standard($action, $inputs)
596 ->withAdditionalTransformation(
597 $this->refinery->custom()->transformation(
598 fn($values) => [
599 'qid' => $values[3]['qid'],
600 'usr_active_id' => $values[3]['usr_active_id'],
601 'attempt' => $values[3]['attempt_id'],
602 'score' => $values[0],
603 'final' => $values[2] ?? false,
604 'feedback' => $values[1],
605 'max_points' => $max_points,
606 ]
607 )
608 );
609 }
610
611 protected function collectForUser(int $usr_active_id, array $question_ids): array
612 {
613 $attempt_id = $this->scoring->getAttemptUsedForEvaluation($usr_active_id);
614 $entries = [];
615 foreach ($question_ids as $question_id) {
616 $content = [
617 $this->getQuestionRepresentation($question_id, true),
618 $this->getUserAnswer($question_id, $usr_active_id, $attempt_id, true, true, true)
619 ];
620 $panel = $this->ui_factory->panel()->standard('', $content);
621 $entries[] = $this->ui_factory->legacy()->content(sprintf('<a id="anchor_%s_%s"></a>', $question_id, $usr_active_id));
622 $entries[] = $panel;
623 }
624 return $entries;
625 }
626
627 protected function collectForQuestion(int $question_id, array $usr_active_ids): array
628 {
629 $entries = [];
630 foreach ($usr_active_ids as $usr_active_id) {
631 $attempt_id = $this->scoring->getAttemptUsedForEvaluation($usr_active_id);
632 $content = [
633 $this->getUserRepresentation($usr_active_id, $attempt_id),
634 $this->getUserAnswer($question_id, $usr_active_id, $attempt_id, true, true, true)
635 ];
636 $panel = $this->ui_factory->panel()->standard('', $content);
637 $entries[] = $this->ui_factory->legacy()->content(sprintf('<a id="anchor_%s_%s"></a>', $question_id, $usr_active_id));
638 $entries[] = $panel;
639 }
640 return $entries;
641 }
642
643 protected function singleSegmentContent(
644 int $question_id,
645 int $usr_active_id,
646 int $attempt_id,
647 ServerRequestInterface $request
648 ): Alignment {
649 $form = $this->getScoringForm(self::ACTION_STORE, $question_id, $usr_active_id, $attempt_id);
650 if ($request->getMethod() === 'POST') {
651 $form = $form->withRequest($request);
652 }
653
654 $feedback_properties = $this->getWithFinalizedProperties(
655 $this->scoring->getSingleManualFeedback($question_id, $usr_active_id, $attempt_id),
656 $this->ui_factory->listing()->property()
657 );
658
659 return $this->ui_factory->layout()->alignment()->horizontal()->evenlyDistributed(
660 $this->getUserAnswer($question_id, $usr_active_id, $attempt_id),
661 $this->ui_factory->panel()->standard('', [$form, $feedback_properties])
662 );
663 }
664
665 protected function getSingleFormButton(int $question_id, int $usr_active_id, int $attempt_id): StdButton
666 {
667 $url = $this->scoring_url_builder
668 ->withAction(self::ACTION_FORM_STATE)
669 ->withIdParameters($question_id, $usr_active_id, $attempt_id)
670 ->buildURI();
671
672 return $this->ui_factory->button()->standard(
673 $this->lng->txt('edit_score'),
674 $this->prompt->getShowSignal($url)
675 );
676 }
677
678 protected function getSegmentActionsForUser(int $usr_active_id): array
679 {
680 $done_label = 'set_manscoring_done';
681 $done_action = self::ACTION_SCORING_COMPLETE;
682 if ($this->scoring->isScoringComplete($usr_active_id)) {
683 $done_label = 'set_manscoring_open';
684 $done_action = self::ACTION_SCORING_INCOMPLETE;
685 }
686 $btn_done = $this->ui_factory->button()->standard(
687 $this->lng->txt($done_label),
688 $this->scoring_url_builder
689 ->withAction($done_action)
690 ->withUserId($usr_active_id)
691 ->buildURI()->__toString()
692 );
693 return [$btn_done];
694 }
695
696 protected function store(array $data)
697 {
698 $this->scoring->store(
699 $data['qid'],
700 $data['usr_active_id'],
701 $data['attempt'],
702 $data['score'],
703 $data['final'],
704 $data['feedback'],
705 $data['max_points']
706 );
707 }
708
712 public function getWithFinalizedProperties(array $feedback, PropertyListing $info): PropertyListing
713 {
714 if (array_key_exists('finalized_by_usr_id', $feedback) && $feedback['finalized_by_usr_id'] !== 0) {
715 $feedback_usr_data = $this->object->getUserData([$feedback['finalized_by_usr_id']])[$feedback['finalized_by_usr_id']];
716 $feedback_usr_name = $feedback_usr_data['firstname'] . ' ' . $feedback_usr_data['lastname'];
717 $info = $info->withProperty(
718 $this->lng->txt('finalized_by'),
719 $feedback_usr_name
720 )->withProperty(
721 $this->lng->txt('finalized_on'),
722 (string) $feedback['finalized_time'],
723 false
724 );
725 }
726 return $info;
727 }
728}
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Builds data types.
Definition: Factory.php:36
getSingleFormButton(int $question_id, int $usr_active_id, int $attempt_id)
singleSegmentContent(int $question_id, int $usr_active_id, int $attempt_id, ServerRequestInterface $request)
__construct(protected readonly \ilCtrlInterface $ctrl, protected readonly \ilGlobalTemplateInterface $tpl, protected readonly \ilTabsGUI $tabs, protected readonly \ilLanguage $lng, protected readonly \ilObjTest $object, protected readonly \ilTestAccess $test_access, protected readonly UIFactory $ui_factory, protected UIRenderer $ui_renderer, protected readonly Refinery $refinery, protected readonly ServerRequestInterface $request, protected readonly ResponseHandler $test_response, protected readonly ConsecutiveScoring $scoring, protected readonly ConsecutiveScoringURLs $scoring_url_builder, protected readonly \ilUIFilterService $filter_service,)
getUserRepresentation(int $usr_active_id, int $attempt_id)
getAllPositions(ServerRequestInterface $request, mixed $viewcontrol_values, mixed $filter_values)
collectForUser(int $usr_active_id, array $question_ids)
getQuestionRepresentation(int $question_id, bool $show_title=false)
collectForQuestion(int $question_id, array $usr_active_ids)
getSegment(ServerRequestInterface $request, mixed $position_data, mixed $viewcontrol_values, mixed $filter_values)
Receives position data (provided by getAllPositions) and builds a segment.
getWithFinalizedProperties(array $feedback, PropertyListing $info)
getUserAnswer(int $question_id, int $usr_active_id, int $attempt_id, bool $show_feedback_html=false, bool $show_grade_btn=false, bool $show_properties=false)
getScoringForm(string $action, int $question_id, int $usr_active_id, int $attempt_id)
withDetails(PropertyListing|Content ... $details)
Definition: Entity.php:223
language handling
static buildExamId($active_id, $pass, $test_obj_id=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$info
Definition: entry_point.php:21
The SegmentRetrieval defines available stops for the sequence and builds it's segments.
An entity that renders components to a string output.
Definition: Renderer.php:31
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
withAdditionalTransformation(Transformation $trafo)
@inheritDoc
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:61
global $lng
Definition: privfeed.php:26
if(!file_exists('../ilias.ini.php'))
$url
Definition: shib_logout.php:70
$response
Definition: xapitoken.php:90