PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

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

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