ILIAS  release_8 Revision v8.24
class.ilRemoteObjectBase.php
Go to the documentation of this file.
1<?php
2
18declare(strict_types=1);
19
25abstract class ilRemoteObjectBase extends ilObject2
26{
27 protected ?string $local_information = null;
28 protected ?string $remote_link = null;
29 protected ?string $organization = null;
30 protected ?int $mid = null;
31 protected string $auth_hash = '';
32
33 protected string $realm_plain = '';
34
36
37 public const MAIL_SENDER = 6;
38 public const OBJECT_OWNER = 6;
39
40 public function __construct(int $a_id = 0, bool $a_call_by_reference = true)
41 {
42 global $DIC;
43
44 parent::__construct($a_id, $a_call_by_reference);
45
46 $this->logger = $DIC->logger()->wsrv();
47 }
48
54 public static function getInstanceByEventType(string $a_type)
55 {
56 switch ($a_type) {
58 return new ilObjRemoteCourse();
59
61 return new ilObjRemoteCategory();
62
64 return new ilObjRemoteFile();
65
67 return new ilObjRemoteGlossary();
68
70 return new ilObjRemoteGroup();
71
73 return new ilObjRemoteLearningModule();
74
76 return new ilObjRemoteWiki();
77
79 return new ilObjRemoteTest();
80
81 default:
82 return null;
83 }
84 }
85
86 protected function beforeCreate(): bool
87 {
88 $this->setOwner(self::OBJECT_OWNER);
89 return parent::beforeCreate();
90 }
91
95 abstract protected function getTableName(): string;
96
100 abstract protected function getECSObjectType(): string;
101
102
106 public function getRealmPlain(): string
107 {
108 return $this->realm_plain;
109 }
110
114 public function setOrganization(string $a_organization): void
115 {
116 $this->organization = $a_organization;
117 }
118
122 public function getOrganization(): string
123 {
124 return $this->organization;
125 }
126
130 public function getLocalInformation(): string
131 {
132 return $this->local_information ?? '';
133 }
134
140 public function setLocalInformation(string $a_info): void
141 {
142 $this->local_information = $a_info;
143 }
144
148 public function getMID(): int
149 {
150 return $this->mid;
151 }
152
158 public function setMID(int $a_mid): void
159 {
160 $this->mid = $a_mid;
161 }
162
168 public function setRemoteLink(string $a_link): void
169 {
170 $this->remote_link = $a_link;
171 }
172
176 public function getRemoteLink(): string
177 {
178 return $this->remote_link;
179 }
180
187 public function getFullRemoteLink(): string
188 {
189 $server_id = ilECSImportManager::getInstance()->lookupServerId($this->getId());
191 $setting = ilECSParticipantSetting::getInstance($server_id, $this->mid);
192 $user = new ilECSUser($this->user);
193 $ecs_user_data = $user->toGET($setting);
194 $this->logger->info(__METHOD__ . ': Using ecs user data ' . $ecs_user_data);
195
196 // check token mechanism enabled
197 $part = new ilECSParticipantSetting($server_id, $this->getMID());
198 if (!$part->isTokenEnabled()) {
199 return $this->getRemoteLink();
200 }
201
202 $auth_hash = $this->createAuthResource($this->getRemoteLink() . $user->toREALM());
203 $ecs_url_hash = 'ecs_hash_url=' . urlencode($server->getServerURI() . '/sys/auths/' . $auth_hash);
204
205 if (strpos($this->getRemoteLink(), '?')) {
206 $link = $this->getRemoteLink() . '&ecs_hash=' . $auth_hash . $ecs_user_data . '&' . $ecs_url_hash;
207 } else {
208 $link = $this->getRemoteLink() . '?ecs_hash=' . $auth_hash . $ecs_user_data . '&' . $ecs_url_hash;
209 }
210 $this->logger->info(__METHOD__ . ': ECS full link: ' . $link);
211 return $link;
212 }
213
217 public function createAuthResource(string $a_plain_realm)
218 {
219 try {
220 $server_id = ilECSImportManager::getInstance()->lookupServerId($this->getId());
221 $import_info = new ilECSImport($server_id, $this->getId());
222
223 $connector = new ilECSConnector(ilECSSetting::getInstanceByServerId($server_id));
224 $auth = new ilECSAuth();
225 $auth->setPid($import_info->getMID());
226 //TODO URL is deprecated
227 $auth->setUrl($this->getRemoteLink());
228 $realm = sha1($a_plain_realm);
229 $this->logger->info(__METHOD__ . ': Using realm ' . $a_plain_realm);
230 $auth->setRealm($realm);
231 $this->logger->info(__METHOD__ . ' Mid is ' . $this->getMID());
232 //TODO remove @
233 $this->auth_hash = $connector->addAuth(json_encode($auth, JSON_THROW_ON_ERROR), $this->getMID());
234 return $this->auth_hash;
235 } catch (ilECSConnectorException $exc) {
236 $this->logger->info(__METHOD__ . ': Caught error from ECS Auth resource: ' . $exc->getMessage());
237 return false;
238 }
239 }
240
241 protected function doCreate(bool $clone_mode = false): void
242 {
243 $fields = array(
244 "obj_id" => array("integer", $this->getId()),
245 "local_information" => array("text", ""),
246 "remote_link" => array("text", ""),
247 "mid" => array("integer", 0),
248 "organization" => array("text", "")
249 );
250
251 $this->doCreateCustomFields($fields);
252
253 $this->db->insert($this->getTableName(), $fields);
254 }
255
259 protected function doCreateCustomFields(array &$a_fields): void
260 {
261 }
262
266 protected function doUpdate(): void
267 {
268 $fields = array(
269 "local_information" => array("text", $this->getLocalInformation()),
270 "remote_link" => array("text", $this->getRemoteLink()),
271 "mid" => array("integer", $this->getMID()),
272 "organization" => array("text", $this->getOrganization())
273 );
274
275 $this->doUpdateCustomFields($fields);
276
277 $where = array("obj_id" => array("integer", $this->getId()));
278
279 $this->db->update($this->getTableName(), $fields, $where);
280 }
281
285 protected function doUpdateCustomFields(array &$a_fields): void
286 {
287 }
288
292 protected function doDelete(): void
293 {
294 //put here your module specific stuff
295 ilECSImportManager::getInstance()->_deleteByObjId($this->getId());
296
297 $query = "DELETE FROM " . $this->getTableName() .
298 " WHERE obj_id = " . $this->db->quote($this->getId(), 'integer') . " ";
299 $this->db->manipulate($query);
300 }
301
302 protected function doRead(): void
303 {
304 $query = "SELECT * FROM " . $this->getTableName() .
305 " WHERE obj_id = " . $this->db->quote($this->getId(), 'integer') . " ";
306 $res = $this->db->query($query);
307 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
308 if (!is_null($row->local_information)) {
309 $this->setLocalInformation($row->local_information);
310 }
311 if (!is_null($row->remote_link)) {
312 $this->setRemoteLink($row->remote_link);
313 }
314 $this->setMID((int) $row->mid);
315 if (!is_null($row->organization)) {
316 $this->setOrganization($row->organization);
317 }
318 $this->doReadCustomFields($row);
319 }
320 }
321
325 protected function doReadCustomFields(object $a_row): void
326 {
327 }
328
336 public function createFromECSEContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner): void
337 {
338 $this->create();
339 $this->log->info("Done calling create, creating reference");
340 // won't work for personal workspace
341 $this->createReference();
342 $this->log->info("Done creating reference, setting permissions");
343 $this->setPermissions($a_server->getImportId());
344 $this->log->info("Done setting permissions, putting object in tree");
345
346 $matchable_content = ilECSUtils::getMatchableContent(
347 $this->getECSObjectType(),
348 $a_server->getServerId(),
349 $a_ecs_content,
350 $a_owner
351 );
352
354 $a_server->getServerId(),
355 $matchable_content
356 ));
357 $this->log->info("Done putting object in tree, updateing object");
358
359 $this->updateFromECSContent($a_server, $a_ecs_content, $a_owner);
360 }
361
367 public function updateFromECSContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner): void
368 {
369 $this->logger->info('updateFromECSContent: ' . print_r($a_ecs_content, true));
370
371 // Get organisation for owner (ObjectListGUI performance)
372 $organisation = null;
373 if ($a_owner) {
374 $organisation = ilECSCommunityReader::getInstanceByServerId($a_server->getServerId())
375 ->getParticipantNameByMid($a_owner);
376 $this->logger->info('found organisation: ' . $organisation);
377 }
378
379 $this->setMID($a_owner); // obsolete?
380 $this->setOrganization($organisation);
381 $this->setTitle($a_ecs_content->title);
382 if (!is_null($a_ecs_content->abstract)) {
383 $this->setDescription($a_ecs_content->abstract);
384 }
385 $this->setRemoteLink($a_ecs_content->url);
386
387 $this->logger->info('updateCustomFromECSContent');
388 $this->updateCustomFromECSContent($a_server, $a_ecs_content);
389
390 // we are updating late so custom values can be set
391
392 $this->logger->info('ilObject->update()');
393 $this->update();
394
395 $matchable_content = ilECSUtils::getMatchableContent(
396 $this->getECSObjectType(),
397 $a_server->getServerId(),
398 $a_ecs_content,
399 $a_owner
400 );
401
402 // rule-based category mapping
404 $this->getId(),
405 $a_server->getServerId(),
406 $matchable_content
407 );
408 }
409
414 protected function importMetadataFromJson(object $a_json, ilECSSetting $a_server, array $a_definition, int $a_mapping_mode): void
415 {
416 $this->logger->info("importing metadata from json: " . print_r($a_json, true));
417
419 $values_records = ilAdvancedMDValues::getInstancesForObjectId($this->getId(), $this->getType());
420 foreach ($values_records as $values_record) {
421 // this correctly binds group and definitions
422 $values_record->read();
423 }
424
425 $do_save = false;
426
427 foreach ($a_definition as $id => $type) {
428 if (is_array($type)) {
429 [$type, $target] = $type;
430 } else {
431 $target = $id;
432 }
433
434 $timePlace = null;
435 if ($field = $mappings->getMappingByECSName($a_mapping_mode, $id)) {
436 // find element in records
437 $adv_md_def = null;
438 foreach ($values_records as $values_record) {
439 $adv_md_defs = $values_record->getDefinitions();
440 if (isset($adv_md_defs[$field])) {
441 $adv_md_def = $adv_md_defs[$field];
442 break;
443 }
444 }
445 if (!$adv_md_def) {
446 continue;
447 }
448
449 $raw_value = $a_json->{$target};
450
452 if (!is_object($timePlace)) {
453 $timePlace = new ilECSTimePlace();
454 if (is_object($raw_value)) {
455 $timePlace->loadFromJSON($raw_value);
456 }
457 }
458 $raw_value = $timePlace;
459 }
460
461 if ($adv_md_def->importFromECS((string) $type, (string) $raw_value, $id)) {
462 $do_save = true;
463 }
464 }
465 }
466
467 if ($do_save) {
468 foreach ($values_records as $values_record) {
469 $additional = array();
470 foreach ($values_record->getADTGroup()->getElements() as $element_id => $element) {
471 if (!$element->isNull()) {
472 $additional[$element_id] = array("disabled" => array("integer", 1));
473 }
474 }
475 $values_record->write($additional);
476 }
477 }
478 }
479
486 protected function updateCustomFromECSContent(ilECSSetting $a_server, $ecs_content): void
487 {
488 }
489
495 public function isLocalObject(): bool
496 {
497 if (ilECSExportManager::getInstance()->_isRemote(
498 ilECSImportManager::getInstance()->lookupServerId($this->getId()),
499 (int) ilECSImportManager::getInstance()->_lookupEContentId($this->getId())
500 )) {
501 return false;
502 }
503 return true;
504 }
505
511 public function handleCreate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids): bool
512 {
513 return $this->handleUpdate($a_server, $a_econtent_id, $a_mids);
514 }
515
521 public function handleUpdate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids): bool
522 {
523 // get content details
525 $a_server->getServerId(),
526 $a_econtent_id,
527 $this->getECSObjectType()
528 );
529 if (!$details instanceof ilECSEContentDetails) {
530 $this->handleDelete($a_server, $a_econtent_id);
531 $this->logger->info(__METHOD__ . ': Handling delete of deprecated remote object. DONE');
532 return true;
533 }
534
535 $this->logger->info(__METHOD__ . ': Receivers are ' . print_r($details->getReceivers(), true));
536 $this->logger->info(__METHOD__ . ': Senders are ' . print_r($details->getSenders(), true));
537
538 // check owner (sender mid)
539 if (!ilECSParticipantSettings::getInstanceByServerId($a_server->getServerId())->isImportAllowed($details->getSenders())) {
540 $this->logger->info('Ignoring disabled participant. MID: ' . $details->getOwner());
541 return true;
542 }
543
544 // new mids
545 foreach (array_intersect($a_mids, $details->getReceivers()) as $mid) {
546 try {
547 $connector = new ilECSConnector($a_server);
548 $res = $connector->getResource($this->getECSObjectType(), $a_econtent_id);
549 if ($res->getHTTPCode() === ilECSConnector::HTTP_CODE_NOT_FOUND) {
550 continue;
551 }
552 $json = $res->getResult();
553 $this->logger->info(__METHOD__ . ': Received json: ' . print_r($json, true));
554 if (!is_object($json)) {
555 // try as array (workaround for invalid content)
556 $json = $json[0];
557 if (!is_object($json)) {
558 throw new ilECSConnectorException('invalid json');
559 }
560 }
561 } catch (ilECSConnectorException $exc) {
562 $this->logger->error(__METHOD__ . ': Error parsing result. ' . $exc->getMessage());
563 $this->logger->logStack(ilLogLevel::ERROR);
564 return false;
565 }
566
567 // Update existing
568
569 // Check receiver mid
570 if ($obj_id = ilECSImportManager::getInstance()->_isImported($a_server->getServerId(), (string) $a_econtent_id, $mid)) {
571 $this->logger->info(__METHOD__ . ': Handling update for existing object');
572 $remote = ilObjectFactory::getInstanceByObjId($obj_id, false);
573 if (!$remote instanceof self) {
574 $this->logger->info(__METHOD__ . ': Cannot instantiate remote object. Got object type ' . $remote->getType());
575 continue;
576 }
577 $remote->updateFromECSContent($a_server, $json, $details->getMySender());
578 } else {
579 $this->logger->info(__METHOD__ . ': my sender ' . $details->getMySender() . 'vs mid' . $mid);
580
581 $this->logger->info(__METHOD__ . ': Handling create for non existing object');
582 $this->createFromECSEContent($a_server, $json, $details->getMySender());
583
584 // update import status
585 $this->logger->info(__METHOD__ . ': Updating import status');
586 $import = new ilECSImport($a_server->getServerId(), $this->getId());
587 $import->setEContentId((string) $a_econtent_id);
588 // Store receiver mid
589 $import->setMID($mid);
590 $import->save();
591
592 $this->logger->info(__METHOD__ . ': Sending notification');
593 $this->sendNewContentNotification($a_server->getServerId());
594 }
595 }
596
597 $this->logger->info(__METHOD__ . ': done');
598 return true;
599 }
600
604 protected function sendNewContentNotification($a_server_id): void
605 {
607 if (!count($settings->getEContentRecipients())) {
608 return;
609 }
610
612 $lang->loadLanguageModule('ecs');
613
614 $mail = new ilMail(self::MAIL_SENDER);
615 $message = $lang->txt('ecs_' . $this->getType() . '_created_body_a') . "\n\n";
616 $message .= $lang->txt('title') . ': ' . $this->getTitle() . "\n";
617 if ($desc = ($this->getDescription() !== '')) {
618 $message .= $lang->txt('desc') . ': ' . $desc . "\n";
619 }
620
621 $href = ilLink::_getStaticLink($this->getRefId(), $this->getType(), true);
622 $message .= $lang->txt("perma_link") . ': ' . $href . "\n\n";
624
625 $mail->enqueue(
626 $settings->getEContentRecipientsAsString(),
627 '',
628 '',
629 $lang->txt('ecs_new_econtent_subject'),
630 $message,
631 array()
632 );
633 }
634
640 public function handleDelete(ilECSSetting $a_server, int $a_econtent_id, $a_mid = 0): bool
641 {
642 // there is no information about the original mid anymore.
643 // Therefor delete any remote objects with given econtent id
644 $obj_ids = ilECSImportManager::getInstance()->_lookupObjIds($a_server->getServerId(), $a_econtent_id);
645 $this->logger->info(__METHOD__ . ': Received obj_ids ' . print_r($obj_ids, true));
646
647 foreach ($obj_ids as $obj_id) {
648 $references = ilObject::_getAllReferences($obj_id);
649 foreach ($references as $ref_id) {
650 if ($tmp_obj = ilObjectFactory::getInstanceByRefId($ref_id, false)) {
651 $this->logger->info(__METHOD__ . ': Deleting obsolete remote course: ' . $tmp_obj->getTitle());
652 $this->logger->info(print_r($this->tree->getNodeData($ref_id), true));
653 $this->logger->info(print_r($this->tree->getNodeData($tmp_obj->getId()), true));
654 $this->tree->deleteTree($this->tree->getNodeData($ref_id));
655 $tmp_obj->delete();
656 }
657 unset($tmp_obj);
658 }
659 }
660 return true;
661 }
662
666 public function getAllResourceIds(ilECSSetting $a_server, bool $a_sender_only = false): array
667 {
668 try {
669 $connector = new ilECSConnector($a_server);
670 $connector->addHeader('X-EcsQueryStrings', $a_sender_only ? 'sender=true' : 'all=true'); // #11301
671 $list = $connector->getResourceList($this->getECSObjectType());
672 if ($list instanceof ilECSResult) {
673 return $list->getResult()->getLinkIds();
674 }
675 } catch (ilECSConnectorException $exc) {
676 $this->logger->error(__METHOD__ . ': Error getting resource list for type . ' . $this->getECSObjectType() . ' with message: ' . $exc->getMessage());
677 }
678
679 return [];
680 }
681}
static getInstancesForObjectId(int $a_obj_id, ?string $a_obj_type=null, string $a_sub_type="-", int $a_sub_id=0)
static handleUpdate(int $a_obj_id, int $a_server_id, array $a_matchable_content)
Handle update of ecs content and create references.
static getMatchingCategory(int $a_server_id, array $a_matchable_content)
get matching category
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
static getInstanceByServerId(int $a_server_id)
Get singleton instance.
Presentation of ecs content details (http://...campusconnect/courselinks/id/details)
static getInstanceFromServer(int $a_server_id, int $a_econtent_id, string $a_resource_type)
Get data from server.
static getInstance()
Get the singelton instance of this ilECSExportManager.
static getInstance()
Get the singleton instance of this ilECSImportManager.
Storage of ECS imported objects.
static getInstance(int $a_server_id, int $mid)
Get instance by server id and mid.
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
getServerId()
Get current server id.
static getInstanceByServerId(int $a_server_id)
Get singleton instance per server.
getImportId()
get import id
Representation of ECS EContent Time Place.
Stores relevant user data.
const TYPE_TIMEPLACE
static getMatchableContent(string $a_resource_id, int $a_server_id, object $a_ecs_content, int $a_owner)
Convert ECS content to rule matchable values.
static _getLanguage(string $a_lang_key='')
Get language object.
Component logger with individual log levels by component id.
static _getAutoGeneratedMessageString(ilLanguage $lang=null)
Remote category app class.
Remote course app class.
Remote file app class.
Remote glossary app class.
Remote group app class.
Remote learning module app class.
Remote test app class.
Remote wiki app class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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
setPermissions(int $parent_ref_id)
createReference()
creates reference for object
putInTree(int $parent_ref_id)
maybe this method should be in tree object!?
static _getAllReferences(int $id)
get all reference ids for object ID
setTitle(string $title)
setOwner(int $usr_id)
create()
note: title, description and type should be set when this function is called
ilObjUser $user
string $type
setDescription(string $desc)
Remote object app base class.
updateCustomFromECSContent(ilECSSetting $a_server, $ecs_content)
update remote object settings from ecs content
doUpdateCustomFields(array &$a_fields)
Add custom fields to db update.
static getInstanceByEventType(string $a_type)
Get instance by ilECSEvent(QueueReader) type.
createAuthResource(string $a_plain_realm)
create authentication resource on ecs server
getOrganization()
get organization
handleUpdate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids)
Handle update event.
setRemoteLink(string $a_link)
set remote link
getTableName()
Get db table name.
handleCreate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids)
Handle creation.
getLocalInformation()
get local information
setLocalInformation(string $a_info)
set local information
__construct(int $a_id=0, bool $a_call_by_reference=true)
Constructor.
doCreate(bool $clone_mode=false)
createFromECSEContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner)
create remote object from ECSContent object
doUpdate()
Update remote object.
isLocalObject()
Is remote object from same installation?
getFullRemoteLink()
get full remote link Including ecs generated hash and auth mode
doDelete()
Delete remote object.
importMetadataFromJson(object $a_json, ilECSSetting $a_server, array $a_definition, int $a_mapping_mode)
Add advanced metadata to json (export)
doReadCustomFields(object $a_row)
Read custom fields from db row.
updateFromECSContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner)
update remote object settings from ecs content
getRealmPlain()
Get realm plain.
setOrganization(string $a_organization)
set organization
getECSObjectType()
Get ECS resource identifier, e.g.
handleDelete(ilECSSetting $a_server, int $a_econtent_id, $a_mid=0)
Handle delete event.
getAllResourceIds(ilECSSetting $a_server, bool $a_sender_only=false)
Get all available resources.
beforeCreate()
If overwritten this method should return true, there is currently no "abort" handling for cases where...
sendNewContentNotification($a_server_id)
send notifications about new EContent
doCreateCustomFields(array &$a_fields)
Add custom fields to db insert.
$server
global $DIC
Definition: feed.php:28
$additional
Definition: goto.php:53
$ref_id
Definition: ltiauth.php:67
$res
Definition: ltiservices.php:69
$auth
Definition: metadata.php:76
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
array $details
Details for error message relating to last request processed.
Definition: System.php:109
array $settings
Setting values (LTI parameters, custom parameters and local parameters).
Definition: System.php:200
$query
$lang
Definition: xapiexit.php:26
$message
Definition: xapiexit.php:32