ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilECSCourseCreationHandler.php
Go to the documentation of this file.
1 <?php
2 
18 declare(strict_types=1);
19 
24 {
25  private ilLogger $logger;
26  private ilLanguage $lng;
27  private ilTree $tree;
28 
29 
32  private ?\ilECSCourseUrl $course_url = null;
33  private bool $object_created = false;
34  private array $courses_created = array();
35 
36  private int $mid;
37 
38  public function __construct(ilECSSetting $server, int $a_mid)
39  {
40  global $DIC;
41 
42  $this->logger = $DIC->logger()->wsrv();
43  $this->lng = $DIC->language();
44  $this->tree = $DIC->repositoryTree();
45 
46  $this->server = $server;
47  $this->mid = $a_mid;
48  $this->mapping = ilECSNodeMappingSettings::getInstanceByServerMid($this->server->getServerId(), $this->getMid());
49 
50  $this->course_url = new ilECSCourseUrl();
51  }
52 
53 
57  public function getServer(): ilECSSetting
58  {
59  return $this->server;
60  }
61 
67  {
68  return $this->mapping;
69  }
70 
75  public function getCourseUrl(): ?\ilECSCourseUrl
76  {
77  return $this->course_url;
78  }
79 
83  public function isObjectCreated(): bool
84  {
85  return $this->object_created;
86  }
87 
91  public function setObjectCreated(bool $a_status): void
92  {
93  $this->object_created = $a_status;
94  }
95 
99  protected function getCreatedCourses(): array
100  {
101  return $this->courses_created;
102  }
103 
107  public function getMid(): int
108  {
109  return $this->mid;
110  }
111 
116  public function handle(int $a_content_id, $course): bool
117  {
118  // prepare course url
119  // if any object (course group) will be created, a list of all course urls
120  // will be sent to ecs.
121  $this->setObjectCreated(false);
122  $this->course_url->setECSId($a_content_id);
123 
124 
125  if ($this->getMapping()->isAttributeMappingEnabled()) {
126  $this->logger->debug('Handling advanced attribute mapping');
127  return $this->doAttributeMapping($a_content_id, $course);
128  }
129 
130  if ($this->getMapping()->isAllInOneCategoryEnabled()) {
131  $this->logger->debug('Handling course all in one category setting');
132  $this->doSync($a_content_id, $course, ilObject::_lookupObjId($this->getMapping()->getAllInOneCategory()));
133  return true;
134  }
135 
136  $parent_obj_id = $this->syncParentContainer($a_content_id, $course);
137  if ($parent_obj_id) {
138  $this->logger->info('Using already mapped category: ' . ilObject::_lookupTitle($parent_obj_id));
139  $this->doSync($a_content_id, $course, $parent_obj_id);
140  return true;
141  }
142  $this->logger->info('Using course default category');
143  $this->doSync($a_content_id, $course, ilObject::_lookupObjId($this->getMapping()->getDefaultCourseCategory()));
144  return true;
145  }
146 
150  protected function doAttributeMapping($a_content_id, $course): bool
151  {
152  // Check if course is already created
153  $course_id = $course->lectureID;
154  $obj_id = $this->getImportId((int) $course_id);
155 
156  if ($obj_id) {
157  // do update
158  $this->logger->debug('Performing update of already imported course.');
159 
160  $refs = ilObject::_getAllReferences($obj_id);
161  $ref = end($refs);
162 
163  $this->doSync(
164  $a_content_id,
165  $course,
166  ilObject::_lookupObjId($this->tree->getParentId($ref))
167  );
168  return true;
169  }
170 
171  // Get all rules
172  $matching_rules = [];
173  foreach (ilECSCourseMappingRule::getRuleRefIds($this->getServer()->getServerId(), $this->getMid()) as $ref_id) {
174  $matching_index = ilECSCourseMappingRule::isMatching(
175  $course,
176  $this->getServer()->getServerId(),
177  $this->getMid(),
178  $ref_id
179  );
180  if (strcmp($matching_index, '0') !== 0) {
181  $matching_rules[$matching_index] = $ref_id;
182  }
183  }
184  ksort($matching_rules);
185 
186  $this->logger->dump($matching_rules);
187 
188  if (!count($matching_rules)) {
189  // Put course in default category
190  $this->logger->debug('No matching attribute mapping rule found.');
191  $this->logger->info('Using course default category');
192  $this->doSync($a_content_id, $course, ilObject::_lookupObjId($this->getMapping()->getDefaultCourseCategory()));
193  return true;
194  }
195 
196  $this->logger->debug('Matching rules:');
197  $this->logger->dump($matching_rules, ilLogLevel::DEBUG);
198 
199  $all_parent_refs = [];
200  foreach ($matching_rules as $matching_rule) {
201  $this->logger->debug('Handling matching rule: ' . $matching_rule);
202  $parent_refs = ilECSCourseMappingRule::doMappings(
203  $course,
204  $this->getServer()->getServerId(),
205  $this->getMid(),
206  $matching_rule
207  );
208  // map according mapping rules
209  $this->logger->debug('Adding parent references: ' . print_r($parent_refs, true));
210  if (count($parent_refs)) {
211  $all_parent_refs = array_unique(array_merge($all_parent_refs, $parent_refs));
212  }
213  }
214 
215  // parent refs are an array of created categories
216  // the first ref should contain the main course or parallel courses.
217  // all other refs wil contain course references.
218  $first = true;
219  foreach ($all_parent_refs as $category_ref) {
220  if ($first) {
221  $this->logger->debug('Creating new course instance in: ' . $category_ref);
222  $this->doSync($a_content_id, $course, ilObject::_lookupObjId($category_ref));
223  $first = false;
224  continue;
225  }
226  $this->logger->debug('Creating new course reference instance in: ' . $category_ref);
227  $this->createCourseReferenceObjects($category_ref);
228  }
229  return true;
230  }
231 
235  protected function createCourseReferenceObjects(int $a_parent_ref_id): void
236  {
237  $this->logger->debug('Created new course reference in : ' . ilObject::_lookupTitle(ilObject::_lookupObjId($a_parent_ref_id)));
238  foreach ($this->getCreatedCourses() as $ref_id) {
239  $crsr = new ilObjCourseReference();
240  $crsr->setOwner(SYSTEM_USER_ID);
241  $crsr->setTargetRefId($ref_id);
242  $crsr->setTargetId(ilObject::_lookupObjId($ref_id));
243  $crsr->create();
244  $crsr->update();
245  $crsr->createReference();
246  $crsr->putInTree($a_parent_ref_id);
247  $crsr->setPermissions($a_parent_ref_id);
248 
249  $this->logger->debug('Created new course reference for : ' . ilObject::_lookupTitle(ilObject::_lookupObjId($ref_id)));
250  }
251  }
252 
256  protected function syncParentContainer($a_content_id, $course): int
257  {
258  if (!is_array($course->allocations)) {
259  $this->logger->debug('No allocation in course defined.');
260  return 0;
261  }
262  if (!$course->allocations[0]->parentID) {
263  $this->logger->debug('No allocation parent in course defined.');
264  return 0;
265  }
266  $parent_id = $course->allocations[0]->parentID;
267 
268  $parent_tid = ilECSCmsData::lookupFirstTreeOfNode($this->getServer()->getServerId(), $this->getMid(), $parent_id);
269  return $this->syncNodetoTop($parent_tid, $parent_id);
270  }
271 
276  protected function syncNodeToTop($tree_id, $cms_id): int
277  {
278  $obj_id = $this->getImportId($cms_id);
279  if ($obj_id) {
280  // node already imported
281  return $obj_id;
282  }
283 
284  $tobj_id = ilECSCmsData::lookupObjId(
285  $this->getServer()->getServerId(),
286  $this->getMid(),
287  $tree_id,
288  $cms_id
289  );
290 
291  // node is not imported
292  $this->logger->debug('ecs node with id ' . $cms_id . ' is not imported for mid ' . $this->getMid() . ' tree_id ' . $tree_id);
293 
294  // check for mapping: if mapping is available create category
295  $ass = new ilECSNodeMappingAssignment(
296  $this->getServer()->getServerId(),
297  $this->getMid(),
298  $tree_id,
299  $tobj_id
300  );
301 
302  if ($ass->isMapped()) {
303  $this->logger->debug('node is mapped');
304  return $this->syncCategory($tobj_id, $ass->getRefId());
305  }
306 
307  // Start recursion to top
308  $tree = new ilECSCmsTree($tree_id);
309  $parent_tobj_id = $tree->getParentId($tobj_id);
310  if ($parent_tobj_id) {
311  $cms_ids = ilECSCmsData::lookupCmsIds(array($parent_tobj_id));
312  $obj_id = $this->syncNodeToTop($tree_id, $cms_ids[0]);
313  }
314 
315  if ($obj_id) {
316  $refs = ilObject::_getAllReferences($obj_id);
317  $ref_id = end($refs);
318  return $this->syncCategory($tobj_id, $ref_id);
319  }
320  return 0;
321  }
322 
326  protected function syncCategory($tobj_id, $parent_ref_id): int
327  {
328  $data = new ilECSCmsData($tobj_id);
329 
330  $cat = new ilObjCategory();
331  $cat->setOwner(SYSTEM_USER_ID);
332  $cat->setTitle($data->getTitle());
333  $cat->create(); // true for upload
334  $cat->createReference();
335  $cat->putInTree($parent_ref_id);
336  $cat->setPermissions($parent_ref_id);
337  $cat->deleteTranslation($this->lng->getDefaultLanguage());
338  $cat->addTranslation(
339  $data->getTitle(),
340  $cat->getLongDescription(),
341  $this->lng->getDefaultLanguage(),
342  $this->lng->getDefaultLanguage()
343  );
344 
345  // set imported
346  $import = new ilECSImport(
347  $this->getServer()->getServerId(),
348  $cat->getId()
349  );
350  $import->setMID($this->getMid());
351  $import->setContentId($data->getCmsId());
352  $import->setImported(true);
353  $import->save();
354 
355  return $cat->getId();
356  }
357 
363  protected function doSync($a_content_id, $course, $a_parent_obj_id): bool
364  {
365  // Check if course is already created
366  $course_id = $course->lectureID;
367  $this->course_url->setCmsLectureId((string) $course_id);
368 
369  $obj_id = $this->getImportId((int) $course_id);
370 
371  $this->logger->debug('Found obj_id ' . $obj_id . ' for course_id ' . $course_id);
372 
373  // Handle parallel groups
374  if ($obj_id) {
375  // update multiple courses/groups according to parallel scenario
376  $this->logger->debug('Group scenario ' . $course->groupScenario);
377  switch ((int) $course->groupScenario) {
379  $this->logger->debug('Performing update for parallel groups in course.');
380  $this->updateParallelGroups($a_content_id, $course, $obj_id);
381  break;
382 
384  $this->logger->debug('Performing update for parallel courses.');
385  $this->updateParallelCourses($a_content_id, $course, $a_parent_obj_id);
386  break;
387 
389  default:
390  // nothing to do
391  break;
392 
393  }
394 
395  // do update
396  $this->updateCourseData($course, $obj_id);
397  } else {
398  switch ((int) $course->groupScenario) {
400  $this->logger->debug('Parallel scenario "groups in courses".');
401  $crs = $this->createCourseData($course);
402  $crs = $this->createCourseReference($crs, $a_parent_obj_id);
403  $this->setImported((int) $course_id, $crs, $a_content_id);
404 
405  // Create parallel groups under crs
406  $this->createParallelGroups($a_content_id, $course, $crs->getRefId());
407  break;
408 
410  $this->logger->debug('Parallel scenario "Courses foreach Lecturer".');
411  // Import empty to store the ecs ressource id (used for course member update).
412  $this->setImported((int) $course_id, null, $a_content_id);
413  break;
414 
416  $this->logger->debug('Parallel scenario "Many courses".');
417  $refs = ilObject::_getAllReferences($a_parent_obj_id);
418  $ref = end($refs);
419  // do not create master course for this scenario
420  //$crs = $this->createCourseData($course);
421  //$this->createCourseReference($crs, $a_parent_obj_id);
422  //$this->setImported($course_id, $crs, $a_content_id);
423  $this->createParallelCourses($a_content_id, $course, $ref);
424  break;
425 
426  default:
428  $this->logger->debug('Parallel scenario "One Course".');
429  $crs = $this->createCourseData($course);
430  $this->createCourseReference($crs, $a_parent_obj_id);
431  $this->setImported((int) $course_id, $crs, $a_content_id);
432  break;
433 
434 
435  }
436  }
437  // finally update course urls
438  $this->handleCourseUrlUpdate();
439  return true;
440  }
441 
445  protected function createParallelCourses(int $a_content_id, $course, $parent_ref): bool
446  {
447  foreach ((array) $course->groups as $group) {
448  $this->createParallelCourse($a_content_id, $course, $group, $parent_ref);
449  }
450  return true;
451  }
452 
456  protected function createParallelCourse($a_content_id, $course, $group, $parent_ref): bool
457  {
458  if ($this->getImportId((int) $course->lectureID, (string) $group->id)) {
459  $this->logger->debug('Parallel course already created');
460  return false;
461  }
462 
463  $course_obj = new ilObjCourse();
464  $course_obj->setOwner(SYSTEM_USER_ID);
465  $title = $course->title;
466  if ($group->title !== '') {
467  $title .= ' (' . $group->title . ')';
468  }
469  $this->logger->debug('Creating new parallel course instance from ecs : ' . $title);
470  $course_obj->setTitle($title);
471  $course_obj->setSubscriptionMaxMembers((int) $group->maxParticipants);
472  $course_obj->setOfflineStatus(true);
473  $course_obj->create();
474 
475  $this->createCourseReference($course_obj, ilObject::_lookupObjId($parent_ref));
476  $this->setImported((int) $course->lectureID, $course_obj, $a_content_id, $group->id);
477  $this->setObjectCreated(true);
478  return true;
479  }
480 
484  protected function updateParallelCourses($a_content_id, $course, $parent_obj): bool
485  {
486  $parent_refs = ilObject::_getAllReferences($parent_obj);
487  $parent_ref = end($parent_refs);
488 
489  foreach ((array) $course->groups as $group) {
490  $title = $course->title;
491  if ($group->title !== '') {
492  $title .= ' (' . $group->title . ')';
493  }
494 
495  $obj_id = $this->getImportId((int) $course->lectureID, (string) $group->id);
496  $this->logger->debug('Imported obj id is ' . $obj_id);
497  if (!$obj_id) {
498  $this->createParallelCourse($a_content_id, $course, $group, $parent_ref);
499  } else {
500  $course_obj = ilObjectFactory::getInstanceByObjId($obj_id, false);
501  if ($course_obj instanceof ilObjCourse) {
502  $this->logger->debug('New title is ' . $title);
503  $course_obj->setTitle($title);
504  if(!is_null($group->maxParticipants)) {
505  $course_obj->setSubscriptionMaxMembers($group->maxParticipants);
506  }
507  $course_obj->update();
508  }
509  }
510  $this->addUrlEntry($this->getImportId((int) $course->lectureID, (string) $group->ID));
511  }
512  return true;
513  }
514 
515 
516 
520  protected function createParallelGroups($a_content_id, $course, $parent_ref): bool
521  {
522  foreach ((array) $course->groups as $group) {
523  $this->createParallelGroup($a_content_id, $course, $group, $parent_ref);
524  }
525  return true;
526  }
527 
531  protected function createParallelGroup($a_content_id, $course, $group, $parent_ref): void
532  {
533  $group_obj = new ilObjGroup();
534  $group_obj->setOwner(SYSTEM_USER_ID);
535  $title = $group->title !== '' ? $group->title : $course->title;
536  $group_obj->setTitle($title);
537  $group_obj->setMaxMembers((int) $group->maxParticipants);
538  $group_obj->create();
539  $group_obj->createReference();
540  $group_obj->putInTree($parent_ref);
541  $group_obj->setPermissions($parent_ref);
542  $group_obj->updateGroupType(ilGroupConstants::GRP_TYPE_CLOSED);
543  $this->setImported((int) $course->lectureID, $group_obj, $a_content_id, $group->id);
544  $this->setObjectCreated(true);
545  }
546 
547 
551  protected function updateParallelGroups($a_content_id, $course, int $parent_obj): void
552  {
553  $parent_refs = ilObject::_getAllReferences($parent_obj);
554  $parent_ref = end($parent_refs);
555 
556  foreach ((array) $course->groups as $group) {
557  $obj_id = $this->getImportId((int) $course->lectureID, (string) $group->id);
558  $this->logger->debug('Imported obj id is ' . $obj_id);
559  if (!$obj_id) {
560  $this->createParallelGroup($a_content_id, $course, $group, $parent_ref);
561  } else {
562  $group_obj = ilObjectFactory::getInstanceByObjId($obj_id, false);
563  if ($group_obj instanceof ilObjGroup) {
564  $title = $group->title !== '' ? $group->title : $course->title;
565  $this->logger->debug('New title is ' . $title);
566  $group_obj->setTitle($title);
567  if(!is_null($group->maxParticipants)) {
568  $group_obj->setMaxMembers((int) $group->maxParticipants);
569  }
570  $group_obj->update();
571  }
572  }
573  $this->addUrlEntry($this->getImportId((int) $course->lectureID, (string) $group->id));
574  }
575  }
576 
582  protected function getImportId(int $a_content_id, string $a_sub_id = null): int
583  {
584  return ilECSImportManager::getInstance()->lookupObjIdByContentId(
585  $this->getServer()->getServerId(),
586  $this->getMid(),
587  $a_content_id,
588  $a_sub_id
589  );
590  }
591 
595  protected function updateCourseData($course, $obj_id): bool
596  {
597  // do update
598  $refs = ilObject::_getAllReferences($obj_id);
599  $ref_id = end($refs);
600  $crs_obj = ilObjectFactory::getInstanceByRefId($ref_id, false);
601  if (!$crs_obj instanceof ilObject) {
602  $this->logger->debug('Cannot instantiate course instance');
603  return true;
604  }
605 
606  // Update title
607  $title = $course->title;
608  $this->logger->debug('new title is : ' . $title);
609 
610  $crs_obj->setTitle($title);
611  $crs_obj->update();
612  return true;
613  }
614 
618  protected function createCourseData($course): \ilObjCourse
619  {
620  $course_obj = new ilObjCourse();
621  $course_obj->setOwner(SYSTEM_USER_ID);
622  $title = $course->title;
623  $this->logger->debug('Creating new course instance from ecs : ' . $title);
624  $course_obj->setTitle($title);
625  $course_obj->setOfflineStatus(true);
626  $course_obj->create();
627  return $course_obj;
628  }
629 
633  protected function createCourseReference(ilObjCourse $crs, int $a_parent_obj_id): \ilObjCourse
634  {
635  $ref_ids = ilObject::_getAllReferences($a_parent_obj_id);
636  $ref_id = end($ref_ids);
637 
638  $crs->createReference();
639  $crs->putInTree($ref_id);
640  $crs->setPermissions($ref_id);
641 
642  $this->setObjectCreated(true);
643  $this->addUrlEntry($crs->getId());
644 
645  $this->courses_created[] = $crs->getRefId();
646 
647  return $crs;
648  }
649 
653  protected function setImported(int $a_content_id, $object, $a_ecs_id = 0, $a_sub_id = null): bool
654  {
655  $import = new ilECSImport(
656  $this->getServer()->getServerId(),
657  is_object($object) ? $object->getId() : 0
658  );
659 
660 
661  $import->setSubId((string) $a_sub_id);
662  $import->setMID($this->getMid());
663  $import->setEContentId((string) $a_ecs_id);
664  $import->setContentId((string) $a_content_id);
665  $import->setImported(true);
666  $import->save();
667  return true;
668  }
669 
673  protected function addUrlEntry(int $a_obj_id): bool
674  {
675  $refs = ilObject::_getAllReferences($a_obj_id);
676  $ref_id = end($refs);
677 
678  if (!$ref_id) {
679  return false;
680  }
681  $lms_url = new ilECSCourseLmsUrl();
682  $lms_url->setTitle(ilObject::_lookupTitle($a_obj_id));
683 
684  $lms_url->setUrl(ilLink::_getLink($ref_id));
685  $this->course_url->addLmsCourseUrls($lms_url);
686  return true;
687  }
688 
692  protected function handleCourseUrlUpdate(): void
693  {
694  $this->logger->debug('Starting course url update');
695  if ($this->isObjectCreated()) {
696  $this->logger->debug('Sending new course group url');
697  $this->course_url->send($this->getServer(), $this->getMid());
698  } else {
699  $this->logger->debug('No courses groups created. Aborting');
700  }
701  }
702 }
updateParallelCourses($a_content_id, $course, $parent_obj)
Update parallel group data.
syncNodeToTop($tree_id, $cms_id)
Sync node to top.
static getInstanceByServerMid(int $a_server_id, int $a_mid)
Get instance.
const SYSTEM_USER_ID
This file contains constants for PHPStan analyis, see: https://phpstan.org/config-reference#constants...
Definition: constants.php:26
static _getAllReferences(int $id)
get all reference ids for object ID
getImportId(int $a_content_id, string $a_sub_id=null)
Get import id of remote course Return 0 if object isn&#39;t imported.
__construct(ilECSSetting $server, int $a_mid)
syncCategory($tobj_id, $parent_ref_id)
Sync category.
putInTree(int $parent_ref_id)
updateParallelGroups($a_content_id, $course, int $parent_obj)
Update parallel group data.
static lookupObjId(int $a_server_id, int $a_mid, int $a_tree_id, string $cms_id)
setPermissions(int $parent_ref_id)
static _lookupObjId(int $ref_id)
static isMatching($course, int $a_sid, int $a_mid, int $a_ref_id)
Check if rule matches.
global $DIC
Definition: feed.php:28
createReference()
creates reference for object
static lookupFirstTreeOfNode($a_server_id, $a_mid, $cms_id)
Lookup first obj_id of cms node.
createCourseReferenceObjects(int $a_parent_ref_id)
Create course reference objects.
static getInstance()
Get the singleton instance of this ilECSImportManager.
createParallelCourse($a_content_id, $course, $group, $parent_ref)
Create parallel course.
$ref_id
Definition: ltiauth.php:67
static _lookupTitle(int $obj_id)
createParallelGroup($a_content_id, $course, $group, $parent_ref)
Create parallel group.
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
Represents a ecs course lms url.
setObjectCreated(bool $a_status)
Set object created status.
Storage of ECS imported objects.
static getRuleRefIds(int $a_sid, int $a_mid)
doAttributeMapping($a_content_id, $course)
Sync attribute mapping.
static lookupCmsIds(array $a_obj_ids)
handle(int $a_content_id, $course)
Handle sync request.
addUrlEntry(int $a_obj_id)
Add an url entry.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
isObjectCreated()
Check if an object (course / group) has been created.
Represents a ecs course url.
static getInstanceByObjId(?int $obj_id, bool $stop_on_error=true)
get an instance of an Ilias object by object id
static doMappings($course, int $a_sid, int $a_mid, int $a_ref_id)
doSync($a_content_id, $course, $a_parent_obj_id)
Handle all in one setting.
createCourseReference(ilObjCourse $crs, int $a_parent_obj_id)
Create course reference.
Class ilObjGroup.
updateCourseData($course, $obj_id)
Update course data.
createParallelCourses(int $a_content_id, $course, $parent_ref)
Create parallel courses.
createParallelGroups($a_content_id, $course, $parent_ref)
This create parallel groups.
createCourseData($course)
Create course data from json.
syncParentContainer($a_content_id, $course)
Sync parent container.
setImported(int $a_content_id, $object, $a_ecs_id=0, $a_sub_id=null)
Set new course object imported.
setMID($a_mid)
set mid
setSubId(string $a_id)