ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilStudyProgrammeUserTable.php
Go to the documentation of this file.
1 <?php
2 
19 declare(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);
194  $row = new ilStudyProgrammeUserTableRow(
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 
212  $row = $row
213  ->withUserActiveRaw($ass->getUserInformation()->isActive())
214  ->withUserActive($this->activeToRepresent($ass->getUserInformation()->isActive()))
215  ->withFirstname($ass->getUserInformation()->getFirstname())
216  ->withLastname($ass->getUserInformation()->getLastname())
217  ->withLogin($ass->getUserInformation()->getLogin())
218  ->withOrgUs($ass->getUserInformation()->getOrguRepresentation())
219  ->withGender($this->lng->txt('gender_' . $ass->getUserInformation()->getGender()))
220  ->withStatus($show_lp ? $this->statusToRepresent($pgs->getStatus()) : '')
221  ->withStatusRaw($pgs->getStatus())
222  ->withCompletionDate(
223  $show_lp && $pgs->getCompletionDate() ? $pgs->getCompletionDate()->format($this->getUserDateFormat()) : ''
224  )
225  ->withCompletionBy(
226  $show_lp && $pgs->getCompletionBy() ? $this->completionByToRepresent($pgs) : ''
227  )
228  ->withCompletionByObjIds(
229  $show_lp && $pgs->getCompletionBy() ? $this->completionByToCollection($pgs) : null
230  )
231  ->withPointsReachable($points_reachable)
232  ->withPointsRequired((string) $pgs->getAmountOfPoints())
233  ->withPointsCurrent($show_lp ? (string) $pgs->getCurrentAmountOfPoints() : '')
234  ->withCustomPlan($this->boolToRepresent($pgs->hasIndividualModifications()))
235  ->withBelongsTo($this::lookupTitle($ass->getRootId()))
236  ->withAssignmentDate($pgs->getAssignmentDate()->format($this->getUserDateFormat()))
237  ->withAssignmentBy(
239  $ass->isManuallyAssigned(),
240  $ass->getLastChangeBy()
241  )
242  )
243  ->withDeadline(
244  $show_lp && $pgs->getDeadline() && !$pgs->isSuccessful() ? $pgs->getDeadline()->format($this->getUserDateFormat()) : ''
245  )
246  ->withExpiryDate(
247  $show_lp && $pgs->getValidityOfQualification() ? $pgs->getValidityOfQualification()->format($this->getUserDateFormat()) : ''
248  )
249  ->withValidity($show_lp ? $this->validToRepresent($pgs) : '')
250  ->withRestartDate($ass->getRestartDate() ? $ass->getRestartDate()->format($this->getUserDateFormat()) : '')
251  ->withNodeLifecycleStatus($prg_lifecycle_status)
252  ->withCertificateRelevance(
253  in_array($ass->getId(), $cert_ass_ids)
254  && $this->cert_validator->isCertificateDownloadable($ass->getUserId(), $ass->getRootId())
255  )
256  ;
257  return $row;
258  }
259 
260  protected function getUserDateFormat(): string
261  {
262  return ilCalendarUtil::getUserDateFormat(0, true);
263  }
264 
268  public function statusToRepresent($a_status): string
269  {
270  if ($a_status == ilPRGProgress::STATUS_IN_PROGRESS) {
271  return $this->lng->txt("prg_status_in_progress");
272  }
273  if ($a_status == ilPRGProgress::STATUS_COMPLETED) {
274  return $this->lng->txt("prg_status_completed");
275  }
276  if ($a_status == ilPRGProgress::STATUS_ACCREDITED) {
277  return $this->lng->txt("prg_status_accredited");
278  }
279  if ($a_status == ilPRGProgress::STATUS_NOT_RELEVANT) {
280  return $this->lng->txt("prg_status_not_relevant");
281  }
282  if ($a_status == ilPRGProgress::STATUS_FAILED) {
283  return $this->lng->txt("prg_status_failed");
284  }
285  throw new ilException("Unknown status: '$a_status'");
286  }
287 
288  public function boolToRepresent(bool $value): string
289  {
290  return ($value) ? $this->lng->txt("yes") : $this->lng->txt("no");
291  }
292 
293  public function validToRepresent(ilPRGProgress $pgs): string
294  {
295  if (!$pgs->isSuccessful()) {
296  return '-';
297  }
298  return $pgs->isInvalidated() ? $this->lng->txt("prg_not_valid") : $this->lng->txt("prg_still_valid");
299  }
300 
301  public function activeToRepresent(bool $value): string
302  {
303  return $value ? $this->lng->txt('active') : $this->lng->txt('inactive');
304  }
305 
306  public function assignmentSourceToRepresent(bool $manually, int $assignment_src): string
307  {
309  $srcs[ilPRGAssignment::AUTO_ASSIGNED_BY_RESTART] = 'restarted';
310  if ($manually || ! array_key_exists($assignment_src, $srcs)) {
311  return $this::lookupTitle($assignment_src);
312  }
313  return implode(' ', [
314  $this->lng->txt('prg_autoassignment'),
315  $this->lng->txt($srcs[$assignment_src])
316  ]);
317  }
318 
319  public function completionByToRepresent(ilPRGProgress $progress): string
320  {
321  $completion_by = $progress->getCompletionBy();
322  if ($completion_by !== ilPRGProgress::COMPLETED_BY_SUBNODES) {
323  return $this::lookupTitle($completion_by);
324  }
325 
326  $out = array_map(
327  fn(int $node_obj_id): string => self::lookupTitle($node_obj_id),
328  $this->completionByToCollection($progress)
329  );
330 
331  return implode(', ', $out);
332  }
333 
334  protected function completionByToCollection(ilPRGProgress $progress): array
335  {
336  $completion_by = $progress->getCompletionBy();
337  if ($completion_by !== ilPRGProgress::COMPLETED_BY_SUBNODES) {
338  return [$completion_by];
339  }
340  $successful_subnodes = array_filter(
341  $progress->getSubnodes(),
342  static fn(ilPRGProgress $pgs): bool => $pgs->isSuccessful()
343  );
344  return array_map(
345  static fn(ilPRGProgress $pgs): int => $pgs->getNodeId(),
346  $successful_subnodes
347  );
348  }
349 
350  public static function lookupTitle(int $obj_id): string
351  {
352  $type = ilObject::_lookupType($obj_id);
353  switch ($type) {
354  case 'usr':
355  return ilObject::_lookupTitle($obj_id);
356  case 'prg':
357  $title = ilObject::_lookupTitle($obj_id);
359  return sprintf('(%s)', $title);
360  }
361  return $title;
362  case 'crs':
363  $title = ilObject::_lookupTitle($obj_id);
364  $refs = ilObject::_getAllReferences($obj_id);
365  $target_ref_id = array_shift($refs) ?? null;
366  if ($target_ref_id === null || ilObject::_isInTrash($target_ref_id)) {
367  return sprintf('(%s)', $title);
368  }
369  return $title;
370  }
371 
372  if ($del = ilObjectDataDeletionLog::get($obj_id)) {
373  return sprintf('(%s)', $del['title']);
374  }
375  return 'object id ' . $obj_id;
376  }
377 
378  protected function postOrder(array $list, \ILIAS\Data\Order $order): array
379  {
380  [$aspect, $direction] = $order->join('', function ($i, $k, $v) {
381  return [$k, $v];
382  });
383 
384  if (array_key_exists($aspect, self::ORDER_MAPPING)) {
385  $aspect = self::ORDER_MAPPING[$aspect];
386  }
387 
388  usort($list, static function (ilStudyProgrammeUserTableRow $a, ilStudyProgrammeUserTableRow $b) use ($aspect): 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  return strcmp($a[$aspect], $b[$aspect]);
400  });
401 
402  if ($direction === $order::DESC) {
403  $list = array_reverse($list);
404  }
405  return $list;
406  }
407 }
ilStudyProgrammeUserTable provides a flattened list of progresses at a programme-node.
fetchData(int $prg_id, ?array $valid_user_ids, Order $order, ilPRGAssignmentFilter $custom_filters=null, int $limit=null, int $offset=null)
getColumns(int $prg_id, bool $add_active_column=false, bool $add_cert_column=false)
Class ChatMainBarProvider .
static _getAllReferences(int $id)
get all reference ids for object ID
completionByToRepresent(ilPRGProgress $progress)
static getUserDateFormat(int $a_add_time=0, bool $a_for_parsing=false)
Parse current user setting into date/time format.
assignmentSourceToRepresent(bool $manually, int $assignment_src)
Both the subject and the direction need to be specified when expressing an order. ...
Definition: Order.php:12
toRow(ilPRGAssignment $ass, int $node_id, array $cert_ass_ids)
A Progress is the status of a user on a single node of an assignment; it is unique by assignment_id:u...
static _lookupTitle(int $obj_id)
$lng
Validates if an active certificate is stored in the database and can be downloaded by the user...
static _isInTrash(int $ref_id)
$out
Definition: buildRTE.php:24
completionByToCollection(ilPRGProgress $progress)
countFetchData(int $prg_id, ?array $valid_user_ids, ilPRGAssignmentFilter $custom_filters)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByObjId(int $obj_id)
ilStudyProgrammeUserTable provides a flattened list of progresses at a programme-node.
Assignments are relations of users to a PRG; They hold progress-information for (sub-)nodes of the PR...
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
static getRefIdFor(int $obj_id)
__construct(protected ilDBInterface $db, protected ilExportFieldsInfo $export_fields_info, protected ilPRGAssignmentDBRepository $assignment_repo, protected ilLanguage $lng, protected ilPRGPermissionsHelper $permissions, protected ilCertificateDownloadValidator $cert_validator)
getProgressForNode(int $node_id)
Assignments are relations of users to a PRG; They hold progress-information for (sub-)nodes of the PR...
static _lookupType(int $id, bool $reference=false)
postOrder(array $list, \ILIAS\Data\Order $order)
$r