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