ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilObjStudyProgramme.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
24 {
25  public const CP_TYPE = 'cont';
26 
28 
32  protected $parent;
33 
37  protected ?array $children = null;
38 
42  protected ?array $lp_children = null;
43 
51 
52  // GLOBALS from ILIAS
53 
57  protected ?array $members_cache = null;
58 
62  protected ?array $reference_children = null;
63 
64  protected Filesystem $webdir;
65  protected ilObjUser $ilUser;
68  protected ilLogger $logger;
69 
74  public function __construct(int $id = 0, bool $call_by_reference = true)
75  {
77  $this->type = "prg";
78 
79  $this->type_repository = $dic['model.Type.ilStudyProgrammeTypeRepository'];
80  $this->auto_categories_repository = $dic['model.AutoCategories.ilStudyProgrammeAutoCategoriesRepository'];
81  $this->auto_memberships_repository = $dic['model.AutoMemberships.ilStudyProgrammeAutoMembershipsRepository'];
82  $this->membersourcereader_factory = $dic['model.AutoMemberships.ilStudyProgrammeMembershipSourceReaderFactory'];
83 
84  $this->settings_repository = $dic['model.Settings.ilStudyProgrammeSettingsRepository'];
85  $this->assignment_repository = $dic['repo.assignment'];
86  $this->events = $dic['ilStudyProgrammeEvents'];
87 
89 
90  $this->clearParentCache();
91  $this->clearChildrenCache();
92  $this->clearLPChildrenCache();
93 
94  global $DIC;
95  $tree = $DIC['tree'];
96  $ilUser = $DIC['ilUser'];
97  $this->webdir = $DIC->filesystem()->web();
98  $this->tree = $tree;
99  $this->ilUser = $ilUser;
100  $this->db = $DIC['ilDB'];
101  $this->lng = $DIC['lng'];
102  $this->logger = ilLoggerFactory::getLogger($this->type);
103 
104  $this->object_factory = ilObjectFactoryWrapper::singleton();
105 
106  $this->custom_icon_factory = $DIC['object.customicons.factory'];
107 
108  self::initStudyProgrammeCache();
109  }
110 
111  public static function initStudyProgrammeCache(): void
112  {
113  if (self::$study_programme_cache === null) {
114  self::$study_programme_cache = ilObjStudyProgrammeCache::singleton();
115  }
116  }
117 
121  protected function clearParentCache(): void
122  {
123  // This is not initialized, but we need null if there is no parent.
124  $this->parent = false;
125  }
126 
130  protected function clearChildrenCache(): void
131  {
132  $this->children = null;
133  }
134 
138  protected function clearLPChildrenCache(): void
139  {
140  $this->lp_children = null;
141  }
142 
143  public static function getRefIdFor(int $obj_id): int
144  {
145  $refs = ilObject::_getAllReferences($obj_id);
146  if (count($refs) < 1) {
147  throw new ilException("Could not find ref_id for programme with obj_id $obj_id");
148  }
149  return (int) array_shift($refs);
150  }
151 
152  protected function getPrgInstanceByObjId(int $obj_id): ilObjStudyProgramme
153  {
154  return self::getInstanceByRefId(self::getRefIdFor($obj_id));
155  }
156 
157  public static function getInstanceByObjId(int $obj_id): ilObjStudyProgramme
158  {
159  return self::getInstanceByRefId(self::getRefIdFor($obj_id));
160  }
161 
163  {
164  if (self::$study_programme_cache === null) {
165  self::initStudyProgrammeCache();
166  }
167  return self::$study_programme_cache->getInstanceByRefId((int) $ref_id);
168  }
169 
171  {
173  }
175  {
177  }
178  protected function getTree(): ilTree
179  {
180  return $this->tree;
181  }
182  protected function getLogger(): ilLogger
183  {
184  return $this->logger;
185  }
186 
192  public static function createInstance(): ilObjStudyProgramme
193  {
194  $obj = new ilObjStudyProgramme();
195  $obj->create();
196  $obj->createReference();
197  self::$study_programme_cache->addInstance($obj);
198  return $obj;
199  }
200 
202  // CRUD
204 
206  {
207  return $this->getSettingsRepository()->get($this->getId());
208  }
209 
210  public function updateSettings(ilStudyProgrammeSettings $settings): bool
211  {
212  if ($settings->getObjId() !== $this->getId()) {
213  throw new Exception("The given settings-object does not belong to this programme", 1);
214  }
215  $this->getSettingsRepository()->update($settings);
216 
217  return true;
218  }
219 
220  protected function deleteSettings(): void
221  {
222  $this->getSettingsRepository()->delete($this->getSettings());
223  }
224 
230  protected function deleteAssignmentsAndProgresses(): void
231  {
232  $this->assignment_repository->deleteAllAssignmentsForProgrammeId($this->getId());
233  }
234 
238  public function create(): int
239  {
240  $id = (int) parent::create();
241  $this->getSettingsRepository()->createFor($id);
242  return $id;
243  }
244 
248  public function update(): bool
249  {
250  parent::update();
251 
252  $type_settings = $this->getSettings()->getTypeSettings();
253  // Update selection for advanced metadata of the type
254  if ($type_settings->getTypeId()) {
256  $this->getId(),
257  'prg_type',
258  $this->type_repository->getAssignedAMDRecordIdsByType($type_settings->getTypeId())
259  );
260  } else {
261  // If no type is assigned, delete relations by passing an empty array
262  ilAdvancedMDRecord::saveObjRecSelection($this->getId(), 'prg_type', array());
263  }
264  return true;
265  }
266 
272  public function delete(): bool
273  {
274  // always call parent delete function first!!
275  if (!parent::delete()) {
276  return false;
277  }
278 
279  $this->deleteSettings();
281  try {
282  $this->auto_categories_repository->deleteFor($this->getId());
284  // This would be the case when SP is in trash (#17797)
285  }
286 
289 
290  $this->events->raise('delete', ['object' => $this, 'obj_id' => $this->getId()]);
291  return true;
292  }
293 
294  public function hasAdvancedMetadata(): bool
295  {
296  $sub_type_id = $this->getSettings()->getTypeSettings()->getTypeId();
297  $type = null;
298  if ($sub_type_id) {
299  $type = $this->type_repository->getType($sub_type_id);
300  }
301 
302  return !is_null($type) && count($this->type_repository->getAssignedAMDRecordIdsByType($type->getId(), true)) > 0;
303  }
304 
305  public function cloneObject(int $target_ref_id, int $copy_id = 0, bool $omit_tree = false): ?ilObject
306  {
307  $new_obj = parent::cloneObject($target_ref_id, $copy_id, $omit_tree);
308  $settings = $this->getSettings()->withObjId($new_obj->getId());
309  $settings = $settings->withAssessmentSettings(
310  $settings->getAssessmentSettings()->withStatus(ilStudyProgrammeSettings::STATUS_DRAFT)
311  );
312  $new_obj->updateSettings($settings);
313  return $new_obj;
314  }
315 
317  // GETTERS AND SETTERS
319 
323  public function getLastChange(): DateTime
324  {
325  return $this->getSettings()->getLastChange();
326  }
327 
331  public function getPoints(): int
332  {
333  return $this->getSettings()->getAssessmentSettings()->getPoints();
334  }
335 
341  public function setPoints(int $points): ilObjStudyProgramme
342  {
343  $settings = $this->getSettings();
344  $this->updateSettings(
345  $settings->withAssessmentSettings($settings->getAssessmentSettings()->withPoints($points))
346  );
347  $this->updateLastChange();
348  return $this;
349  }
350 
351  public function getLPMode(): int
352  {
353  return $this->getSettings()->getLPMode();
354  }
355 
364  public function adjustLPMode(): void
365  {
366  // Clear caches here, there have been some changes, because this method
367  // would not have been called otherwise, and the changer just does not
368  // know if we have filled the caches already...
369  $this->clearLPChildrenCache();
370  $this->clearChildrenCache();
371 
372  if ($this->tree->isInTree($this->getRefId())) {
373  if ($this->getAmountOfLPChildren() > 0) {
374  $this->settings_repository->update(
376  );
377  } elseif ($this->getAmountOfChildren(true) > 0) {
378  $this->settings_repository->update(
380  );
381  } else {
382  $this->settings_repository->update(
384  );
385  }
386  }
387  }
388 
389  public function getStatus(): int
390  {
391  return $this->getSettings()->getAssessmentSettings()->getStatus();
392  }
393 
399  public function setStatus(int $a_status): ilObjStudyProgramme
400  {
401  $settings = $this->getSettings();
402  $this->updateSettings(
403  $settings->withAssessmentSettings($settings->getAssessmentSettings()->withStatus($a_status))
404  );
405  $this->updateLastChange();
406  return $this;
407  }
408 
409  public function isActive(): bool
410  {
412  }
413 
417  public function getSubType(): ?ilStudyProgrammeType
418  {
419  $type_settings = $this->getSettings()->getTypeSettings();
420  if (!in_array($type_settings->getTypeId(), array("-", "0"))) {
421  $subtype_id = $type_settings->getTypeId();
422  return $this->type_repository->getType($subtype_id);
423  }
424 
425  return null;
426  }
427 
428  public function isCertificateActive(): bool
429  {
430  $global_settings = new ilSetting('certificate');
431  $global_active = (bool) $global_settings->get('active', '0');
432  if (!$global_active) {
433  return false;
434  }
436  $certificate_template = $certificate_template_repository->fetchCurrentlyUsedCertificate($this->getId());
437  return $certificate_template->isCurrentlyActive();
438  }
439 
440 
442  // TREE NAVIGATION
444 
453  public static function getAllChildren(int $a_ref_id, bool $include_references = false): array
454  {
455  $ret = array();
456  $root = self::getInstanceByRefId($a_ref_id);
457  $root_id = $root->getId();
458  $root->applyToSubTreeNodes(function (ilObjStudyProgramme $prg) use (&$ret, $root_id) {
459  // exclude root node of subtree.
460  if ($prg->getId() === $root_id) {
461  return;
462  }
463  $ret[] = $prg;
464  }, $include_references);
465  return $ret;
466  }
467 
468  public function getAllPrgChildren(): array
469  {
470  $ret = [];
471  $this->applyToSubTreeNodes(
472  function (ilObjStudyProgramme $prg) use (&$ret) {
473  if ($prg->getId() === $this->getId()) {
474  return;
475  }
476  $ret[] = $prg;
477  }
478  );
479  return $ret;
480  }
481 
489  public function getChildren(bool $include_references = false): array
490  {
491  $this->throwIfNotInTree();
492 
493  if ($this->children === null) {
494  $ref_ids = $this->tree->getChildsByType($this->getRefId(), "prg");
495 
496  // apply container sorting to tree
497  $sorting = ilContainerSorting::_getInstance($this->getId());
498  $ref_ids = $sorting->sortItems(array('prg' => $ref_ids));
499  $ref_ids = $ref_ids['prg'];
500 
501  $this->children = array_map(static function ($node_data) {
502  return ilObjStudyProgramme::getInstanceByRefId($node_data["child"]);
503  }, $ref_ids);
504  }
505 
506  if ($include_references && $this->reference_children === null) {
507  $this->reference_children = [];
508  $ref_child_ref_ids = $this->tree->getChildsByType($this->getRefId(), "prgr");
509  foreach (
510  array_unique(
511  array_map(
512  static function ($data) {
513  return (int) $data['child'];
514  },
515  array_filter($ref_child_ref_ids, static function ($data) {
516  return $data["deleted"] === null;
517  })
518  )
519  ) as $prg_ref_id
520  ) {
521  $this->reference_children[] =
522  (new ilObjStudyProgrammeReference($prg_ref_id))->getReferencedObject();
523  }
524  }
525  return $include_references ?
526  array_merge($this->children, $this->reference_children) :
528  }
529 
536  public function getParent(): ?ilObjStudyProgramme
537  {
538  if ($this->parent === false) {
539  $this->throwIfNotInTree();
540  $parent_data = $this->tree->getParentNodeData($this->getRefId());
541  if ($parent_data["type"] !== "prg") {
542  $this->parent = null;
543  } else {
544  $this->parent = self::getInstanceByRefId($parent_data["ref_id"]);
545  }
546  }
547  return $this->parent;
548  }
549 
550  protected function getReferencesTo(ilObjStudyProgramme $prg): array
551  {
552  $tree = $this->tree;
553  return array_filter(
554  array_map(
555  static function ($id) {
556  $refs = ilObject::_getAllReferences((int) $id);
557  return new ilObjStudyProgrammeReference(
558  array_shift($refs)
559  );
560  },
562  ),
563  static function ($prg_ref) use ($tree) {
564  return !$tree->isDeleted($prg_ref->getRefId());
565  }
566  );
567  }
568 
569  public function getReferencesToSelf(): array
570  {
571  return $this->getReferencesTo($this);
572  }
573 
579  public function getParents(bool $include_references = false): array
580  {
581  $current = $this;
582  $parents = [];
583  $queque = [$current];
584  while ($element = array_shift($queque)) {
585  $parent = $element->getParent();
586  if ($parent === null || $include_references) {
587  foreach ($this->getReferencesTo($element) as $reference) {
588  if ($this->tree->isDeleted($reference->getRefId())) {
589  continue;
590  }
591  $r_parent = $reference->getParent();
592  if (is_null($r_parent)) {
593  continue;
594  }
595  $queque[] = $r_parent;
596  $parents[] = $r_parent;
597  }
598  continue;
599  }
600  $queque[] = $parent;
601  $parents[] = $parent;
602  }
603  return array_reverse($parents);
604  }
605 
611  public function hasChildren(bool $include_references = false): bool
612  {
613  return $this->getAmountOfChildren($include_references) > 0;
614  }
615 
622  public function getAmountOfChildren($include_references = false): int
623  {
624  return count($this->getChildren($include_references));
625  }
626 
633  public function getDepth(): int
634  {
635  $cur = $this;
636  $count = 0;
637  while ($cur = $cur->getParent()) {
638  $count++;
639  }
640  return $count;
641  }
642 
647  public function getRoot(): ilObjStudyProgramme
648  {
649  $parents = $this->getParents();
650  if (count($parents) < 1) {
651  return $this;
652  }
653  return $parents[0];
654  }
655 
662  public function getLPChildren(): array
663  {
664  $this->throwIfNotInTree();
665 
666  if ($this->lp_children === null) {
667  $this->lp_children = array();
668 
669  $ref_ids = $this->tree->getChildsByType($this->getRefId(), "crsr");
670 
671  // apply container sorting to tree
672  $sorting = ilContainerSorting::_getInstance($this->getId());
673  $ref_ids = $sorting->sortItems(array('crs_ref' => $ref_ids));
674  $ref_ids = $ref_ids['crs_ref'];
675 
676  $lp_children = array_map(function ($node_data) {
677  $lp_obj = $this->object_factory->getInstanceByRefId((int) $node_data["child"]);
678 
679  // filter out all StudyProgramme instances
680  return ($lp_obj instanceof $this) ? null : $lp_obj;
681  }, $ref_ids);
682 
683  $this->lp_children = array_filter($lp_children);
684  }
685  return $this->lp_children;
686  }
687 
694  public function getLPChildrenIds(): array
695  {
696  return array_map(static function ($child) {
697  return $child->getId();
698  }, $this->getLPChildren());
699  }
700 
705  public function getAmountOfLPChildren(): int
706  {
707  return count($this->getLPChildren());
708  }
709 
710  public function hasLPChildren(): bool
711  {
712  return ($this->getAmountOfLPChildren() > 0);
713  }
714 
718  protected function throwIfNotInTree(): void
719  {
720  if (!$this->tree->isInTree($this->getRefId())) {
721  throw new ilStudyProgrammeTreeException("This program is not in tree.");
722  }
723  }
724 
726  // QUERIES ON SUBTREE
728 
736  public function applyToSubTreeNodes(Closure $fun, bool $include_references = false): void
737  {
738  $this->throwIfNotInTree();
739 
740  if ($fun($this) !== false) {
741  foreach ($this->getChildren($include_references) as $child) {
742  $child->applyToSubTreeNodes($fun, $include_references);
743  }
744  }
745  }
746 
750  public function getCompletedCourses(ilPRGAssignment $assignment): array
751  {
752  $completed_crss = [];
753  $f = function ($prg) use (&$completed_crss, $assignment) {
754  if ($prg->isActive() &&
755  $assignment->getProgressForNode($prg->getId())->isRelevant()
756  ) {
757  foreach ($prg->getLPChildren() as $child) {
758  $crs_id = (int) ilContainerReference::_lookupTargetId((int) $child->getId());
759  $crs_ref_id = (int) ilContainerReference::_lookupTargetRefId((int) $child->getId());
760  $crsr_ref_id = (int) $child->getRefId();
761 
762  if (ilObject::_exists($crsr_ref_id, true) &&
763  is_null(ilObject::_lookupDeletedDate($crsr_ref_id)) &&
764  ilObject::_exists($crs_id, false) &&
765  is_null(ilObject::_lookupDeletedDate($crs_ref_id)) &&
766  ilLPStatus::_hasUserCompleted($crs_id, $assignment->getUserId())
767  ) {
768  $completed_crss[] = [
769  'crs_id' => $crs_id,
770  'prg_ref_id' => $prg->getRefId(),
771  'prg_obj_id' => $prg->getId(),
772  'crsr_ref_id' => $crsr_ref_id,
773  'crsr_id' => $child->getId(),
774  'crs_ref_id' => $crs_ref_id,
775  'title' => ilContainerReference::_lookupTitle((int) $child->getId()),
776  ];
777  }
778  }
779  return true;
780  }
781  return false;
782  };
783  $this->applyToSubTreeNodes($f, true);
784  return $completed_crss;
785  }
786 
788  // TREE MANIPULATION
790 
802  {
803  $this->throwIfNotInTree();
804 
806  throw new ilStudyProgrammeTreeException("Program already contains leafs.");
807  }
808 
809  if ($this->tree->isInTree($a_prg->getRefId())) {
810  throw new ilStudyProgrammeTreeException("Other program already is in tree.");
811  }
812 
813  if ($a_prg->getRefId() === null) {
814  $a_prg->createReference();
815  }
816  $a_prg->putInTree($this->getRefId());
817  return $this;
818  }
819 
828  public function nodeInserted($prg): void
829  {
830  if (! $prg instanceof ilObjStudyProgrammeReference &&
831  ! $prg instanceof ilObjStudyProgramme
832  ) {
833  throw new ilStudyProgrammeTreeException("Wrong type of node: " . get_class($prg));
834  }
836  throw new ilStudyProgrammeTreeException("Program already contains leafs.");
837  }
838 
840  $this->settings_repository->update(
842  );
843  }
844 
845  $this->clearChildrenCache();
846  $this->addMissingProgresses();
847  }
848 
856  public function putInTree(int $parent_ref_id): void
857  {
858  parent::putInTree($parent_ref_id);
859 
860  if (ilObject::_lookupType($parent_ref_id, true) === "prg") {
861  $par = self::getInstanceByRefId($parent_ref_id);
862  $par->nodeInserted($this);
863  }
864  }
865 
876  {
877  if ($a_prg->getParent()->getId() !== $this->getId()) {
878  throw new ilStudyProgrammeTreeException("This is no parent of the given programm.");
879  }
880 
881  if (!$a_prg->canBeRemoved()) {
882  throw new ilStudyProgrammeTreeException("The node has relevant assignments.");
883  }
884 
885  // *sigh*...
886  $node_data = $this->tree->getNodeData($a_prg->getRefId());
887  $this->tree->deleteTree($node_data);
888  $a_prg->clearParentCache();
889  $this->clearChildrenCache();
890 
891  return $this;
892  }
893 
898  public function canBeRemoved(): bool
899  {
900  return ! $this->hasRelevantProgresses();
901  }
902 
912  public function moveTo(ilObjStudyProgramme $new_parent): ilObjStudyProgramme
913  {
914  global $DIC;
915  $rbacadmin = $DIC['rbacadmin'];
916 
917  if ($parent = $this->getParent()) {
918  // TODO: check if there some leafs in the new parent
919 
920  $this->tree->moveTree($this->getRefId(), $new_parent->getRefId());
921  // necessary to clean up permissions
922  $rbacadmin->adjustMovedObjectPermissions($this->getRefId(), $parent->getRefId());
923 
924  // TODO: lp-progress needs to be updated
925 
926  // clear caches on different nodes
927  $this->clearParentCache();
928 
929  $parent->clearChildrenCache();
930  $parent->clearLPChildrenCache();
931 
932  $new_parent->clearChildrenCache();
933  $new_parent->clearLPChildrenCache();
934  }
935 
936  return $this;
937  }
938 
940  // USER ASSIGNMENTS
942 
953  public function assignUser(int $usr_id, int $acting_usr_id = null, $raise_event = true): ilPRGAssignment
954  {
955  $this->members_cache = null;
956 
958  throw new ilException(
959  "ilObjStudyProgramme::assignUser: Can't assign user to program '"
960  . $this->getId() . "', since it's not in active status."
961  );
962  }
963 
964  if (is_null($acting_usr_id)) {
965  $acting_usr_id = $this->getLoggedInUserId();
966  }
967 
968  $ass = $this->assignment_repository->createFor($this->getId(), $usr_id, $acting_usr_id);
969  $ass = $ass
970  ->initAssignmentDates();
971 
972  $ass = $ass->resetProgresses(
973  $this->getSettingsRepository(),
974  $acting_usr_id
975  );
976 
977  $this->assignment_repository->store($ass);
978 
979  if ($raise_event) {
980  $this->events->userAssigned($ass);
981  }
982  return $ass;
983  }
984 
993  {
994  $this->members_cache = null;
995  if ($assignment->getRootId() !== $this->getId()) {
996  throw new ilException(
997  "ilObjStudyProgramme::removeAssignment: Assignment '"
998  . $assignment->getId() . "' does not belong to study "
999  . "program '" . $this->getId() . "'."
1000  );
1001  }
1002 
1003  $this->assignment_repository->delete($assignment);
1004 
1005  $affected_node_ids = array_map(fn($pgs) => $pgs->getNodeId(), $assignment->getProgresses());
1006  foreach ($affected_node_ids as $node_obj_id) {
1007  $this->refreshLPStatus($assignment->getUserId(), $node_obj_id);
1008  }
1009 
1010  $this->events->userDeassigned($assignment);
1011  return $this;
1012  }
1013 
1014  public function getSpecificAssignment(int $assignment_id): ilPRGAssignment
1015  {
1016  return $this->assignment_repository->get($assignment_id);
1017  }
1018 
1019  public function storeExpiryInfoSentFor(ilPRGAssignment $ass): void
1020  {
1021  $this->assignment_repository->storeExpiryInfoSentFor($ass);
1022  }
1023 
1024  public function resetExpiryInfoSentFor(ilPRGAssignment $ass): void
1025  {
1026  $this->assignment_repository->resetExpiryInfoSentFor($ass);
1027  }
1028 
1029  public function storeRiskyToFailSentFor(ilPRGAssignment $ass): void
1030  {
1031  $this->assignment_repository->storeRiskyToFailSentFor($ass);
1032  }
1033 
1034  public function resetRiskyToFailSentFor(ilPRGAssignment $ass): void
1035  {
1036  $this->assignment_repository->resetRiskyToFailSentFor($ass);
1037  }
1038 
1042  public function hasAssignmentOf(int $user_id): bool
1043  {
1044  return $this->getAmountOfAssignmentsOf($user_id) > 0;
1045  }
1046 
1051  public function getAmountOfAssignmentsOf(int $user_id): int
1052  {
1053  return count($this->getAssignmentsOf($user_id));
1054  }
1055 
1063  public function getAssignmentsOf(int $user_id): array
1064  {
1065  $assignments = $this->assignment_repository->getAllForNodeIsContained(
1066  $this->getId(),
1067  [$user_id]
1068  );
1069 
1070  usort($assignments, function ($a_one, $a_other) {
1071  return strcmp(
1072  $a_one->getLastChange()->format('Y-m-d'),
1073  $a_other->getLastChange()->format('Y-m-d')
1074  );
1075  });
1076  return $assignments;
1077  }
1078 
1082  public function getAssignments(): array
1083  {
1084  return $this->assignment_repository->getAllForNodeIsContained($this->getId());
1085  }
1086 
1091  public function getMembers(): array
1092  {
1093  $usr_ids = [];
1094  foreach ($this->getAssignments() as $assignment) {
1095  $usr_ids[] = $assignment->getUserId();
1096  }
1097  return array_unique($usr_ids);
1098  }
1099 
1103  public function getLocalMembers(): array
1104  {
1105  if (!$this->members_cache) {
1106  $this->members_cache = array_map(
1107  static function ($assignment) {
1108  return $assignment->getUserId();
1109  },
1110  $this->assignment_repository->getByPrgId($this->getId())
1111  );
1112  }
1113  return $this->members_cache;
1114  }
1115 
1119  public function hasAssignments(): bool
1120  {
1121  $filter = new ilPRGAssignmentFilter($this->lng);
1122  $count = $this->assignment_repository->countAllForNodeIsContained(
1123  $this->getId(),
1124  null,
1125  $filter
1126  );
1127  return $count > 0;
1128 
1129  }
1130 
1136  public function getAssignmentsOfSingleProgramForUser(int $usr_id): array
1137  {
1138  return $this->assignment_repository->getAllForSpecificNode($this->getId(), [$usr_id]);
1139  }
1140 
1144  public function hasAssignmentsOfSingleProgramForUser(int $usr_id): bool
1145  {
1146  return count($this->getAssignmentsOfSingleProgramForUser($usr_id)) > 0;
1147  }
1148 
1149  public function getCertificateRelevantAssignmentIds(int ...$usr_ids): array
1150  {
1151  return $this->assignment_repository->getCertificateRelevantAssignmentIds(
1152  $this->getId(),
1153  ...$usr_ids
1154  );
1155  }
1156 
1157 
1159  // USER PROGRESS
1161 
1167  public function addMissingProgresses(): void
1168  {
1169  $assignments = $this->getAssignments();
1170  foreach ($assignments as $ass) {
1171  $this->assignment_repository->store($ass);
1172  }
1173  }
1174 
1178  public function hasRelevantProgresses(): bool
1179  {
1180  $filter = new ilPRGAssignmentFilter($this->lng);
1181  $filter = $filter->withValues([
1182  'prg_status_hide_irrelevant' => true
1183  ]);
1184  $count = $this->assignment_repository->countAllForNodeIsContained(
1185  $this->getId(),
1186  null,
1187  $filter
1188  );
1189  return $count > 0;
1190  }
1191 
1192  public function getIdsOfUsersWithRelevantProgress(): array
1193  {
1194  return array_map(
1195  fn($ass) => $ass->getUserId(),
1196  $this->getAssignments()
1197  );
1198  }
1199 
1200 
1202  // AUTOMATIC CONTENT CATEGORIES
1204 
1209  public function getAutomaticContentCategories(): array
1210  {
1211  return $this->auto_categories_repository->getFor($this->getId());
1212  }
1213 
1214  public function hasAutomaticContentCategories(): bool
1215  {
1216  return count($this->getAutomaticContentCategories()) > 0;
1217  }
1218 
1219 
1224  public function storeAutomaticContentCategory(int $category_ref_id): void
1225  {
1226  $ac = $this->auto_categories_repository->create(
1227  $this->getId(),
1228  $category_ref_id
1229  );
1230  $this->auto_categories_repository->update($ac);
1231  }
1232 
1237  public function deleteAutomaticContentCategories(array $category_ids = []): void
1238  {
1239  $this->auto_categories_repository->delete($this->getId(), $category_ids);
1240  }
1241 
1245  public function deleteAllAutomaticContentCategories(): void
1246  {
1247  $this->auto_categories_repository->deleteFor($this->getId());
1248  }
1249 
1253  public static function addCrsToProgrammes(int $crs_ref_id, int $cat_ref_id): void
1254  {
1255  foreach (self::getProgrammesMonitoringCategory($cat_ref_id) as $prg) {
1256  $course_ref = new ilObjCourseReference();
1257  $course_ref->setTitleType(ilContainerReference::TITLE_TYPE_REUSE);
1258  $course_ref->setTargetRefId($crs_ref_id);
1259  $course_ref->create();
1260  $course_ref->createReference();
1261  $course_ref->putInTree($prg->getRefId());
1262  $course_ref->setPermissions($crs_ref_id);
1263  $course_ref->setTargetId(ilObject::_lookupObjectId($crs_ref_id));
1264  $course_ref->update();
1265  $lp = new ilLPObjSettings($course_ref->getId());
1266  $lp->insert();
1267  $lp->setMode($lp::LP_MODE_COURSE_REFERENCE);
1268  $lp->update(false);
1269  }
1270  }
1271 
1277  public static function removeCrsFromProgrammes(int $crs_ref_id, int $cat_ref_id): void
1278  {
1279  foreach (self::getProgrammesMonitoringCategory($cat_ref_id) as $prg) {
1280  foreach ($prg->getLPChildren() as $child) {
1281  if ((int) $child->getTargetRefId() === $crs_ref_id) {
1282  $child->delete();
1283  }
1284  }
1285  }
1286  }
1287 
1292  protected static function getProgrammesMonitoringCategory(int $cat_ref_id): array
1293  {
1294  $db = ilStudyProgrammeDIC::dic()['model.AutoCategories.ilStudyProgrammeAutoCategoriesRepository'];
1295  $programmes =
1296  array_filter(
1297  array_map(
1298  static function (array $rec) {
1299  $values = array_values($rec);
1300  $prg_obj_id = (int) array_shift($values);
1301 
1302  $references = ilObject::_getAllReferences($prg_obj_id);
1303  $prg_ref_id = (int) array_shift($references);
1304 
1305  $prg = self::getInstanceByRefId($prg_ref_id);
1306  if ($prg->isAutoContentApplicable()) {
1307  return $prg;
1308  }
1309  },
1310  $db::getProgrammesFor($cat_ref_id)
1311  )
1312  );
1313  return $programmes;
1314  }
1315 
1322  public function isAutoContentApplicable(): bool
1323  {
1324  $valid_status = in_array(
1325  $this->getSettings()->getAssessmentSettings()->getStatus(),
1326  [
1329  ],
1330  true
1331  );
1332 
1333  $crslnk_allowed = (
1334  $this->hasLPChildren()
1335  || $this->getAmountOfChildren(true) === 0
1336  );
1337 
1338  return $valid_status && $crslnk_allowed;
1339  }
1340 
1341 
1343  // AUTOMATIC MEMBERSHIPS
1345 
1350  public function getAutomaticMembershipSources(): array
1351  {
1352  return $this->auto_memberships_repository->getFor($this->getId());
1353  }
1354 
1358  public function storeAutomaticMembershipSource(string $type, int $src_id, bool $search_recursive): void
1359  {
1360  $ams = $this->auto_memberships_repository->create(
1361  $this->getId(),
1362  $type,
1363  $src_id,
1364  false,
1365  null,
1366  null,
1367  $search_recursive
1368  );
1369  $this->auto_memberships_repository->update($ams);
1370  }
1371 
1375  public function deleteAutomaticMembershipSource(string $type, int $src_id): void
1376  {
1377  $this->auto_memberships_repository->delete($this->getId(), $type, $src_id);
1378  }
1379 
1383  public function deleteAllAutomaticMembershipSources(): void
1384  {
1385  $this->auto_memberships_repository->deleteFor($this->getId());
1386  }
1387 
1391  public function disableAutomaticMembershipSource(string $type, int $src_id, bool $search_recursive): void
1392  {
1393  $ams = $this->auto_memberships_repository->create(
1394  $this->getId(),
1395  $type,
1396  $src_id,
1397  false,
1398  null,
1399  null,
1400  $search_recursive
1401  );
1402  $this->auto_memberships_repository->update($ams);
1403  }
1404 
1409  public function enableAutomaticMembershipSource(string $type, int $src_id, bool $search_recursive, $assign_now = false): void
1410  {
1411  if ($assign_now) {
1413  $member_ids = $this->getMembersOfMembershipSource($type, $src_id);
1414  foreach ($member_ids as $usr_id) {
1415  if (!$this->getAssignmentsOfSingleProgramForUser($usr_id)) {
1416  $this->assignUser($usr_id, $assigned_by);
1417  }
1418  }
1419  }
1420  $ams = $this->auto_memberships_repository->create(
1421  $this->getId(),
1422  $type,
1423  $src_id,
1424  true,
1425  null,
1426  null,
1427  $search_recursive
1428  );
1429  $this->auto_memberships_repository->update($ams);
1430  }
1431 
1437  protected function getMembersOfMembershipSource(ilStudyProgrammeAutoMembershipSource $ams, ?int $exclude_id): array
1438  {
1439  $source_reader = $this->membersourcereader_factory->getReaderFor($ams, $exclude_id);
1440  return $source_reader->getMemberIds();
1441  }
1442 
1447  protected static function getProgrammesMonitoringMemberSource(string $src_type, int $src_id): array
1448  {
1449  $db = ilStudyProgrammeDIC::dic()['model.AutoMemberships.ilStudyProgrammeAutoMembershipsRepository'];
1450  $programmes = array_map(
1451  static function ($rec) {
1452  $values = array_values($rec);
1453  $prg_obj_id = (int) array_shift($values);
1454 
1455  $references = ilObject::_getAllReferences($prg_obj_id);
1456  $prg_ref_id = (int) array_shift($references);
1457 
1458  $prg = self::getInstanceByRefId($prg_ref_id);
1459  return $prg;
1460  },
1461  $db::getProgrammesFor($src_type, $src_id)
1462  );
1463  return $programmes;
1464  }
1465 
1466  public static function addMemberToProgrammes(string $src_type, int $src_id, int $usr_id): void
1467  {
1468  foreach (self::getProgrammesMonitoringMemberSource($src_type, $src_id) as $prg) {
1469  if ($prg->isActive() &&
1470  !$prg->hasAssignmentsOfSingleProgramForUser($usr_id)) {
1471  $assigned_by = ilStudyProgrammeAutoMembershipSource::SOURCE_MAPPING[$src_type];
1472  $prg->assignUser($usr_id, $assigned_by);
1473  }
1474  }
1475  }
1476 
1477  public static function removeMemberFromProgrammes(string $src_type, int $src_id, int $usr_id): void
1478  {
1479  $now = new DateTimeImmutable();
1480  $assignment_repository = ilStudyProgrammeDIC::dic()['repo.assignment'];
1481  foreach (self::getProgrammesMonitoringMemberSource($src_type, $src_id) as $prg) {
1482  $assignments = $prg->getAssignmentsOfSingleProgramForUser($usr_id);
1483  $next_membership_source = $prg->getApplicableMembershipSourceForUser($usr_id, $src_id);
1484 
1485  foreach ($assignments as $assignment) {
1486  if (!$assignment->getProgressTree()->isInProgress()) {
1487  continue;
1488  }
1489 
1490  if (
1491  $next_membership_source !== null
1492  && $next_membership_source?->isEnabled()
1493  && $next_membership_source->getSourceId() !== $src_id
1494  ) {
1495  $new_src_type = $next_membership_source->getSourceType();
1496  $assigned_by = ilStudyProgrammeAutoMembershipSource::SOURCE_MAPPING[$new_src_type];
1497  $assignment = $assignment->withLastChange($assigned_by, $now);
1498  $assignment_repository->store($assignment);
1499  break;
1500  } else {
1501  $assignment_repository->delete($assignment);
1502  }
1503  }
1504  }
1505  }
1506 
1508  int $usr_id,
1509  ?int $exclude_id
1511  foreach ($this->getAutomaticMembershipSources() as $ams) {
1512  if ($ams->isEnabled()) {
1513  $source_members = $this->getMembersOfMembershipSource($ams, $exclude_id);
1514  if (in_array($usr_id, $source_members)) {
1515  return $ams;
1516  }
1517  }
1518  }
1519  return null;
1520  }
1521 
1523  // HELPERS
1525 
1529  protected function updateLastChange(): void
1530  {
1531  $this->getSettings()->updateLastChange();
1532  if ($parent = $this->getParent()) {
1533  $parent->updateLastChange();
1534  }
1535  $this->update();
1536  }
1537 
1549  public static function setProgressesCompletedFor(int $obj_id, int $user_id): void
1550  {
1551  // We only use courses via crs_refs
1552  $type = ilObject::_lookupType($obj_id);
1553  if ($type === "crsr") {
1554  foreach (ilObject::_getAllReferences($obj_id) as $ref_id) {
1555  self::setProgressesCompletedIfParentIsProgrammeInLPCompletedMode($ref_id, $obj_id, $user_id);
1556  }
1557  }
1558  }
1559 
1564  int $ref_id,
1565  int $obj_id,
1566  int $user_id
1567  ): void {
1568  global $DIC; // TODO: replace this by a settable static for testing purpose?
1569  $tree = $DIC['tree'];
1570  $node_data = $tree->getParentNodeData($ref_id);
1571  if (count($node_data) === 0 || !array_key_exists('type', $node_data) || $node_data["type"] !== "prg") {
1572  return;
1573  }
1574  self::initStudyProgrammeCache();
1575  $prg = self::getInstanceByRefId($node_data["child"]);
1576  if ($prg->getLPMode() !== ilStudyProgrammeSettings::MODE_LP_COMPLETED) {
1577  return;
1578  }
1579  $prg->succeed($user_id, $obj_id);
1580  }
1581 
1582  public function succeed(int $usr_id, int $triggering_obj_id, ilPRGAssignment $ass = null): void
1583  {
1584  $progress_node_id = $this->getId();
1585  if (is_null($ass)) {
1586  $user_assignments = $this->assignment_repository
1587  ->getAllForNodeIsContained($progress_node_id, [$usr_id]);
1588  } else {
1589  $user_assignments = [$ass];
1590  }
1591 
1592  foreach ($user_assignments as $ass) {
1593  $ass = $ass->succeed(
1594  $this->getSettingsRepository(),
1595  $progress_node_id,
1596  $triggering_obj_id
1597  );
1598  $this->assignment_repository->store($ass);
1599  }
1600  }
1601 
1602  public function updateCustomIcon(): void
1603  {
1604  $customIcon = $this->custom_icon_factory->getByObjId($this->getId(), $this->getType());
1605  $subtype = $this->getSubType();
1606 
1607  if ($subtype && $subtype->getIconIdentifier()) {
1608  $src = $this->type_repository->getIconPathFS($subtype);
1609 
1610  //This is a horrible hack to allow Flysystem/LocalFilesystem to read the file.
1611  $tmp = 'ico_' . $this->getId();
1612  copy($src, \ilFileUtils::getDataDir() . '/temp/' . $tmp);
1613 
1614  $customIcon->saveFromTempFileName($tmp);
1615  } else {
1616  $customIcon->remove();
1617  }
1618  }
1619 
1621  // HOOKS
1623 
1634  public static function getCreatableSubObjects(array $subobjects, $ref_id): array
1635  {
1636  if ($ref_id === null) {
1637  return $subobjects;
1638  }
1639 
1640  if (ilObject::_lookupType($ref_id, true) !== "prg") {
1641  throw new ilException("Ref-Id '$ref_id' does not belong to a study programme object.");
1642  }
1643 
1644  $parent = self::getInstanceByRefId($ref_id);
1645 
1646  $mode = $parent->getLPMode();
1647 
1648  switch ($mode) {
1650  $possible_subobjects = $subobjects;
1651  break;
1653  $possible_subobjects = [
1654  "prg" => $subobjects["prg"],
1655  "prgr" => $subobjects["prgr"]
1656  ];
1657  break;
1659  $possible_subobjects = ['crsr' => $subobjects['crsr']];
1660  break;
1661  default:
1662  throw new ilException("Undefined mode for study programme: '$mode'");
1663  }
1664 
1665  if ($parent->hasAutomaticContentCategories()) {
1666  $possible_subobjects = array_filter(
1667  $possible_subobjects,
1668  static function ($subtype) {
1669  return $subtype === 'crsr';
1670  },
1671  ARRAY_FILTER_USE_KEY
1672  );
1673  }
1674  return $possible_subobjects;
1675  }
1676 
1677 
1678  protected function getLoggedInUserId(): int
1679  {
1680  return $this->ilUser->getId();
1681  }
1682 
1683  protected function getNow(): DateTimeImmutable
1684  {
1685  return new DateTimeImmutable();
1686  }
1687 
1688  protected function refreshLPStatus(int $usr_id, int $node_obj_id = null): void
1689  {
1690  if (is_null($node_obj_id)) {
1691  $node_obj_id = $this->getId();
1692  }
1693  ilLPStatusWrapper::_updateStatus($node_obj_id, $usr_id);
1694  }
1695 
1696  public function markAccredited(
1697  int $assignment_id,
1698  int $acting_usr_id,
1699  ilPRGMessageCollection $err_collection
1700  ): void {
1701  $progress_node_id = $this->getId();
1702  $assignment = $this->assignment_repository->get($assignment_id)
1703  ->markAccredited(
1704  $this->getSettingsRepository(),
1705  $this->events,
1706  $progress_node_id,
1707  $acting_usr_id,
1708  $err_collection
1709  );
1710 
1711  $this->assignment_repository->store($assignment);
1712  }
1713 
1714  public function unmarkAccredited(
1715  int $assignment_id,
1716  int $acting_usr_id,
1717  ilPRGMessageCollection $err_collection
1718  ): void {
1719  $progress_node_id = $this->getId();
1720  $assignment = $this->assignment_repository->get($assignment_id)
1721  ->unmarkAccredited(
1722  $this->getSettingsRepository(),
1723  $progress_node_id,
1724  $acting_usr_id,
1725  $err_collection
1726  );
1727 
1728  $this->assignment_repository->store($assignment);
1729  $this->refreshLPStatus($assignment->getUserId());
1730  }
1731 
1732  public function markNotRelevant(
1733  int $assignment_id,
1734  int $acting_usr_id,
1735  ilPRGMessageCollection $err_collection
1736  ): void {
1737  $progress_node_id = $this->getId();
1738  $assignment = $this->assignment_repository->get($assignment_id)
1739  ->markNotRelevant(
1740  $this->getSettingsRepository(),
1741  $progress_node_id,
1742  $acting_usr_id,
1743  $err_collection
1744  );
1745 
1746  $this->assignment_repository->store($assignment);
1747  $this->refreshLPStatus($assignment->getUserId());
1748  }
1749 
1750  public function markRelevant(
1751  int $assignment_id,
1752  int $acting_usr_id,
1753  ilPRGMessageCollection $err_collection
1754  ): void {
1755  $progress_node_id = $this->getId();
1756  $assignment = $this->assignment_repository->get($assignment_id)
1757  ->markRelevant(
1758  $this->getSettingsRepository(),
1759  $progress_node_id,
1760  $acting_usr_id,
1761  $err_collection
1762  );
1763 
1764  $this->assignment_repository->store($assignment);
1765  $this->refreshLPStatus($assignment->getUserId());
1766  }
1767 
1768  public function changeProgressDeadline(
1769  int $assignment_id,
1770  int $acting_usr_id,
1771  ilPRGMessageCollection $err_collection,
1772  ?DateTimeImmutable $deadline
1773  ): void {
1774  $progress_node_id = $this->getId();
1775  $assignment = $this->assignment_repository->get($assignment_id)
1776  ->changeProgressDeadline(
1777  $this->getSettingsRepository(),
1778  $progress_node_id,
1779  $acting_usr_id,
1780  $err_collection,
1781  $deadline
1782  );
1783 
1784  $this->assignment_repository->store($assignment);
1785  $this->refreshLPStatus($assignment->getUserId());
1786  }
1787 
1789  int $assignment_id,
1790  int $acting_usr_id,
1791  ilPRGMessageCollection $err_collection,
1792  ?DateTimeImmutable $validity
1793  ): void {
1794  $progress_node_id = $this->getId();
1795  $assignment = $this->assignment_repository->get($assignment_id)
1796  ->changeProgressValidityDate(
1797  $this->getSettingsRepository(),
1798  $progress_node_id,
1799  $acting_usr_id,
1800  $err_collection,
1801  $validity
1802  );
1803 
1804  $this->assignment_repository->store($assignment);
1805  $this->refreshLPStatus($assignment->getUserId());
1806  }
1807 
1808  public function changeAmountOfPoints(
1809  int $assignment_id,
1810  int $acting_usr_id,
1811  ilPRGMessageCollection $err_collection,
1812  int $points
1813  ): void {
1814  $progress_node_id = $this->getId();
1815  $assignment = $this->assignment_repository->get($assignment_id)
1816  ->changeAmountOfPoints(
1817  $this->getSettingsRepository(),
1818  $progress_node_id,
1819  $acting_usr_id,
1820  $err_collection,
1821  $points
1822  );
1823 
1824  $this->assignment_repository->store($assignment);
1825  $this->refreshLPStatus($assignment->getUserId());
1826  }
1827 
1828  public function updatePlanFromRepository(
1829  int $assignment_id,
1830  int $acting_usr_id,
1831  ilPRGMessageCollection $err_collection = null
1832  ): void {
1833  $assignment = $this->assignment_repository->get($assignment_id)
1834  ->updatePlanFromRepository(
1835  $this->getSettingsRepository(),
1836  $acting_usr_id,
1837  $err_collection
1838  );
1839 
1840  $this->assignment_repository->store($assignment);
1841  $this->refreshLPStatus($assignment->getUserId());
1842  }
1843 
1844  public function acknowledgeCourses(
1845  int $assignment_id,
1846  array $nodes,
1847  ilPRGMessageCollection $err_collection = null
1848  ): void {
1849  $acting_usr_id = $this->getLoggedInUserId();
1850  $assignment = $this->assignment_repository->get($assignment_id);
1851  foreach ($nodes as $nodeinfo) {
1852  [$node_obj_id, $course_obj_id] = $nodeinfo;
1853 
1854  $assignment = $assignment->succeed(
1855  $this->settings_repository,
1856  $node_obj_id,
1857  $course_obj_id
1858  );
1859 
1860  $msg = sprintf(
1861  '%s, progress-id (%s/%s)',
1862  $assignment->getUserInformation()->getFullname(),
1863  $assignment->getId(),
1864  (string) $node_obj_id
1865  );
1866  $err_collection->add(true, 'acknowledged_course', $msg);
1867  }
1868  $this->assignment_repository->store($assignment);
1869  $this->refreshLPStatus($assignment->getUserId());
1870  }
1871 
1872  public function canBeCompleted(ilPRGProgress $progress): bool
1873  {
1875  return false;
1876  }
1878  return true;
1879  }
1880  $possible_points = $progress->getPossiblePointsOfRelevantChildren();
1881  return $possible_points >= $progress->getAmountOfPoints();
1882  }
1883 
1887  public function statusToRepr(int $status): string
1888  {
1889  $lng = $this->lng;
1890  $lng->loadLanguageModule("prg");
1891  if ($status === ilPRGProgress::STATUS_IN_PROGRESS) {
1892  return $lng->txt("prg_status_in_progress");
1893  }
1894  if ($status === ilPRGProgress::STATUS_COMPLETED) {
1895  return $lng->txt("prg_status_completed");
1896  }
1897  if ($status === ilPRGProgress::STATUS_ACCREDITED) {
1898  return $lng->txt("prg_status_accredited");
1899  }
1900  if ($status === ilPRGProgress::STATUS_NOT_RELEVANT) {
1901  return $lng->txt("prg_status_not_relevant");
1902  }
1903  if ($status === ilPRGProgress::STATUS_FAILED) {
1904  return $lng->txt("prg_status_failed");
1905  }
1906  throw new ilException("Unknown status: '$status'");
1907  }
1908 
1909  public function hasContentPage(): bool
1910  {
1911  return \ilContainerPage::_exists(self::CP_TYPE, $this->getId());
1912  }
1913  public function createContentPage(): void
1914  {
1915  if ($this->hasContentPage()) {
1916  throw new \LogicException('will not create content page - it already exists.');
1917  }
1918  $new_page_object = new \ilContainerPage();
1919  $new_page_object->setId($this->getId());
1920  $new_page_object->setParentId($this->getId());
1921  $new_page_object->createFromXML();
1922  }
1923 }
setStatus(int $a_status)
Set the status of the node.
getCertificateRelevantAssignmentIds(int ... $usr_ids)
static _hasUserCompleted(int $a_obj_id, int $a_user_id)
Lookup user object completion.
adjustLPMode()
Adjust the lp mode to match current state of tree:
string $type
getCompletedCourses(ilPRGAssignment $assignment)
Get courses in this program that the given user already completed.
addNode(ilObjStudyProgramme $a_prg)
Inserts another ilObjStudyProgramme in this object.
disableAutomaticMembershipSource(string $type, int $src_id, bool $search_recursive)
Disable a membership source.
clearLPChildrenCache()
Clear the cached lp children.
static addCrsToProgrammes(int $crs_ref_id, int $cat_ref_id)
Check, if a category is under surveilllance and automatically add the course.
getSubType()
Gets the SubType Object.
static _lookupTitle(int $obj_id)
markRelevant(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection)
storeAutomaticContentCategory(int $category_ref_id)
Store a Category with auto-content for this StudyProgramme; a category can only be referenced once (p...
static getLogger(string $a_component_id)
Get component logger.
getParent()
Get the parent ilObjStudyProgramme of this object.
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
getApplicableMembershipSourceForUser(int $usr_id, ?int $exclude_id)
changeProgressValidityDate(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection, ?DateTimeImmutable $validity)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
isAutoContentApplicable()
AutoContent should only be available in active- or draft-mode, and only, if there is no sub-programme...
assignUser(int $usr_id, int $acting_usr_id=null, $raise_event=true)
Assign a user to this node at the study program.
getMembers()
get usr_ids with any progress on this node
unmarkAccredited(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
ilStudyProgrammeMembershipSourceReaderFactory $membersourcereader_factory
getRefIdFor(int $obj_id)
getChildren(bool $include_references=false)
Get all ilObjStudyProgrammes that are direct children of this object.
static getProgrammesMonitoringMemberSource(string $src_type, int $src_id)
Get all StudyProgrammes monitoring this membership-source.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getLPChildren()
Get the leafs the study programme contains.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getAllReferences(int $id)
get all reference ids for object ID
nodeInserted($prg)
Clears child cache and adds progress for new node.
ilTree $tree
isDeleted(int $a_node_id)
This is a wrapper for isSaved() with a more useful name.
__construct(int $id=0, bool $call_by_reference=true)
ATTENTION: After using the constructor the object won&#39;t be in the cache.
static saveObjRecSelection(int $a_obj_id, string $a_sub_type="", array $a_records=null, bool $a_delete_before=true)
Save repository object record selection.
applyToSubTreeNodes(Closure $fun, bool $include_references=false)
Apply the given Closure to every node in the subtree starting at this object.
static getCreatableSubObjects(array $subobjects, $ref_id)
Filter the list of possible subobjects for the objects that actually could be created on a concrete n...
loadLanguageModule(string $a_module)
Load language module.
deleteAssignmentsAndProgresses()
Delete all assignments from the DB.
markNotRelevant(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection)
hasAssignmentOf(int $user_id)
Check whether user is assigned to this program or any node above.
storeRiskyToFailSentFor(ilPRGAssignment $ass)
storeExpiryInfoSentFor(ilPRGAssignment $ass)
getLocalMembers()
get usr_ids with assignment on this node
enableAutomaticMembershipSource(string $type, int $src_id, bool $search_recursive, $assign_now=false)
Enable a membership source.
getAssignmentsOf(int $user_id)
Get the assignments of user at this program or any node above.
changeProgressDeadline(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection, ?DateTimeImmutable $deadline)
getAmountOfLPChildren()
Get the amount of leafs the study programme contains.
getRoot()
Get the ilObjStudyProgramme that is the root node of the tree this programme is in.
static getProgrammesMonitoringCategory(int $cat_ref_id)
Get all (not OUTDATED) StudyProgrammes monitoring this category.
static removeCrsFromProgrammes(int $crs_ref_id, int $cat_ref_id)
Check, if a category is under surveillance and automatically remove the deleted course.
resetRiskyToFailSentFor(ilPRGAssignment $ass)
createReference()
creates reference for object
removeNode(ilObjStudyProgramme $a_prg)
Remove a node from this object.
hasAssignments()
Are there any assignments on this node or any node above?
A Progress is the status of a user on a single node of an assignment; it is unique by assignment_id:u...
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Provides adapters to read member-ids from a specific source.
clearChildrenCache()
Clear the cached children.
getAutomaticContentCategories()
Get configuration of categories with auto-content for this StudyProgramme;.
getParentNodeData(int $a_node_id)
get data of parent node from tree and object_data
resetExpiryInfoSentFor(ilPRGAssignment $ass)
deleteAllAutomaticContentCategories()
Delete all configuration of categories with auto-content for this StudyProgramme;.
ilStudyProgrammeAutoMembershipsDBRepository $auto_memberships_repository
hasRelevantProgresses()
Are there any users that have a relevant progress on this programme?
removeAssignment(ilPRGAssignment $assignment)
Remove an assignment from this program.
getMembersOfMembershipSource(ilStudyProgrammeAutoMembershipSource $ams, ?int $exclude_id)
Get member-ids of a certain source.
ilLanguage $lng
static addMemberToProgrammes(string $src_type, int $src_id, int $usr_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
bool $call_by_reference
getParents(bool $include_references=false)
Get all parents of the node, where the root of the program comes first.
ilDBInterface $db
cloneObject(int $target_ref_id, int $copy_id=0, bool $omit_tree=false)
getAssignmentsOfSingleProgramForUser(int $usr_id)
Get assignments of user to this program-node only.
static ilObjStudyProgrammeCache $study_programme_cache
getSpecificAssignment(int $assignment_id)
acknowledgeCourses(int $assignment_id, array $nodes, ilPRGMessageCollection $err_collection=null)
global $DIC
Definition: shib_login.php:25
getProgresses(array &$ret=[], ilPRGProgress $pgs=null)
static _lookupObjectId(int $ref_id)
statusToRepr(int $status)
Get a user readable representation of a status.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
hasAssignmentsOfSingleProgramForUser(int $usr_id)
Get assignments of user to this program-node only.
markAccredited(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection)
changeAmountOfPoints(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection, int $points)
static getDataDir()
get data directory (outside webspace)
moveTo(ilObjStudyProgramme $new_parent)
Move this tree node to a new parent.
succeed(int $usr_id, int $triggering_obj_id, ilPRGAssignment $ass=null)
static removeMemberFromProgrammes(string $src_type, int $src_id, int $usr_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static setProgressesCompletedFor(int $obj_id, int $user_id)
Succeed all StudyProgramme(Nodes) where the object with the given id (a CRSR) is in a Programme with ...
static _lookupSourceIds(int $a_target_id)
Get ids of all container references that target the object with the given id.
canBeCompleted(ilPRGProgress $progress)
setPoints(int $points)
Set the amount of points.
updatePlanFromRepository(int $assignment_id, int $acting_usr_id, ilPRGMessageCollection $err_collection=null)
static getInstanceByObjId(int $obj_id)
getLastChange()
Get the timestamp of the last change on this program or sub program.
ilStudyProgrammeEvents $events
getObjId()
Get the id of the study program.
fetchCurrentlyUsedCertificate(int $objId)
static setProgressesCompletedIfParentIsProgrammeInLPCompletedMode(int $ref_id, int $obj_id, int $user_id)
ilPRGAssignmentDBRepository $assignment_repository
addMissingProgresses()
Add missing progress records for all assignments of this programm.
getReferencesTo(ilObjStudyProgramme $prg)
Class ilStudyProgrammeType.
storeAutomaticMembershipSource(string $type, int $src_id, bool $search_recursive)
Store a source to be monitored for automatic memberships.
static getAllChildren(int $a_ref_id, bool $include_references=false)
Get a list of all ilObjStudyProgrammes in the subtree starting at $a_ref_id.
canBeRemoved()
Check weather a node can be removed.
Assignments are relations of users to a PRG; They hold progress-information for (sub-)nodes of the PR...
getAutomaticMembershipSources()
Get sources for auto-memberships.
getDepth()
Get the depth of this StudyProgramme in the tree starting at the topmost StudyProgramme (not root nod...
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:24
hasChildren(bool $include_references=false)
Does this StudyProgramme have other ilObjStudyProgrammes as children?
__construct(Container $dic, ilPlugin $plugin)
ilStudyProgrammeAutoCategoryDBRepository $auto_categories_repository
putInTree(int $parent_ref_id)
Overwritten from ilObject.
ilObjectFactoryWrapper $object_factory
static _getInstance(int $a_obj_id)
static _lookupTargetRefId(int $a_obj_id)
getLPChildrenIds()
Get the obj-ids of the leafs the program contains.
static _lookupTargetId(int $a_obj_id)
$dic
Definition: ltiresult.php:33
static createInstance()
Create an instance of ilObjStudyProgramme, put in cache.
static getRefIdFor(int $obj_id)
deleteAutomaticContentCategories(array $category_ids=[])
Delete configuration of categories with auto-content for this StudyProgramme;.
getPoints()
Get the amount of points.
getProgressForNode(int $node_id)
ilStudyProgrammeSettingsDBRepository $settings_repository
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)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAmountOfChildren($include_references=false)
Get the amount of other StudyProgrammes this StudyProgramme has as children.
refreshLPStatus(int $usr_id, int $node_obj_id=null)
getAmountOfAssignmentsOf(int $user_id)
Get the amount of assignments a user has on this program node or any node above.
ilObjectCustomIconFactory $custom_icon_factory
static _lookupDeletedDate(int $ref_id)
deleteAllAutomaticMembershipSources()
Delete all membership sources of this StudyProgramme;.
updateLastChange()
Update last change timestamp on this node and its parents.
ilCertificateTemplateRepository $certificate_template_repository
clearParentCache()
Clear the cached parent to query it again at the tree.
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
deleteAutomaticMembershipSource(string $type, int $src_id)
Delete a membership source.
Holds information about multi-actions, mainly in context of member-assignemnts and status changes...
ilStudyProgrammeTypeDBRepository $type_repository
updateSettings(ilStudyProgrammeSettings $settings)