ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilStudyProgrammeUserTable.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
27{
28 public const OPTION_ALL = -1;
29 public const VALIDITY_OPTION_VALID = 1;
30 public const VALIDITY_OPTION_INVALID = 3;
31 public const OPTION_USR_ACTIVE = 1;
32 public const OPTION_USR_INACTIVE = 2;
33
34 public const PRG_COLS = [
35 ['name', 'name', false, true, true],
36 ['login', 'login', false, true, true],
37 ['prg_status', 'prg_status', false, true, true],
38 ['prg_completion_date', 'prg_completion_date', true, true, true],
39 ['prg_completion_by', 'prg_completion_by', true, true, true],
40 ['points', 'prg_points_reachable', false, true, false],
41 ['points_required', 'prg_points_required', false, false, true],
42 ['points_current', 'prg_points_current', false, false, true],
43 ['prg_custom_plan', 'prg_custom_plan', true, true, true],
44 ['prg_belongs_to', 'prg_belongs_to', true, true, true],
45 ['prg_assign_date', 'prg_assign_date', false, true, true],
46 ['prg_assigned_by', 'prg_assigned_by', true, true, true],
47 ['prg_deadline', 'prg_deadline', true, true, true],
48 ['prg_expiry_date', 'prg_expiry_date', true, true, true],
49 ['prg_validity', 'prg_validity', true, true, true]
50 ];
51
52 private const ORDER_MAPPING = [
53 'prg_status' => 'status',
54 'prg_custom_plan' => 'custom_plan',
55 'prg_belongs_to' => 'belongs_to',
56 'prg_validity' => 'validity',
57 'prg_orgus' => 'orgus',
58 'prg_completion_by' => 'completion_by',
59 'prg_completion_date' => 'completion_date',
60 'prg_assign_date' => 'assign_date',
61 'prg_assigned_by' => 'assigned_by',
62 'prg_deadline' => 'deadline',
63 'prg_expiry_date' => 'expiry_date',
64 'pgs_id' => 'prgrs_id'
65 ];
66
68
69 public function __construct(
70 protected ilDBInterface $db,
71 protected ilExportFieldsInfo $export_fields_info,
72 protected ilPRGAssignmentDBRepository $assignment_repo,
73 protected ilLanguage $lng,
74 protected ilPRGPermissionsHelper $permissions,
75 protected ilCertificateDownloadValidator $cert_validator
76 ) {
77 $this->lng->loadLanguageModule("prg");
78 $this->user_ids_viewer_may_read_learning_progress_of = $this->permissions->getUserIdsSusceptibleTo(
80 );
81 }
82
83 protected function getUserDataColumns(int $prg_id): array
84 {
85 $cols = [];
86 $user_data_cols = $this->export_fields_info->getSelectableFieldsInfo($prg_id);
87 foreach ($user_data_cols as $k => $column_definition) {
88 $cols[$k] = [$k, $column_definition['txt'], true, true, true];
89 }
90 return $cols;
91 }
92
93 protected function getPrgColumns(): array
94 {
95 $cols = [];
96 foreach (self::PRG_COLS as $k) {
97 $k[1] = $this->lng->txt($k[1]);
98 $cols[$k[0]] = $k;
99 }
100
101 return $cols;
102 }
103
104 public function getColumns(
105 int $prg_id,
106 bool $add_active_column = false,
107 bool $add_cert_column = false
108 ): array {
109 $prg_cols = $this->getPrgColumns();
110 $prg_cols_pre = array_slice($prg_cols, 0, 2);
111 $prg_cols_post = array_slice($prg_cols, 2);
112
113 $columns = array_merge(
114 $prg_cols_pre,
115 $this->getUserDataColumns($prg_id),
116 $prg_cols_post
117 );
118
119 if ($add_active_column) {
120 $columns["active"] = ["active", $this->lng->txt("active"), true, true, true];
121 }
122 if ($add_cert_column) {
123 $columns["cert_relevance"] = ["cert_relevance", $this->lng->txt("cert_relevance"), true, true, true];
124 }
125 return $columns;
126 }
127
128
129 public function countFetchData(int $prg_id, ?array $valid_user_ids, ilPRGAssignmentFilter $custom_filters): int
130 {
131 return $this->assignment_repo->countAllForNodeIsContained($prg_id, $valid_user_ids, $custom_filters);
132 }
133
138 public function fetchData(
139 int $prg_id,
140 ?array $valid_user_ids,
141 Order $order,
142 ?ilPRGAssignmentFilter $custom_filters = null,
143 ?int $limit = null,
144 ?int $offset = null
145 ): array {
146 $data = $this->assignment_repo->getAllForNodeIsContained(
147 $prg_id,
148 $valid_user_ids,
149 $custom_filters
150 );
151
152 $root_assignemnts = array_filter(
153 $data,
154 fn($ass) => $ass->getRootId() === $prg_id
155 );
156 $root_usr_ids = array_map(fn($r) => $r->getUserid(), $root_assignemnts);
157 $cert_ass_ids = $this->assignment_repo->getCertificateRelevantAssignmentIds(
158 $prg_id,
159 ...$root_usr_ids
160 );
161
162 $rows = array_map(fn($ass) => $this->toRow($ass, $prg_id, $cert_ass_ids), $data);
163 $rows = $this->postOrder($rows, $order);
164 if ($limit) {
165 $offset = $offset ?? 0;
166 $rows = array_slice($rows, $offset, $limit);
167 }
168 return $rows;
169 }
170
171 public function fetchSingleUserRootAssignments(int $usr_id): array
172 {
173 $data = $this->assignment_repo->getForUser($usr_id);
174 $row = array_map(fn($ass) => $this->toRow($ass, $ass->getRootId(), []), $data);
175 return $row;
176 }
177
178
179 protected $skip_perm_check_on_user = false;
180 public function disablePermissionCheck($flag = false): void
181 {
182 $this->skip_perm_check_on_user = $flag;
183 }
184
185 protected function includeLearningProgress(int $usr_id): bool
186 {
187 return $this->skip_perm_check_on_user
188 || in_array($usr_id, $this->user_ids_viewer_may_read_learning_progress_of);
189 }
190
191 protected function toRow(ilPRGAssignment $ass, int $node_id, array $cert_ass_ids): ilStudyProgrammeUserTableRow
192 {
193 $pgs = $ass->getProgressForNode($node_id);
195 $ass->getId(),
196 $ass->getUserId(),
197 $node_id,
198 $ass->getRootId() === $node_id,
199 $ass->getUserInformation()
200 );
201
202 $show_lp = $this->includeLearningProgress($ass->getUserId());
203
204 $prg_node = ilObjStudyProgramme::getInstanceByObjId($node_id);
205 $points_reachable = (string) $pgs->getPossiblePointsOfRelevantChildren();
206 if ($prg_node->getLPMode() === ilStudyProgrammeSettings::MODE_LP_COMPLETED) {
207 $points_reachable = (string) $pgs->getAmountOfPoints();
208 }
209
210 $prg_lifecycle_status = $prg_node->getStatus();
211 $row = $row
212 ->withUserActiveRaw($ass->getUserInformation()->isActive())
213 ->withUserActive($this->activeToRepresent($ass->getUserInformation()->isActive()))
214 ->withFirstname($ass->getUserInformation()->getFirstname())
215 ->withLastname($ass->getUserInformation()->getLastname())
216 ->withLogin($ass->getUserInformation()->getLogin())
217 ->withOrgUs($ass->getUserInformation()->getOrguRepresentation())
218 ->withGender($this->lng->txt('gender_' . $ass->getUserInformation()->getGender()))
219 ->withStatus($show_lp ? $this->statusToRepresent($pgs->getStatus()) : '')
220 ->withStatusRaw($pgs->getStatus())
221 ->withCompletionDate(
222 $show_lp && $pgs->getCompletionDate() ? $pgs->getCompletionDate()->format($this->getUserDateFormat()) : ''
223 )
224 ->withCompletionBy(
225 $show_lp && $pgs->getCompletionBy() ? $this->completionByToRepresent($pgs) : ''
226 )
227 ->withCompletionByObjIds(
228 $show_lp && $pgs->getCompletionBy() ? $this->completionByToCollection($pgs) : null
229 )
230 ->withPointsReachable($points_reachable)
231 ->withPointsRequired((string) $pgs->getAmountOfPoints())
232 ->withPointsCurrent($show_lp ? (string) $pgs->getCurrentAmountOfPoints() : '')
233 ->withCustomPlan($this->boolToRepresent($pgs->hasIndividualModifications()))
234 ->withBelongsTo($this::lookupTitle($ass->getRootId()))
235 ->withAssignmentDate($pgs->getAssignmentDate()->format($this->getUserDateFormat()))
236 ->withAssignmentBy(
237 $this->assignmentSourceToRepresent(
238 $ass->isManuallyAssigned(),
239 $ass->getLastChangeBy()
240 )
241 )
242 ->withDeadline(
243 $show_lp && $pgs->getDeadline() && !$pgs->isSuccessful() ? $pgs->getDeadline()->format($this->getUserDateFormat()) : ''
244 )
245 ->withExpiryDate(
246 $show_lp && $pgs->getValidityOfQualification() ? $pgs->getValidityOfQualification()->format($this->getUserDateFormat()) : ''
247 )
248 ->withValidity($show_lp ? $this->validToRepresent($pgs) : '')
249 ->withRestartDate($ass->getRestartDate() ? $ass->getRestartDate()->format($this->getUserDateFormat()) : '')
250 ->withNodeLifecycleStatus($prg_lifecycle_status)
251 ->withCertificateRelevance(
252 in_array($ass->getId(), $cert_ass_ids)
253 && $this->cert_validator->isCertificateDownloadable($ass->getUserId(), $ass->getRootId())
254 )
255 ;
256 return $row;
257 }
258
259 protected function getUserDateFormat(): string
260 {
261 return ilCalendarUtil::getUserDateFormat(0, true);
262 }
263
267 public function statusToRepresent($a_status): string
268 {
269 if ($a_status == ilPRGProgress::STATUS_IN_PROGRESS) {
270 return $this->lng->txt("prg_status_in_progress");
271 }
272 if ($a_status == ilPRGProgress::STATUS_COMPLETED) {
273 return $this->lng->txt("prg_status_completed");
274 }
275 if ($a_status == ilPRGProgress::STATUS_ACCREDITED) {
276 return $this->lng->txt("prg_status_accredited");
277 }
278 if ($a_status == ilPRGProgress::STATUS_NOT_RELEVANT) {
279 return $this->lng->txt("prg_status_not_relevant");
280 }
281 if ($a_status == ilPRGProgress::STATUS_FAILED) {
282 return $this->lng->txt("prg_status_failed");
283 }
284 throw new ilException("Unknown status: '$a_status'");
285 }
286
287 public function boolToRepresent(bool $value): string
288 {
289 return ($value) ? $this->lng->txt("yes") : $this->lng->txt("no");
290 }
291
292 public function validToRepresent(ilPRGProgress $pgs): string
293 {
294 if (!$pgs->isSuccessful()) {
295 return '-';
296 }
297 return $pgs->isInvalidated() ? $this->lng->txt("prg_not_valid") : $this->lng->txt("prg_still_valid");
298 }
299
300 public function activeToRepresent(bool $value): string
301 {
302 return $value ? $this->lng->txt('active') : $this->lng->txt('inactive');
303 }
304
305 public function assignmentSourceToRepresent(bool $manually, int $assignment_src): string
306 {
309 if ($manually || ! array_key_exists($assignment_src, $srcs)) {
310 return $this::lookupTitle($assignment_src);
311 }
312 return implode(' ', [
313 $this->lng->txt('prg_autoassignment'),
314 $this->lng->txt($srcs[$assignment_src])
315 ]);
316 }
317
318 public function completionByToRepresent(ilPRGProgress $progress): string
319 {
320 $completion_by = $progress->getCompletionBy();
321 if ($completion_by !== ilPRGProgress::COMPLETED_BY_SUBNODES) {
322 return $this::lookupTitle($completion_by);
323 }
324
325 $out = array_map(
326 fn(int $node_obj_id): string => self::lookupTitle($node_obj_id),
327 $this->completionByToCollection($progress)
328 );
329
330 return implode(', ', $out);
331 }
332
333 protected function completionByToCollection(ilPRGProgress $progress): array
334 {
335 $completion_by = $progress->getCompletionBy();
336 if ($completion_by !== ilPRGProgress::COMPLETED_BY_SUBNODES) {
337 return [$completion_by];
338 }
339 $successful_subnodes = array_filter(
340 $progress->getSubnodes(),
341 static fn(ilPRGProgress $pgs): bool => $pgs->isSuccessful()
342 );
343 return array_map(
344 static fn(ilPRGProgress $pgs): int => $pgs->getNodeId(),
345 $successful_subnodes
346 );
347 }
348
349 public static function lookupTitle(int $obj_id): string
350 {
351 $type = ilObject::_lookupType($obj_id);
352 switch ($type) {
353 case 'usr':
354 return ilObject::_lookupTitle($obj_id);
355 case 'prg':
356 $title = ilObject::_lookupTitle($obj_id);
358 return sprintf('(%s)', $title);
359 }
360 return $title;
361 case 'crs':
362 $title = ilObject::_lookupTitle($obj_id);
363 $refs = ilObject::_getAllReferences($obj_id);
364 $target_ref_id = array_shift($refs) ?? null;
365 if ($target_ref_id === null || ilObject::_isInTrash($target_ref_id)) {
366 return sprintf('(%s)', $title);
367 }
368 return $title;
369 }
370
371 if ($del = ilObjectDataDeletionLog::get($obj_id)) {
372 return sprintf('(%s)', $del['title']);
373 }
374 return 'object id ' . $obj_id;
375 }
376
377 protected function postOrder(array $list, \ILIAS\Data\Order $order): array
378 {
379 [$aspect, $direction] = $order->join('', function ($i, $k, $v) {
380 return [$k, $v];
381 });
382
383 if (array_key_exists($aspect, self::ORDER_MAPPING)) {
384 $aspect = self::ORDER_MAPPING[$aspect];
385 }
386
387 $user_date_format = $this->getUserDateFormat();
388 usort($list, static function (ilStudyProgrammeUserTableRow $a, ilStudyProgrammeUserTableRow $b) use ($aspect, $user_date_format): int {
389 $a = $a->toArray();
390 $b = $b->toArray();
391
392 if (is_numeric($a[$aspect])) {
393 return $a[$aspect] <=> $b[$aspect];
394 }
395 if (is_bool($a[$aspect])) {
396 return (int) $a[$aspect] <=> (int) $b[$aspect];
397 }
398
399 if (in_array($aspect, [
400 'completion_date',
401 'deadline',
402 'assign_date',
403 'expiry_date',
404 ])) {
405 return \DateTimeImmutable::createFromFormat($user_date_format, $a[$aspect])
406 <=> \DateTimeImmutable::createFromFormat($user_date_format, $b[$aspect]);
407 }
408 return strcmp($a[$aspect], $b[$aspect]);
409 });
410
411 if ($direction === $order::DESC) {
412 $list = array_reverse($list);
413 }
414 return $list;
415 }
416}
$out
Definition: buildRTE.php:24
Both the subject and the direction need to be specified when expressing an order.
Definition: Order.php:29
static getUserDateFormat(int $a_add_time=0, bool $a_for_parsing=false)
Parse current user setting into date/time format.
Validates if an active certificate is stored in the database and can be downloaded by the user.
Base class for ILIAS Exception handling.
language handling
static getInstanceByObjId(int $obj_id)
static getRefIdFor(int $obj_id)
static _lookupType(int $id, bool $reference=false)
static _getAllReferences(int $id)
get all reference ids for object ID
static _isInTrash(int $ref_id)
static _lookupTitle(int $obj_id)
Assignments are relations of users to a PRG; They hold progress-information for (sub-)nodes of the PR...
Assignments are relations of users to a PRG; They hold progress-information for (sub-)nodes of the PR...
getProgressForNode(int $node_id)
Both role and OrgU-based permissions are relevant in many places of the PRG.
A Progress is the status of a user on a single node of an assignment; it is unique by assignment_id:u...
ilStudyProgrammeUserTable provides a flattened list of progresses at a programme-node.
ilStudyProgrammeUserTable provides a flattened list of progresses at a programme-node.
__construct(protected ilDBInterface $db, protected ilExportFieldsInfo $export_fields_info, protected ilPRGAssignmentDBRepository $assignment_repo, protected ilLanguage $lng, protected ilPRGPermissionsHelper $permissions, protected ilCertificateDownloadValidator $cert_validator)
completionByToRepresent(ilPRGProgress $progress)
completionByToCollection(ilPRGProgress $progress)
postOrder(array $list, \ILIAS\Data\Order $order)
toRow(ilPRGAssignment $ass, int $node_id, array $cert_ass_ids)
getColumns(int $prg_id, bool $add_active_column=false, bool $add_cert_column=false)
assignmentSourceToRepresent(bool $manually, int $assignment_src)
countFetchData(int $prg_id, ?array $valid_user_ids, ilPRGAssignmentFilter $custom_filters)
fetchData(int $prg_id, ?array $valid_user_ids, Order $order, ?ilPRGAssignmentFilter $custom_filters=null, ?int $limit=null, ?int $offset=null)
Interface ilDBInterface.
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
global $lng
Definition: privfeed.php:31