Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

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