ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
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((int) $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($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 (!property_exists($course, 'allocations') || !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  if (property_exists($course, 'groupScenario')) {
377  $this->logger->debug('Group scenario ' . $course->groupScenario);
378  switch ((int) $course->groupScenario) {
380  $this->logger->debug('Performing update for parallel groups in course.');
381  $this->updateParallelGroups($a_content_id, $course, $obj_id);
382  break;
383 
385  $this->logger->debug('Performing update for parallel courses.');
386  $this->updateParallelCourses($a_content_id, $course, $a_parent_obj_id);
387  break;
388 
390  default:
391  // nothing to do
392  break;
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  // finally update course urls
436  $this->handleCourseUrlUpdate();
437  return true;
438  }
439 
443  protected function createParallelCourses(int $a_content_id, $course, $parent_ref): bool
444  {
445  foreach ((array) $course->groups as $group) {
446  $this->createParallelCourse($a_content_id, $course, $group, $parent_ref);
447  }
448  return true;
449  }
450 
454  protected function createParallelCourse($a_content_id, $course, $group, $parent_ref): bool
455  {
456  if ($this->getImportId((int) $course->lectureID, (string) $group->id)) {
457  $this->logger->debug('Parallel course already created');
458  return false;
459  }
460 
461  $course_obj = new ilObjCourse();
462  $course_obj->setOwner(SYSTEM_USER_ID);
463  $title = $course->title;
464  if (property_exists($group, 'title') && $group->title !== '') {
465  $title .= ' (' . $group->title . ')';
466  }
467  $this->logger->debug('Creating new parallel course instance from ecs : ' . $title);
468  $course_obj->setTitle($title);
469  if (property_exists($group, 'maxParticipants')) {
470  $course_obj->setSubscriptionMaxMembers((int) $group->maxParticipants);
471  }
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 (property_exists($group, 'maxParticipants') && !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 = (property_exists($group, 'title') && $group->title !== '') ? $group->title : $course->title;
536  $group_obj->setTitle($title);
537  if (property_exists($group, 'maxParticipants')) {
538  $group_obj->setMaxMembers((int) $group->maxParticipants);
539  }
540  $group_obj->create();
541  $group_obj->createReference();
542  $group_obj->putInTree($parent_ref);
543  $group_obj->setPermissions($parent_ref);
544  $group_obj->updateGroupType(ilGroupConstants::GRP_TYPE_CLOSED);
545  $this->setImported((int) $course->lectureID, $group_obj, $a_content_id, $group->id);
546  $this->setObjectCreated(true);
547  }
548 
549 
553  protected function updateParallelGroups($a_content_id, $course, int $parent_obj): void
554  {
555  $parent_refs = ilObject::_getAllReferences($parent_obj);
556  $parent_ref = end($parent_refs);
557 
558  foreach ((array) $course->groups as $group) {
559  $obj_id = $this->getImportId((int) $course->lectureID, (string) $group->id);
560  $this->logger->debug('Imported obj id is ' . $obj_id);
561  if (!$obj_id) {
562  $this->createParallelGroup($a_content_id, $course, $group, $parent_ref);
563  } else {
564  $group_obj = ilObjectFactory::getInstanceByObjId($obj_id, false);
565  if ($group_obj instanceof ilObjGroup) {
566  $title = $group->title !== '' ? $group->title : $course->title;
567  $this->logger->debug('New title is ' . $title);
568  $group_obj->setTitle($title);
569  if (property_exists($group, 'maxParticipants') && !is_null($group->maxParticipants)) {
570  $group_obj->setMaxMembers((int) $group->maxParticipants);
571  }
572  $group_obj->update();
573  }
574  }
575  $this->addUrlEntry($this->getImportId((int) $course->lectureID, (string) $group->id));
576  }
577  }
578 
584  protected function getImportId(int $a_content_id, string $a_sub_id = null): int
585  {
586  return ilECSImportManager::getInstance()->lookupObjIdByContentId(
587  $this->getServer()->getServerId(),
588  $this->getMid(),
589  $a_content_id,
590  $a_sub_id
591  );
592  }
593 
597  protected function updateCourseData($course, $obj_id): bool
598  {
599  // do update
600  $refs = ilObject::_getAllReferences($obj_id);
601  $ref_id = end($refs);
602  $crs_obj = ilObjectFactory::getInstanceByRefId($ref_id, false);
603  if (!$crs_obj instanceof ilObject) {
604  $this->logger->debug('Cannot instantiate course instance');
605  return true;
606  }
607 
608  // Update title
609  $title = $course->title;
610  $this->logger->debug('new title is : ' . $title);
611 
612  $crs_obj->setTitle($title);
613  $crs_obj->update();
614  return true;
615  }
616 
620  protected function createCourseData($course): \ilObjCourse
621  {
622  $course_obj = new ilObjCourse();
623  $course_obj->setOwner(SYSTEM_USER_ID);
624  $title = $course->title;
625  $this->logger->debug('Creating new course instance from ecs : ' . $title);
626  $course_obj->setTitle($title);
627  $course_obj->setOfflineStatus(true);
628  $course_obj->create();
629  return $course_obj;
630  }
631 
635  protected function createCourseReference(ilObjCourse $crs, int $a_parent_obj_id): \ilObjCourse
636  {
637  $ref_ids = ilObject::_getAllReferences($a_parent_obj_id);
638  $ref_id = end($ref_ids);
639 
640  $crs->createReference();
641  $crs->putInTree($ref_id);
642  $crs->setPermissions($ref_id);
643 
644  $this->setObjectCreated(true);
645  $this->addUrlEntry($crs->getId());
646 
647  $this->courses_created[] = $crs->getRefId();
648 
649  return $crs;
650  }
651 
655  protected function setImported(int $a_content_id, $object, $a_ecs_id = 0, $a_sub_id = null): bool
656  {
657  $import = new ilECSImport(
658  $this->getServer()->getServerId(),
659  is_object($object) ? $object->getId() : 0
660  );
661 
662 
663  $import->setSubId((string) $a_sub_id);
664  $import->setMID($this->getMid());
665  $import->setEContentId((string) $a_ecs_id);
666  $import->setContentId((string) $a_content_id);
667  $import->setImported(true);
668  $import->save();
669  return true;
670  }
671 
675  protected function addUrlEntry(int $a_obj_id): bool
676  {
677  $refs = ilObject::_getAllReferences($a_obj_id);
678  $ref_id = end($refs);
679 
680  if (!$ref_id) {
681  return false;
682  }
683  $lms_url = new ilECSCourseLmsUrl();
684  $lms_url->setTitle(ilObject::_lookupTitle($a_obj_id));
685 
686  $lms_url->setUrl(ilLink::_getLink($ref_id));
687  $this->course_url->addLmsCourseUrls($lms_url);
688  return true;
689  }
690 
694  protected function handleCourseUrlUpdate(): void
695  {
696  $this->logger->debug('Starting course url update');
697  if ($this->isObjectCreated()) {
698  $this->logger->debug('Sending new course group url');
699  $this->course_url->send($this->getServer(), $this->getMid());
700  } else {
701  $this->logger->debug('No courses groups created. Aborting');
702  }
703  }
704 }
updateParallelCourses($a_content_id, $course, $parent_obj)
Update parallel group data.
syncNodeToTop($tree_id, $cms_id)
Sync node to top.
static isMatching($course, $a_sid, $a_mid, $a_ref_id)
Check if rule matches.
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)
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.
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)
createCourseReferenceObjects($a_parent_ref_id)
Create course reference objects.
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)