ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
ResourceLink.php
Go to the documentation of this file.
1<?php
2
4
5use DOMDocument;
6use DOMElement;
11
22{
23
27 const EXT_READ = 1;
31 const EXT_WRITE = 2;
35 const EXT_DELETE = 3;
39 const EXT_CREATE = 4;
43 const EXT_UPDATE = 5;
44
48 const EXT_TYPE_DECIMAL = 'decimal';
52 const EXT_TYPE_PERCENTAGE = 'percentage';
56 const EXT_TYPE_RATIO = 'ratio';
60 const EXT_TYPE_LETTER_AF = 'letteraf';
64 const EXT_TYPE_LETTER_AF_PLUS = 'letterafplus';
68 const EXT_TYPE_PASS_FAIL = 'passfail';
72 const EXT_TYPE_TEXT = 'freetext';
73
79 public $title = null;
85 public $ltiResourceLinkId = null;
91 public $groupSets = null;
97 public $groups = null;
103 public $extRequest = null;
109 public $extRequestHeaders = null;
115 public $extResponse = null;
121 public $extResponseHeaders = null;
133 public $shareApproved = null;
139 public $created = null;
145 public $updated = null;
146
152 private $id = null;
158 private $consumer = null;
164 private $consumerId = null;
170 private $context = null;
176 private $contextId = null;
182 private $settings = null;
188 private $settingsChanged = false;
194 private $extDoc = null;
200 private $extNodes = null;
206 private $dataConnector = null;
207
211 public function __construct()
212 {
213
214 $this->initialize();
215
216 }
217
221 public function initialize()
222 {
223
224 $this->title = '';
225 $this->settings = array();
226 $this->groupSets = null;
227 $this->groups = null;
228 $this->primaryResourceLinkId = null;
229 $this->shareApproved = null;
230 $this->created = null;
231 $this->updated = null;
232
233 }
234
240 public function initialise()
241 {
242
243 $this->initialize();
244
245 }
246
252 public function save()
253 {
254
255 $ok = $this->getDataConnector()->saveResourceLink($this);
256 if ($ok) {
257 $this->settingsChanged = false;
258 }
259
260 return $ok;
261
262 }
263
269 public function delete()
270 {
271
272 return $this->getDataConnector()->deleteResourceLink($this);
273
274 }
275
281 public function getConsumer()
282 {
283
284 if (is_null($this->consumer)) {
285 // begin-patch ilias
286 #if (!is_null($this->context) || !is_null($this->contextId)) {
287 if($this->context || $this->contextId) {
288 $this->consumer = $this->getContext()->getConsumer();
289 } else {
290 $this->consumer = ToolConsumer::fromRecordId($this->consumerId, $this->getDataConnector());
291 }
292 }
293
294 return $this->consumer;
295
296 }
297
303 public function setConsumerId($consumerId)
304 {
305
306 $this->consumer = null;
307 $this->consumerId = $consumerId;
308
309 }
310
316 public function getContext()
317 {
318
319 if (is_null($this->context) && !is_null($this->contextId)) {
320 $this->context = Context::fromRecordId($this->contextId, $this->getDataConnector());
321 }
322
323 return $this->context;
324
325 }
326
332 public function getContextId()
333 {
334
335 return $this->contextId;
336
337 }
338
344 public function setContextId($contextId)
345 {
346
347 $this->context = null;
348 $this->contextId = $contextId;
349
350 }
351
357 public function getKey()
358 {
359
360 return $this->getConsumer()->getKey();
361
362 }
363
369 public function getId()
370 {
371
373
374 }
375
381 public function getRecordId()
382 {
383
384 return $this->id;
385
386 }
387
393 public function setRecordId($id)
394 {
395
396 $this->id = $id;
397
398 }
399
405 public function getDataConnector()
406 {
407
409
410 }
411
420 public function getSetting($name, $default = '')
421 {
422
423 if (array_key_exists($name, $this->settings)) {
424 $value = $this->settings[$name];
425 } else {
426 $value = $default;
427 }
428
429 return $value;
430
431 }
432
439 public function setSetting($name, $value = null)
440 {
441
442 $old_value = $this->getSetting($name);
443 if ($value !== $old_value) {
444 if (!empty($value)) {
445 $this->settings[$name] = $value;
446 } else {
447 unset($this->settings[$name]);
448 }
449 $this->settingsChanged = true;
450 }
451
452 }
453
459 public function getSettings()
460 {
461
462 return $this->settings;
463
464 }
465
471 public function setSettings($settings)
472 {
473
474 $this->settings = $settings;
475
476 }
477
483 public function saveSettings()
484 {
485
486 if ($this->settingsChanged) {
487 $ok = $this->save();
488 } else {
489 $ok = true;
490 }
491
492 return $ok;
493
494 }
495
501 public function hasOutcomesService()
502 {
503
504 $url = $this->getSetting('ext_ims_lis_basic_outcome_url') . $this->getSetting('lis_outcome_service_url');
505
506 return !empty($url);
507
508 }
509
515 public function hasMembershipsService()
516 {
517
518 $url = $this->getSetting('ext_ims_lis_memberships_url');
519
520 return !empty($url);
521
522 }
523
529 public function hasSettingService()
530 {
531
532 $url = $this->getSetting('ext_ims_lti_tool_setting_url');
533
534 return !empty($url);
535
536 }
537
547 public function doOutcomesService($action, $ltiOutcome, $user)
548 {
549 global $DIC;
550 $logger = $DIC->logger()->lti();
551
552 $response = false;
553 $this->extResponse = null;
554
555// Lookup service details from the source resource link appropriate to the user (in case the destination is being shared)
556 $sourceResourceLink = $user->getResourceLink();
557 $sourcedId = $user->ltiResultSourcedId;
558
559// Use LTI 1.1 service in preference to extension service if it is available
560 $urlLTI11 = $sourceResourceLink->getSetting('lis_outcome_service_url');
561 $urlExt = $sourceResourceLink->getSetting('ext_ims_lis_basic_outcome_url');
562 if ($urlExt || $urlLTI11) {
563 switch ($action) {
564 case self::EXT_READ:
565 if ($urlLTI11 && ($ltiOutcome->type === self::EXT_TYPE_DECIMAL)) {
566 $do = 'readResult';
567 } else if ($urlExt) {
568 $urlLTI11 = null;
569 $do = 'basic-lis-readresult';
570 }
571 break;
572 case self::EXT_WRITE:
573 if ($urlLTI11 && $this->checkValueType($ltiOutcome, array(self::EXT_TYPE_DECIMAL))) {
574 $do = 'replaceResult';
575 } else if ($this->checkValueType($ltiOutcome)) {
576 $urlLTI11 = null;
577 $do = 'basic-lis-updateresult';
578 }
579 break;
580 case self::EXT_DELETE:
581 if ($urlLTI11 && ($ltiOutcome->type === self::EXT_TYPE_DECIMAL)) {
582 $do = 'deleteResult';
583 } else if ($urlExt) {
584 $urlLTI11 = null;
585 $do = 'basic-lis-deleteresult';
586 }
587 break;
588 }
589 }
590
591 $logger->debug('Command is: ' . $do);
592
593 if (isset($do)) {
594 $value = $ltiOutcome->getValue();
595 if (is_null($value)) {
596 $value = '';
597 }
598 if ($urlLTI11) {
599 $xml = '';
600 if ($action === self::EXT_WRITE) {
601 $xml = <<<EOF
602
603 <result>
604 <resultScore>
605 <language>{$ltiOutcome->language}</language>
606 <textString>{$value}</textString>
607 </resultScore>
608 </result>
609EOF;
610 }
611 $sourcedId = htmlentities($sourcedId);
612 $xml = <<<EOF
613 <resultRecord>
614 <sourcedGUID>
615 <sourcedId>{$sourcedId}</sourcedId>
616 </sourcedGUID>{$xml}
617 </resultRecord>
618EOF;
619
620 $logger->debug($urlLTI11);
621 $logger->debug('xml for doLTI11Service: ' . $xml);
622
623 if ($this->doLTI11Service($do, $urlLTI11, $xml)) {
624 switch ($action) {
625 case self::EXT_READ:
626 if (!isset($this->extNodes['imsx_POXBody']["{$do}Response"]['result']['resultScore']['textString'])) {
627 break;
628 } else {
629 $ltiOutcome->setValue($this->extNodes['imsx_POXBody']["{$do}Response"]['result']['resultScore']['textString']);
630 }
631 case self::EXT_WRITE:
632 case self::EXT_DELETE:
633 $response = true;
634 break;
635 }
636 }
637 } else {
638 $params = array();
639 $params['sourcedid'] = $sourcedId;
640 $params['result_resultscore_textstring'] = $value;
641 if (!empty($ltiOutcome->language)) {
642 $params['result_resultscore_language'] = $ltiOutcome->language;
643 }
644 if (!empty($ltiOutcome->status)) {
645 $params['result_statusofresult'] = $ltiOutcome->status;
646 }
647 if (!empty($ltiOutcome->date)) {
648 $params['result_date'] = $ltiOutcome->date;
649 }
650 if (!empty($ltiOutcome->type)) {
651 $params['result_resultvaluesourcedid'] = $ltiOutcome->type;
652 }
653 if (!empty($ltiOutcome->data_source)) {
654 $params['result_datasource'] = $ltiOutcome->data_source;
655 }
656
657 $logger->debug($urlExt);
658 $logger->dump($params);
659
660
661 if ($this->doService($do, $urlExt, $params)) {
662 switch ($action) {
663 case self::EXT_READ:
664 if (isset($this->extNodes['result']['resultscore']['textstring'])) {
665 $response = $this->extNodes['result']['resultscore']['textstring'];
666 }
667 break;
668 case self::EXT_WRITE:
669 case self::EXT_DELETE:
670 $response = true;
671 break;
672 }
673 }
674 }
675 if (is_array($response) && (count($response) <= 0)) {
676 $response = '';
677 }
678 }
679
680 return $response;
681
682 }
683
693 public function doMembershipsService($withGroups = false)
694 {
695
696 $users = array();
698 $this->extResponse = null;
699 $url = $this->getSetting('ext_ims_lis_memberships_url');
700 $params = array();
701 $params['id'] = $this->getSetting('ext_ims_lis_memberships_id');
702 $ok = false;
703 if ($withGroups) {
704 $ok = $this->doService('basic-lis-readmembershipsforcontextwithgroups', $url, $params);
705 }
706 if ($ok) {
707 $this->groupSets = array();
708 $this->groups = array();
709 } else {
710 $ok = $this->doService('basic-lis-readmembershipsforcontext', $url, $params);
711 }
712
713 if ($ok) {
714 if (!isset($this->extNodes['memberships']['member'])) {
715 $members = array();
716 } else if (!isset($this->extNodes['memberships']['member'][0])) {
717 $members = array();
718 $members[0] = $this->extNodes['memberships']['member'];
719 } else {
720 $members = $this->extNodes['memberships']['member'];
721 }
722
723 for ($i = 0; $i < count($members); $i++) {
724
725 $user = User::fromResourceLink($this, $members[$i]['user_id']);
726
727// Set the user name
728 $firstname = (isset($members[$i]['person_name_given'])) ? $members[$i]['person_name_given'] : '';
729 $lastname = (isset($members[$i]['person_name_family'])) ? $members[$i]['person_name_family'] : '';
730 $fullname = (isset($members[$i]['person_name_full'])) ? $members[$i]['person_name_full'] : '';
731 $user->setNames($firstname, $lastname, $fullname);
732
733// Set the user email
734 $email = (isset($members[$i]['person_contact_email_primary'])) ? $members[$i]['person_contact_email_primary'] : '';
735 $user->setEmail($email, $this->getConsumer()->defaultEmail);
736
738 if (isset($members[$i]['roles'])) {
739 $user->roles = ToolProvider::parseRoles($members[$i]['roles']);
740 }
741
742// Set the user groups
743 if (!isset($members[$i]['groups']['group'])) {
744 $groups = array();
745 } else if (!isset($members[$i]['groups']['group'][0])) {
746 $groups = array();
747 $groups[0] = $members[$i]['groups']['group'];
748 } else {
749 $groups = $members[$i]['groups']['group'];
750 }
751 for ($j = 0; $j < count($groups); $j++) {
752 $group = $groups[$j];
753 if (isset($group['set'])) {
754 $set_id = $group['set']['id'];
755 if (!isset($this->groupSets[$set_id])) {
756 $this->groupSets[$set_id] = array('title' => $group['set']['title'], 'groups' => array(),
757 'num_members' => 0, 'num_staff' => 0, 'num_learners' => 0);
758 }
759 $this->groupSets[$set_id]['num_members']++;
760 if ($user->isStaff()) {
761 $this->groupSets[$set_id]['num_staff']++;
762 }
763 if ($user->isLearner()) {
764 $this->groupSets[$set_id]['num_learners']++;
765 }
766 if (!in_array($group['id'], $this->groupSets[$set_id]['groups'])) {
767 $this->groupSets[$set_id]['groups'][] = $group['id'];
768 }
769 $this->groups[$group['id']] = array('title' => $group['title'], 'set' => $set_id);
770 } else {
771 $this->groups[$group['id']] = array('title' => $group['title']);
772 }
773 $user->groups[] = $group['id'];
774 }
775
776// If a result sourcedid is provided save the user
777 if (isset($members[$i]['lis_result_sourcedid'])) {
778 $user->ltiResultSourcedId = $members[$i]['lis_result_sourcedid'];
779 $user->save();
780 }
781 $users[] = $user;
782
783// Remove old user (if it exists)
784 unset($oldUsers[$user->getId(ToolProvider::ID_SCOPE_RESOURCE)]);
785 }
786
787// Delete any old users which were not in the latest list from the tool consumer
788 foreach ($oldUsers as $id => $user) {
789 $user->delete();
790 }
791 } else {
792 $users = false;
793 }
794
795 return $users;
796
797 }
798
807 public function doSettingService($action, $value = null)
808 {
809
810 $response = false;
811 $this->extResponse = null;
812 switch ($action) {
813 case self::EXT_READ:
814 $do = 'basic-lti-loadsetting';
815 break;
816 case self::EXT_WRITE:
817 $do = 'basic-lti-savesetting';
818 break;
819 case self::EXT_DELETE:
820 $do = 'basic-lti-deletesetting';
821 break;
822 }
823 if (isset($do)) {
824
825 $url = $this->getSetting('ext_ims_lti_tool_setting_url');
826 $params = array();
827 $params['id'] = $this->getSetting('ext_ims_lti_tool_setting_id');
828 if (is_null($value)) {
829 $value = '';
830 }
831 $params['setting'] = $value;
832
833 if ($this->doService($do, $url, $params)) {
834 switch ($action) {
835 case self::EXT_READ:
836 if (isset($this->extNodes['setting']['value'])) {
837 $response = $this->extNodes['setting']['value'];
838 if (is_array($response)) {
839 $response = '';
840 }
841 }
842 break;
843 case self::EXT_WRITE:
844 $this->setSetting('ext_ims_lti_tool_setting', $value);
845 $this->saveSettings();
846 $response = true;
847 break;
848 case self::EXT_DELETE:
849 $response = true;
850 break;
851 }
852 }
853 }
854
855 return $response;
856
857 }
858
864 public function hasToolSettingsService()
865 {
866
867 $url = $this->getSetting('custom_link_setting_url');
868
869 return !empty($url);
870
871 }
872
881 public function getToolSettings($mode = Service\ToolSettings::MODE_CURRENT_LEVEL, $simple = true)
882 {
883
884 $url = $this->getSetting('custom_link_setting_url');
885 $service = new Service\ToolSettings($this, $url, $simple);
886 $response = $service->get($mode);
887
888 return $response;
889
890 }
891
899 public function setToolSettings($settings = array())
900 {
901
902 $url = $this->getSetting('custom_link_setting_url');
903 $service = new Service\ToolSettings($this, $url);
904 $response = $service->set($settings);
905
906 return $response;
907
908 }
909
915 public function hasMembershipService()
916 {
917
918 $has = !empty($this->contextId);
919 if ($has) {
920 $has = !empty($this->getContext()->getSetting('custom_context_memberships_url'));
921 }
922
923 return $has;
924
925 }
926
932 public function getMembership()
933 {
934
935 $response = false;
936 if (!empty($this->contextId)) {
937 $url = $this->getContext()->getSetting('custom_context_memberships_url');
938 if (!empty($url)) {
939 $service = new Service\Membership($this, $url);
940 $response = $service->get();
941 }
942 }
943
944 return $response;
945
946 }
947
959 public function getUserResultSourcedIDs($localOnly = false, $idScope = null)
960 {
961
962 return $this->getDataConnector()->getUserResultSourcedIDsResourceLink($this, $localOnly, $idScope);
963
964 }
965
971 public function getShares()
972 {
973
974 return $this->getDataConnector()->getSharesResourceLink($this);
975
976 }
977
986 public static function fromConsumer($consumer, $ltiResourceLinkId, $tempId = null)
987 {
988
989 $resourceLink = new ResourceLink();
990 $resourceLink->consumer = $consumer;
991 $resourceLink->dataConnector = $consumer->getDataConnector();
992 $resourceLink->ltiResourceLinkId = $ltiResourceLinkId;
993 if (!empty($ltiResourceLinkId)) {
994 $resourceLink->load();
995 if (is_null($resourceLink->id) && !empty($tempId)) {
996 $resourceLink->ltiResourceLinkId = $tempId;
997 $resourceLink->load();
998 $resourceLink->ltiResourceLinkId = $ltiResourceLinkId;
999 }
1000 }
1001
1002 return $resourceLink;
1003
1004 }
1005
1014 public static function fromContext($context, $ltiResourceLinkId, $tempId = null)
1015 {
1016
1017 $resourceLink = new ResourceLink();
1018 $resourceLink->setContextId($context->getRecordId());
1019 $resourceLink->context = $context;
1020 $resourceLink->dataConnector = $context->getDataConnector();
1021 $resourceLink->ltiResourceLinkId = $ltiResourceLinkId;
1022 if (!empty($ltiResourceLinkId)) {
1023 $resourceLink->load();
1024 if (is_null($resourceLink->id) && !empty($tempId)) {
1025 $resourceLink->ltiResourceLinkId = $tempId;
1026 $resourceLink->load();
1027 $resourceLink->ltiResourceLinkId = $ltiResourceLinkId;
1028 }
1029 }
1030
1031 return $resourceLink;
1032
1033 }
1034
1043 public static function fromRecordId($id, $dataConnector)
1044 {
1045 $resourceLink = new ResourceLink();
1046 $resourceLink->dataConnector = $dataConnector;
1047 $resourceLink->load($id);
1048
1049 return $resourceLink;
1050
1051 }
1052
1053###
1054### PRIVATE METHODS
1055###
1056
1064 private function load($id = null)
1065 {
1066
1067 $this->initialize();
1068 $this->id = $id;
1069
1070 return $this->getDataConnector()->loadResourceLink($this);
1071
1072 }
1073
1082 private function checkValueType($ltiOutcome, $supportedTypes = null)
1083 {
1084
1085 if (empty($supportedTypes)) {
1086 $supportedTypes = explode(',', str_replace(' ', '', strtolower($this->getSetting('ext_ims_lis_resultvalue_sourcedids', self::EXT_TYPE_DECIMAL))));
1087 }
1088 $type = $ltiOutcome->type;
1089 $value = $ltiOutcome->getValue();
1090// Check whether the type is supported or there is no value
1091 $ok = in_array($type, $supportedTypes) || (strlen($value) <= 0);
1092 if (!$ok) {
1093// Convert numeric values to decimal
1094 if ($type === self::EXT_TYPE_PERCENTAGE) {
1095 if (substr($value, -1) === '%') {
1096 $value = substr($value, 0, -1);
1097 }
1098 $ok = is_numeric($value) && ($value >= 0) && ($value <= 100);
1099 if ($ok) {
1100 $ltiOutcome->setValue($value / 100);
1101 $ltiOutcome->type = self::EXT_TYPE_DECIMAL;
1102 }
1103 } else if ($type === self::EXT_TYPE_RATIO) {
1104 $parts = explode('/', $value, 2);
1105 $ok = (count($parts) === 2) && is_numeric($parts[0]) && is_numeric($parts[1]) && ($parts[0] >= 0) && ($parts[1] > 0);
1106 if ($ok) {
1107 $ltiOutcome->setValue($parts[0] / $parts[1]);
1108 $ltiOutcome->type = self::EXT_TYPE_DECIMAL;
1109 }
1110// Convert letter_af to letter_af_plus or text
1111 } else if ($type === self::EXT_TYPE_LETTER_AF) {
1112 if (in_array(self::EXT_TYPE_LETTER_AF_PLUS, $supportedTypes)) {
1113 $ok = true;
1114 $ltiOutcome->type = self::EXT_TYPE_LETTER_AF_PLUS;
1115 } else if (in_array(self::EXT_TYPE_TEXT, $supportedTypes)) {
1116 $ok = true;
1117 $ltiOutcome->type = self::EXT_TYPE_TEXT;
1118 }
1119// Convert letter_af_plus to letter_af or text
1120 } else if ($type === self::EXT_TYPE_LETTER_AF_PLUS) {
1121 if (in_array(self::EXT_TYPE_LETTER_AF, $supportedTypes) && (strlen($value) === 1)) {
1122 $ok = true;
1123 $ltiOutcome->type = self::EXT_TYPE_LETTER_AF;
1124 } else if (in_array(self::EXT_TYPE_TEXT, $supportedTypes)) {
1125 $ok = true;
1126 $ltiOutcome->type = self::EXT_TYPE_TEXT;
1127 }
1128// Convert text to decimal
1129 } else if ($type === self::EXT_TYPE_TEXT) {
1130 $ok = is_numeric($value) && ($value >= 0) && ($value <=1);
1131 if ($ok) {
1132 $ltiOutcome->type = self::EXT_TYPE_DECIMAL;
1133 } else if (substr($value, -1) === '%') {
1134 $value = substr($value, 0, -1);
1135 $ok = is_numeric($value) && ($value >= 0) && ($value <=100);
1136 if ($ok) {
1137 if (in_array(self::EXT_TYPE_PERCENTAGE, $supportedTypes)) {
1138 $ltiOutcome->type = self::EXT_TYPE_PERCENTAGE;
1139 } else {
1140 $ltiOutcome->setValue($value / 100);
1141 $ltiOutcome->type = self::EXT_TYPE_DECIMAL;
1142 }
1143 }
1144 }
1145 }
1146 }
1147
1148 return $ok;
1149
1150 }
1151
1161 private function doService($type, $url, $params)
1162 {
1163
1164 $ok = false;
1165 $this->extRequest = null;
1166 $this->extRequestHeaders = '';
1167 $this->extResponse = null;
1168 $this->extResponseHeaders = '';
1169 if (!empty($url)) {
1170 $params = $this->getConsumer()->signParameters($url, $type, $this->getConsumer()->ltiVersion, $params);
1171// Connect to tool consumer
1172 $http = new HTTPMessage($url, 'POST', $params);
1173 \ilLoggerFactory::getLogger('lti')->debug('Sending to ' . $url);
1175
1176// Parse XML response
1177 if ($http->send()) {
1178 $this->extResponse = $http->response;
1179 $this->extResponseHeaders = $http->responseHeaders;
1180
1181 \ilLoggerFactory::getLogger('lti')->debug('Response: ' . $http->response);
1182 \ilLoggerFactory::getLogger('lti')->debug('Response: ' . $http->responseHeaders);
1183
1184 try {
1185 $this->extDoc = new DOMDocument();
1186 $this->extDoc->loadXML($http->response);
1187 $this->extNodes = $this->domnodeToArray($this->extDoc->documentElement);
1188 if (isset($this->extNodes['statusinfo']['codemajor']) && ($this->extNodes['statusinfo']['codemajor'] === 'Success')) {
1189 $ok = true;
1190 }
1191 } catch (\Exception $e) {
1192 \ilLoggerFactory::getLogger('lti')->warning('Outcome failed with message: ' . $e->getMessage());
1193 }
1194 }
1195 $this->extRequest = $http->request;
1196 $this->extRequestHeaders = $http->requestHeaders;
1197
1198 \ilLoggerFactory::getLogger('lti')->debug('Request: ' . $http->request);
1199 \ilLoggerFactory::getLogger('lti')->debug('RequestHeaders: ' . $http->requestHeaders);
1200 }
1201
1202 return $ok;
1203
1204 }
1205
1215 private function doLTI11Service($type, $url, $xml)
1216 {
1217
1218 $ok = false;
1219 $this->extRequest = null;
1220 $this->extRequestHeaders = '';
1221 $this->extResponse = null;
1222 $this->extResponseHeaders = '';
1223 if (!empty($url)) {
1224 $id = uniqid();
1225 $xmlRequest = <<< EOD
1226<?xml version = "1.0" encoding = "UTF-8"?>
1227<imsx_POXEnvelopeRequest xmlns = "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
1228 <imsx_POXHeader>
1229 <imsx_POXRequestHeaderInfo>
1230 <imsx_version>V1.0</imsx_version>
1231 <imsx_messageIdentifier>{$id}</imsx_messageIdentifier>
1232 </imsx_POXRequestHeaderInfo>
1233 </imsx_POXHeader>
1234 <imsx_POXBody>
1235 <{$type}Request>
1236{$xml}
1237 </{$type}Request>
1238 </imsx_POXBody>
1239</imsx_POXEnvelopeRequest>
1240EOD;
1241// Calculate body hash
1242 $hash = base64_encode(sha1($xmlRequest, true));
1243 $params = array('oauth_body_hash' => $hash);
1244
1245// Add OAuth signature
1246 $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1();
1247 $consumer = new OAuth\OAuthConsumer($this->getConsumer()->getKey(), $this->getConsumer()->secret, null);
1249 $req->sign_request($hmacMethod, $consumer, null);
1250 $params = $req->get_parameters();
1251 $header = $req->to_header();
1252 $header .= "\nContent-Type: application/xml";
1253// Connect to tool consumer
1254 $http = new HTTPMessage($url, 'POST', $xmlRequest, $header);
1255
1256 \ilLoggerFactory::getLogger('lti')->debug('Sending post: ' . $header);
1257 \ilLoggerFactory::getLogger('lti')->debug('Sending post: ' . $xmlRequest);
1258
1259// Parse XML response
1260 if ($http->send()) {
1261 $this->extResponse = $http->response;
1262 $this->extResponseHeaders = $http->responseHeaders;
1263 \ilLoggerFactory::getLogger('lti')->debug('Got response: ' . $http->response);
1264 \ilLoggerFactory::getLogger('lti')->debug('Got response: ' . $http->responseHeaders);
1265 try {
1266 $this->extDoc = new DOMDocument();
1267 $this->extDoc->loadXML($http->response);
1268 $this->extNodes = $this->domnodeToArray($this->extDoc->documentElement);
1269 if (isset($this->extNodes['imsx_POXHeader']['imsx_POXResponseHeaderInfo']['imsx_statusInfo']['imsx_codeMajor']) &&
1270 ($this->extNodes['imsx_POXHeader']['imsx_POXResponseHeaderInfo']['imsx_statusInfo']['imsx_codeMajor'] === 'success')) {
1271 $ok = true;
1272 }
1273 } catch (\Exception $e) {
1274 \ilLoggerFactory::getLogger('lti')->warning('lti 1.1 outcome failed with message: ' . $e->getMessage());
1275 }
1276 }
1277 else {
1278 \ilLoggerFactory::getLogger('lti')->debug('Got response: ' . $http->response);
1279 \ilLoggerFactory::getLogger('lti')->debug('Got response: ' . $http->responseHeaders);
1280 }
1281 $this->extRequest = $http->request;
1282 $this->extRequestHeaders = $http->requestHeaders;
1283 }
1284
1285 return $ok;
1286
1287 }
1288
1296 private function domnodeToArray($node)
1297 {
1298
1299 $output = '';
1300 switch ($node->nodeType) {
1301 case XML_CDATA_SECTION_NODE:
1302 case XML_TEXT_NODE:
1303 $output = trim($node->textContent);
1304 break;
1305 case XML_ELEMENT_NODE:
1306 for ($i = 0; $i < $node->childNodes->length; $i++) {
1307 $child = $node->childNodes->item($i);
1308 $v = $this->domnodeToArray($child);
1309 if (isset($child->tagName)) {
1310 $t = $child->tagName;
1311 if (!isset($output[$t])) {
1312 $output[$t] = array();
1313 }
1314 $output[$t][] = $v;
1315 } else {
1316 $s = (string) $v;
1317 if (strlen($s) > 0) {
1318 $output = $s;
1319 }
1320 }
1321 }
1322 if (is_array($output)) {
1323 if ($node->attributes->length) {
1324 $a = array();
1325 foreach ($node->attributes as $attrName => $attrNode) {
1326 $a[$attrName] = (string) $attrNode->value;
1327 }
1328 $output['@attributes'] = $a;
1329 }
1330 foreach ($output as $t => $v) {
1331 if (is_array($v) && count($v)==1 && $t!='@attributes') {
1332 $output[$t] = $v[0];
1333 }
1334 }
1335 }
1336 break;
1337 }
1338
1339 return $output;
1340
1341 }
1342
1343}
const EOF
How fgetc() reports an End Of File.
Definition: JSMin_lib.php:92
$users
Definition: authpage.php:44
$default
Definition: build.php:20
An exception for terminatinating execution or to throw for unit testing.
Class to represent an HTTP message.
Definition: HTTPMessage.php:15
Class to represent an OAuth Consumer.
static from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=null)
pretty much a helper function to set up the request
Class to represent an OAuth HMAC_SHA1 signature method.
static fromRecordId($id, $dataConnector)
Load the context from the database.
Definition: Context.php:407
Class to provide a connection to a persistent store for LTI objects.
Class to implement the Membership service.
Definition: Membership.php:17
Class to implement a service.
Definition: Service.php:18
Class to implement the Tool Settings service.
const MODE_CURRENT_LEVEL
Settings at current level mode.
static fromRecordId($id, $dataConnector)
Load the tool consumer from the database by its record ID.
static parseRoles($roles)
Get an array of fully qualified user roles.
const ID_SCOPE_RESOURCE
Prefix the ID with the consumer key and resource ID.
static fromResourceLink($resourceLink, $ltiUserId)
Class constructor from resource link.
Definition: User.php:413
static getLogger($a_component_id)
Get component logger.
$action
$i
Definition: disco.tpl.php:19
$req
Definition: getUserInfo.php:20
if( $orgName !==null) if($spconfig->hasValue('contacts')) $email
Definition: metadata.php:201
$user
Definition: migrateto20.php:57
$type
$url
$response
$s
Definition: pwgen.php:45
$http
Definition: raiseError.php:7
global $DIC
Definition: saml.php:7
settings()
Definition: settings.php:2