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