ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.ilStudyProgrammeUserProgress.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 2015 Richard Klees <richard.klees@concepts-and-training.de> Extended GPL, see docs/LICENSE */
4/* Copyright (c) 2019 Stefan Hecken <stefan.hecken@concepts-and-training.de> Extended GPL, see docs/LICENSE */
5
6declare(strict_types=1);
7
15{
16 const ACTION_MARK_ACCREDITED = "mark_accredited";
17 const ACTION_UNMARK_ACCREDITED = "unmark_accredited";
18 const ACTION_SHOW_INDIVIDUAL_PLAN = "show_individual_plan";
19 const ACTION_REMOVE_USER = "remove_user";
20 const ACTION_CHANGE_EXPIRE_DATE = "change_expire_date";
21 const ACTION_CHANGE_DEADLINE = "change_deadline";
22
26 protected $progress;
27
32
37
41 protected $events;
42
43 public function __construct(
48 ) {
49 $this->progress = $progress;
50 $this->progress_repository = $progress_repository;
51 $this->assignment_repository = $assignment_repository;
52 $this->events = $events;
53 }
54
65 {
66 $refs = ilObject::_getAllReferences($this->progress->getNodeId());
67 if (!count($refs)) {
68 throw new ilException(
69 "ilStudyProgrammeUserAssignment::getStudyProgramme: "
70 . "could not find ref_id for program '"
71 . $this->progress->getNodeId() . "'."
72 )
73 ;
74 }
75 return ilObjStudyProgramme::getInstanceByRefId(array_shift($refs));
76 }
77
81 public function getAssignmentId() : int
82 {
83 return $this->progress->getAssignmentId();
84 }
85
89 public function getId() : int
90 {
91 return $this->progress->getId();
92 }
93
97 public function getNodeId() : int
98 {
99 return $this->progress->getNodeId();
100 }
101
105 public function getUserId() : int
106 {
107 return $this->progress->getUserId();
108 }
109
113 public function getStatus() : int
114 {
115 return $this->progress->getStatus();
116 }
117
122 public function getAmountOfPoints() : int
123 {
124 return $this->progress->getAmountOfPoints();
125 }
126
130 public function getCurrentAmountOfPoints() : int
131 {
132 if (
133 $this->isAccredited() ||
134 ($this->isSuccessful() && $this->getStudyProgramme()->hasLPChildren())
135 ) {
136 return $this->getAmountOfPoints();
137 }
138
139 return $this->progress->getCurrentAmountOfPoints();
140 }
141
145 public function getLastChange() : DateTime
146 {
147 return $this->progress->getLastChange();
148 }
149
153 public function getLastChangeBy() : ?int
154 {
155 return $this->progress->getLastChangeBy();
156 }
157
161 public function getCompletionBy()
162 {
163 return $this->progress->getCompletionBy();
164 }
165
169 public function getAssignmentDate() : DateTime
170 {
171 return $this->progress->getAssignmentDate();
172 }
173
177 public function getCompletionDate() : ?DateTime
178 {
179 return $this->progress->getCompletionDate();
180 }
181
185 public function getDeadline()
186 {
187 return $this->progress->getDeadline();
188 }
189
193 public function setDeadline(DateTime $deadline = null) : ilStudyProgrammeProgress
194 {
195 return $this->progress->setDeadline($deadline);
196 }
197
203 public function getValidityOfQualification() : ?DateTime
204 {
205 return $this->progress->getValidityOfQualification();
206 }
207
211 public function setValidityOfQualification(DateTime $date = null) : void
212 {
213 $this->progress->setValidityOfQualification($date);
214 }
215
216 public function storeProgress() : void
217 {
218 $this->progress_repository->update($this->progress);
219 }
220
224 public function delete() : void
225 {
226 $this->progress_repository->delete($this->progress);
227 }
228
229
238 public function markAccredited(int $user_id) : ilStudyProgrammeUserProgress
239 {
240 $prg = $this->getStudyProgramme();
242 if ($prg->getStatus() == ilStudyProgrammeSettings::STATUS_OUTDATED) {
243 throw new ilException(
244 "ilStudyProgrammeUserProgress::markAccredited: "
245 . "Can't mark as accredited since program is outdated."
246 );
247 }
248 }
249 $progress = $this->progress
251 ->setCompletionBy($user_id)
252 ->setLastChangeBy($user_id)
253 ->setLastChange(new DateTime())
254 ->setCompletionDate(new DateTime())
255 ;
256
257 $this->progress_repository->update($progress);
258
259 $assignment = $this->assignment_repository->read($this->getAssignmentId());
260 if ((int) $prg->getId() === $assignment->getRootId()) {
261 $this->maybeLimitProgressValidity($prg, $assignment);
262 }
263
264 $this->events->userSuccessful($this);
265 $this->updateParentStatus();
266
267 return $this;
268 }
269
278 {
279 if ($this->progress->getStatus() != ilStudyProgrammeProgress::STATUS_ACCREDITED) {
280 throw new ilException("Expected status ACCREDITED.");
281 }
282
283 $this->progress_repository->update(
284 $this->progress
286 ->setCompletionBy(null)
287 ->setCompletionDate(null)
288 );
289
290 $this->refreshLPStatus();
291 $this->updateParentStatus();
292
293 return $this;
294 }
295
303 public function markFailed(int $a_user_id) : ilStudyProgrammeUserProgress
304 {
305 $status = array(
309 );
310
311 if (in_array($this->getStatus(), $status)) {
312 throw new ilException("Can't mark as failed since program is passed.");
313 }
314
315 $this->progress
317 ->setLastChangeBy($a_user_id)
318 ->setCompletionDate(null);
319
320 $this->progress_repository->update($this->progress);
321 $this->refreshLPStatus();
322
323 return $this;
324 }
325
334 {
335 $status = array(
339 );
340
341 if (in_array($this->getStatus(), $status) && !$this->isSuccessfulExpired()) {
342 throw new ilException("Can't mark as failed since program is passed.");
343 }
344
345 $this->progress_repository->update(
346 $this->progress->invalidate()
347 );
348
349 $this->refreshLPStatus();
350
351 return $this;
352 }
353
354 public function isInvalidated() : bool
355 {
356 return $this->progress->isInvalidated();
357 }
358
362 public function isSuccessfulExpired() : bool
363 {
364 if ($this->getValidityOfQualification() === null) {
365 return false;
366 }
367
368 if (!$this->isSuccessful()) {
369 return false;
370 }
371
372 if (
373 $this->getValidityOfQualification()->format('Y-m-d') < (new DateTime())->format('Y-m-d')
374 ) {
375 return true;
376 }
377
378 return false;
379 }
380
388 public function markNotFailed(int $user_id) : ilStudyProgrammeUserProgress
389 {
390 if ($this->progress->getStatus() != ilStudyProgrammeProgress::STATUS_FAILED) {
391 throw new ilException("Expected status FAILED.");
392 }
393
394 $this->progress_repository->update(
395 $this->progress
397 ->setCompletionBy(null)
398 ->setLastChangeBy($user_id)
399 );
400
401 $this->refreshLPStatus();
402
403 return $this;
404 }
405
415 public function markNotRelevant(int $user_id) : ilStudyProgrammeUserProgress
416 {
417 $this->progress_repository->update(
418 $this->progress
420 ->setCompletionBy($user_id)
421 ->setLastChangeBy($user_id)
422 );
423
424 $this->updateStatus();
425
426 return $this;
427 }
428
436 public function markRelevant(int $user_id) : ilStudyProgrammeUserProgress
437 {
438 if ($this->progress->getStatus() != ilStudyProgrammeProgress::STATUS_NOT_RELEVANT) {
439 throw new ilException("Expected status IN_PROGRESS.");
440 }
441
442 $this->progress_repository->update(
443 $this->progress
445 ->setCompletionBy($user_id)
446 ->setLastChangeBy($user_id)
447 );
448
449 $this->updateStatus();
450
451 return $this;
452 }
453
462 int $a_points,
463 int $user_id
465 $this->progress_repository->update(
466 $this->progress
467 ->setAmountOfPoints($a_points)
468 ->setLastChangeBy($user_id)
469 );
470
471 $this->updateStatus();
472
473 return $this;
474 }
475
486 public function getMaximumPossibleAmountOfPoints(bool $only_relevant = false) : int
487 {
488 $prg = $this->getStudyProgramme();
489 if ($prg->getLPMode() == ilStudyProgrammeSettings::MODE_LP_COMPLETED) {
490 return $this->getAmountOfPoints();
491 }
492
493 $children = $prg->getChildren();
494 $ass = $this->progress->getAssignmentId();
495 $points = array_map(function ($child) use ($ass, $only_relevant) {
496 $relevant = $child->getProgressForAssignment($ass)->isRelevant();
497 if ($only_relevant) {
498 if ($relevant) {
499 return $child->getProgressForAssignment($ass)->getAmountOfPoints();
500 } else {
501 return 0;
502 }
503 } else {
504 return $child->getProgressForAssignment($ass)->getAmountOfPoints();
505 }
506 }, $children);
507
508 return array_reduce($points, function ($a, $b) {
509 return $a + $b;
510 }, 0);
511 }
512
519 public function canBeCompleted() : bool
520 {
521 $prg = $this->getStudyProgramme();
522
523 if ($prg->getLPMode() == ilStudyProgrammeSettings::MODE_LP_COMPLETED) {
524 return true;
525 }
526
527 if ($this->getMaximumPossibleAmountOfPoints(true) < $this->getAmountOfPoints()) {
528 // Fast track
529 return false;
530 }
531
532 $children_progress = $this->getChildrenProgress();
533 foreach ($children_progress as $progress) {
534 if ($progress->isRelevant() && !$progress->canBeCompleted()) {
535 return false;
536 }
537 }
538
539 return true;
540 }
541
545 public function hasIndividualModifications() : bool
546 {
547 return $this->getLastChangeBy() !== null;
548 }
549
554 public function isSuccessful() : bool
555 {
556 $status = $this->getStatus();
557
558 return
561 ;
562 }
563
567 public function isFailed() : bool
568 {
569 $status = $this->getStatus();
570
572 }
573
579 public function recalculateFailedToDeadline() : void
580 {
581 $deadline = $this->getDeadline();
583
584 if ($deadline
585 && $deadline->format(ilStudyProgrammeProgress::DATE_FORMAT) < $today
586 && $this->progress->getStatus() === ilStudyProgrammeProgress::STATUS_IN_PROGRESS
587 ) {
588 $this->progress_repository->update(
589 $this->progress
591 );
592 }
593 }
594
598 public function isAccredited() : bool
599 {
600 return $this->getStatus() == ilStudyProgrammeProgress::STATUS_ACCREDITED;
601 }
602
606 public function isRelevant() : bool
607 {
608 return $this->getStatus() != ilStudyProgrammeProgress::STATUS_NOT_RELEVANT;
609 }
610
619 public function updateFromProgramNode()
620 {
621 if ($this->hasIndividualModifications()) {
622 return false;
623 }
624
625 if ($this->getStatus() == ilStudyProgrammeProgress::STATUS_COMPLETED) {
626 return false;
627 }
628
629 $prg = $this->getStudyProgramme();
630
632 if ($prg->getStatus() == ilStudyProgrammeSettings::STATUS_ACTIVE) {
634 }
635
636 $this->progress_repository->update(
637 $this->progress
638 ->setAmountOfPoints($prg->getPoints())
639 ->setStatus($status)
640 );
641
642 $this->updateStatus();
643 }
644
652 protected function updateStatus()
653 {
654 $prg = $this->getStudyProgramme();
655 if (
656 ($prg->getLPMode() == ilStudyProgrammeSettings::MODE_LP_COMPLETED &&
657 $this->getStatus() != ilStudyProgrammeProgress::STATUS_ACCREDITED) ||
659 ) {
660 // Nothing to do here, as the status will be set by LP.
661 // OR current status is NOT RELEVANT
662 return;
663 }
664
665 $add = function ($a, $b) {
666 return $a + $b;
667 };
668 $get_points = function ($child) {
669 if (!$child->isSuccessful()) {
670 return 0;
671 }
672 return $child->getAmountOfPoints();
673 };
674
675 $achieved_points = array_reduce(array_map($get_points, $this->getChildrenProgress()), $add);
676 if (!$achieved_points) {
677 $achieved_points = 0;
678 }
679
680 $successful = $achieved_points >= $this->getAmountOfPoints() && $this->hasSuccessfullChildren();
681 $this->progress->setCurrentAmountOfPoints($achieved_points);
682
683 if ($successful) {
684 $this->progress->setStatus(ilStudyProgrammeProgress::STATUS_COMPLETED);
685 if (!$this->progress->getCompletionDate()) {
686 $this->progress->setCompletionDate(new DateTime());
687 }
688
689 $assignment = $this->assignment_repository->read($this->getAssignmentId());
690 if ((int) $prg->getId() === $assignment->getRootId()) {
691 $this->maybeLimitProgressValidity($prg, $assignment);
692 }
693 $this->events->userSuccessful($this);
694 } else {
695 $this->progress->setStatus(ilStudyProgrammeProgress::STATUS_IN_PROGRESS);
696 $this->progress->setCompletionDate(null);
697 }
698
699 $this->progress_repository->update(
700 $this->progress
701 );
702
703 $this->refreshLPStatus();
704 $this->updateParentStatus();
705 }
706
710 protected function hasSuccessfullChildren() : bool
711 {
712 foreach ($this->getChildrenProgress() as $child) {
713 if ($child->isSuccessful()) {
714 return true;
715 }
716 }
717
718 return false;
719 }
720
724 protected function updateParentStatus() : void
725 {
726 foreach ($this->getParentProgresses() as $parent) {
727 $parent->updateStatus();
728 }
729 }
730
742 public function setLPCompleted(int $obj_id, int $usr_id)
743 {
744 if ($this->isSuccessful() || !$this->isRelevant()) {
745 return true;
746 }
747
748 $prg = $this->getStudyProgramme();
749 if ($prg->getLPMode() != ilStudyProgrammeSettings::MODE_LP_COMPLETED) {
750 throw new ilException(
751 "ilStudyProgrammeUserProgress::setLPCompleted: "
752 . "The node '" . $prg->getId() . "' is not in LP_COMPLETED mode."
753 );
754 }
755
756 if ($this->getUserId() != $usr_id) {
757 throw new ilException(
758 "ilStudyProgrammeUserProgress::setLPCompleted: "
759 . "This progress does belong to user '" . $this->getUserId()
760 . "' and not to user '$usr_id'"
761 );
762 }
763
764 if (!in_array($obj_id, $prg->getLPChildrenIds())) {
765 throw new ilException(
766 "ilStudyProgrammeUserProgress::setLPCompleted: "
767 . "Object '$obj_id' is no child of node '" . $prg->getId() . "'."
768 );
769 }
770
771 $this->progress_repository->update(
772 $this->progress
774 ->setCompletionBy($obj_id)
775 ->setCompletionDate(new DateTime())
776 );
777
778 $this->refreshLPStatus();
779
780 $assignment = $this->assignment_repository->read($this->getAssignmentId());
781 if ((int) $prg->getId() === $assignment->getRootId()) {
782 $this->maybeLimitProgressValidity($prg, $assignment);
783 }
784
785 $this->events->userSuccessful($this);
786 $this->updateParentStatus();
787 }
788
792 protected function maybeLimitProgressValidity(
795 ) : void {
796 $qualification_date = $prg->getValidityOfQualificationSettings()->getQualificationDate();
797 $qualification_period = $prg->getValidityOfQualificationSettings()->getQualificationPeriod();
798 if (!is_null($qualification_date)) {
799 $date = $qualification_date;
800 } elseif (
802 ) {
803 $date = new DateTime();
804 $date->add(new DateInterval('P' . $qualification_period . 'D'));
805 } else {
806 // nothing to do
807 return;
808 }
809
810 $this->progress_repository->update($this->progress->setValidityOfQualification($date));
811
812 $restart_period = $prg->getValidityOfQualificationSettings()->getRestartPeriod();
813 if (ilStudyProgrammeSettings::NO_RESTART !== $restart_period) {
814 $date->sub(new DateInterval('P' . $restart_period . 'D'));
815 $this->assignment_repository->update($assignment->setRestartDate($date));
816 }
817 }
818
826 protected function getParentProgresses() : array
827 {
828 if ($this->getStudyProgramme()->getId() == $this->assignment_repository->read($this->getAssignmentId())->getRootId()) {
829 return [];
830 }
831
832 $overall_parents = [];
833 $prg = $this->getStudyProgramme();
834 $parent = $prg->getParent();
835
836 if ($parent) {
837 $overall_parents[] = $parent;
838 }
839
840 foreach ($prg->getReferencesToSelf() as $ref) {
841 $overall_parents[] = $ref->getParent();
842 }
843
844 return array_map(
845 function ($parent) {
846 return $parent->getProgressForAssignment($this->progress->getAssignmentId());
847 },
848 $overall_parents
849 );
850 }
851
859 public function getChildrenProgress() : array
860 {
861 $prg = $this->getStudyProgramme();
863 throw new ilException(
864 "ilStudyProgrammeUserProgress::getChildrenProgress: "
865 . "There is some problem in the implementation. This "
866 . "method should only be callled for nodes in points "
867 . "mode."
868 );
869 }
870
871 $ass_id = $this->progress->getAssignmentId();
872
873 return array_map(function ($child) use ($ass_id) {
874 return $child->getProgressForAssignment($ass_id);
875 }, $prg->getChildren(true));
876 }
877
886 {
887 $prg = $this->getStudyProgramme();
888 $children = $prg->getChildren(true);
889 $ass_id = $this->progress->getAssignmentId();
890 $names = array();
891
892 foreach ($children as $child) {
893 $prgrs = $child->getProgressForAssignment($ass_id);
894 if (!$prgrs->isSuccessful()) {
895 continue;
896 }
897 $names[] = $child->getTitle();
898 }
899
900 return $names;
901 }
902
908 public static function getPossibleActions(
909 int $node_id,
910 int $root_prg_id,
911 int $status
912 ) : array {
913 $actions = array();
914
915 if ($node_id == $root_prg_id) {
916 $actions[] = self::ACTION_SHOW_INDIVIDUAL_PLAN;
917 $actions[] = self::ACTION_REMOVE_USER;
918 }
919
921 $actions[] = self::ACTION_UNMARK_ACCREDITED;
923 $actions[] = self::ACTION_MARK_ACCREDITED;
924 }
925
926 return $actions;
927 }
928
929 protected function refreshLPStatus() : void
930 {
931 // thanks to some caching within ilLPStatusWrapper
932 // the status may not be read properly otherwise ...
933 ilLPStatusWrapper::_resetInfoCaches($this->progress->getNodeId());
935 $this->getStudyProgramme()->getId(),
936 array($this->getUserId())
937 );
938 }
939
945 public function updateProgress(int $user_id) : void
946 {
947 $this->progress_repository->update(
948 $this->progress->setLastChangeBy($user_id)
949 );
950 }
951
952 public function informUserForRiskToFail() : void
953 {
954 $this->events->userRiskyToFail($this);
955 }
956
960 public static function sendRiskyToFailMail(int $progress_id, int $usr_id) : void
961 {
962 global $DIC;
963 $lng = $DIC['lng'];
964 $log = $DIC['ilLog'];
965 $lng->loadLanguageModule("prg");
966 $lng->loadLanguageModule("mail");
967
969 $usr_progress_db = ilStudyProgrammeDIC::dic()['ilStudyProgrammeUserProgressDB'];
971 $usr_progress = $usr_progress_db->getInstanceById($progress_id);
973 $prg = $usr_progress->getStudyProgramme();
974
975 if (!$prg->shouldSendRiskyToFailMail()) {
976 $log->write("Send risky to fail mail is deactivated in study programme settings");
977 return;
978 }
979
980 $subject = $lng->txt("risky_to_fail_mail_subject");
981 $gender = ilObjUser::_lookupGender($usr_id);
983 $body = sprintf(
984 $lng->txt("risky_to_fail_mail_body"),
985 $lng->txt("mail_salutation_" . $gender),
986 $name,
987 $prg->getTitle()
988 );
989
990 $send = true;
991 $mail = new ilMail(ANONYMOUS_USER_ID);
992 try {
993 $mail->enqueue(
995 '',
996 '',
997 $subject,
998 $body,
999 null
1000 );
1001 } catch (Exception $e) {
1002 $send = false;
1003 }
1004
1005 if ($send) {
1006 $usr_progress_db->reminderSendFor($usr_progress->getId());
1007 }
1008 }
1009
1010 public function hasSuccessStatus() : bool
1011 {
1012 return in_array(
1013 $this->getStatus(),
1014 [
1017 ]
1018 );
1019 }
1020}
An exception for terminatinating execution or to throw for unit testing.
Base class for ILIAS Exception handling.
static _resetInfoCaches($a_obj_id)
static _refreshStatus($a_obj_id, $a_users=null)
Set dirty.
static getInstanceByRefId($a_ref_id)
getChildren(bool $include_references=false)
Get all ilObjStudyProgrammes that are direct children of this object.
getParent()
Get the parent ilObjStudyProgramme of this object.
static _lookupLogin($a_user_id)
lookup login
static _lookupGender($a_user_id)
Lookup gender.
static _lookupFullname($a_user_id)
Lookup Full Name.
static _getAllReferences($a_id)
get all reference ids of object
getTitle()
get object title @access public
Class ilStudyProgrammeAssignment.
setRestartDate(DateTime $date=null)
Set the date, at which the user is to be reassigned to the programme.
Class ilStudyProgrammeProgress.
setDeadline(DateTime $deadline=null)
Set the deadline of this progress.
Represents the progress of a user at one node of a study programme.
setValidityOfQualification(DateTime $date=null)
Set validity of qualification.
getDeadline()
Get the deadline of this node.
getCompletionBy()
Get the id of the user or course that lead to completion of this node.
updateProgress(int $user_id)
Updates current progress.
__construct(ilStudyProgrammeProgress $progress, ilStudyProgrammeProgressRepository $progress_repository, ilStudyProgrammeAssignmentRepository $assignment_repository, ilStudyProgrammeEvents $events)
getChildrenProgress()
Get the progresses on the child nodes of this node for the same assignment this progress belongs to.
isFailed()
Check whether user as failed on this node.
recalculateFailedToDeadline()
Recalculates the status according to deadline.
getValidityOfQualification()
Get validity of qualification.
getMaximumPossibleAmountOfPoints(bool $only_relevant=false)
Get the maximum possible amount of points a user can achieve for the completion of this node.
markAccredited(int $user_id)
Mark this progress as accredited.
getStatus()
Get the status of the progress.
updateStatus()
Updates the status of this progress based on the status of the progress on the sub nodes.
markNotRelevant(int $user_id)
Set the node to be not relevant for the user.
markFailed(int $a_user_id)
Mark this progress as failed.
isSuccessfulExpired()
Check, whether a the course is passed and expired due to limited validity.
getNamesOfCompletedOrAccreditedChildren()
Get a list with the names of the children of this node that a were completed or accredited for the gi...
canBeCompleted()
Check whether the user can achieve enough points on the subnodes to be able to complete this node.
getNodeId()
Get the id of the program node the progress belongs to.
isAccredited()
Check whether the user was accredited on this node.
unmarkAccredited()
Set the node to in progress.
getAssignmentId()
Get the assignment this progress belongs to.
maybeLimitProgressValidity(ilObjStudyProgramme $prg, ilStudyProgrammeAssignment $assignment)
isSuccessful()
Check whether the user was successful on this node.
setRequiredAmountOfPoints(int $a_points, int $user_id)
Set the amount of points the user is required to have to complete this node.
getCompletionDate()
Get the completion date of this node.
getAssignmentDate()
Get the assignment date of this node.
getCurrentAmountOfPoints()
Get the amount of points the user currently achieved.
setDeadline(DateTime $deadline=null)
Set the deadline of this node.
markNotFailed(int $user_id)
Set the node to in progress.
updateParentStatus()
Update the status of the parent of this node.
static getPossibleActions(int $node_id, int $root_prg_id, int $status)
Get a list with possible actions on a progress record.
getUserId()
Get the id of the user who is assigned.
getAmountOfPoints()
Get the amount of points needed to complete the node.
hasIndividualModifications()
Check whether there are individual modifications for the user on this program.
getStudyProgramme()
Get the program node this progress belongs to.
updateFromProgramNode()
Update the progress from its program node.
setLPCompleted(int $obj_id, int $usr_id)
Set this node to be completed due to a completed learning progress.
isRelevant()
Check whether this node is relevant for the user.
markRelevant(int $user_id)
Set the node to be relevant for the user.
getParentProgresses()
Get the progress on the parent node for the same assignment this progress belongs to.
getLastChange()
Get the timestamp when the last change was made on this progress.
getLastChangeBy()
Get the id of the user who did the last change on this progress.
Covers the persistence of settings belonging to a study programme (SP).
if($format !==null) $name
Definition: metadata.php:230
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
$log
Definition: result.php:15
$lng
$DIC
Definition: xapitoken.php:46