PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ltiprovider/src/ToolProvider/DataConnector/DataConnector_pdo.php

https://bitbucket.org/moodle/moodle
PHP | 1190 lines | 835 code | 145 blank | 210 comment | 91 complexity | 712254d62f0d40aa9bf872edfcbb71a8 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
  1. <?php
  2. namespace IMSGlobal\LTI\ToolProvider\DataConnector;
  3. use IMSGlobal\LTI\ToolProvider;
  4. use IMSGlobal\LTI\ToolProvider\ConsumerNonce;
  5. use IMSGlobal\LTI\ToolProvider\Context;
  6. use IMSGlobal\LTI\ToolProvider\ResourceLink;
  7. use IMSGlobal\LTI\ToolProvider\ResourceLinkShareKey;
  8. use IMSGlobal\LTI\ToolProvider\ToolConsumer;
  9. use IMSGlobal\LTI\ToolProvider\User;
  10. use PDO;
  11. /**
  12. * Class to represent an LTI Data Connector for PDO connections
  13. *
  14. * @author Stephen P Vickers <svickers@imsglobal.org>
  15. * @copyright IMS Global Learning Consortium Inc
  16. * @date 2016
  17. * @version 3.0.0
  18. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  19. */
  20. class DataConnector_pdo extends DataConnector
  21. {
  22. /**
  23. * Class constructor
  24. *
  25. * @param object $db Database connection object
  26. * @param string $dbTableNamePrefix Prefix for database table names (optional, default is none)
  27. */
  28. public function __construct($db, $dbTableNamePrefix = '')
  29. {
  30. parent::__construct($db, $dbTableNamePrefix);
  31. if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'oci') {
  32. $this->date_format = 'd-M-Y';
  33. }
  34. }
  35. ###
  36. ### ToolConsumer methods
  37. ###
  38. /**
  39. * Load tool consumer object.
  40. *
  41. * @param ToolConsumer $consumer ToolConsumer object
  42. *
  43. * @return boolean True if the tool consumer object was successfully loaded
  44. */
  45. public function loadToolConsumer($consumer)
  46. {
  47. $ok = false;
  48. if (!empty($consumer->getRecordId())) {
  49. $sql = 'SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' .
  50. 'consumer_name, consumer_version, consumer_guid, ' .
  51. 'profile, tool_proxy, settings, protected, enabled, ' .
  52. 'enable_from, enable_until, last_access, created, updated ' .
  53. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' .
  54. 'WHERE consumer_pk = :id';
  55. $query = $this->db->prepare($sql);
  56. $id = $consumer->getRecordId();
  57. $query->bindValue('id', $id, PDO::PARAM_INT);
  58. } else {
  59. $sql = 'SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' .
  60. 'consumer_name, consumer_version, consumer_guid, ' .
  61. 'profile, tool_proxy, settings, protected, enabled, ' .
  62. 'enable_from, enable_until, last_access, created, updated ' .
  63. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' .
  64. 'WHERE consumer_key256 = :key256';
  65. $query = $this->db->prepare($sql);
  66. $key256 = DataConnector::getConsumerKey($consumer->getKey());
  67. $query->bindValue('key256', $key256, PDO::PARAM_STR);
  68. }
  69. if ($query->execute()) {
  70. while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
  71. $row = array_change_key_case($row);
  72. if (empty($key256) || empty($row['consumer_key']) || ($consumer->getKey() === $row['consumer_key'])) {
  73. $consumer->setRecordId(intval($row['consumer_pk']));
  74. $consumer->name = $row['name'];
  75. $consumer->setkey(empty($row['consumer_key']) ? $row['consumer_key256'] : $row['consumer_key']);
  76. $consumer->secret = $row['secret'];
  77. $consumer->ltiVersion = $row['lti_version'];
  78. $consumer->consumerName = $row['consumer_name'];
  79. $consumer->consumerVersion = $row['consumer_version'];
  80. $consumer->consumerGuid = $row['consumer_guid'];
  81. $consumer->profile = json_decode($row['profile']);
  82. $consumer->toolProxy = $row['tool_proxy'];
  83. $settings = unserialize($row['settings']);
  84. if (!is_array($settings)) {
  85. $settings = array();
  86. }
  87. $consumer->setSettings($settings);
  88. $consumer->protected = (intval($row['protected']) === 1);
  89. $consumer->enabled = (intval($row['enabled']) === 1);
  90. $consumer->enableFrom = null;
  91. if (!is_null($row['enable_from'])) {
  92. $consumer->enableFrom = strtotime($row['enable_from']);
  93. }
  94. $consumer->enableUntil = null;
  95. if (!is_null($row['enable_until'])) {
  96. $consumer->enableUntil = strtotime($row['enable_until']);
  97. }
  98. $consumer->lastAccess = null;
  99. if (!is_null($row['last_access'])) {
  100. $consumer->lastAccess = strtotime($row['last_access']);
  101. }
  102. $consumer->created = strtotime($row['created']);
  103. $consumer->updated = strtotime($row['updated']);
  104. $ok = true;
  105. break;
  106. }
  107. }
  108. }
  109. return $ok;
  110. }
  111. /**
  112. * Save tool consumer object.
  113. *
  114. * @param ToolConsumer $consumer Consumer object
  115. *
  116. * @return boolean True if the tool consumer object was successfully saved
  117. */
  118. public function saveToolConsumer($consumer)
  119. {
  120. $id = $consumer->getRecordId();
  121. $key = $consumer->getKey();
  122. $key256 = $this->getConsumerKey($key);
  123. if ($key === $key256) {
  124. $key = null;
  125. }
  126. $protected = ($consumer->protected) ? 1 : 0;
  127. $enabled = ($consumer->enabled)? 1 : 0;
  128. $profile = (!empty($consumer->profile)) ? json_encode($consumer->profile) : null;
  129. $settingsValue = serialize($consumer->getSettings());
  130. $time = time();
  131. $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
  132. $from = null;
  133. if (!is_null($consumer->enableFrom)) {
  134. $from = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableFrom);
  135. }
  136. $until = null;
  137. if (!is_null($consumer->enableUntil)) {
  138. $until = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableUntil);
  139. }
  140. $last = null;
  141. if (!is_null($consumer->lastAccess)) {
  142. $last = date($this->dateFormat, $consumer->lastAccess);
  143. }
  144. if (empty($id)) {
  145. $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' (consumer_key256, consumer_key, name, ' .
  146. 'secret, lti_version, consumer_name, consumer_version, consumer_guid, profile, tool_proxy, settings, protected, enabled, ' .
  147. 'enable_from, enable_until, last_access, created, updated) ' .
  148. 'VALUES (:key256, :key, :name, :secret, :lti_version, :consumer_name, :consumer_version, :consumer_guid, :profile, :tool_proxy, :settings, ' .
  149. ':protected, :enabled, :enable_from, :enable_until, :last_access, :created, :updated)';
  150. $query = $this->db->prepare($sql);
  151. $query->bindValue('key256', $key256, PDO::PARAM_STR);
  152. $query->bindValue('key', $key, PDO::PARAM_STR);
  153. $query->bindValue('name', $consumer->name, PDO::PARAM_STR);
  154. $query->bindValue('secret', $consumer->secret, PDO::PARAM_STR);
  155. $query->bindValue('lti_version', $consumer->ltiVersion, PDO::PARAM_STR);
  156. $query->bindValue('consumer_name', $consumer->consumerName, PDO::PARAM_STR);
  157. $query->bindValue('consumer_version', $consumer->consumerVersion, PDO::PARAM_STR);
  158. $query->bindValue('consumer_guid', $consumer->consumerGuid, PDO::PARAM_STR);
  159. $query->bindValue('profile', $profile, PDO::PARAM_STR);
  160. $query->bindValue('tool_proxy', $consumer->toolProxy, PDO::PARAM_STR);
  161. $query->bindValue('settings', $settingsValue, PDO::PARAM_STR);
  162. $query->bindValue('protected', $protected, PDO::PARAM_INT);
  163. $query->bindValue('enabled', $enabled, PDO::PARAM_INT);
  164. $query->bindValue('enable_from', $from, PDO::PARAM_STR);
  165. $query->bindValue('enable_until', $until, PDO::PARAM_STR);
  166. $query->bindValue('last_access', $last, PDO::PARAM_STR);
  167. $query->bindValue('created', $now, PDO::PARAM_STR);
  168. $query->bindValue('updated', $now, PDO::PARAM_STR);
  169. } else {
  170. $sql = 'UPDATE ' . $this->dbTableNamePrefix . DataConnector::CONSUMER_TABLE_NAME . ' ' .
  171. 'SET consumer_key256 = :key256, consumer_key = :key, name = :name, secret = :secret, lti_version = :lti_version, ' .
  172. 'consumer_name = :consumer_name, consumer_version = :consumer_version, consumer_guid = :consumer_guid, ' .
  173. 'profile = :profile, tool_proxy = :tool_proxy, settings = :settings, ' .
  174. 'protected = :protected, enabled = :enabled, enable_from = :enable_from, enable_until = :enable_until, last_access = :last_access, updated = :updated ' .
  175. 'WHERE consumer_pk = :id';
  176. $query = $this->db->prepare($sql);
  177. $query->bindValue('key256', $key256, PDO::PARAM_STR);
  178. $query->bindValue('key', $key, PDO::PARAM_STR);
  179. $query->bindValue('name', $consumer->name, PDO::PARAM_STR);
  180. $query->bindValue('secret', $consumer->secret, PDO::PARAM_STR);
  181. $query->bindValue('lti_version', $consumer->ltiVersion, PDO::PARAM_STR);
  182. $query->bindValue('consumer_name', $consumer->consumerName, PDO::PARAM_STR);
  183. $query->bindValue('consumer_version', $consumer->consumerVersion, PDO::PARAM_STR);
  184. $query->bindValue('consumer_guid', $consumer->consumerGuid, PDO::PARAM_STR);
  185. $query->bindValue('profile', $profile, PDO::PARAM_STR);
  186. $query->bindValue('tool_proxy', $consumer->toolProxy, PDO::PARAM_STR);
  187. $query->bindValue('settings', $settingsValue, PDO::PARAM_STR);
  188. $query->bindValue('protected', $protected, PDO::PARAM_INT);
  189. $query->bindValue('enabled', $enabled, PDO::PARAM_INT);
  190. $query->bindValue('enable_from', $from, PDO::PARAM_STR);
  191. $query->bindValue('enable_until', $until, PDO::PARAM_STR);
  192. $query->bindValue('last_access', $last, PDO::PARAM_STR);
  193. $query->bindValue('updated', $now, PDO::PARAM_STR);
  194. $query->bindValue('id', $id, PDO::PARAM_INT);
  195. }
  196. $ok = $query->execute();
  197. if ($ok) {
  198. if (empty($id)) {
  199. $consumer->setRecordId(intval($this->db->lastInsertId()));
  200. $consumer->created = $time;
  201. }
  202. $consumer->updated = $time;
  203. }
  204. return $ok;
  205. }
  206. /**
  207. * Delete tool consumer object.
  208. *
  209. * @param ToolConsumer $consumer Consumer object
  210. *
  211. * @return boolean True if the tool consumer object was successfully deleted
  212. */
  213. public function deleteToolConsumer($consumer)
  214. {
  215. $id = $consumer->getRecordId();
  216. // Delete any nonce values for this consumer
  217. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE consumer_pk = :id';
  218. $query = $this->db->prepare($sql);
  219. $query->bindValue('id', $id, PDO::PARAM_INT);
  220. $query->execute();
  221. // Delete any outstanding share keys for resource links for this consumer
  222. $sql = 'DELETE sk ' .
  223. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' .
  224. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' .
  225. 'WHERE rl.consumer_pk = :id';
  226. $query = $this->db->prepare($sql);
  227. $query->bindValue('id', $id, PDO::PARAM_INT);
  228. $query->execute();
  229. // Delete any outstanding share keys for resource links for contexts in this consumer
  230. $sql = 'DELETE sk ' .
  231. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' .
  232. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' .
  233. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
  234. 'WHERE c.consumer_pk = :id';
  235. $query = $this->db->prepare($sql);
  236. $query->bindValue('id', $id, PDO::PARAM_INT);
  237. $query->execute();
  238. // Delete any users in resource links for this consumer
  239. $sql = 'DELETE u ' .
  240. "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' .
  241. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' .
  242. 'WHERE rl.consumer_pk = :id';
  243. $query = $this->db->prepare($sql);
  244. $query->bindValue('id', $id, PDO::PARAM_INT);
  245. $query->execute();
  246. // Delete any users in resource links for contexts in this consumer
  247. $sql = 'DELETE u ' .
  248. "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' .
  249. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' .
  250. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
  251. 'WHERE c.consumer_pk = :id';
  252. $query = $this->db->prepare($sql);
  253. $query->bindValue('id', $id, PDO::PARAM_INT);
  254. $query->execute();
  255. // Update any resource links for which this consumer is acting as a primary resource link
  256. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' .
  257. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' .
  258. 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' .
  259. 'WHERE rl.consumer_pk = :id';
  260. $query = $this->db->prepare($sql);
  261. $query->bindValue('id', $id, PDO::PARAM_INT);
  262. $query->execute();
  263. // Update any resource links for contexts in which this consumer is acting as a primary resource link
  264. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' .
  265. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' .
  266. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
  267. 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' .
  268. 'WHERE c.consumer_pk = :id';
  269. $query = $this->db->prepare($sql);
  270. $query->bindValue('id', $id, PDO::PARAM_INT);
  271. $query->execute();
  272. // Delete any resource links for this consumer
  273. $sql = 'DELETE rl ' .
  274. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' .
  275. 'WHERE rl.consumer_pk = :id';
  276. $query = $this->db->prepare($sql);
  277. $query->bindValue('id', $id, PDO::PARAM_INT);
  278. $query->execute();
  279. // Delete any resource links for contexts in this consumer
  280. $sql = 'DELETE rl ' .
  281. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' .
  282. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
  283. 'WHERE c.consumer_pk = :id';
  284. $query = $this->db->prepare($sql);
  285. $query->bindValue('id', $id, PDO::PARAM_INT);
  286. $query->execute();
  287. // Delete any contexts for this consumer
  288. $sql = 'DELETE c ' .
  289. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' .
  290. 'WHERE c.consumer_pk = :id';
  291. $query = $this->db->prepare($sql);
  292. $query->bindValue('id', $id, PDO::PARAM_INT);
  293. $query->execute();
  294. // Delete consumer
  295. $sql = 'DELETE c ' .
  296. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' c ' .
  297. 'WHERE c.consumer_pk = :id';
  298. $query = $this->db->prepare($sql);
  299. $query->bindValue('id', $id, PDO::PARAM_INT);
  300. $ok = $query->execute();
  301. if ($ok) {
  302. $consumer->initialize();
  303. }
  304. return $ok;
  305. }
  306. ###
  307. # Load all tool consumers from the database
  308. ###
  309. public function getToolConsumers()
  310. {
  311. $consumers = array();
  312. $sql = 'SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' .
  313. 'consumer_name, consumer_version, consumer_guid, ' .
  314. 'profile, tool_proxy, settings, protected, enabled, ' .
  315. 'enable_from, enable_until, last_access, created, updated ' .
  316. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' .
  317. 'ORDER BY name';
  318. $query = $this->db->prepare($sql);
  319. $ok = ($query !== FALSE);
  320. if ($ok) {
  321. $ok = $query->execute();
  322. }
  323. if ($ok) {
  324. while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
  325. $row = array_change_key_case($row);
  326. $key = empty($row['consumer_key']) ? $row['consumer_key256'] : $row['consumer_key'];
  327. $consumer = new ToolProvider\ToolConsumer($key, $this);
  328. $consumer->setRecordId(intval($row['consumer_pk']));
  329. $consumer->name = $row['name'];
  330. $consumer->secret = $row['secret'];
  331. $consumer->ltiVersion = $row['lti_version'];
  332. $consumer->consumerName = $row['consumer_name'];
  333. $consumer->consumerVersion = $row['consumer_version'];
  334. $consumer->consumerGuid = $row['consumer_guid'];
  335. $consumer->profile = json_decode($row['profile']);
  336. $consumer->toolProxy = $row['tool_proxy'];
  337. $settings = unserialize($row['settings']);
  338. if (!is_array($settings)) {
  339. $settings = array();
  340. }
  341. $consumer->setSettings($settings);
  342. $consumer->protected = (intval($row['protected']) === 1);
  343. $consumer->enabled = (intval($row['enabled']) === 1);
  344. $consumer->enableFrom = null;
  345. if (!is_null($row['enable_from'])) {
  346. $consumer->enableFrom = strtotime($row['enable_from']);
  347. }
  348. $consumer->enableUntil = null;
  349. if (!is_null($row['enable_until'])) {
  350. $consumer->enableUntil = strtotime($row['enable_until']);
  351. }
  352. $consumer->lastAccess = null;
  353. if (!is_null($row['last_access'])) {
  354. $consumer->lastAccess = strtotime($row['last_access']);
  355. }
  356. $consumer->created = strtotime($row['created']);
  357. $consumer->updated = strtotime($row['updated']);
  358. $consumers[] = $consumer;
  359. }
  360. }
  361. return $consumers;
  362. }
  363. ###
  364. ### ToolProxy methods
  365. ###
  366. ###
  367. # Load the tool proxy from the database
  368. ###
  369. public function loadToolProxy($toolProxy)
  370. {
  371. return false;
  372. }
  373. ###
  374. # Save the tool proxy to the database
  375. ###
  376. public function saveToolProxy($toolProxy)
  377. {
  378. return false;
  379. }
  380. ###
  381. # Delete the tool proxy from the database
  382. ###
  383. public function deleteToolProxy($toolProxy)
  384. {
  385. return false;
  386. }
  387. ###
  388. ### Context methods
  389. ###
  390. /**
  391. * Load context object.
  392. *
  393. * @param Context $context Context object
  394. *
  395. * @return boolean True if the context object was successfully loaded
  396. */
  397. public function loadContext($context)
  398. {
  399. $ok = false;
  400. if (!empty($context->getRecordId())) {
  401. $sql = 'SELECT context_pk, consumer_pk, lti_context_id, type, settings, created, updated ' .
  402. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' .
  403. 'WHERE (context_pk = :id)';
  404. $query = $this->db->prepare($sql);
  405. $query->bindValue('id', $context->getRecordId(), PDO::PARAM_INT);
  406. } else {
  407. $sql = 'SELECT context_pk, consumer_pk, lti_context_id, type, settings, created, updated ' .
  408. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' .
  409. 'WHERE (consumer_pk = :cid) AND (lti_context_id = :ctx)';
  410. $query = $this->db->prepare($sql);
  411. $query->bindValue('cid', $context->getConsumer()->getRecordId(), PDO::PARAM_INT);
  412. $query->bindValue('ctx', $context->ltiContextId, PDO::PARAM_STR);
  413. }
  414. $ok = $query->execute();
  415. if ($ok) {
  416. $row = $query->fetch(PDO::FETCH_ASSOC);
  417. $ok = ($row !== FALSE);
  418. }
  419. if ($ok) {
  420. $row = array_change_key_case($row);
  421. $context->setRecordId(intval($row['context_pk']));
  422. $context->setConsumerId(intval($row['consumer_pk']));
  423. $context->ltiContextId = $row['lti_context_id'];
  424. $context->type = $row['type'];
  425. $settings = unserialize($row['settings']);
  426. if (!is_array($settings)) {
  427. $settings = array();
  428. }
  429. $context->setSettings($settings);
  430. $context->created = strtotime($row['created']);
  431. $context->updated = strtotime($row['updated']);
  432. }
  433. return $ok;
  434. }
  435. /**
  436. * Save context object.
  437. *
  438. * @param Context $context Context object
  439. *
  440. * @return boolean True if the context object was successfully saved
  441. */
  442. public function saveContext($context)
  443. {
  444. $time = time();
  445. $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
  446. $settingsValue = serialize($context->getSettings());
  447. $id = $context->getRecordId();
  448. $consumer_pk = $context->getConsumer()->getRecordId();
  449. if (empty($id)) {
  450. $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' (consumer_pk, lti_context_id, ' .
  451. 'type, settings, created, updated) ' .
  452. 'VALUES (:cid, :ctx, :type, :settings, :created, :updated)';
  453. $query = $this->db->prepare($sql);
  454. $query->bindValue('cid', $consumer_pk, PDO::PARAM_INT);
  455. $query->bindValue('ctx', $context->ltiContextId, PDO::PARAM_STR);
  456. $query->bindValue('type', $context->type, PDO::PARAM_STR);
  457. $query->bindValue('settings', $settingsValue, PDO::PARAM_STR);
  458. $query->bindValue('created', $now, PDO::PARAM_STR);
  459. $query->bindValue('updated', $now, PDO::PARAM_STR);
  460. } else {
  461. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' SET ' .
  462. 'lti_context_id = :ctx, type = :type, settings = :settings, '.
  463. 'updated = :updated ' .
  464. 'WHERE (consumer_pk = :cid) AND (context_pk = :ctxid)';
  465. $query = $this->db->prepare($sql);
  466. $query->bindValue('ctx', $context->ltiContextId, PDO::PARAM_STR);
  467. $query->bindValue('type', $context->type, PDO::PARAM_STR);
  468. $query->bindValue('settings', $settingsValue, PDO::PARAM_STR);
  469. $query->bindValue('updated', $now, PDO::PARAM_STR);
  470. $query->bindValue('cid', $consumer_pk, PDO::PARAM_INT);
  471. $query->bindValue('ctxid', $id, PDO::PARAM_INT);
  472. }
  473. $ok = $query->execute();
  474. if ($ok) {
  475. if (empty($id)) {
  476. $context->setRecordId(intval($this->db->lastInsertId()));
  477. $context->created = $time;
  478. }
  479. $context->updated = $time;
  480. }
  481. return $ok;
  482. }
  483. /**
  484. * Delete context object.
  485. *
  486. * @param Context $context Context object
  487. *
  488. * @return boolean True if the Context object was successfully deleted
  489. */
  490. public function deleteContext($context)
  491. {
  492. $id = $context->getRecordId();
  493. // Delete any outstanding share keys for resource links for this context
  494. $sql = 'DELETE sk ' .
  495. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' .
  496. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' .
  497. 'WHERE rl.context_pk = :id';
  498. $query = $this->db->prepare($sql);
  499. $query->bindValue('id', $id, PDO::PARAM_INT);
  500. $query->execute();
  501. // Delete any users in resource links for this context
  502. $sql = 'DELETE u ' .
  503. "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' .
  504. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' .
  505. 'WHERE rl.context_pk = :id';
  506. $query = $this->db->prepare($sql);
  507. $query->bindValue('id', $id, PDO::PARAM_INT);
  508. $query->execute();
  509. // Update any resource links for which this consumer is acting as a primary resource link
  510. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' .
  511. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' .
  512. 'SET prl.primary_resource_link_pk = null, prl.share_approved = null ' .
  513. 'WHERE rl.context_pk = :id';
  514. $query = $this->db->prepare($sql);
  515. $query->bindValue('id', $id, PDO::PARAM_INT);
  516. $query->execute();
  517. // Delete any resource links for this consumer
  518. $sql = 'DELETE rl ' .
  519. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' .
  520. 'WHERE rl.context_pk = :id';
  521. $query = $this->db->prepare($sql);
  522. $query->bindValue('id', $id, PDO::PARAM_INT);
  523. $query->execute();
  524. // Delete context
  525. $sql = 'DELETE c ' .
  526. "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' .
  527. 'WHERE c.context_pk = :id';
  528. $query = $this->db->prepare($sql);
  529. $query->bindValue('id', $id, PDO::PARAM_INT);
  530. $ok = $query->execute();
  531. if ($ok) {
  532. $context->initialize();
  533. }
  534. return $ok;
  535. }
  536. ###
  537. ### ResourceLink methods
  538. ###
  539. /**
  540. * Load resource link object.
  541. *
  542. * @param ResourceLink $resourceLink Resource_Link object
  543. *
  544. * @return boolean True if the resource link object was successfully loaded
  545. */
  546. public function loadResourceLink($resourceLink)
  547. {
  548. if (!empty($resourceLink->getRecordId())) {
  549. $sql = 'SELECT resource_link_pk, context_pk, consumer_pk, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' .
  550. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' .
  551. 'WHERE (resource_link_pk = :id)';
  552. $query = $this->db->prepare($sql);
  553. $query->bindValue('id', $resourceLink->getRecordId(), PDO::PARAM_INT);
  554. } else if (!empty($resourceLink->getContext())) {
  555. $sql = 'SELECT resource_link_pk, context_pk, consumer_pk, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' .
  556. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' .
  557. 'WHERE (context_pk = :id) AND (lti_resource_link_id = :rlid)';
  558. $query = $this->db->prepare($sql);
  559. $query->bindValue('id', $resourceLink->getContext()->getRecordId(), PDO::PARAM_INT);
  560. $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR);
  561. } else {
  562. $sql = 'SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' .
  563. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' .
  564. $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME . ' c ON r.context_pk = c.context_pk ' .
  565. ' WHERE ((r.consumer_pk = :id1) OR (c.consumer_pk = :id2)) AND (lti_resource_link_id = :rlid)';
  566. $query = $this->db->prepare($sql);
  567. $query->bindValue('id1', $resourceLink->getConsumer()->getRecordId(), PDO::PARAM_INT);
  568. $query->bindValue('id2', $resourceLink->getConsumer()->getRecordId(), PDO::PARAM_INT);
  569. $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR);
  570. }
  571. $ok = $query->execute();
  572. if ($ok) {
  573. $row = $query->fetch(PDO::FETCH_ASSOC);
  574. $ok = ($row !== FALSE);
  575. }
  576. if ($ok) {
  577. $row = array_change_key_case($row);
  578. $resourceLink->setRecordId(intval($row['resource_link_pk']));
  579. if (!is_null($row['context_pk'])) {
  580. $resourceLink->setContextId(intval($row['context_pk']));
  581. } else {
  582. $resourceLink->setContextId(null);
  583. }
  584. if (!is_null($row['consumer_pk'])) {
  585. $resourceLink->setConsumerId(intval($row['consumer_pk']));
  586. } else {
  587. $resourceLink->setConsumerId(null);
  588. }
  589. $resourceLink->ltiResourceLinkId = $row['lti_resource_link_id'];
  590. $settings = unserialize($row['settings']);
  591. if (!is_array($settings)) {
  592. $settings = array();
  593. }
  594. $resourceLink->setSettings($settings);
  595. if (!is_null($row['primary_resource_link_pk'])) {
  596. $resourceLink->primaryResourceLinkId = intval($row['primary_resource_link_pk']);
  597. } else {
  598. $resourceLink->primaryResourceLinkId = null;
  599. }
  600. $resourceLink->shareApproved = (is_null($row['share_approved'])) ? null : (intval($row['share_approved']) === 1);
  601. $resourceLink->created = strtotime($row['created']);
  602. $resourceLink->updated = strtotime($row['updated']);
  603. }
  604. return $ok;
  605. }
  606. /**
  607. * Save resource link object.
  608. *
  609. * @param ResourceLink $resourceLink Resource_Link object
  610. *
  611. * @return boolean True if the resource link object was successfully saved
  612. */
  613. public function saveResourceLink($resourceLink) {
  614. $time = time();
  615. $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
  616. $settingsValue = serialize($resourceLink->getSettings());
  617. if (!empty($resourceLink->getContext())) {
  618. $consumerId = null;
  619. $contextId = strval($resourceLink->getContext()->getRecordId());
  620. } else if (!empty($resourceLink->getContextId())) {
  621. $consumerId = null;
  622. $contextId = strval($resourceLink->getContextId());
  623. } else {
  624. $consumerId = strval($resourceLink->getConsumer()->getRecordId());
  625. $contextId = null;
  626. }
  627. if (empty($resourceLink->primaryResourceLinkId)) {
  628. $primaryResourceLinkId = null;
  629. } else {
  630. $primaryResourceLinkId = $resourceLink->primaryResourceLinkId;
  631. }
  632. $id = $resourceLink->getRecordId();
  633. if (empty($id)) {
  634. $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' (consumer_pk, context_pk, ' .
  635. 'lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated) ' .
  636. 'VALUES (:cid, :ctx, :rlid, :settings, :prlid, :share_approved, :created, :updated)';
  637. $query = $this->db->prepare($sql);
  638. $query->bindValue('cid', $consumerId, PDO::PARAM_INT);
  639. $query->bindValue('ctx', $contextId, PDO::PARAM_INT);
  640. $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR);
  641. $query->bindValue('settings', $settingsValue, PDO::PARAM_STR);
  642. $query->bindValue('prlid', $primaryResourceLinkId, PDO::PARAM_INT);
  643. $query->bindValue('share_approved', $resourceLink->shareApproved, PDO::PARAM_INT);
  644. $query->bindValue('created', $now, PDO::PARAM_STR);
  645. $query->bindValue('updated', $now, PDO::PARAM_STR);
  646. } else if (!is_null($contextId)) {
  647. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' SET ' .
  648. 'consumer_pk = NULL, context_pk = :ctx, lti_resource_link_id = :rlid, settings = :settings, '.
  649. 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' .
  650. 'WHERE (resource_link_pk = :id)';
  651. $query = $this->db->prepare($sql);
  652. $query->bindValue('ctx', $contextId, PDO::PARAM_INT);
  653. $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR);
  654. $query->bindValue('settings', $settingsValue, PDO::PARAM_STR);
  655. $query->bindValue('prlid', $primaryResourceLinkId, PDO::PARAM_INT);
  656. $query->bindValue('share_approved', $resourceLink->shareApproved, PDO::PARAM_INT);
  657. $query->bindValue('updated', $now, PDO::PARAM_STR);
  658. $query->bindValue('id', $id, PDO::PARAM_INT);
  659. } else {
  660. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' SET ' .
  661. 'context_pk = :ctx, lti_resource_link_id = :rlid, settings = :settings, '.
  662. 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' .
  663. 'WHERE (consumer_pk = :cid) AND (resource_link_pk = :id)';
  664. $query = $this->db->prepare($sql);
  665. $query->bindValue('ctx', $contextId, PDO::PARAM_INT);
  666. $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR);
  667. $query->bindValue('settings', $settingsValue, PDO::PARAM_STR);
  668. $query->bindValue('prlid', $primaryResourceLinkId, PDO::PARAM_INT);
  669. $query->bindValue('share_approved', $resourceLink->shareApproved, PDO::PARAM_INT);
  670. $query->bindValue('updated', $now, PDO::PARAM_STR);
  671. $query->bindValue('cid', $consumerId, PDO::PARAM_INT);
  672. $query->bindValue('id', $id, PDO::PARAM_INT);
  673. }
  674. $ok = $query->execute();
  675. if ($ok) {
  676. if (empty($id)) {
  677. $resourceLink->setRecordId(intval($this->db->lastInsertId()));
  678. $resourceLink->created = $time;
  679. }
  680. $resourceLink->updated = $time;
  681. }
  682. return $ok;
  683. }
  684. /**
  685. * Delete resource link object.
  686. *
  687. * @param ResourceLink $resourceLink Resource_Link object
  688. *
  689. * @return boolean True if the resource link object was successfully deleted
  690. */
  691. public function deleteResourceLink($resourceLink)
  692. {
  693. $id = $resourceLink->getRecordId();
  694. // Delete any outstanding share keys for resource links for this consumer
  695. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' .
  696. 'WHERE (resource_link_pk = :id)';
  697. $query = $this->db->prepare($sql);
  698. $query->bindValue('id', $id, PDO::PARAM_INT);
  699. $ok = $query->execute();
  700. // Delete users
  701. if ($ok) {
  702. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' .
  703. 'WHERE (resource_link_pk = :id)';
  704. $query = $this->db->prepare($sql);
  705. $query->bindValue('id', $id, PDO::PARAM_INT);
  706. $ok = $query->execute();
  707. }
  708. // Update any resource links for which this is the primary resource link
  709. if ($ok) {
  710. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' .
  711. 'SET primary_resource_link_pk = NULL ' .
  712. 'WHERE (primary_resource_link_pk = :id)';
  713. $query = $this->db->prepare($sql);
  714. $query->bindValue('id', $id, PDO::PARAM_INT);
  715. $ok = $query->execute();
  716. }
  717. // Delete resource link
  718. if ($ok) {
  719. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' .
  720. 'WHERE (resource_link_pk = :id)';
  721. $query = $this->db->prepare($sql);
  722. $query->bindValue('id', $id, PDO::PARAM_INT);
  723. $ok = $query->execute();
  724. }
  725. if ($ok) {
  726. $resourceLink->initialize();
  727. }
  728. return $ok;
  729. }
  730. /**
  731. * Get array of user objects.
  732. *
  733. * Obtain an array of User objects for users with a result sourcedId. The array may include users from other
  734. * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope.
  735. *
  736. * @param ResourceLink $resourceLink Resource link object
  737. * @param boolean $localOnly True if only users within the resource link are to be returned (excluding users sharing this resource link)
  738. * @param int $idScope Scope value to use for user IDs
  739. *
  740. * @return array Array of User objects
  741. */
  742. public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $idScope)
  743. {
  744. $id = $resourceLink->getRecordId();
  745. $users = array();
  746. if ($localOnly) {
  747. $sql = 'SELECT u.user_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' .
  748. "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' .
  749. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' .
  750. 'ON u.resource_link_pk = rl.resource_link_pk ' .
  751. 'WHERE (rl.resource_link_pk = :id) AND (rl.primary_resource_link_pk IS NULL)';
  752. $query = $this->db->prepare($sql);
  753. $query->bindValue('id', $id, PDO::PARAM_INT);
  754. } else {
  755. $sql = 'SELECT u.user_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' .
  756. "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' .
  757. "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' .
  758. 'ON u.resource_link_pk = rl.resource_link_pk ' .
  759. 'WHERE ((rl.resource_link_pk = :id) AND (rl.primary_resource_link_pk IS NULL)) OR ' .
  760. '((rl.primary_resource_link_pk = :pid) AND (share_approved = 1))';
  761. $query = $this->db->prepare($sql);
  762. $query->bindValue('id', $id, PDO::PARAM_INT);
  763. $query->bindValue('pid', $id, PDO::PARAM_INT);
  764. }
  765. if ($query->execute()) {
  766. while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
  767. $row = array_change_key_case($row);
  768. $user = ToolProvider\User::fromRecordId($row['user_pk'], $resourceLink->getDataConnector());
  769. if (is_null($idScope)) {
  770. $users[] = $user;
  771. } else {
  772. $users[$user->getId($idScope)] = $user;
  773. }
  774. }
  775. }
  776. return $users;
  777. }
  778. /**
  779. * Get array of shares defined for this resource link.
  780. *
  781. * @param ResourceLink $resourceLink Resource_Link object
  782. *
  783. * @return array Array of ResourceLinkShare objects
  784. */
  785. public function getSharesResourceLink($resourceLink)
  786. {
  787. $id = $resourceLink->getRecordId();
  788. $shares = array();
  789. $sql = 'SELECT consumer_pk, resource_link_pk, share_approved ' .
  790. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' .
  791. 'WHERE (primary_resource_link_pk = :id) ' .
  792. 'ORDER BY consumer_pk';
  793. $query = $this->db->prepare($sql);
  794. $query->bindValue('id', $id, PDO::PARAM_INT);
  795. if ($query->execute()) {
  796. while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
  797. $row = array_change_key_case($row);
  798. $share = new ToolProvider\ResourceLinkShare();
  799. $share->resourceLinkId = intval($row['resource_link_pk']);
  800. $share->approved = (intval($row['share_approved']) === 1);
  801. $shares[] = $share;
  802. }
  803. }
  804. return $shares;
  805. }
  806. ###
  807. ### ConsumerNonce methods
  808. ###
  809. /**
  810. * Load nonce object.
  811. *
  812. * @param ConsumerNonce $nonce Nonce object
  813. *
  814. * @return boolean True if the nonce object was successfully loaded
  815. */
  816. public function loadConsumerNonce($nonce)
  817. {
  818. $ok = true;
  819. // Delete any expired nonce values
  820. $now = date("{$this->dateFormat} {$this->timeFormat}", time());
  821. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE expires <= :now';
  822. $query = $this->db->prepare($sql);
  823. $query->bindValue('now', $now, PDO::PARAM_STR);
  824. $query->execute();
  825. // Load the nonce
  826. $id = $nonce->getConsumer()->getRecordId();
  827. $value = $nonce->getValue();
  828. $sql = "SELECT value T FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE (consumer_pk = :id) AND (value = :value)';
  829. $query = $this->db->prepare($sql);
  830. $query->bindValue('id', $id, PDO::PARAM_INT);
  831. $query->bindValue('value', $value, PDO::PARAM_STR);
  832. $ok = $query->execute();
  833. if ($ok) {
  834. $row = $query->fetch(PDO::FETCH_ASSOC);
  835. if ($row === false) {
  836. $ok = false;
  837. }
  838. }
  839. return $ok;
  840. }
  841. /**
  842. * Save nonce object.
  843. *
  844. * @param ConsumerNonce $nonce Nonce object
  845. *
  846. * @return boolean True if the nonce object was successfully saved
  847. */
  848. public function saveConsumerNonce($nonce)
  849. {
  850. $id = $nonce->getConsumer()->getRecordId();
  851. $value = $nonce->getValue();
  852. $expires = date("{$this->dateFormat} {$this->timeFormat}", $nonce->expires);
  853. $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' (consumer_pk, value, expires) VALUES (:id, :value, :expires)';
  854. $query = $this->db->prepare($sql);
  855. $query->bindValue('id', $id, PDO::PARAM_INT);
  856. $query->bindValue('value', $value, PDO::PARAM_STR);
  857. $query->bindValue('expires', $expires, PDO::PARAM_STR);
  858. $ok = $query->execute();
  859. return $ok;
  860. }
  861. ###
  862. ### ResourceLinkShareKey methods
  863. ###
  864. /**
  865. * Load resource link share key object.
  866. *
  867. * @param ResourceLinkShareKey $shareKey Resource_Link share key object
  868. *
  869. * @return boolean True if the resource link share key object was successfully loaded
  870. */
  871. public function loadResourceLinkShareKey($shareKey)
  872. {
  873. $ok = false;
  874. // Clear expired share keys
  875. $now = date("{$this->dateFormat} {$this->timeFormat}", time());
  876. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' WHERE expires <= :now';
  877. $query = $this->db->prepare($sql);
  878. $query->bindValue('now', $now, PDO::PARAM_STR);
  879. $query->execute();
  880. // Load share key
  881. $id = $shareKey->getId();
  882. $sql = 'SELECT resource_link_pk, auto_approve, expires ' .
  883. "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' .
  884. 'WHERE share_key_id = :id';
  885. $query = $this->db->prepare($sql);
  886. $query->bindValue('id', $id, PDO::PARAM_STR);
  887. if ($query->execute()) {
  888. $row = $query->fetch(PDO::FETCH_ASSOC);
  889. if ($row !== FALSE) {
  890. $row = array_change_key_case($row);
  891. if (intval($row['resource_link_pk']) === $shareKey->resourceLinkId) {
  892. $shareKey->autoApprove = ($row['auto_approve'] === 1);
  893. $shareKey->expires = strtotime($row['expires']);
  894. $ok = true;
  895. }
  896. }
  897. }
  898. return $ok;
  899. }
  900. /**
  901. * Save resource link share key object.
  902. *
  903. * @param ResourceLinkShareKey $shareKey Resource link share key object
  904. *
  905. * @return boolean True if the resource link share key object was successfully saved
  906. */
  907. public function saveResourceLinkShareKey($shareKey)
  908. {
  909. $id = $shareKey->getId();
  910. $expires = date("{$this->dateFormat} {$this->timeFormat}", $shareKey->expires);
  911. $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' .
  912. '(share_key_id, resource_link_pk, auto_approve, expires) ' .
  913. 'VALUES (:id, :prlid, :approve, :expires)';
  914. $query = $this->db->prepare($sql);
  915. $query->bindValue('id', $id, PDO::PARAM_STR);
  916. $query->bindValue('prlid', $shareKey->resourceLinkId, PDO::PARAM_INT);
  917. $query->bindValue('approve', $shareKey->autoApprove, PDO::PARAM_INT);
  918. $query->bindValue('expires', $expires, PDO::PARAM_STR);
  919. $ok = $query->execute();
  920. return $ok;
  921. }
  922. /**
  923. * Delete resource link share key object.
  924. *
  925. * @param ResourceLinkShareKey $shareKey Resource link share key object
  926. *
  927. * @return boolean True if the resource link share key object was successfully deleted
  928. */
  929. public function deleteResourceLinkShareKey($shareKey)
  930. {
  931. $id = $shareKey->getId();
  932. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' WHERE share_key_id = :id';
  933. $query = $this->db->prepare($sql);
  934. $query->bindValue('id', $id, PDO::PARAM_STR);
  935. $ok = $query->execute();
  936. if ($ok) {
  937. $shareKey->initialize();
  938. }
  939. return $ok;
  940. }
  941. ###
  942. ### User methods
  943. ###
  944. /**
  945. * Load user object.
  946. *
  947. * @param User $user User object
  948. *
  949. * @return boolean True if the user object was successfully loaded
  950. */
  951. public function loadUser($user)
  952. {
  953. $ok = false;
  954. if (!empty($user->getRecordId())) {
  955. $id = $user->getRecordId();
  956. $sql = 'SELECT user_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' .
  957. "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' .
  958. 'WHERE (user_pk = :id)';
  959. $query = $this->db->prepare($sql);
  960. $query->bindValue('id', $id, PDO::PARAM_INT);
  961. } else {
  962. $id = $user->getResourceLink()->getRecordId();
  963. $uid = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY);
  964. $sql = 'SELECT user_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' .
  965. "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' .
  966. 'WHERE (resource_link_pk = :id) AND (lti_user_id = :uid)';
  967. $query = $this->db->prepare($sql);
  968. $query->bindValue('id', $id, PDO::PARAM_INT);
  969. $query->bindValue('uid', $uid, PDO::PARAM_STR);
  970. }
  971. if ($query->execute()) {
  972. $row = $query->fetch(PDO::FETCH_ASSOC);
  973. if ($row !== false) {
  974. $row = array_change_key_case($row);
  975. $user->setRecordId(intval($row['user_pk']));
  976. $user->setResourceLinkId(intval($row['resource_link_pk']));
  977. $user->ltiUserId = $row['lti_user_id'];
  978. $user->ltiResultSourcedId = $row['lti_result_sourcedid'];
  979. $user->created = strtotime($row['created']);
  980. $user->updated = strtotime($row['updated']);
  981. $ok = true;
  982. }
  983. }
  984. return $ok;
  985. }
  986. /**
  987. * Save user object.
  988. *
  989. * @param User $user User object
  990. *
  991. * @return boolean True if the user object was successfully saved
  992. */
  993. public function saveUser($user)
  994. {
  995. $time = time();
  996. $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
  997. if (is_null($user->created)) {
  998. $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' (resource_link_pk, ' .
  999. 'lti_user_id, lti_result_sourcedid, created, updated) ' .
  1000. 'VALUES (:rlid, :uid, :sourcedid, :created, :updated)';
  1001. $query = $this->db->prepare($sql);
  1002. $query->bindValue('rlid', $user->getResourceLink()->getRecordId(), PDO::PARAM_INT);
  1003. $query->bindValue('uid', $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY), PDO::PARAM_STR);
  1004. $query->bindValue('sourcedid', $user->ltiResultSourcedId, PDO::PARAM_STR);
  1005. $query->bindValue('created', $now, PDO::PARAM_STR);
  1006. $query->bindValue('updated', $now, PDO::PARAM_STR);
  1007. } else {
  1008. $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' .
  1009. 'SET lti_result_sourcedid = :sourcedid, updated = :updated ' .
  1010. 'WHERE (user_pk = :id)';
  1011. $query = $this->db->prepare($sql);
  1012. $query->bindValue('sourcedid', $user->ltiResultSourcedId, PDO::PARAM_STR);
  1013. $query->bindValue('updated', $now, PDO::PARAM_STR);
  1014. $query->bindValue('id', $user->getRecordId(), PDO::PARAM_INT);
  1015. }
  1016. $ok = $query->execute();
  1017. if ($ok) {
  1018. if (is_null($user->created)) {
  1019. $user->setRecordId(intval($this->db->lastInsertId()));
  1020. $user->created = $time;
  1021. }
  1022. $user->updated = $time;
  1023. }
  1024. return $ok;
  1025. }
  1026. /**
  1027. * Delete user object.
  1028. *
  1029. * @param User $user User object
  1030. *
  1031. * @return boolean True if the user object was successfully deleted
  1032. */
  1033. public function deleteUser($user)
  1034. {
  1035. $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' .
  1036. 'WHERE (user_pk = :id)';
  1037. $query = $this->db->prepare($sql);
  1038. $query->bindValue('id', $user->getRecordId(), PDO::PARAM_INT);
  1039. $ok = $query->execute();
  1040. if ($ok) {
  1041. $user->initialize();
  1042. }
  1043. return $ok;
  1044. }
  1045. }