19 declare(strict_types=1);
46 private readonly \
ilObjUser $current_user,
50 private readonly
bool $scoredonly =
true 52 $this->user_date_format = $this->current_user->getDateTimeFormat();
53 $this->aggregated_data = $test_obj->getAggregatedResultsData();
54 $this->worksheet = new \ilExcel();
66 $this->worksheet->addSheet($this->
lng->txt(
'tst_results_aggregated'));
78 $this->worksheet->addSheet($this->
lng->txt(
'tst_results'));
85 $usersheet_titles = [];
86 foreach ($this->
getCompleteData()->getParticipants() as $active_id => $user_data) {
89 $user_data->getName(),
95 foreach ($passes as $pass) {
96 $pass_nr = $pass->getPass();
100 $user_data->getName(),
101 $user_data->getScoredPass() === $pass_nr
106 $user_data->getQuestions($pass_nr),
124 if (!str_ends_with(
$path, $extension)) {
128 $this->worksheet->writeToFile(
$path);
137 $this->worksheet->sendToClient($this->filename);
147 if ($this->complete_data ===
null) {
150 if ($this->
filter !== []) {
151 $filter_key = key($this->
filter);
152 $filter_text = current($this->
filter);
154 $this->complete_data = $this->test_obj->getCompleteEvaluationData($filter_key, $filter_text);
162 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'result'));
163 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'value'));
165 $this->worksheet->setBold(
'A' . $current_row .
':' . $this->worksheet->getColumnCoord($col - 1) . $current_row);
166 $this->worksheet->setColors(
'A' . $current_row .
':' . $this->worksheet->getColumnCoord($col - 1) . $current_row, self::EXCEL_BACKGROUND_COLOR);
167 return ++$current_row;
172 foreach ($this->aggregated_data[
'overview'] as $key => $value) {
174 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt($key));
175 $this->worksheet->setCell($current_row, $col++, $value);
178 return ++$current_row;
184 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'question_id'));
185 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'question_title'));
186 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'average_reached_points'));
187 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'points'));
188 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'percentage'));
189 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'number_of_answers'));
191 $this->worksheet->setBold(
'A' . $current_row .
':' . $this->worksheet->getColumnCoord($col - 1) . $current_row);
192 $this->worksheet->setColors(
'A' . $current_row .
':' . $this->worksheet->getColumnCoord($col - 1) . $current_row, self::EXCEL_BACKGROUND_COLOR);
193 return ++$current_row;
198 foreach ($this->aggregated_data[
'questions'] as $key => $value) {
200 $this->worksheet->setCell($current_row, $col++, $key);
201 $this->worksheet->setCell($current_row, $col++, $value[0]);
202 $this->worksheet->setCell($current_row, $col++, $value[4]);
203 $this->worksheet->setCell($current_row, $col++, $value[5]);
204 $this->worksheet->setCell($current_row, $col++, $value[6]);
205 $this->worksheet->setCell($current_row, $col++, $value[3]);
218 if (!$this->scoredonly) {
219 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'scored_pass'));
222 $this->worksheet->setCell(
225 $this->test_obj->getAnonymity() ? $this->
lng->txt(
'counter') : $this->
lng->txt(
'name')
228 if (!$this->test_obj->getAnonymity()) {
229 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'login'));
230 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'email'));
231 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'matriculation'));
232 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'gender'));
233 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'street'));
234 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'city'));
235 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'zipcode'));
236 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'country'));
237 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'institution'));
238 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'department'));
241 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_firstvisit'));
242 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_lastvisit'));
243 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_total_timeontask'));
245 if ($this->test_obj->isShowExamIdInTestResultsEnabled()) {
246 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'exam_id_label'));
249 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_resultspoints'));
250 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'maximum_points'));
251 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_resultsmarks'));
252 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_qmax'));
253 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_qworkedthrough'));
254 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_pworkedthrough'));
255 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_timeontask'));
256 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_atimeofwork'));
257 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_stat_result_rank_participant'));
258 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_tbl_col_started_passes'));
259 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'tst_tbl_col_finished_passes'));
260 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'scored_pass'));
261 $this->worksheet->setCell(1, $col++, $this->
lng->txt(
'pass'));
264 foreach ($this->question_repository->getForParentObjectId($this->test_obj->getId()) as $question_properties) {
265 $question_cols[$question_properties->getQuestionId()] = $col;
266 $this->worksheet->setCell(1, $col++, $question_properties->getTitle());
269 $this->worksheet->setBold(
'A1:' . $this->worksheet->getColumnCoord($col - 1) .
'1');
270 $this->worksheet->setColors(
'A1:' . $this->worksheet->getColumnCoord($col - 1) .
'1', self::EXCEL_BACKGROUND_COLOR);
272 return $question_cols;
275 private function addResultsContent(array $cols_for_question_ids):
void 278 foreach ($this->
getCompleteData()->getParticipants() as $active_id => $user_data) {
280 for ($test_attempt = 0; $test_attempt <= $user_data->getLastPass(); $test_attempt++) {
282 $is_scored_attempt = $test_attempt === $user_data->getScoredPass();
284 || $this->scoredonly && !$is_scored_attempt) {
289 $test_attempt_data = $user_data->getPass($test_attempt);
292 if (!$this->scoredonly) {
293 $this->worksheet->setCell(
296 $is_scored_attempt ?
'x' :
'' 300 $this->worksheet->setCell(
303 $this->test_obj->getAnonymity() ? $current_row - 1 : $user_data->getName()
305 if (!$this->test_obj->getAnonymity()) {
306 $this->worksheet->setCell($current_row, $col++, $user_data->getLogin());
307 $this->worksheet->setCell($current_row, $col++, $userfields[
'email'] ??
'');
308 $this->worksheet->setCell($current_row, $col++, $userfields[
'matriculation'] ??
'');
309 $this->worksheet->setCell($current_row, $col++, isset($userfields[
'gender']) && $userfields[
'gender'] !==
'' 310 ? $this->
lng->txt(
'gender_' . $userfields[
'gender'])
312 $this->worksheet->setCell($current_row, $col++, $userfields[
'street'] ??
'');
313 $this->worksheet->setCell($current_row, $col++, $userfields[
'city'] ??
'');
314 $this->worksheet->setCell($current_row, $col++, $userfields[
'zipcode'] ??
'');
315 $this->worksheet->setCell($current_row, $col++, $userfields[
'country'] ??
'');
316 $this->worksheet->setCell($current_row, $col++, $userfields[
'institution'] ??
'');
317 $this->worksheet->setCell($current_row, $col++, $userfields[
'departement'] ??
'');
324 if ($this->test_obj->isShowExamIdInTestResultsEnabled()) {
325 $this->worksheet->setCell($current_row, $col++, $test_attempt_data->getExamId());
328 $this->worksheet->setCell($current_row, $col++, $test_attempt_data->getReachedPoints());
329 $this->worksheet->setCell($current_row, $col++, $test_attempt_data->getMaxpoints());
330 $this->worksheet->setCell($current_row, $col++, $test_attempt_data->getMark()?->getShortName() ??
'');
331 $this->worksheet->setCell($current_row, $col++, $test_attempt_data->getQuestionCount());
332 $this->worksheet->setCell($current_row, $col++, $test_attempt_data->getNrOfAnsweredQuestions());
333 $this->worksheet->setCell($current_row, $col++, $test_attempt_data->getReachedPointsInPercent());
336 $test_attempt_data->getAnsweredQuestionCount() !== 0 ? intdiv($test_attempt_data->getWorkingTime(), $test_attempt_data->getAnsweredQuestionCount()) : 0
340 if ($is_scored_attempt) {
342 $test_attempt_data->getReachedPoints()
345 $this->worksheet->setCell(
351 $this->worksheet->setCell($current_row, $col++, $user_data->getPassCount());
352 $this->worksheet->setCell($current_row, $col++, $user_data->getFinishedPasses());
354 $this->worksheet->setCell($current_row, $col++, $user_data->getBestPass() + 1);
356 $this->worksheet->setCell($current_row, $col++, $user_data->getLastPass() + 1);
358 $this->worksheet->setCell($current_row, $col++, $test_attempt + 1);
360 foreach ($test_attempt_data->getAnsweredQuestions() as $question) {
361 $this->worksheet->setCell(
363 $cols_for_question_ids[$question[
'id']],
374 array $usersheet_titles,
378 $username = mb_substr(
379 $user_name !==
'' ? $user_name :
"ID {$active_id}",
383 $username_to_lower = strtolower($username);
384 if (array_key_exists($username_to_lower, $usersheet_titles)) {
385 $username .=
' (' . ++$usersheet_titles[$username_to_lower] .
')';
387 $usersheet_titles[$username_to_lower] = 0;
390 $this->worksheet->addSheet($username);
391 return $usersheet_titles;
398 bool $is_scored_test_attempt
401 $this->
lng->txt(
'tst_result_user_name_pass'),
406 if (!$this->scoredonly && $is_scored_test_attempt) {
407 $scoring_type = $this->test_obj->getPassScoring()
408 ? $this->
lng->txt(
'tst_pass_scoring_best')
409 : $this->
lng->txt(
'tst_pass_scoring_last');
410 $title .=
" - {$this->lng->txt('exp_scored_test_attempt')} ({$scoring_type})";
413 $this->worksheet->setCell($current_row, 0, $title);
418 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'title'));
419 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'question_type'));
420 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'answer'));
421 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'correct_answers'));
422 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'variables'));
423 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'tst_reached_points'));
424 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt(
'tst_maximum_points'));
426 $this->worksheet->mergeCells(
'A' . $current_row - 1 .
':' . $this->worksheet->getColumnCoord($col - 1) . $current_row - 1);
427 $this->worksheet->setBold(
'A' . $current_row - 1 .
':' . $this->worksheet->getColumnCoord($col - 1) . $current_row);
428 $this->worksheet->setColors(
'A' . $current_row - 1 .
':' . $this->worksheet->getColumnCoord($col - 1) . $current_row, self::EXCEL_BACKGROUND_COLOR);
430 return ++$current_row;
439 if ($questions ===
null) {
445 static fn(array
$a, array
$b):
int => $a[
'sequence'] - $b[
'sequence']
448 foreach ($questions as $question) {
449 $question_id = (
int) $question[
'id'];
455 if ($question_from_answered_questions !==
null 456 && $question_from_answered_questions[
'isAnswered']) {
457 $answers = $question_obj->getSolutionForTextOutput($active_id, $test_attempt->
getPass());
460 if (is_array($answers)) {
461 $answers = implode(
"\n", $answers);
464 $disable_strip_tags_for_answers = $question_obj instanceof \assTextQuestion
465 && $this->test_obj->getGlobalSettings()->getExportEssayQuestionsAsHtml();
467 $correct_answers = $question_obj->getCorrectSolutionForTextOutput($active_id, $test_attempt->
getPass());
468 if (is_array($correct_answers)) {
469 $correct_answers = implode(
"\n", $correct_answers);
473 $this->worksheet->setCell($current_row, $col++, $question_obj->getTitle());
474 $this->worksheet->setCell($current_row, $col++, $this->
lng->txt($question_obj->getQuestionType()));
475 $this->worksheet->setCell($current_row, $col++, $answers, DataType::TYPE_STRING, $disable_strip_tags_for_answers);
476 $this->worksheet->setCell($current_row, $col++, $correct_answers);
477 $this->worksheet->setCell($current_row, $col++, implode(
', ', $question_obj->getVariablesAsTextArray($active_id, $test_attempt->
getPass())));
479 $this->worksheet->setCell($current_row, $col++, $question[
'points']);
492 if ($this->scoredonly) {
500 if ($user_id ===
null) {
508 $diff_hours = floor($seconds / 3600);
509 $seconds -= $diff_hours * 3600;
510 $diff_minutes = floor($seconds / 60);
511 $seconds -= $diff_minutes * 60;
512 return sprintf(
'%02d:%02d:%02d', $diff_hours, $diff_minutes, $seconds);
517 if ($date_time ===
null) {
522 ->setTimezone(
new \
DateTimeZone($this->current_user->getTimeZone()))
523 ->format($this->user_date_format->toString());
ilTestEvaluationData $complete_data
convertToUserDateFormat(?\DateTimeImmutable $date_time)
static lookupPassResultsUpdateTimestamp($active_id, $pass)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const FILTER_BY_ACTIVE_ID
addAggregatedQuestionsContent(int $current_row)
getPassesDataFromUserData(\ilTestEvaluationUserData $user_data)
secondsToHoursMinutesSecondsString(int $seconds)
getScoredPassObject()
returns the object of class ilTestEvaluationPassData that relates to the the scored test pass (best p...
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
addAggregatedQuestionsHeader(int $current_row)
withFilterByActiveId(int $active_id)
addAggregatedOverviewContent(int $current_row)
static instantiateQuestion(int $question_id)
addAggregatedOverviewHeader(int $current_row)
addUserHeader(int $current_row, int $test_attempt, string $user_name, bool $is_scored_test_attempt)
__construct(private readonly \ilLanguage $lng, private readonly \ilObjUser $current_user, private readonly \ilObjTest $test_obj, private readonly GeneralQuestionPropertiesRepository $question_repository, private readonly string $filename='', private readonly bool $scoredonly=true)
static _lookupFields(int $a_user_id)
lookup fields (deprecated; use more specific methods instead)
DateFormat $user_date_format
const EXCEL_BACKGROUND_COLOR
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
addUserSheet(array $usersheet_titles, string $user_name, int $active_id)
getUserFieldsForUserID(?int $user_id)
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
getAnsweredQuestionByQuestionId(int $question_id)
filter(string $filter_id, $class_path, string $cmd, bool $activated=true, bool $expanded=true)
addUserContent(int $current_row, ?array $questions, \ilTestEvaluationPassData $test_attempt, int $active_id)
withAggregatedResultsPage()