MDL-73233 course: Remove make_active() call
[moodle.git] / enrol / lti / classes / data_connector.php
blobb061da986ad64bc69ae07573d2c4b74079d3e2bd
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Extends the IMS Tool provider library data connector for moodle.
20 * @package enrol_lti
21 * @copyright 2016 John Okely <john@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 namespace enrol_lti;
27 defined('MOODLE_INTERNAL') || die;
29 use IMSGlobal\LTI\ToolProvider;
30 use IMSGlobal\LTI\ToolProvider\ConsumerNonce;
31 use IMSGlobal\LTI\ToolProvider\Context;
32 use IMSGlobal\LTI\ToolProvider\DataConnector\DataConnector;
33 use IMSGlobal\LTI\ToolProvider\ResourceLink;
34 use IMSGlobal\LTI\ToolProvider\ResourceLinkShare;
35 use IMSGlobal\LTI\ToolProvider\ResourceLinkShareKey;
36 use IMSGlobal\LTI\ToolProvider\ToolConsumer;
37 use IMSGlobal\LTI\ToolProvider\ToolProxy;
38 use IMSGlobal\LTI\ToolProvider\User;
39 use stdClass;
41 /**
42 * Extends the IMS Tool provider library data connector for moodle.
44 * @package enrol_lti
45 * @copyright 2016 John Okely <john@moodle.com>
46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
48 class data_connector extends DataConnector {
50 /** @var string Tool consumer table name. */
51 protected $consumertable;
52 /** @var string Context table name. */
53 protected $contexttable;
54 /** @var string Consumer nonce table name. */
55 protected $noncetable;
56 /** @var string Resource link table name. */
57 protected $resourcelinktable;
58 /** @var string Resource link share key table name. */
59 protected $sharekeytable;
60 /** @var string Tool proxy table name. */
61 protected $toolproxytable;
62 /** @var string User result table name. */
63 protected $userresulttable;
65 /**
66 * data_connector constructor.
68 public function __construct() {
69 parent::__construct(null, 'enrol_lti_');
71 // Set up table names.
72 $this->consumertable = $this->dbTableNamePrefix . DataConnector::CONSUMER_TABLE_NAME;
73 $this->contexttable = $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME;
74 $this->noncetable = $this->dbTableNamePrefix . DataConnector::NONCE_TABLE_NAME;
75 $this->resourcelinktable = $this->dbTableNamePrefix . DataConnector::RESOURCE_LINK_TABLE_NAME;
76 $this->sharekeytable = $this->dbTableNamePrefix . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME;
77 $this->toolproxytable = $this->dbTableNamePrefix . DataConnector::TOOL_PROXY_TABLE_NAME;
78 $this->userresulttable = $this->dbTableNamePrefix . DataConnector::USER_RESULT_TABLE_NAME;
81 /**
82 * Load tool consumer object.
84 * @param ToolConsumer $consumer ToolConsumer object
85 * @return boolean True if the tool consumer object was successfully loaded
87 public function loadToolConsumer($consumer) {
88 global $DB;
90 $id = $consumer->getRecordId();
92 if (!empty($id)) {
93 $result = $DB->get_record($this->consumertable, ['id' => $id]);
94 } else {
95 $key256 = DataConnector::getConsumerKey($consumer->getKey());
96 $result = $DB->get_record($this->consumertable, ['consumerkey256' => $key256]);
99 if ($result) {
100 if (empty($key256) || empty($result->consumerkey) || ($consumer->getKey() === $result->consumerkey)) {
101 $this->build_tool_consumer_object($result, $consumer);
102 return true;
106 return false;
110 * Save tool consumer object.
112 * @param ToolConsumer $consumer Consumer object
113 * @return boolean True if the tool consumer object was successfully saved
115 public function saveToolConsumer($consumer) {
116 global $DB;
118 $key = $consumer->getKey();
119 $key256 = DataConnector::getConsumerKey($key);
120 if ($key === $key256) {
121 $key = null;
123 $protected = ($consumer->protected) ? 1 : 0;
124 $enabled = ($consumer->enabled) ? 1 : 0;
125 $profile = (!empty($consumer->profile)) ? json_encode($consumer->profile) : null;
126 $settingsvalue = serialize($consumer->getSettings());
127 $now = time();
128 $consumer->updated = $now;
129 $data = [
130 'consumerkey256' => $key256,
131 'consumerkey' => $key,
132 'name' => $consumer->name,
133 'secret' => $consumer->secret,
134 'ltiversion' => $consumer->ltiVersion,
135 'consumername' => $consumer->consumerName,
136 'consumerversion' => $consumer->consumerVersion,
137 'consumerguid' => $consumer->consumerGuid,
138 'profile' => $profile,
139 'toolproxy' => $consumer->toolProxy,
140 'settings' => $settingsvalue,
141 'protected' => $protected,
142 'enabled' => $enabled,
143 'enablefrom' => $consumer->enableFrom,
144 'enableuntil' => $consumer->enableUntil,
145 'lastaccess' => $consumer->lastAccess,
146 'updated' => $consumer->updated,
149 $id = $consumer->getRecordId();
151 if (empty($id)) {
152 $consumer->created = $now;
153 $data['created'] = $consumer->created;
154 $id = $DB->insert_record($this->consumertable, (object) $data);
155 if ($id) {
156 $consumer->setRecordId($id);
157 return true;
159 } else {
160 $data['id'] = $id;
161 return $DB->update_record($this->consumertable, (object) $data);
164 return false;
168 * Delete tool consumer object and related records.
170 * @param ToolConsumer $consumer Consumer object
171 * @return boolean True if the tool consumer object was successfully deleted
173 public function deleteToolConsumer($consumer) {
174 global $DB;
176 $consumerpk = $consumer->getRecordId();
177 $deletecondition = ['consumerid' => $consumerpk];
179 // Delete any nonce values for this consumer.
180 $DB->delete_records($this->noncetable, $deletecondition);
182 // Delete any outstanding share keys for resource links for this consumer.
183 $where = "resourcelinkid IN (
184 SELECT rl.id
185 FROM {{$this->resourcelinktable}} rl
186 WHERE rl.consumerid = :consumerid
188 $DB->delete_records_select($this->sharekeytable, $where, $deletecondition);
190 // Delete any outstanding share keys for resource links for contexts in this consumer.
191 $where = "resourcelinkid IN (
192 SELECT rl.id
193 FROM {{$this->resourcelinktable}} rl
194 INNER JOIN {{$this->contexttable}} c
195 ON rl.contextid = c.id
196 WHERE c.consumerid = :consumerid
198 $DB->delete_records_select($this->sharekeytable, $where, $deletecondition);
200 // Delete any users in resource links for this consumer.
201 $where = "resourcelinkid IN (
202 SELECT rl.id
203 FROM {{$this->resourcelinktable}} rl
204 WHERE rl.consumerid = :consumerid
206 $DB->delete_records_select($this->userresulttable, $where, $deletecondition);
208 // Delete any users in resource links for contexts in this consumer.
209 $where = "resourcelinkid IN (
210 SELECT rl.id
211 FROM {{$this->resourcelinktable}} rl
212 INNER JOIN {{$this->contexttable}} c
213 ON rl.contextid = c.id
214 WHERE c.consumerid = :consumerid
216 $DB->delete_records_select($this->userresulttable, $where, $deletecondition);
218 // Update any resource links for which this consumer is acting as a primary resource link.
219 $where = "primaryresourcelinkid IN (
220 SELECT rl.id
221 FROM {{$this->resourcelinktable}} rl
222 WHERE rl.consumerid = :consumerid
224 $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $deletecondition);
225 foreach ($updaterecords as $record) {
226 $record->primaryresourcelinkid = null;
227 $record->shareapproved = null;
228 $DB->update_record($this->resourcelinktable, $record);
231 // Update any resource links for contexts in which this consumer is acting as a primary resource link.
232 $where = "primaryresourcelinkid IN (
233 SELECT rl.id
234 FROM {{$this->resourcelinktable}} rl
235 INNER JOIN {{$this->contexttable}} c
236 ON rl.contextid = c.id
237 WHERE c.consumerid = :consumerid
239 $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $deletecondition);
240 foreach ($updaterecords as $record) {
241 $record->primaryresourcelinkid = null;
242 $record->shareapproved = null;
243 $DB->update_record($this->resourcelinktable, $record);
246 // Delete any resource links for contexts in this consumer.
247 $where = "contextid IN (
248 SELECT c.id
249 FROM {{$this->contexttable}} c
250 WHERE c.consumerid = :consumerid
252 $DB->delete_records_select($this->resourcelinktable, $where, $deletecondition);
254 // Delete any resource links for this consumer.
255 $DB->delete_records($this->resourcelinktable, $deletecondition);
257 // Delete any contexts for this consumer.
258 $DB->delete_records($this->contexttable, $deletecondition);
260 // Delete consumer.
261 $DB->delete_records($this->consumertable, ['id' => $consumerpk]);
263 $consumer->initialize();
265 return true;
269 * Load all tool consumers from the database.
270 * @return array
272 public function getToolConsumers() {
273 global $DB;
274 $consumers = [];
276 $rsconsumers = $DB->get_recordset($this->consumertable, null, 'name');
277 foreach ($rsconsumers as $row) {
278 $consumer = new ToolProvider\ToolConsumer($row->consumerkey, $this);
279 $this->build_tool_consumer_object($row, $consumer);
280 $consumers[] = $consumer;
282 $rsconsumers->close();
284 return $consumers;
288 * ToolProxy methods.
292 * Load the tool proxy from the database.
294 * @param ToolProxy $toolproxy
295 * @return bool
297 public function loadToolProxy($toolproxy) {
298 return false;
302 * Save the tool proxy to the database.
304 * @param ToolProxy $toolproxy
305 * @return bool
307 public function saveToolProxy($toolproxy) {
308 return false;
312 * Delete the tool proxy from the database.
314 * @param ToolProxy $toolproxy
315 * @return bool
317 public function deleteToolProxy($toolproxy) {
318 return false;
322 * Context methods.
326 * Load context object.
328 * @param Context $context Context object
329 * @return boolean True if the context object was successfully loaded
331 public function loadContext($context) {
332 global $DB;
334 if (!empty($context->getRecordId())) {
335 $params = ['id' => $context->getRecordId()];
336 } else {
337 $params = [
338 'consumerid' => $context->getConsumer()->getRecordId(),
339 'lticontextkey' => $context->ltiContextId
342 if ($row = $DB->get_record($this->contexttable, $params)) {
343 $context->setRecordId($row->id);
344 $context->setConsumerId($row->consumerid);
345 $context->ltiContextId = $row->lticontextkey;
346 $context->type = $row->type;
347 $settings = unserialize($row->settings);
348 if (!is_array($settings)) {
349 $settings = array();
351 $context->setSettings($settings);
352 $context->created = $row->created;
353 $context->updated = $row->updated;
354 return true;
357 return false;
361 * Save context object.
363 * @param Context $context Context object
364 * @return boolean True if the context object was successfully saved
366 public function saveContext($context) {
367 global $DB;
368 $now = time();
369 $context->updated = $now;
370 $settingsvalue = serialize($context->getSettings());
371 $id = $context->getRecordId();
372 $consumerpk = $context->getConsumer()->getRecordId();
374 $isinsert = empty($id);
375 if ($isinsert) {
376 $context->created = $now;
377 $params = [
378 'consumerid' => $consumerpk,
379 'lticontextkey' => $context->ltiContextId,
380 'type' => $context->type,
381 'settings' => $settingsvalue,
382 'created' => $context->created,
383 'updated' => $context->updated,
385 $id = $DB->insert_record($this->contexttable, (object) $params);
386 if ($id) {
387 $context->setRecordId($id);
388 return true;
390 } else {
391 $data = (object) [
392 'id' => $id,
393 'contextid' => $consumerpk,
394 'lticontextkey' => $context->ltiContextId,
395 'type' => $context->type,
396 'settings' => $settingsvalue,
397 'updated' => $context->updated,
399 return $DB->update_record($this->contexttable, $data);
402 return false;
406 * Delete context object.
408 * @param Context $context Context object
409 * @return boolean True if the Context object was successfully deleted
411 public function deleteContext($context) {
412 global $DB;
414 $contextid = $context->getRecordId();
416 $params = ['id' => $contextid];
418 // Delete any outstanding share keys for resource links for this context.
419 $where = "resourcelinkid IN (
420 SELECT rl.id
421 FROM {{$this->resourcelinktable}} rl
422 WHERE rl.contextid = :id
424 $DB->delete_records_select($this->sharekeytable, $where, $params);
426 // Delete any users in resource links for this context.
427 $DB->delete_records_select($this->userresulttable, $where, $params);
429 // Update any resource links for which this consumer is acting as a primary resource link.
430 $where = "primaryresourcelinkid IN (
431 SELECT rl.id
432 FROM {{$this->resourcelinktable}} rl
433 WHERE rl.contextid = :id
435 $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $params);
436 foreach ($updaterecords as $record) {
437 $record->primaryresourcelinkid = null;
438 $record->shareapproved = null;
439 $DB->update_record($this->resourcelinktable, $record);
442 // Delete any resource links for this context.
443 $DB->delete_records($this->resourcelinktable, ['contextid' => $contextid]);
445 // Delete context.
446 $DB->delete_records($this->contexttable, $params);
448 $context->initialize();
450 return true;
454 * ResourceLink methods
458 * Load resource link object.
460 * @param ResourceLink $resourcelink ResourceLink object
461 * @return boolean True if the resource link object was successfully loaded
463 public function loadResourceLink($resourcelink) {
464 global $DB;
466 $resourceid = $resourcelink->getRecordId();
467 if (!empty($resourceid)) {
468 $params = ['id' => $resourceid];
469 $row = $DB->get_record($this->resourcelinktable, $params);
470 } else if (!empty($resourcelink->getContext())) {
471 $params = [
472 'contextid' => $resourcelink->getContext()->getRecordId(),
473 'ltiresourcelinkkey' => $resourcelink->getId()
475 $row = $DB->get_record($this->resourcelinktable, $params);
476 } else {
477 $sql = "SELECT r.*
478 FROM {{$this->resourcelinktable}} r
479 LEFT OUTER JOIN {{$this->contexttable}} c
480 ON r.contextid = c.id
481 WHERE (r.consumerid = ? OR c.consumerid = ?)
482 AND ltiresourcelinkkey = ?";
483 $params = [
484 $resourcelink->getConsumer()->getRecordId(),
485 $resourcelink->getConsumer()->getRecordId(),
486 $resourcelink->getId()
488 $row = $DB->get_record_sql($sql, $params);
490 if ($row) {
491 $resourcelink->setRecordId($row->id);
492 if (!is_null($row->contextid)) {
493 $resourcelink->setContextId($row->contextid);
494 } else {
495 $resourcelink->setContextId(null);
497 if (!is_null($row->consumerid)) {
498 $resourcelink->setConsumerId($row->consumerid);
499 } else {
500 $resourcelink->setConsumerId(null);
502 $resourcelink->ltiResourceLinkId = $row->ltiresourcelinkkey;
503 $settings = unserialize($row->settings);
504 if (!is_array($settings)) {
505 $settings = array();
507 $resourcelink->setSettings($settings);
508 if (!is_null($row->primaryresourcelinkid)) {
509 $resourcelink->primaryResourceLinkId = $row->primaryresourcelinkid;
510 } else {
511 $resourcelink->primaryResourceLinkId = null;
513 $resourcelink->shareApproved = (is_null($row->shareapproved)) ? null : ($row->shareapproved == 1);
514 $resourcelink->created = $row->created;
515 $resourcelink->updated = $row->updated;
516 return true;
519 return false;
523 * Save resource link object.
525 * @param ResourceLink $resourcelink Resource_Link object
526 * @return boolean True if the resource link object was successfully saved
528 public function saveResourceLink($resourcelink) {
529 global $DB;
531 if (is_null($resourcelink->shareApproved)) {
532 $approved = null;
533 } else if ($resourcelink->shareApproved) {
534 $approved = 1;
535 } else {
536 $approved = 0;
538 if (empty($resourcelink->primaryResourceLinkId)) {
539 $primaryresourcelinkid = null;
540 } else {
541 $primaryresourcelinkid = $resourcelink->primaryResourceLinkId;
543 $now = time();
544 $resourcelink->updated = $now;
545 $settingsvalue = serialize($resourcelink->getSettings());
546 if (!empty($resourcelink->getContext())) {
547 $consumerid = null;
548 $contextid = $resourcelink->getContext()->getRecordId();
549 } else if (!empty($resourcelink->getContextId())) {
550 $consumerid = null;
551 $contextid = $resourcelink->getContextId();
552 } else {
553 $consumerid = $resourcelink->getConsumer()->getRecordId();
554 $contextid = null;
556 $id = $resourcelink->getRecordId();
558 $data = [
559 'consumerid' => $consumerid,
560 'contextid' => $contextid,
561 'ltiresourcelinkkey' => $resourcelink->getId(),
562 'settings' => $settingsvalue,
563 'primaryresourcelinkid' => $primaryresourcelinkid,
564 'shareapproved' => $approved,
565 'updated' => $resourcelink->updated,
568 $returnid = null;
570 if (empty($id)) {
571 $resourcelink->created = $now;
572 $data['created'] = $resourcelink->created;
573 $id = $DB->insert_record($this->resourcelinktable, (object) $data);
574 if ($id) {
575 $resourcelink->setRecordId($id);
576 return true;
579 } else {
580 $data['id'] = $id;
581 return $DB->update_record($this->resourcelinktable, (object) $data);
584 return false;
588 * Delete resource link object.
590 * @param ResourceLink $resourcelink ResourceLink object
591 * @return boolean True if the resource link object and its related records were successfully deleted.
592 * Otherwise, a DML exception is thrown.
594 public function deleteResourceLink($resourcelink) {
595 global $DB;
597 $resourcelinkid = $resourcelink->getRecordId();
599 // Delete any outstanding share keys for resource links for this consumer.
600 $DB->delete_records($this->sharekeytable, ['resourcelinkid' => $resourcelinkid]);
602 // Delete users.
603 $DB->delete_records($this->userresulttable, ['resourcelinkid' => $resourcelinkid]);
605 // Update any resource links for which this is the primary resource link.
606 $records = $DB->get_records($this->resourcelinktable, ['primaryresourcelinkid' => $resourcelinkid]);
607 foreach ($records as $record) {
608 $record->primaryresourcelinkid = null;
609 $DB->update_record($this->resourcelinktable, $record);
612 // Delete resource link.
613 $DB->delete_records($this->resourcelinktable, ['id' => $resourcelinkid]);
615 $resourcelink->initialize();
617 return true;
621 * Get array of user objects.
623 * Obtain an array of User objects for users with a result sourcedId. The array may include users from other
624 * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope.
626 * @param ResourceLink $resourcelink Resource link object
627 * @param boolean $localonly True if only users within the resource link are to be returned
628 * (excluding users sharing this resource link)
629 * @param int $idscope Scope value to use for user IDs
630 * @return array Array of User objects
632 public function getUserResultSourcedIDsResourceLink($resourcelink, $localonly, $idscope) {
633 global $DB;
635 $users = [];
637 $params = ['resourcelinkid' => $resourcelink->getRecordId()];
639 // Where clause for the subquery.
640 $subwhere = "(id = :resourcelinkid AND primaryresourcelinkid IS NULL)";
641 if (!$localonly) {
642 $subwhere .= " OR (primaryresourcelinkid = :resourcelinkid2 AND shareapproved = 1)";
643 $params['resourcelinkid2'] = $resourcelink->getRecordId();
646 // The subquery.
647 $subsql = "SELECT id
648 FROM {{$this->resourcelinktable}}
649 WHERE {$subwhere}";
651 // Our main where clause.
652 $where = "resourcelinkid IN ($subsql)";
654 // Fields to be queried.
655 $fields = 'id, ltiresultsourcedid, ltiuserkey, created, updated';
657 // Fetch records.
658 $rs = $DB->get_recordset_select($this->userresulttable, $where, $params, '', $fields);
659 foreach ($rs as $row) {
660 $user = User::fromResourceLink($resourcelink, $row->ltiuserkey);
661 $user->setRecordId($row->id);
662 $user->ltiResultSourcedId = $row->ltiresultsourcedid;
663 $user->created = $row->created;
664 $user->updated = $row->updated;
665 if (is_null($idscope)) {
666 $users[] = $user;
667 } else {
668 $users[$user->getId($idscope)] = $user;
671 $rs->close();
673 return $users;
677 * Get array of shares defined for this resource link.
679 * @param ResourceLink $resourcelink ResourceLink object
680 * @return array Array of ResourceLinkShare objects
682 public function getSharesResourceLink($resourcelink) {
683 global $DB;
685 $shares = [];
687 $params = ['primaryresourcelinkid' => $resourcelink->getRecordId()];
688 $fields = 'id, shareapproved, consumerid';
689 $records = $DB->get_records($this->resourcelinktable, $params, 'consumerid', $fields);
690 foreach ($records as $record) {
691 $share = new ResourceLinkShare();
692 $share->resourceLinkId = $record->id;
693 $share->approved = $record->shareapproved == 1;
694 $shares[] = $share;
697 return $shares;
701 * ConsumerNonce methods
705 * Load nonce object.
707 * @param ConsumerNonce $nonce Nonce object
708 * @return boolean True if the nonce object was successfully loaded
710 public function loadConsumerNonce($nonce) {
711 global $DB;
713 // Delete any expired nonce values.
714 $now = time();
715 $DB->delete_records_select($this->noncetable, "expires <= ?", [$now]);
717 // Load the nonce.
718 $params = [
719 'consumerid' => $nonce->getConsumer()->getRecordId(),
720 'value' => $nonce->getValue()
722 $result = $DB->get_field($this->noncetable, 'value', $params);
724 return !empty($result);
728 * Save nonce object.
730 * @param ConsumerNonce $nonce Nonce object
731 * @return boolean True if the nonce object was successfully saved
733 public function saveConsumerNonce($nonce) {
734 global $DB;
736 $data = [
737 'consumerid' => $nonce->getConsumer()->getRecordId(),
738 'value' => $nonce->getValue(),
739 'expires' => $nonce->expires
742 return $DB->insert_record($this->noncetable, (object) $data, false);
746 * ResourceLinkShareKey methods.
750 * Load resource link share key object.
752 * @param ResourceLinkShareKey $sharekey ResourceLink share key object
753 * @return boolean True if the resource link share key object was successfully loaded
755 public function loadResourceLinkShareKey($sharekey) {
756 global $DB;
758 // Clear expired share keys.
759 $now = time();
760 $where = "expires <= :expires";
762 $DB->delete_records_select($this->sharekeytable, $where, ['expires' => $now]);
764 // Load share key.
765 $fields = 'resourcelinkid, autoapprove, expires';
766 if ($sharekeyrecord = $DB->get_record($this->sharekeytable, ['sharekey' => $sharekey->getId()], $fields)) {
767 if ($sharekeyrecord->resourcelinkid == $sharekey->resourceLinkId) {
768 $sharekey->autoApprove = $sharekeyrecord->autoapprove == 1;
769 $sharekey->expires = $sharekeyrecord->expires;
770 return true;
774 return false;
778 * Save resource link share key object.
780 * @param ResourceLinkShareKey $sharekey Resource link share key object
781 * @return boolean True if the resource link share key object was successfully saved
783 public function saveResourceLinkShareKey($sharekey) {
784 global $DB;
786 if ($sharekey->autoApprove) {
787 $approve = 1;
788 } else {
789 $approve = 0;
792 $expires = $sharekey->expires;
794 $params = [
795 'sharekey' => $sharekey->getId(),
796 'resourcelinkid' => $sharekey->resourceLinkId,
797 'autoapprove' => $approve,
798 'expires' => $expires
801 return $DB->insert_record($this->sharekeytable, (object) $params, false);
805 * Delete resource link share key object.
807 * @param ResourceLinkShareKey $sharekey Resource link share key object
808 * @return boolean True if the resource link share key object was successfully deleted
810 public function deleteResourceLinkShareKey($sharekey) {
811 global $DB;
813 $DB->delete_records($this->sharekeytable, ['sharekey' => $sharekey->getId()]);
814 $sharekey->initialize();
816 return true;
820 * User methods
824 * Load user object.
826 * @param User $user User object
827 * @return boolean True if the user object was successfully loaded
829 public function loadUser($user) {
830 global $DB;
832 $userid = $user->getRecordId();
833 $fields = 'id, resourcelinkid, ltiuserkey, ltiresultsourcedid, created, updated';
834 if (!empty($userid)) {
835 $row = $DB->get_record($this->userresulttable, ['id' => $userid], $fields);
836 } else {
837 $resourcelinkid = $user->getResourceLink()->getRecordId();
838 $userid = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY);
839 $row = $DB->get_record_select(
840 $this->userresulttable,
841 "resourcelinkid = ? AND ltiuserkey = ?",
842 [$resourcelinkid, $userid],
843 $fields
846 if ($row) {
847 $user->setRecordId($row->id);
848 $user->setResourceLinkId($row->resourcelinkid);
849 $user->ltiUserId = $row->ltiuserkey;
850 $user->ltiResultSourcedId = $row->ltiresultsourcedid;
851 $user->created = $row->created;
852 $user->updated = $row->updated;
853 return true;
856 return false;
860 * Save user object.
862 * @param User $user User object
863 * @return boolean True if the user object was successfully saved
865 public function saveUser($user) {
866 global $DB;
868 $now = time();
869 $isinsert = is_null($user->created);
870 $user->updated = $now;
872 $params = [
873 'ltiresultsourcedid' => $user->ltiResultSourcedId,
874 'updated' => $user->updated
877 if ($isinsert) {
878 $params['resourcelinkid'] = $user->getResourceLink()->getRecordId();
879 $params['ltiuserkey'] = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY);
880 $user->created = $now;
881 $params['created'] = $user->created;
882 $id = $DB->insert_record($this->userresulttable, (object) $params);
883 if ($id) {
884 $user->setRecordId($id);
885 return true;
888 } else {
889 $params['id'] = $user->getRecordId();
890 return $DB->update_record($this->userresulttable, (object) $params);
893 return false;
897 * Delete user object.
899 * @param User $user User object
900 * @return boolean True if the user object was successfully deleted
902 public function deleteUser($user) {
903 global $DB;
905 $DB->delete_records($this->userresulttable, ['id' => $user->getRecordId()]);
906 $user->initialize();
908 return true;
912 * Fetches the list of Context objects that are linked to a ToolConsumer.
914 * @param ToolConsumer $consumer
915 * @return Context[]
917 public function get_contexts_from_consumer(ToolConsumer $consumer) {
918 global $DB;
920 $contexts = [];
921 $contextrecords = $DB->get_records($this->contexttable, ['consumerid' => $consumer->getRecordId()], '', 'lticontextkey');
922 foreach ($contextrecords as $record) {
923 $context = Context::fromConsumer($consumer, $record->lticontextkey);
924 $contexts[] = $context;
927 return $contexts;
931 * Fetches a resource link record that is associated with a ToolConsumer.
933 * @param ToolConsumer $consumer
934 * @return ResourceLink
936 public function get_resourcelink_from_consumer(ToolConsumer $consumer) {
937 global $DB;
939 $resourcelink = null;
940 if ($resourcelinkrecord = $DB->get_record($this->resourcelinktable, ['consumerid' => $consumer->getRecordId()],
941 'ltiresourcelinkkey')) {
942 $resourcelink = ResourceLink::fromConsumer($consumer, $resourcelinkrecord->ltiresourcelinkkey);
945 return $resourcelink;
949 * Fetches a resource link record that is associated with a Context object.
951 * @param Context $context
952 * @return ResourceLink
954 public function get_resourcelink_from_context(Context $context) {
955 global $DB;
957 $resourcelink = null;
958 if ($resourcelinkrecord = $DB->get_record($this->resourcelinktable, ['contextid' => $context->getRecordId()],
959 'ltiresourcelinkkey')) {
960 $resourcelink = ResourceLink::fromContext($context, $resourcelinkrecord->ltiresourcelinkkey);
963 return $resourcelink;
968 * Fetches the list of ToolConsumer objects that are linked to a tool.
970 * @param int $toolid
971 * @return ToolConsumer[]
973 public function get_consumers_mapped_to_tool($toolid) {
974 global $DB;
976 $consumers = [];
977 $consumerrecords = $DB->get_records('enrol_lti_tool_consumer_map', ['toolid' => $toolid], '', 'consumerid');
978 foreach ($consumerrecords as $record) {
979 $consumers[] = ToolConsumer::fromRecordId($record->consumerid, $this);
981 return $consumers;
985 * Builds a ToolConsumer object from a record object from the DB.
987 * @param stdClass $record The DB record object.
988 * @param ToolConsumer $consumer
990 protected function build_tool_consumer_object($record, ToolConsumer $consumer) {
991 $consumer->setRecordId($record->id);
992 $consumer->name = $record->name;
993 $key = empty($record->consumerkey) ? $record->consumerkey256 : $record->consumerkey;
994 $consumer->setKey($key);
995 $consumer->secret = $record->secret;
996 $consumer->ltiVersion = $record->ltiversion;
997 $consumer->consumerName = $record->consumername;
998 $consumer->consumerVersion = $record->consumerversion;
999 $consumer->consumerGuid = $record->consumerguid;
1000 $consumer->profile = json_decode($record->profile);
1001 $consumer->toolProxy = $record->toolproxy;
1002 $settings = unserialize($record->settings);
1003 if (!is_array($settings)) {
1004 $settings = array();
1006 $consumer->setSettings($settings);
1007 $consumer->protected = $record->protected == 1;
1008 $consumer->enabled = $record->enabled == 1;
1009 $consumer->enableFrom = null;
1010 if (!is_null($record->enablefrom)) {
1011 $consumer->enableFrom = $record->enablefrom;
1013 $consumer->enableUntil = null;
1014 if (!is_null($record->enableuntil)) {
1015 $consumer->enableUntil = $record->enableuntil;
1017 $consumer->lastAccess = null;
1018 if (!is_null($record->lastaccess)) {
1019 $consumer->lastAccess = $record->lastaccess;
1021 $consumer->created = $record->created;
1022 $consumer->updated = $record->updated;