LTI Integration Library  3.1.0
PHP class library for building LTI integrations
DataConnector_mysqli.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use ceLTIc\LTI;
13 
22 ###
23 # NB This class assumes that a MySQLi connection has already been opened to the appropriate schema
24 ###
25 
26 
28 {
29 ###
30 ### ToolConsumer methods
31 ###
32 
40  public function loadToolConsumer($consumer)
41  {
42  $ok = false;
43  if (!is_null($consumer->getRecordId())) {
44  $sql = sprintf('SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' .
45  'signature_method, consumer_name, consumer_version, consumer_guid, ' .
46  'profile, tool_proxy, settings, protected, enabled, ' .
47  'enable_from, enable_until, last_access, created, updated ' .
48  "FROM {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' ' .
49  "WHERE consumer_pk = %d", $consumer->getRecordId());
50  } else {
51  $key256 = static::getConsumerKey($consumer->getKey());
52  $sql = sprintf('SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' .
53  'signature_method, consumer_name, consumer_version, consumer_guid, ' .
54  'profile, tool_proxy, settings, protected, enabled, ' .
55  'enable_from, enable_until, last_access, created, updated ' .
56  "FROM {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' ' .
57  "WHERE consumer_key256 = %s", $this->escape($key256));
58  }
59  $rsConsumer = mysqli_query($this->db, $sql);
60  if ($rsConsumer) {
61  while ($row = mysqli_fetch_object($rsConsumer)) {
62  if (empty($key256) || empty($row->consumer_key) || ($consumer->getKey() === $row->consumer_key)) {
63  $consumer->setRecordId(intval($row->consumer_pk));
64  $consumer->name = $row->name;
65  $consumer->setkey(empty($row->consumer_key) ? $row->consumer_key256 : $row->consumer_key);
66  $consumer->secret = $row->secret;
67  $consumer->ltiVersion = $row->lti_version;
68  $consumer->signatureMethod = $row->signature_method;
69  $consumer->consumerName = $row->consumer_name;
70  $consumer->consumerVersion = $row->consumer_version;
71  $consumer->consumerGuid = $row->consumer_guid;
72  $consumer->profile = json_decode($row->profile);
73  $consumer->toolProxy = $row->tool_proxy;
74  $settings = json_decode($row->settings, TRUE);
75  if (!is_array($settings)) {
76  $settings = @unserialize($row->settings); // check for old serialized setting
77  }
78  if (!is_array($settings)) {
79  $settings = array();
80  }
81  $consumer->setSettings($settings);
82  $consumer->protected = (intval($row->protected) === 1);
83  $consumer->enabled = (intval($row->enabled) === 1);
84  $consumer->enableFrom = null;
85  if (!is_null($row->enable_from)) {
86  $consumer->enableFrom = strtotime($row->enable_from);
87  }
88  $consumer->enableUntil = null;
89  if (!is_null($row->enable_until)) {
90  $consumer->enableUntil = strtotime($row->enable_until);
91  }
92  $consumer->lastAccess = null;
93  if (!is_null($row->last_access)) {
94  $consumer->lastAccess = strtotime($row->last_access);
95  }
96  $consumer->created = strtotime($row->created);
97  $consumer->updated = strtotime($row->updated);
98  $ok = true;
99  break;
100  }
101  }
102  mysqli_free_result($rsConsumer);
103  }
104 
105  return $ok;
106  }
107 
115  public function saveToolConsumer($consumer)
116  {
117  $id = $consumer->getRecordId();
118  $key = $consumer->getKey();
119  $key256 = static::getConsumerKey($key);
120  if ($key === $key256) {
121  $key = null;
122  }
123  $protected = ($consumer->protected) ? 1 : 0;
124  $enabled = ($consumer->enabled) ? 1 : 0;
125  $profile = (!empty($consumer->profile)) ? json_encode($consumer->profile) : null;
126  $settingsValue = json_encode($consumer->getSettings());
127  $time = time();
128  $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
129  $from = null;
130  if (!is_null($consumer->enableFrom)) {
131  $from = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableFrom);
132  }
133  $until = null;
134  if (!is_null($consumer->enableUntil)) {
135  $until = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableUntil);
136  }
137  $last = null;
138  if (!is_null($consumer->lastAccess)) {
139  $last = date($this->dateFormat, $consumer->lastAccess);
140  }
141  if (empty($id)) {
142  $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' (consumer_key256, consumer_key, name, ' .
143  'secret, lti_version, signature_method, consumer_name, consumer_version, consumer_guid, profile, ' .
144  'tool_proxy, settings, protected, enabled, ' .
145  'enable_from, enable_until, last_access, created, updated) ' .
146  'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %d, %s, %s, %s, %s, %s)', $this->escape($key256),
147  $this->escape($key), $this->escape($consumer->name), $this->escape($consumer->secret),
148  $this->escape($consumer->ltiVersion), $this->escape($consumer->signatureMethod),
149  $this->escape($consumer->consumerName), $this->escape($consumer->consumerVersion),
150  $this->escape($consumer->consumerGuid), $this->escape($profile), $this->escape($consumer->toolProxy),
151  $this->escape($settingsValue), $protected, $enabled, $this->escape($from), $this->escape($until),
152  $this->escape($last), $this->escape($now), $this->escape($now));
153  } else {
154  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' SET ' .
155  'consumer_key256 = %s, consumer_key = %s, ' .
156  'name = %s, secret= %s, lti_version = %s, signature_method = %s, consumer_name = %s, consumer_version = %s, consumer_guid = %s, ' .
157  'profile = %s, tool_proxy = %s, settings = %s, ' .
158  'protected = %d, enabled = %d, enable_from = %s, enable_until = %s, last_access = %s, updated = %s ' .
159  'WHERE consumer_pk = %d', $this->escape($key256), $this->escape($key), $this->escape($consumer->name),
160  $this->escape($consumer->secret), $this->escape($consumer->ltiVersion), $this->escape($consumer->signatureMethod),
161  $this->escape($consumer->consumerName), $this->escape($consumer->consumerVersion),
162  $this->escape($consumer->consumerGuid), $this->escape($profile), $this->escape($consumer->toolProxy),
163  $this->escape($settingsValue), $protected, $enabled, $this->escape($from), $this->escape($until),
164  $this->escape($last), $this->escape($now), $consumer->getRecordId());
165  }
166  error_log(var_export($sql, true));
167  $ok = mysqli_query($this->db, $sql);
168  if ($ok) {
169  if (empty($id)) {
170  $consumer->setRecordId(mysqli_insert_id($this->db));
171  $consumer->created = $time;
172  }
173  $consumer->updated = $time;
174  }
175 
176  return $ok;
177  }
178 
186  public function deleteToolConsumer($consumer)
187  {
188 // Delete any nonce values for this consumer
189  $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . static::NONCE_TABLE_NAME . ' WHERE consumer_pk = %d',
190  $consumer->getRecordId());
191  mysqli_query($this->db, $sql);
192 
193 // Delete any outstanding share keys for resource links for this consumer
194  $sql = sprintf('DELETE sk ' .
195  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' .
196  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' .
197  'WHERE rl.consumer_pk = %d', $consumer->getRecordId());
198  mysqli_query($this->db, $sql);
199 
200 // Delete any outstanding share keys for resource links for contexts in this consumer
201  $sql = sprintf('DELETE sk ' .
202  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' .
203  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' .
204  "INNER JOIN {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
205  'WHERE c.consumer_pk = %d', $consumer->getRecordId());
206  mysqli_query($this->db, $sql);
207 
208 // Delete any users in resource links for this consumer
209  $sql = sprintf('DELETE u ' .
210  "FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' u ' .
211  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' .
212  'WHERE rl.consumer_pk = %d', $consumer->getRecordId());
213  mysqli_query($this->db, $sql);
214 
215 // Delete any users in resource links for contexts in this consumer
216  $sql = sprintf('DELETE u ' .
217  "FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' u ' .
218  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' .
219  "INNER JOIN {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
220  'WHERE c.consumer_pk = %d', $consumer->getRecordId());
221  mysqli_query($this->db, $sql);
222 
223 // Update any resource links for which this consumer is acting as a primary resource link
224  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' .
225  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' .
226  'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' .
227  'WHERE rl.consumer_pk = %d', $consumer->getRecordId());
228  $ok = mysqli_query($this->db, $sql);
229 
230 // Update any resource links for contexts in which this consumer is acting as a primary resource link
231  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' .
232  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' .
233  "INNER JOIN {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
234  'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' .
235  'WHERE c.consumer_pk = %d', $consumer->getRecordId());
236  $ok = mysqli_query($this->db, $sql);
237 
238 // Delete any resource links for this consumer
239  $sql = sprintf('DELETE rl ' .
240  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ' .
241  'WHERE rl.consumer_pk = %d', $consumer->getRecordId());
242  mysqli_query($this->db, $sql);
243 
244 // Delete any resource links for contexts in this consumer
245  $sql = sprintf('DELETE rl ' .
246  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ' .
247  "INNER JOIN {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' .
248  'WHERE c.consumer_pk = %d', $consumer->getRecordId());
249  mysqli_query($this->db, $sql);
250 
251 // Delete any contexts for this consumer
252  $sql = sprintf('DELETE c ' .
253  "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ' .
254  'WHERE c.consumer_pk = %d', $consumer->getRecordId());
255  mysqli_query($this->db, $sql);
256 
257 // Delete consumer
258  $sql = sprintf('DELETE c ' .
259  "FROM {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' c ' .
260  'WHERE c.consumer_pk = %d', $consumer->getRecordId());
261  $ok = mysqli_query($this->db, $sql);
262 
263  if ($ok) {
264  $consumer->initialize();
265  }
266 
267  return $ok;
268  }
269 
275  public function getToolConsumers()
276  {
277  $consumers = array();
278 
279  $sql = 'SELECT consumer_pk, consumer_key256, consumer_key, name, secret, lti_version, ' .
280  'signature_method, consumer_name, consumer_version, consumer_guid, ' .
281  'profile, tool_proxy, settings, ' .
282  'protected, enabled, enable_from, enable_until, last_access, created, updated ' .
283  "FROM {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' ' .
284  'ORDER BY name';
285  $rsConsumers = mysqli_query($this->db, $sql);
286  if ($rsConsumers) {
287  while ($row = mysqli_fetch_object($rsConsumers)) {
288  $key = empty($row->consumer_key) ? $row->consumer_key256 : $row->consumer_key;
289  $consumer = new ToolConsumer($key, $this);
290  $consumer->setRecordId(intval($row->consumer_pk));
291  $consumer->name = $row->name;
292  $consumer->secret = $row->secret;
293  $consumer->ltiVersion = $row->lti_version;
294  $consumer->signatureMethod = $row->signature_method;
295  $consumer->consumerName = $row->consumer_name;
296  $consumer->consumerVersion = $row->consumer_version;
297  $consumer->consumerGuid = $row->consumer_guid;
298  $consumer->profile = json_decode($row->profile);
299  $consumer->toolProxy = $row->tool_proxy;
300  $settings = json_decode($row->settings, TRUE);
301  if (!is_array($settings)) {
302  $settings = @unserialize($row->settings); // check for old serialized setting
303  }
304  if (!is_array($settings)) {
305  $settings = array();
306  }
307  $consumer->setSettings($settings);
308  $consumer->protected = (intval($row->protected) === 1);
309  $consumer->enabled = (intval($row->enabled) === 1);
310  $consumer->enableFrom = null;
311  if (!is_null($row->enable_from)) {
312  $consumer->enableFrom = strtotime($row->enable_from);
313  }
314  $consumer->enableUntil = null;
315  if (!is_null($row->enable_until)) {
316  $consumer->enableUntil = strtotime($row->enable_until);
317  }
318  $consumer->lastAccess = null;
319  if (!is_null($row->last_access)) {
320  $consumer->lastAccess = strtotime($row->last_access);
321  }
322  $consumer->created = strtotime($row->created);
323  $consumer->updated = strtotime($row->updated);
324  $consumers[] = $consumer;
325  }
326  mysqli_free_result($rsConsumers);
327  }
328 
329  return $consumers;
330  }
331 
332 ###
333 ### Context methods
334 ###
335 
343  public function loadContext($context)
344  {
345  $ok = false;
346  if (!is_null($context->getRecordId())) {
347  $sql = sprintf('SELECT context_pk, consumer_pk, title, lti_context_id, type, settings, created, updated ' .
348  "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' ' .
349  'WHERE (context_pk = %d)', $context->getRecordId());
350  } else {
351  $sql = sprintf('SELECT context_pk, consumer_pk, title, lti_context_id, type, settings, created, updated ' .
352  "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' ' .
353  'WHERE (consumer_pk = %d) AND (lti_context_id = %s)', $context->getConsumer()->getRecordId(),
354  $this->escape($context->ltiContextId));
355  }
356  $rs_context = mysqli_query($this->db, $sql);
357  if ($rs_context) {
358  $row = mysqli_fetch_object($rs_context);
359  if ($row) {
360  $context->setRecordId(intval($row->context_pk));
361  $context->setConsumerId(intval($row->consumer_pk));
362  $context->title = $row->title;
363  $context->ltiContextId = $row->lti_context_id;
364  $context->type = $row->type;
365  $settings = json_decode($row->settings, TRUE);
366  if (!is_array($settings)) {
367  $settings = @unserialize($row->settings); // check for old serialized setting
368  }
369  if (!is_array($settings)) {
370  $settings = array();
371  }
372  $context->setSettings($settings);
373  $context->created = strtotime($row->created);
374  $context->updated = strtotime($row->updated);
375  $ok = true;
376  }
377  }
378 
379  return $ok;
380  }
381 
389  public function saveContext($context)
390  {
391  $time = time();
392  $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
393  $settingsValue = json_encode($context->getSettings());
394  $id = $context->getRecordId();
395  $consumer_pk = $context->getConsumer()->getRecordId();
396  if (empty($id)) {
397  $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' (consumer_pk, title, ' .
398  'lti_context_id, type, settings, created, updated) ' .
399  'VALUES (%d, %s, %s, %s, %s, %s, %s)', $consumer_pk, $this->escape($context->title),
400  $this->escape($context->ltiContextId), $this->escape($context->type), $this->escape($settingsValue),
401  $this->escape($now), $this->escape($now));
402  } else {
403  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' SET ' .
404  'title = %s, lti_context_id = %s, type = %s, settings = %s, ' .
405  'updated = %s' .
406  'WHERE (consumer_pk = %d) AND (context_pk = %d)', $this->escape($context->title),
407  $this->escape($context->ltiContextId), $this->escape($context->type), $this->escape($settingsValue),
408  $this->escape($now), $consumer_pk, $id);
409  }
410  $ok = mysqli_query($this->db, $sql);
411  if ($ok) {
412  if (empty($id)) {
413  $context->setRecordId(mysqli_insert_id($this->db));
414  $context->created = $time;
415  }
416  $context->updated = $time;
417  }
418 
419  return $ok;
420  }
421 
429  public function deleteContext($context)
430  {
431 // Delete any outstanding share keys for resource links for this context
432  $sql = sprintf('DELETE sk ' .
433  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' .
434  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' .
435  'WHERE rl.context_pk = %d', $context->getRecordId());
436  mysqli_query($this->db, $sql);
437 
438 // Delete any users in resource links for this context
439  $sql = sprintf('DELETE u ' .
440  "FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' u ' .
441  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' .
442  'WHERE rl.context_pk = %d', $context->getRecordId());
443  mysqli_query($this->db, $sql);
444 
445 // Update any resource links for which this consumer is acting as a primary resource link
446  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' .
447  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' .
448  'SET prl.primary_resource_link_pk = null, prl.share_approved = null ' .
449  'WHERE rl.context_pk = %d', $context->getRecordId());
450  $ok = mysqli_query($this->db, $sql);
451 
452 // Delete any resource links for this consumer
453  $sql = sprintf('DELETE rl ' .
454  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ' .
455  'WHERE rl.context_pk = %d', $context->getRecordId());
456  mysqli_query($this->db, $sql);
457 
458 // Delete context
459  $sql = sprintf('DELETE c ' .
460  "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ', 'WHERE c.context_pk = %d',
461  $context->getRecordId());
462  $ok = mysqli_query($this->db, $sql);
463  if ($ok) {
464  $context->initialize();
465  }
466 
467  return $ok;
468  }
469 
470 ###
471 ### ResourceLink methods
472 ###
473 
481  public function loadResourceLink($resourceLink)
482  {
483  $ok = false;
484  if (!is_null($resourceLink->getRecordId())) {
485  $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' .
486  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' .
487  'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId());
488  } elseif (!is_null($resourceLink->getContext())) {
489  $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' .
490  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' .
491  'WHERE (context_pk = %d) AND (lti_resource_link_id = %s)', $resourceLink->getContext()->getRecordId(),
492  $this->escape($resourceLink->getId()));
493  } else {
494  $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' .
495  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' .
496  $this->dbTableNamePrefix . static::CONTEXT_TABLE_NAME . ' c ON r.context_pk = c.context_pk ' .
497  ' WHERE ((r.consumer_pk = %d) OR (c.consumer_pk = %d)) AND (lti_resource_link_id = %s)',
498  $resourceLink->getConsumer()->getRecordId(), $resourceLink->getConsumer()->getRecordId(),
499  $this->escape($resourceLink->getId()));
500  }
501  $rsContext = mysqli_query($this->db, $sql);
502  if ($rsContext) {
503  $row = mysqli_fetch_object($rsContext);
504  if ($row) {
505  $resourceLink->setRecordId(intval($row->resource_link_pk));
506  if (!is_null($row->context_pk)) {
507  $resourceLink->setContextId(intval($row->context_pk));
508  } else {
509  $resourceLink->setContextId(null);
510  }
511  if (!is_null($row->consumer_pk)) {
512  $resourceLink->setConsumerId(intval($row->consumer_pk));
513  } else {
514  $resourceLink->setConsumerId(null);
515  }
516  $resourceLink->title = $row->title;
517  $resourceLink->ltiResourceLinkId = $row->lti_resource_link_id;
518  $settings = json_decode($row->settings, TRUE);
519  if (!is_array($settings)) {
520  $settings = @unserialize($row->settings); // check for old serialized setting
521  }
522  if (!is_array($settings)) {
523  $settings = array();
524  }
525  $resourceLink->setSettings($settings);
526  if (!is_null($row->primary_resource_link_pk)) {
527  $resourceLink->primaryResourceLinkId = intval($row->primary_resource_link_pk);
528  } else {
529  $resourceLink->primaryResourceLinkId = null;
530  }
531  $resourceLink->shareApproved = (is_null($row->share_approved)) ? null : (intval($row->share_approved) === 1);
532  $resourceLink->created = strtotime($row->created);
533  $resourceLink->updated = strtotime($row->updated);
534  $ok = true;
535  }
536  }
537 
538  return $ok;
539  }
540 
548  public function saveResourceLink($resourceLink)
549  {
550  if (is_null($resourceLink->shareApproved)) {
551  $approved = 'NULL';
552  } elseif ($resourceLink->shareApproved) {
553  $approved = '1';
554  } else {
555  $approved = '0';
556  }
557  if (empty($resourceLink->primaryResourceLinkId)) {
558  $primaryResourceLinkId = 'NULL';
559  } else {
560  $primaryResourceLinkId = strval($resourceLink->primaryResourceLinkId);
561  }
562  $time = time();
563  $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
564  $settingsValue = json_encode($resourceLink->getSettings());
565  if (!is_null($resourceLink->getContext())) {
566  $consumerId = 'NULL';
567  $contextId = strval($resourceLink->getContext()->getRecordId());
568  } elseif (!is_null($resourceLink->getContextId())) {
569  $consumerId = 'NULL';
570  $contextId = strval($resourceLink->getContextId());
571  } else {
572  $consumerId = strval($resourceLink->getConsumer()->getRecordId());
573  $contextId = 'NULL';
574  }
575  $id = $resourceLink->getRecordId();
576  if (empty($id)) {
577  $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' (consumer_pk, context_pk, ' .
578  'title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated) ' .
579  'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)', $consumerId, $contextId, $this->escape($resourceLink->title),
580  $this->escape($resourceLink->getId()), $this->escape($settingsValue), $primaryResourceLinkId, $approved,
581  $this->escape($now), $this->escape($now));
582  } elseif ($contextId !== 'NULL') {
583  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' .
584  'consumer_pk = %s, title = %s, lti_resource_link_id = %s, settings = %s, ' .
585  'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' .
586  'WHERE (context_pk = %s) AND (resource_link_pk = %d)', $consumerId, $this->escape($resourceLink->title),
587  $this->escape($resourceLink->getId()), $this->escape($settingsValue), $primaryResourceLinkId, $approved,
588  $this->escape($now), $contextId, $id);
589  } else {
590  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' .
591  'context_pk = %s, title = %s, lti_resource_link_id = %s, settings = %s, ' .
592  'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' .
593  'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $contextId, $this->escape($resourceLink->title),
594  $this->escape($resourceLink->getId()), $this->escape($settingsValue), $primaryResourceLinkId, $approved,
595  $this->escape($now), $consumerId, $id);
596  }
597  $ok = mysqli_query($this->db, $sql);
598  if ($ok) {
599  if (empty($id)) {
600  $resourceLink->setRecordId(mysqli_insert_id($this->db));
601  $resourceLink->created = $time;
602  }
603  $resourceLink->updated = $time;
604  }
605 
606  return $ok;
607  }
608 
616  public function deleteResourceLink($resourceLink)
617  {
618 // Delete any outstanding share keys for resource links for this consumer
619  $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' .
620  'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId());
621  $ok = mysqli_query($this->db, $sql);
622 
623 // Delete users
624  if ($ok) {
625  $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' ' .
626  'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId());
627  $ok = mysqli_query($this->db, $sql);
628  }
629 
630 // Update any resource links for which this is the primary resource link
631  if ($ok) {
632  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' .
633  'SET primary_resource_link_pk = NULL ' .
634  'WHERE (primary_resource_link_pk = %d)', $resourceLink->getRecordId());
635  $ok = mysqli_query($this->db, $sql);
636  }
637 
638 // Delete resource link
639  if ($ok) {
640  $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' .
641  'WHERE (resource_link_pk = %s)', $resourceLink->getRecordId());
642  $ok = mysqli_query($this->db, $sql);
643  }
644 
645  if ($ok) {
646  $resourceLink->initialize();
647  }
648 
649  return $ok;
650  }
651 
664  public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $idScope)
665  {
666  $userResults = array();
667 
668  if ($localOnly) {
669  $sql = sprintf('SELECT u.user_result_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' .
670  "FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' AS u ' .
671  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' AS rl ' .
672  'ON u.resource_link_pk = rl.resource_link_pk ' .
673  "WHERE (rl.resource_link_pk = %d) AND (rl.primary_resource_link_pk IS NULL)", $resourceLink->getRecordId());
674  } else {
675  $sql = sprintf('SELECT u.user_result_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' .
676  "FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' AS u ' .
677  "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' AS rl ' .
678  'ON u.resource_link_pk = rl.resource_link_pk ' .
679  'WHERE ((rl.resource_link_pk = %d) AND (rl.primary_resource_link_pk IS NULL)) OR ' .
680  '((rl.primary_resource_link_pk = %d) AND (share_approved = 1))', $resourceLink->getRecordId(),
681  $resourceLink->getRecordId());
682  }
683  $rsUser = mysqli_query($this->db, $sql);
684  if ($rsUser) {
685  while ($row = mysqli_fetch_object($rsUser)) {
686  $userresult = LTI\UserResult::fromResourceLink($resourceLink, $row->lti_user_id);
687  if (is_null($idScope)) {
688  $userResults[] = $userresult;
689  } else {
690  $userResults[$userresult->getId($idScope)] = $userresult;
691  }
692  }
693  }
694 
695  return $userResults;
696  }
697 
705  public function getSharesResourceLink($resourceLink)
706  {
707  $shares = array();
708 
709  $sql = sprintf('SELECT c.consumer_name, r.resource_link_pk, r.title, r.share_approved ' .
710  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' AS r ' .
711  "INNER JOIN {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' AS c ON r.consumer_pk = c.consumer_pk ' .
712  'WHERE (r.primary_resource_link_pk = %d) ' .
713  'UNION ' .
714  'SELECT c2.consumer_name, r2.resource_link_pk, r2.title, r2.share_approved ' .
715  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' AS r2 ' .
716  "INNER JOIN {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' AS x ON r2.context_pk = x.context_pk ' .
717  "INNER JOIN {$this->dbTableNamePrefix}" . static::CONSUMER_TABLE_NAME . ' AS c2 ON x.consumer_pk = c2.consumer_pk ' .
718  'WHERE (r2.primary_resource_link_pk = %d) ' .
719  'ORDER BY consumer_name, title', $resourceLink->getRecordId(), $resourceLink->getRecordId());
720  $rsShare = mysqli_query($this->db, $sql);
721  if ($rsShare) {
722  while ($row = mysqli_fetch_object($rsShare)) {
723  $share = new LTI\ResourceLinkShare();
724  $share->consumerName = $row->consumer_name;
725  $share->resourceLinkId = intval($row->resource_link_pk);
726  $share->title = $row->title;
727  $share->approved = (intval($row->share_approved) === 1);
728  $shares[] = $share;
729  }
730  }
731 
732  return $shares;
733  }
734 
735 ###
736 ### ConsumerNonce methods
737 ###
738 
746  public function loadConsumerNonce($nonce)
747  {
748  $ok = false;
749 
750 // Delete any expired nonce values
751  $now = date("{$this->dateFormat} {$this->timeFormat}", time());
752  $sql = "DELETE FROM {$this->dbTableNamePrefix}" . static::NONCE_TABLE_NAME . " WHERE expires <= '{$now}'";
753  mysqli_query($this->db, $sql);
754 
755 // Load the nonce
756  $sql = sprintf("SELECT value AS T FROM {$this->dbTableNamePrefix}" . static::NONCE_TABLE_NAME . ' WHERE (consumer_pk = %d) AND (value = %s)',
757  $nonce->getConsumer()->getRecordId(), $this->escape($nonce->getValue()));
758  $rs_nonce = mysqli_query($this->db, $sql);
759  if ($rs_nonce) {
760  if (mysqli_fetch_object($rs_nonce)) {
761  $ok = true;
762  }
763  }
764 
765  return $ok;
766  }
767 
775  public function saveConsumerNonce($nonce)
776  {
777  $expires = date("{$this->dateFormat} {$this->timeFormat}", $nonce->expires);
778  $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . static::NONCE_TABLE_NAME . " (consumer_pk, value, expires) VALUES (%d, %s, %s)",
779  $nonce->getConsumer()->getRecordId(), $this->escape($nonce->getValue()), $this->escape($expires));
780  $ok = mysqli_query($this->db, $sql);
781 
782  return $ok;
783  }
784 
785 ###
786 ### ResourceLinkShareKey methods
787 ###
788 
796  public function loadResourceLinkShareKey($shareKey)
797  {
798  $ok = false;
799 
800 // Clear expired share keys
801  $now = date("{$this->dateFormat} {$this->timeFormat}", time());
802  $sql = "DELETE FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . " WHERE expires <= '{$now}'";
803  mysqli_query($this->db, $sql);
804 
805 // Load share key
806  $id = mysqli_real_escape_string($this->db, $shareKey->getId());
807  $sql = 'SELECT resource_link_pk, auto_approve, expires ' .
808  "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' .
809  "WHERE share_key_id = '{$id}'";
810  $rsShareKey = mysqli_query($this->db, $sql);
811  if ($rsShareKey) {
812  $row = mysqli_fetch_object($rsShareKey);
813  if ($row && (intval($row->resource_link_pk) === $shareKey->resourceLinkId)) {
814  $shareKey->autoApprove = (intval($row->auto_approve) === 1);
815  $shareKey->expires = strtotime($row->expires);
816  $ok = true;
817  }
818  }
819 
820  return $ok;
821  }
822 
830  public function saveResourceLinkShareKey($shareKey)
831  {
832  if ($shareKey->autoApprove) {
833  $approve = 1;
834  } else {
835  $approve = 0;
836  }
837  $expires = date("{$this->dateFormat} {$this->timeFormat}", $shareKey->expires);
838  $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' .
839  '(share_key_id, resource_link_pk, auto_approve, expires) ' .
840  "VALUES (%s, %d, {$approve}, '{$expires}')", $this->escape($shareKey->getId()), $shareKey->resourceLinkId);
841  $ok = mysqli_query($this->db, $sql);
842 
843  return $ok;
844  }
845 
853  public function deleteResourceLinkShareKey($shareKey)
854  {
855  $sql = "DELETE FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . " WHERE share_key_id = '{$shareKey->getId()}'";
856 
857  $ok = mysqli_query($this->db, $sql);
858 
859  if ($ok) {
860  $shareKey->initialize();
861  }
862 
863  return $ok;
864  }
865 
866 ###
867 ### UserResult methods
868 ###
869 
877  public function loadUserResult($userresult)
878  {
879  $ok = false;
880  if (!is_null($userresult->getRecordId())) {
881  $sql = sprintf('SELECT user_result_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' .
882  "FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' ' .
883  'WHERE (user_result_pk = %d)', $userresult->getRecordId());
884  } else {
885  $sql = sprintf('SELECT user_result_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' .
886  "FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' ' .
887  'WHERE (resource_link_pk = %d) AND (lti_user_id = %s)', $userresult->getResourceLink()->getRecordId(),
888  $this->escape($userresult->getId(LTI\ToolProvider::ID_SCOPE_ID_ONLY)));
889  }
890  $rsUser = mysqli_query($this->db, $sql);
891  if ($rsUser) {
892  $row = mysqli_fetch_object($rsUser);
893  if ($row) {
894  $userresult->setRecordId(intval($row->user_result_pk));
895  $userresult->setResourceLinkId(intval($row->resource_link_pk));
896  $userresult->ltiUserId = $row->lti_user_id;
897  $userresult->ltiResultSourcedId = $row->lti_result_sourcedid;
898  $userresult->created = strtotime($row->created);
899  $userresult->updated = strtotime($row->updated);
900  $ok = true;
901  }
902  }
903 
904  return $ok;
905  }
906 
914  public function saveUserResult($userresult)
915  {
916  $time = time();
917  $now = date("{$this->dateFormat} {$this->timeFormat}", $time);
918  if (is_null($userresult->created)) {
919  $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' (resource_link_pk, ' .
920  'lti_user_id, lti_result_sourcedid, created, updated) ' .
921  'VALUES (%d, %s, %s, %s, %s)', $userresult->getResourceLink()->getRecordId(),
922  $this->escape($userresult->getId(LTI\ToolProvider::ID_SCOPE_ID_ONLY)),
923  $this->escape($userresult->ltiResultSourcedId), $this->escape($now), $this->escape($now));
924  } else {
925  $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' ' .
926  'SET lti_result_sourcedid = %s, updated = %s ' .
927  'WHERE (user_result_pk = %d)', $this->escape($userresult->ltiResultSourcedId), $this->escape($now),
928  $userresult->getRecordId());
929  }
930  $ok = mysqli_query($this->db, $sql);
931  if ($ok) {
932  if (is_null($userresult->created)) {
933  $userresult->setRecordId(mysqli_insert_id($this->db));
934  $userresult->created = $time;
935  }
936  $userresult->updated = $time;
937  }
938 
939  return $ok;
940  }
941 
949  public function deleteUserResult($userresult)
950  {
951  $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . static::USER_RESULT_TABLE_NAME . ' ' .
952  'WHERE (user_result_pk = %d)', $userresult->getRecordId());
953  $ok = mysqli_query($this->db, $sql);
954 
955  if ($ok) {
956  $userresult->initialize();
957  }
958 
959  return $ok;
960  }
961 
973  public function escape($value, $addQuotes = true)
974  {
975  if (is_null($value)) {
976  $value = 'null';
977  } else {
978  $value = mysqli_real_escape_string($this->db, $value);
979  if ($addQuotes) {
980  $value = "'{$value}'";
981  }
982  }
983 
984  return $value;
985  }
986 
987 }
saveResourceLink($resourceLink)
Save resource link object.
deleteToolConsumer($consumer)
Delete tool consumer object.
static fromResourceLink($resourceLink, $ltiUserId)
Class constructor from resource link.
Definition: UserResult.php:255
Class to provide a connection to a persistent store for LTI objects.
deleteResourceLinkShareKey($shareKey)
Delete resource link share key object.
const ID_SCOPE_ID_ONLY
Use ID value only.
deleteResourceLink($resourceLink)
Delete resource link object.
Class to represent a tool consumer.
loadResourceLink($resourceLink)
Load resource link object.
Class to represent a tool consumer context.
Definition: Context.php:17
getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $idScope)
Get array of user objects.
escape($value, $addQuotes=true)
Escape a string for use in a database query.
saveToolConsumer($consumer)
Save tool consumer object.
Class to represent a tool consumer nonce.
Class to represent a tool consumer resource link share.
deleteUserResult($userresult)
Delete user object.
Class to represent an LTI Data Connector for MySQLi.
loadToolConsumer($consumer)
Load tool consumer object.
Class to represent a tool consumer user.
Definition: UserResult.php:15
saveResourceLinkShareKey($shareKey)
Save resource link share key object.
getSharesResourceLink($resourceLink)
Get array of shares defined for this resource link.
Class to represent a tool consumer resource link share key.
loadResourceLinkShareKey($shareKey)
Load resource link share key object.
getToolConsumers()
Load all tool consumers from the database.