ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
ScoringByQuestionTableBinder.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
28
30{
31 private ?array $participant_data = null;
32 private array $filter_data = [];
33
34 public function __construct(
35 private readonly Language $lng,
36 private readonly \DateTimeZone $timezone,
37 private readonly \ilTestParticipantAccessFilterFactory $participant_access_filter_factory,
38 private readonly \ilObjTest $test_obj,
39 private readonly int $question_id
40 ) {
41 }
42
43 public function withFilterData(array $filter_data): self
44 {
45 $clone = clone $this;
46 $clone->filter_data = $filter_data;
47 return $clone;
48 }
49
50 public function getRows(
51 DataRowBuilder $row_builder,
52 array $visible_column_ids,
54 Order $order,
55 ?array $filter_data,
56 ?array $additional_parameters
57 ): \Generator {
58 if ($this->participant_data === null) {
59 $this->participant_data = $this->getFilteredData($this->question_id);
60 }
61 $this->sortData($order);
62 $data = array_slice($this->participant_data, $range->getStart(), $range->getLength());
63 foreach ($data as $row) {
64 if (in_array($row['usr_id'], $this->test_obj->getAnonOnlyParticipantIds())) {
66 }
67 yield $row_builder->buildDataRow(
68 array_shift($row),
69 $row
70 );
71 }
72 }
73
74 public function getTotalRowCount(
75 ?array $filter_data,
76 ?array $additional_parameters
77 ): ?int {
78 if ($this->participant_data === null) {
79 $this->participant_data = $this->getFilteredData($this->question_id);
80 }
81 return count($this->participant_data);
82 }
83
84 public function getMaxAttempts(): int
85 {
86 return $this->test_obj->getMaxPassOfTest();
87 }
88
89 private function getFilteredData(int $question_id): array
90 {
91 $complete_feedback = $this->test_obj->getCompleteManualFeedback($question_id);
92 $data = $this->test_obj->getCompleteEvaluationData();
93
94 $participants = $data->getParticipants();
95 $accessible_user_ids = call_user_func(
96 $this->participant_access_filter_factory->getScoreParticipantsUserFilter($this->test_obj->getRefId()),
97 $this->buildUserIdArrayFromParticipants($participants)
98 );
99 $accessible_participants = array_filter(
100 $participants,
101 static fn(\ilTestEvaluationUserData $v): bool => in_array($v->getUserID(), $accessible_user_ids)
102 );
103
104 return array_reduce(
105 array_keys($accessible_participants),
106 $this->getDataRowClosure($question_id, $accessible_participants, $complete_feedback),
107 []
108 );
109 }
110
111 private function sortData(
112 Order $order
113 ): void {
114 $key = key($order->get());
115 $direction = $order->get()[$key];
116 usort(
117 $this->participant_data,
118 static function (array $a, array $b) use ($key, $direction): int {
119 $left = $a[$key] ?? null;
120 $right = $b[$key] ?? null;
121 if ($direction === 'ASC') {
122 return $left <=> $right;
123 }
124 return $right <=> $left;
125 }
126 );
127 }
128
129 private function getDataRowClosure(
130 int $question_id,
131 array $filtered_participants,
132 array $complete_feedback
133 ): \Closure {
134 return function (
135 array $c,
136 int $active_id
137 ) use ($question_id, $filtered_participants, $complete_feedback): array {
138 $array_of_attempts = $this->buildFilteredArrayOfAttempts(
139 $question_id,
140 $active_id,
141 $filtered_participants,
142 $complete_feedback
143 );
144 return [...$c, ...$array_of_attempts];
145 };
146 }
147
149 int $question_id,
150 int $active_id,
151 array $filtered_participants,
152 array $complete_feedback
153 ): array {
154 return array_reduce(
155 $filtered_participants[$active_id]->getPasses(),
156 function (
157 array $c,
159 ) use ($question_id, $active_id, $filtered_participants, $complete_feedback): array {
160 $question_result = $pd->getAnsweredQuestionByQuestionId($question_id);
161 $feedback_data = $complete_feedback[$active_id][$pd->getPass()][$question_id] ?? [];
162 if ($this->isFilteredAttempt($pd, $question_result, $feedback_data)) {
163 return $c;
164 }
165
166 $current_participant = $filtered_participants[$active_id];
167
168 $row = [
169 "{$active_id}_{$pd->getPass()}",
170 ScoringByQuestionTable::COLUMN_EXAMID => \ilObjTest::buildExamId($active_id, $pd->getPass(), $this->test_obj->getId()),
171 ScoringByQuestionTable::COLUMN_NAME => $current_participant->getName(),
172 ScoringByQuestionTable::COLUMN_ATTEMPT => $pd->getPass() + 1,
173 ScoringByQuestionTable::COLUMN_POINTS_REACHED => $question_result['reached'] ?? 0.0,
174 ScoringByQuestionTable::COLUMN_POINTS_AVAILABLE => $current_participant->getQuestionByAttemptAndId($pd->getPass(), $question_id)['points'] ?? 0.0,
175 ScoringByQuestionTable::COLUMN_FEEDBACK => $feedback_data['feedback'] ?? '',
176 ScoringByQuestionTable::COLUMN_FINALIZED => isset($feedback_data['finalized_evaluation']) && $feedback_data['finalized_evaluation'] === 1,
177 ScoringByQuestionTable::COLUMN_FINALIZED_BY => $this->buildFinalizedByName($feedback_data),
178 'usr_id' => $current_participant->getUserId()
179 ];
180
181 if (isset($feedback_data['finalized_tstamp'])
182 && $feedback_data['finalized_tstamp'] !== 0) {
183 $row[ScoringByQuestionTable::COLUMN_FINALIZED_ON] = (new \DateTimeImmutable(
184 '@' . $feedback_data['finalized_tstamp']
185 )
186 )->setTimezone($this->timezone);
187 }
188 $c[] = $row;
189
190 return $c;
191 },
192 []
193 );
194 }
195
196 private function isFilteredAttempt(
198 ?array $question_info,
199 array $feedback_data
200 ): bool {
201 if ($this->filter_data === []) {
202 return false;
203 }
204
205 if ($this->filter_data[ScoringByQuestionTable::FILTER_FIELD_ONLY_ANSWERED] === '1'
206 && ($question_info === null || $question_info['isAnwered'] === false)
207 || $this->filter_data[ScoringByQuestionTable::COLUMN_ATTEMPT] !== ''
208 && $pd->getPass() !== (int) $this->filter_data[ScoringByQuestionTable::COLUMN_ATTEMPT]
209 || $this->filter_data[ScoringByQuestionTable::COLUMN_FINALIZED] === '1'
210 && (!isset($feedback_data['finalized_evaluation']) || $feedback_data['finalized_evaluation'] !== 1)
211 || $this->filter_data[ScoringByQuestionTable::COLUMN_FINALIZED] === '2'
212 && isset($feedback_data['finalized_evaluation']) && $feedback_data['finalized_evaluation'] === 1) {
213 return true;
214 }
215 return false;
216 }
217
223 private function buildUserIdArrayFromParticipants(array $participants): array
224 {
225 return array_reduce(
226 $participants,
227 static function (array $c, \ilTestEvaluationUserData $v): array {
228 if ($v->getUserID() === null) {
229 return $c;
230 }
231
232 $c[] = $v->getUserID();
233 return $c;
234 },
235 []
236 );
237 }
238
239 private function buildFinalizedByName(array $feedback_data): string
240 {
241 if (isset($feedback_data['finalized_by_usr_id'])
242 && $feedback_data['finalized_by_usr_id'] !== '') {
243 return \ilObjUser::_lookupFullname($feedback_data['finalized_by_usr_id']);
244 }
245 return '';
246 }
247}
Both the subject and the direction need to be specified when expressing an order.
Definition: Order.php:29
A simple class to express a naive range of whole positive numbers.
Definition: Range.php:29
__construct(private readonly Language $lng, private readonly \DateTimeZone $timezone, private readonly \ilTestParticipantAccessFilterFactory $participant_access_filter_factory, private readonly \ilObjTest $test_obj, private readonly int $question_id)
isFilteredAttempt(\ilTestEvaluationPassData $pd, ?array $question_info, array $feedback_data)
getRows(DataRowBuilder $row_builder, array $visible_column_ids, Range $range, Order $order, ?array $filter_data, ?array $additional_parameters)
This is called by the table to retrieve rows; map data-records to rows using the $row_builder e....
getDataRowClosure(int $question_id, array $filtered_participants, array $complete_feedback)
buildFilteredArrayOfAttempts(int $question_id, int $active_id, array $filtered_participants, array $complete_feedback)
getTotalRowCount(?array $filter_data, ?array $additional_parameters)
Mainly for the purpose of pagination-support, it is important to know about the total number of recor...
static buildExamId($active_id, $pass, $test_obj_id=null)
$c
Definition: deliver.php:25
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
get(string $class_name)
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
global $lng
Definition: privfeed.php:31
if(!file_exists('../ilias.ini.php'))