diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d1502b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +vendor/ +composer.lock diff --git a/composer.json b/composer.json index 924ee5c..6581200 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,9 @@ "require":{ "php": ">=5.6.0" }, + "require-dev": { + "squizlabs/php_codesniffer": "^3.2" + }, "autoload":{ "psr-4": { "IMSGlobal\\LTI\\": "src/" diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..d68ac51 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,17 @@ + + + ./src + + + + + + + ./src/OAuth/OAuthSignatureMethod_* + ./src/ToolProvider/DataConnector/DataConnector_* + + + ./src/OAuth/* + ./src/Toolprovider/OAuthDataStore.php + + diff --git a/src/HTTPMessage.php b/src/HTTPMessage.php index 1fa2a9a..3769809 100644 --- a/src/HTTPMessage.php +++ b/src/HTTPMessage.php @@ -1,168 +1,146 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class HTTPMessage { -/** - * True if message was sent successfully. - * - * @var boolean $ok - */ + /** @var bool True if message was sent successfully. */ public $ok = false; -/** - * Request body. - * - * @var request $request - */ + /** @var request Request body. */ public $request = null; -/** - * Request headers. - * - * @var request_headers $requestHeaders - */ + /** @var request_headers Request headers. */ public $requestHeaders = ''; -/** - * Response body. - * - * @var response $response - */ + /** @var response Response body. */ public $response = null; -/** - * Response headers. - * - * @var response_headers $responseHeaders - */ + /** @var response_headers Response headers. */ public $responseHeaders = ''; -/** - * Status of response (0 if undetermined). - * - * @var status $status - */ + /** @var status Status of response (0 if undetermined). */ public $status = 0; -/** - * Error message - * - * @var error $error - */ + /** @var error Error message. */ public $error = ''; -/** - * Request URL. - * - * @var url $url - */ + /** @var url Request URL. */ private $url = null; -/** - * Request method. - * - * @var method $method - */ + /** @var method Request method. */ private $method = null; -/** - * Class constructor. - * - * @param string $url URL to send request to - * @param string $method Request method to use (optional, default is GET) - * @param mixed $params Associative array of parameter values to be passed or message body (optional, default is none) - * @param string $header Values to include in the request header (optional, default is none) - */ - function __construct($url, $method = 'GET', $params = null, $header = null) + /** + * Class constructor. + * + * @param string $url URL to send request to. + * @param string $method Request method to use (optional, default is GET). + * @param mixed $params Associative array of parameter values to be passed or message body (optional, default is none). + * @param string $header Values to include in the request header (optional, default is none). + */ + public function __construct($url, $method = 'GET', $params = null, $header = null) { - $this->url = $url; $this->method = strtoupper($method); + if (is_array($params)) { $this->request = http_build_query($params); } else { $this->request = $params; } + if (!empty($header)) { $this->requestHeaders = explode("\n", $header); } - } -/** - * Send the request to the target URL. - * - * @return boolean True if the request was successful - */ + /** + * Send the request to the target URL. + * + * @return bool TRUE if the request was successful + */ public function send() { - $this->ok = false; -// Try using curl if available + + // Try using curl if available if (function_exists('curl_init')) { $resp = ''; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->url); + if (!empty($this->requestHeaders)) { curl_setopt($ch, CURLOPT_HTTPHEADER, $this->requestHeaders); } else { curl_setopt($ch, CURLOPT_HEADER, 0); } + if ($this->method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $this->request); - } else if ($this->method !== 'GET') { + } elseif ($this->method !== 'GET') { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method); + if (!is_null($this->request)) { curl_setopt($ch, CURLOPT_POSTFIELDS, $this->request); } } + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLINFO_HEADER_OUT, true); curl_setopt($ch, CURLOPT_HEADER, true); + //curl_setopt($ch, CURLOPT_SSLVERSION,3); $chResp = curl_exec($ch); $this->ok = $chResp !== false; + if ($this->ok) { $chResp = str_replace("\r\n", "\n", $chResp); $chRespSplit = explode("\n\n", $chResp, 2); + if ((count($chRespSplit) > 1) && (substr($chRespSplit[1], 0, 5) === 'HTTP/')) { $chRespSplit = explode("\n\n", $chRespSplit[1], 2); } + $this->responseHeaders = $chRespSplit[0]; $resp = $chRespSplit[1]; $this->status = curl_getinfo($ch, CURLINFO_HTTP_CODE); $this->ok = $this->status < 400; + if (!$this->ok) { $this->error = curl_error($ch); } } + $this->requestHeaders = str_replace("\r\n", "\n", curl_getinfo($ch, CURLINFO_HEADER_OUT)); curl_close($ch); $this->response = $resp; } else { -// Try using fopen if curl was not available - $opts = array('method' => $this->method, - 'content' => $this->request - ); + // Try using fopen if curl was not available + $opts = array( + 'method' => $this->method, + 'content' => $this->request + ); + if (!empty($this->requestHeaders)) { $opts['header'] = $this->requestHeaders; } + try { - $ctx = stream_context_create(array('http' => $opts)); + $ctx = stream_context_create(array( + 'http' => $opts + )); $fp = @fopen($this->url, 'rb', false, $ctx); + if ($fp) { $resp = @stream_get_contents($fp); $this->ok = $resp !== false; @@ -171,9 +149,7 @@ public function send() $this->ok = false; } } - + return $this->ok; - } - } diff --git a/src/OAuth/OAuthConsumer.php b/src/OAuth/OAuthConsumer.php index edab669..345ea53 100644 --- a/src/OAuth/OAuthConsumer.php +++ b/src/OAuth/OAuthConsumer.php @@ -1,27 +1,29 @@ key = $key; $this->secret = $secret; $this->callback_url = $callback_url; } - function __toString() { + public function __toString() + { return "OAuthConsumer[key=$this->key,secret=$this->secret]"; } - } diff --git a/src/OAuth/OAuthDataStore.php b/src/OAuth/OAuthDataStore.php index f3df81c..f90643c 100644 --- a/src/OAuth/OAuthDataStore.php +++ b/src/OAuth/OAuthDataStore.php @@ -1,36 +1,41 @@ parameters = $parameters; $this->http_method = $http_method; $this->http_url = $http_url; - } - /** * attempt to build up a request from what was passed to the server */ - public static function from_request($http_method = null, $http_url = null, $parameters = null) { - - $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") - ? 'http' - : 'https'; - $http_url = ($http_url) ? $http_url : $scheme . - '://' . $_SERVER['SERVER_NAME'] . - ':' . - $_SERVER['SERVER_PORT'] . - $_SERVER['REQUEST_URI']; - $http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD']; - - // We weren't handed any parameters, so let's find the ones relevant to - // this request. - // If you run XML-RPC or similar you should use this to provide your own - // parsed parameter-list - if (!$parameters) { - // Find request headers - $request_headers = OAuthUtil::get_headers(); - - // Parse the query-string to find GET parameters - if (isset($_SERVER['QUERY_STRING'])) { - $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); - } else { - $parameters = array(); - } - - // It's a POST request of the proper content-type, so parse POST - // parameters and add those overriding any duplicates from GET - if ($http_method == "POST" - && isset($request_headers['Content-Type']) - && strstr($request_headers['Content-Type'], 'application/x-www-form-urlencoded')) { - $post_data = OAuthUtil::parse_parameters(file_get_contents(self::$POST_INPUT)); - $parameters = array_merge($parameters, $post_data); - } - - // We have a Authorization-header with OAuth data. Parse the header - // and add those overriding any duplicates from GET or POST - if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') { - $header_parameters = OAuthUtil::split_header($request_headers['Authorization']); - $parameters = array_merge($parameters, $header_parameters); - } - - } - - return new OAuthRequest($http_method, $http_url, $parameters); + public static function from_request($http_method = null, $http_url = null, $parameters = null) + { + $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https'; + $http_url = ($http_url) ? $http_url : $scheme . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . + $_SERVER['REQUEST_URI']; + $http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD']; + + // We weren't handed any parameters, so let's find the ones relevant to + // this request. + // If you run XML-RPC or similar you should use this to provide your own + // parsed parameter-list + if (!$parameters) { + // Find request headers + $request_headers = OAuthUtil::get_headers(); + + // Parse the query-string to find GET parameters + if (isset($_SERVER['QUERY_STRING'])) { + $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); + } else { + $parameters = array(); + } + + // It's a POST request of the proper content-type, so parse POST + // parameters and add those overriding any duplicates from GET + if ($http_method == "POST" && isset($request_headers['Content-Type']) && + strstr($request_headers['Content-Type'], 'application/x-www-form-urlencoded')) { + $post_data = OAuthUtil::parse_parameters(file_get_contents(self::$POST_INPUT)); + $parameters = array_merge($parameters, $post_data); + } + + // We have a Authorization-header with OAuth data. Parse the header + // and add those overriding any duplicates from GET or POST + if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') { + $header_parameters = OAuthUtil::split_header($request_headers['Authorization']); + $parameters = array_merge($parameters, $header_parameters); + } + } + + return new OAuthRequest($http_method, $http_url, $parameters); } /** * pretty much a helper function to set up the request */ - public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = null) { - - $parameters = ($parameters) ? $parameters : array(); - $defaults = array('oauth_version' => OAuthRequest::$version, - 'oauth_nonce' => OAuthRequest::generate_nonce(), - 'oauth_timestamp' => OAuthRequest::generate_timestamp(), - 'oauth_consumer_key' => $consumer->key); - if ($token) + public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = null) + { + $parameters = ($parameters) ? $parameters : array(); + $defaults = array( + 'oauth_version' => OAuthRequest::$version, + 'oauth_nonce' => OAuthRequest::generate_nonce(), + 'oauth_timestamp' => OAuthRequest::generate_timestamp(), + 'oauth_consumer_key' => $consumer->key + ); + + if ($token) { $defaults['oauth_token'] = $token->key; - + } + $parameters = array_merge($defaults, $parameters); - + return new OAuthRequest($http_method, $http_url, $parameters); - } - public function set_parameter($name, $value, $allow_duplicates = true) { - - if ($allow_duplicates && isset($this->parameters[$name])) { - // We have already added parameter(s) with this name, so add to the list - if (is_scalar($this->parameters[$name])) { - // This is the first duplicate, so transform scalar (string) - // into an array so we can add the duplicates - $this->parameters[$name] = array($this->parameters[$name]); - } - - $this->parameters[$name][] = $value; - } else { - $this->parameters[$name] = $value; - } + public function set_parameter($name, $value, $allow_duplicates = true) + { + if ($allow_duplicates && isset($this->parameters[$name])) { + // We have already added parameter(s) with this name, so add to the list + if (is_scalar($this->parameters[$name])) { + // This is the first duplicate, so transform scalar (string) + // into an array so we can add the duplicates + $this->parameters[$name] = array( + $this->parameters[$name] + ); + } + + $this->parameters[$name][] = $value; + } else { + $this->parameters[$name] = $value; + } } - public function get_parameter($name) { + public function get_parameter($name) + { return isset($this->parameters[$name]) ? $this->parameters[$name] : null; } - public function get_parameters() { + public function get_parameters() + { return $this->parameters; } - public function unset_parameter($name) { + public function unset_parameter($name) + { unset($this->parameters[$name]); } /** * The request parameters, sorted and concatenated into a normalized string. + * * @return string */ - public function get_signable_parameters() { - + public function get_signable_parameters() + { + // Grab all parameters $params = $this->parameters; - + // Remove oauth_signature if present // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") if (isset($params['oauth_signature'])) { unset($params['oauth_signature']); } - + return OAuthUtil::build_http_query($params); - } /** - * Returns the base string of this request + * Returns the base string of this request. * * The base string defined as the method, the url * and the parameters (normalized), each urlencoded * and the concated with &. */ - public function get_signature_base_string() { + public function get_signature_base_string() + { $parts = array( $this->get_normalized_http_method(), $this->get_normalized_http_url(), $this->get_signable_parameters() ); - + $parts = OAuthUtil::urlencode_rfc3986($parts); - + return implode('&', $parts); - } /** * just uppercases the http method */ - public function get_normalized_http_method() { + public function get_normalized_http_method() + { return strtoupper($this->http_method); } @@ -178,94 +184,92 @@ public function get_normalized_http_method() { * parses the url and rebuilds it to be * scheme://host/path */ - public function get_normalized_http_url() { - + public function get_normalized_http_url() + { $parts = parse_url($this->http_url); - + $scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http'; $port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80'); $host = (isset($parts['host'])) ? strtolower($parts['host']) : ''; $path = (isset($parts['path'])) ? $parts['path'] : ''; - - if (($scheme == 'https' && $port != '443') - || ($scheme == 'http' && $port != '80')) { + + if (($scheme == 'https' && $port != '443') || ($scheme == 'http' && $port != '80')) { $host = "$host:$port"; } - + return "$scheme://$host$path"; - } /** * builds a url usable for a GET request */ - public function to_url() { - + public function to_url() + { $post_data = $this->to_postdata(); $out = $this->get_normalized_http_url(); + if ($post_data) { - $out .= '?'.$post_data; + $out .= '?' . $post_data; } - + return $out; - } /** * builds the data one would send in a POST request */ - public function to_postdata() { + public function to_postdata() + { return OAuthUtil::build_http_query($this->parameters); } /** * builds the Authorization: header */ - public function to_header($realm = null) { - + public function to_header($realm = null) + { $first = true; - if($realm) { + + if ($realm) { $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; $first = false; - } else + } else { $out = 'Authorization: OAuth'; - + } + $total = array(); + foreach ($this->parameters as $k => $v) { - if (substr($k, 0, 5) != "oauth") continue; + if (substr($k, 0, 5) != "oauth") { + continue; + } + if (is_array($v)) { - throw new OAuthException('Arrays not supported in headers'); + throw new OAuthException('Arrays not supported in headers'); } + $out .= ($first) ? ' ' : ','; - $out .= OAuthUtil::urlencode_rfc3986($k) . - '="' . - OAuthUtil::urlencode_rfc3986($v) . - '"'; + $out .= OAuthUtil::urlencode_rfc3986($k) . '="' . OAuthUtil::urlencode_rfc3986($v) . '"'; $first = false; } - + return $out; - } - public function __toString() { + public function __toString() + { return $this->to_url(); } - - public function sign_request($signature_method, $consumer, $token) { - - $this->set_parameter( - "oauth_signature_method", - $signature_method->get_name(), - false - ); + public function sign_request($signature_method, $consumer, $token) + { + $this->set_parameter("oauth_signature_method", $signature_method->get_name(), false); $signature = $this->build_signature($signature_method, $consumer, $token); $this->set_parameter("oauth_signature", $signature, false); - } - public function build_signature($signature_method, $consumer, $token) { + public function build_signature($signature_method, $consumer, $token) + { $signature = $signature_method->build_signature($this, $consumer, $token); return $signature; } @@ -273,18 +277,19 @@ public function build_signature($signature_method, $consumer, $token) { /** * util function: current timestamp */ - private static function generate_timestamp() { + private static function generate_timestamp() + { return time(); } /** * util function: current nonce */ - private static function generate_nonce() { + private static function generate_nonce() + { $mt = microtime(); $rand = mt_rand(); - + return md5($mt . $rand); // md5s look nicer than numbers } - } diff --git a/src/OAuth/OAuthServer.php b/src/OAuth/OAuthServer.php index 98b37bf..76cfe85 100644 --- a/src/OAuth/OAuthServer.php +++ b/src/OAuth/OAuthServer.php @@ -1,199 +1,192 @@ data_store = $data_store; } - public function add_signature_method($signature_method) { + public function add_signature_method($signature_method) + { $this->signature_methods[$signature_method->get_name()] = $signature_method; } - + // high level functions - /** * process a request_token request * returns the request token on success */ - public function fetch_request_token(&$request) { - + public function fetch_request_token(&$request) + { $this->get_version($request); - + $consumer = $this->get_consumer($request); - + // no token required for the initial token request - $token = NULL; - + $token = null; + $this->check_signature($request, $consumer, $token); - + // Rev A change $callback = $request->get_parameter('oauth_callback'); $new_token = $this->data_store->new_request_token($consumer, $callback); - + return $new_token; - } /** * process an access_token request * returns the access token on success */ - public function fetch_access_token(&$request) { - + public function fetch_access_token(&$request) + { $this->get_version($request); - + $consumer = $this->get_consumer($request); - + // requires authorized request token $token = $this->get_token($request, $consumer, "request"); - + $this->check_signature($request, $consumer, $token); - + // Rev A change $verifier = $request->get_parameter('oauth_verifier'); $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); - + return $new_token; - } /** * verify an api call, checks all the parameters */ - public function verify_request(&$request) { - + public function verify_request(&$request) + { $this->get_version($request); $consumer = $this->get_consumer($request); $token = $this->get_token($request, $consumer, "access"); $this->check_signature($request, $consumer, $token); - - return array($consumer, $token); - + + return array( + $consumer, + $token + ); } - + // Internals from here /** * version 1 */ - private function get_version(&$request) { - + private function get_version(&$request) + { $version = $request->get_parameter("oauth_version"); + if (!$version) { // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. // Chapter 7.0 ("Accessing Protected Ressources") $version = '1.0'; } + if ($version !== $this->version) { throw new OAuthException("OAuth version '$version' not supported"); } - + return $version; - } /** * figure out the signature with some defaults */ - private function get_signature_method($request) { - - $signature_method = $request instanceof OAuthRequest - ? $request->get_parameter('oauth_signature_method') : NULL; - + private function get_signature_method($request) + { + $signature_method = $request instanceof OAuthRequest ? $request->get_parameter('oauth_signature_method') : null; + if (!$signature_method) { // According to chapter 7 ("Accessing Protected Ressources") the signature-method // parameter is required, and we can't just fallback to PLAINTEXT throw new OAuthException('No signature method parameter. This parameter is required'); } - - if (!in_array($signature_method, - array_keys($this->signature_methods))) { - throw new OAuthException( - "Signature method '$signature_method' not supported " . - 'try one of the following: ' . - implode(', ', array_keys($this->signature_methods)) - ); + + if (!in_array($signature_method, array_keys($this->signature_methods))) { + throw new OAuthException("Signature method '$signature_method' not supported " . 'try one of the following: ' . + implode(', ', array_keys($this->signature_methods))); } - + return $this->signature_methods[$signature_method]; - } /** * try to find the consumer for the provided request's consumer key */ - private function get_consumer($request) { - - $consumer_key = $request instanceof OAuthRequest - ? $request->get_parameter('oauth_consumer_key') : NULL; - + private function get_consumer($request) + { + $consumer_key = $request instanceof OAuthRequest ? $request->get_parameter('oauth_consumer_key') : null; + if (!$consumer_key) { throw new OAuthException('Invalid consumer key'); } - + $consumer = $this->data_store->lookup_consumer($consumer_key); + if (!$consumer) { throw new OAuthException('Invalid consumer'); } - + return $consumer; - } /** * try to find the token for the provided request's token key */ - private function get_token($request, $consumer, $token_type="access") { - - $token_field = $request instanceof OAuthRequest - ? $request->get_parameter('oauth_token') : NULL; - + private function get_token($request, $consumer, $token_type = "access") + { + $token_field = $request instanceof OAuthRequest ? $request->get_parameter('oauth_token') : null; + $token = $this->data_store->lookup_token($consumer, $token_type, $token_field); + if (!$token) { throw new OAuthException("Invalid $token_type token: $token_field"); } - + return $token; - } /** * all-in-one function to check the signature on a request * should guess the signature method appropriately */ - private function check_signature($request, $consumer, $token) { - + private function check_signature($request, $consumer, $token) + { + // this should probably be in a different method - $timestamp = $request instanceof OAuthRequest - ? $request->get_parameter('oauth_timestamp') - : NULL; - $nonce = $request instanceof OAuthRequest - ? $request->get_parameter('oauth_nonce') - : NULL; - + $timestamp = $request instanceof OAuthRequest ? $request->get_parameter('oauth_timestamp') : null; + $nonce = $request instanceof OAuthRequest ? $request->get_parameter('oauth_nonce') : null; + $this->check_timestamp($timestamp); $this->check_nonce($consumer, $token, $nonce, $timestamp); - + $signature_method = $this->get_signature_method($request); - + $signature = $request->get_parameter('oauth_signature'); $valid_sig = $signature_method->check_signature($request, $consumer, $token, $signature); - + if (!$valid_sig) { throw new OAuthException('Invalid signature'); } @@ -202,32 +195,34 @@ private function check_signature($request, $consumer, $token) { /** * check that the timestamp is new enough */ - private function check_timestamp($timestamp) { - if(!$timestamp) + private function check_timestamp($timestamp) + { + if (!$timestamp) { throw new OAuthException('Missing timestamp parameter. The parameter is required'); - + } + // verify that timestamp is recentish $now = time(); + if (abs($now - $timestamp) > $this->timestamp_threshold) { throw new OAuthException("Expired timestamp, yours $timestamp, ours $now"); } - } /** * check that the nonce is not repeated */ - private function check_nonce($consumer, $token, $nonce, $timestamp) { - - if(!$nonce) - throw new OAuthException('Missing nonce parameter. The parameter is required'); - + private function check_nonce($consumer, $token, $nonce, $timestamp) + { + if (!$nonce) { + throw new OAuthException('Missing nonce parameter. The parameter is required'); + } + // verify that the nonce is uniqueish $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp); + if ($found) { throw new OAuthException("Nonce already used: $nonce"); } - } - } diff --git a/src/OAuth/OAuthSignatureMethod.php b/src/OAuth/OAuthSignatureMethod.php index 8fae1ed..c30db05 100644 --- a/src/OAuth/OAuthSignatureMethod.php +++ b/src/OAuth/OAuthSignatureMethod.php @@ -1,66 +1,70 @@ build_signature($request, $consumer, $token); - + // Check for zero length, although unlikely here if (strlen($built) == 0 || strlen($signature) == 0) { return false; } - + if (strlen($built) != strlen($signature)) { return false; } - + // Avoid a timing leak with a (hopefully) time insensitive compare $result = 0; for ($i = 0; $i < strlen($signature); $i++) { $result |= ord($built{$i}) ^ ord($signature{$i}); } - + return $result == 0; - } - } diff --git a/src/OAuth/OAuthSignatureMethod_HMAC_SHA1.php b/src/OAuth/OAuthSignatureMethod_HMAC_SHA1.php index f75c9cc..9ac7f80 100644 --- a/src/OAuth/OAuthSignatureMethod_HMAC_SHA1.php +++ b/src/OAuth/OAuthSignatureMethod_HMAC_SHA1.php @@ -1,42 +1,39 @@ get_signature_base_string(); $request->base_string = $base_string; - + $key_parts = array( - $consumer->secret, - ($token) ? $token->secret : "" + $consumer->secret, + ($token) ? $token->secret : "" ); - + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); $key = implode('&', $key_parts); - + return base64_encode(hash_hmac('sha1', $base_string, $key, true)); - } - } diff --git a/src/OAuth/OAuthSignatureMethod_HMAC_SHA256.php b/src/OAuth/OAuthSignatureMethod_HMAC_SHA256.php index f599d44..589caf5 100644 --- a/src/OAuth/OAuthSignatureMethod_HMAC_SHA256.php +++ b/src/OAuth/OAuthSignatureMethod_HMAC_SHA256.php @@ -1,43 +1,39 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 2015-11-30 * @license https://opensource.org/licenses/MIT The MIT License */ -/** - * The HMAC-SHA256 signature method uses the HMAC-SHA256 signature algorithm as defined in [RFC6234] - * where the Signature Base String is the text and the key is the concatenated values (each first - * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' - * character (ASCII code 38) even if empty. - */ -class OAuthSignatureMethod_HMAC_SHA256 extends OAuthSignatureMethod { +class OAuthSignatureMethod_HMAC_SHA256 extends OAuthSignatureMethod +{ - function get_name() { + public function get_name() + { return "HMAC-SHA256"; } - public function build_signature($request, $consumer, $token) { - + public function build_signature($request, $consumer, $token) + { $base_string = $request->get_signature_base_string(); $request->base_string = $base_string; - + $key_parts = array( - $consumer->secret, - ($token) ? $token->secret : "" + $consumer->secret, + ($token) ? $token->secret : "" ); - + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); $key = implode('&', $key_parts); - + return base64_encode(hash_hmac('sha256', $base_string, $key, true)); - } - } diff --git a/src/OAuth/OAuthToken.php b/src/OAuth/OAuthToken.php index 4e1f55c..e8a0691 100644 --- a/src/OAuth/OAuthToken.php +++ b/src/OAuth/OAuthToken.php @@ -1,25 +1,27 @@ key = $key; $this->secret = $secret; } @@ -28,15 +30,14 @@ function __construct($key, $secret) { * generates the basic string serialization of a token that a server * would respond to request_token and access_token calls with */ - function to_string() { - return 'oauth_token=' . - OAuthUtil::urlencode_rfc3986($this->key) . - '&oauth_token_secret=' . - OAuthUtil::urlencode_rfc3986($this->secret); + public function to_string() + { + return 'oauth_token=' . OAuthUtil::urlencode_rfc3986($this->key) . '&oauth_token_secret=' . + OAuthUtil::urlencode_rfc3986($this->secret); } - function __toString() { + public function __toString() + { return $this->to_string(); } - } diff --git a/src/OAuth/OAuthUtil.php b/src/OAuth/OAuthUtil.php index 1ad1680..0bafc38 100644 --- a/src/OAuth/OAuthUtil.php +++ b/src/OAuth/OAuthUtil.php @@ -1,69 +1,75 @@ $h) { $params[$h] = OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]); } + if (isset($params['realm'])) { unset($params['realm']); } } - + return $params; - } - + // helper to try to sort out headers for people who aren't running apache - public static function get_headers() { - + public static function get_headers() + { if (function_exists('apache_request_headers')) { // we need this to get the actual Authorization: header // because apache tends to tell us it doesn't exist $headers = apache_request_headers(); - + // sanitize the output of apache_request_headers because // we always want the keys to be Cased-Like-This and arh() // returns the headers in the same case as they are in the // request $out = array(); - foreach ($headers AS $key => $value) { + + foreach ($headers as $key => $value) { $key = str_replace(" ", "-", ucwords(strtolower(str_replace("-", " ", $key)))); $out[$key] = $value; } @@ -71,11 +77,15 @@ public static function get_headers() { // otherwise we don't have apache and are just going to have to hope // that $_SERVER actually contains what we need $out = array(); - if( isset($_SERVER['CONTENT_TYPE']) ) + + if (isset($_SERVER['CONTENT_TYPE'])) { $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; - if( isset($_ENV['CONTENT_TYPE']) ) + } + + if (isset($_ENV['CONTENT_TYPE'])) { $out['Content-Type'] = $_ENV['CONTENT_TYPE']; - + } + foreach ($_SERVER as $key => $value) { if (substr($key, 0, 5) == 'HTTP_') { // this is chaos, basically it is just there to capitalize the first @@ -86,64 +96,74 @@ public static function get_headers() { } } } + return $out; } - + // This function takes a input like a=b&a=c&d=e and returns the parsed // parameters like this // array('a' => array('b','c'), 'd' => 'e') - public static function parse_parameters( $input ) { - - if (!isset($input) || !$input) return array(); - + public static function parse_parameters($input) + { + if (!isset($input) || !$input) { + return array(); + } + $pairs = explode('&', $input); - + $parsed_parameters = array(); + foreach ($pairs as $pair) { $split = explode('=', $pair, 2); $parameter = self::urldecode_rfc3986($split[0]); $value = isset($split[1]) ? self::urldecode_rfc3986($split[1]) : ''; - + if (isset($parsed_parameters[$parameter])) { // We have already recieved parameter(s) with this name, so add to the list // of parameters with this name + if (is_scalar($parsed_parameters[$parameter])) { // This is the first duplicate, so transform scalar (string) into an array // so we can add the duplicates - $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); + $parsed_parameters[$parameter] = array( + $parsed_parameters[$parameter] + ); } - + $parsed_parameters[$parameter][] = $value; } else { $parsed_parameters[$parameter] = $value; } } - + return $parsed_parameters; - } - public static function build_http_query($params) { - - if (!$params) return ''; - + public static function build_http_query($params) + { + if (!$params) { + return ''; + } + // Urlencode both keys and values $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); $values = OAuthUtil::urlencode_rfc3986(array_values($params)); $params = array_combine($keys, $values); - + // Parameters are sorted by name, using lexicographical byte value ordering. // Ref: Spec: 9.1.1 (1) uksort($params, 'strcmp'); - + $pairs = array(); + foreach ($params as $parameter => $value) { if (is_array($value)) { // If two or more parameters share the same name, they are sorted by their value // Ref: Spec: 9.1.1 (1) // June 12th, 2010 - changed to sort because of issue 164 by hidetaka sort($value, SORT_STRING); + foreach ($value as $duplicate_value) { $pairs[] = $parameter . '=' . $duplicate_value; } @@ -151,11 +171,9 @@ public static function build_http_query($params) { $pairs[] = $parameter . '=' . $value; } } - + // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) // Each name-value pair is separated by an '&' character (ASCII code 38) return implode('&', $pairs); - } - } diff --git a/src/Profile/Item.php b/src/Profile/Item.php index 3367704..e86737d 100644 --- a/src/Profile/Item.php +++ b/src/Profile/Item.php @@ -1,77 +1,52 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class Item { -/** - * ID of item. - * - * @var string $id - */ + /** @var string ID of item. */ public $id = null; -/** - * Name of item. - * - * @var string $name - */ + + /** @var string Name of item. */ public $name = null; -/** - * Description of item. - * - * @var string $description - */ + + /** @var string Description of item. */ public $description = null; -/** - * URL of item. - * - * @var string $url - */ + + /** @var string URL of item. */ public $url = null; -/** - * Version of item. - * - * @var string $version - */ + + /** @var string Version of item. */ public $version = null; -/** - * Timestamp of item. - * - * @var int $timestamp - */ - public $timestamp = null; -/** - * Class constructor. - * - * @param string $id ID of item (optional) - * @param string $name Name of item (optional) - * @param string $description Description of item (optional) - * @param string $url URL of item (optional) - * @param string $version Version of item (optional) - * @param int $timestamp Timestamp of item (optional) - */ + /** @var int Timestamp of item. */ + public $timestamp = null; - function __construct($id = null, $name = null, $description = null, $url = null, $version = null, $timestamp = null) + /** + * Class constructor. + * + * @param string $id ID of item (optional). + * @param string $name Name of item (optional). + * @param string $description Description of item (optional). + * @param string $url URL of item (optional). + * @param string $version Version of item (optional). + * @param int $timestamp Timestamp of item (optional). + */ + public function __construct($id = null, $name = null, $description = null, $url = null, $version = null, $timestamp = null) { - $this->id = $id; $this->name = $name; $this->description = $description; $this->url = $url; $this->version = $version; $this->timestamp = $timestamp; - } - } diff --git a/src/Profile/Message.php b/src/Profile/Message.php index 85ccf23..4b0d047 100644 --- a/src/Profile/Message.php +++ b/src/Profile/Message.php @@ -1,71 +1,47 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ - class Message { -/** - * LTI message type. - * - * @var string $type - */ + /** @var string LTI message type. */ public $type = null; -/** - * Path to send message request to (used in conjunction with a base URL for the Tool Provider). - * - * @var string $path - */ + + /** @var string Path to send message request to (used in conjunction with a base URL for the Tool Provider). */ public $path = null; -/** - * Capabilities required by message. - * - * @var array $capabilities - */ + + /** @var array Capabilities required by message. */ public $capabilities = null; -/** - * Variable parameters to accompany message request. - * - * @var array $variables - */ + + /** @var array Variable parameters to accompany message request. */ public $variables = null; -/** - * Fixed parameters to accompany message request. - * - * @var array $constants - */ - public $constants = null; + /** @var array Fixed parameters to accompany message request. */ + public $constants = null; -/** - * Class constructor. - * - * @param string $type LTI message type - * @param string $path Path to send message request to - * @param array $capabilities Array of capabilities required by message - * @param array $variables Array of variable parameters to accompany message request - * @param array $constants Array of fixed parameters to accompany message request - */ - function __construct($type, $path, $capabilities = array(), $variables = array(), $constants = array()) + /** + * Class constructor. + * + * @param string $type LTI message type. + * @param string $path Path to send message request to. + * @param array $capabilities Array of capabilities required by message. + * @param array $variables Array of variable parameters to accompany message request. + * @param array $constants Array of fixed parameters to accompany message request. + */ + public function __construct($type, $path, $capabilities = array(), $variables = array(), $constants = array()) { - $this->type = $type; $this->path = $path; $this->capabilities = $capabilities; $this->variables = $variables; $this->constants = $constants; - } - } diff --git a/src/Profile/ResourceHandler.php b/src/Profile/ResourceHandler.php index c86eab7..9a684ec 100644 --- a/src/Profile/ResourceHandler.php +++ b/src/Profile/ResourceHandler.php @@ -1,61 +1,42 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ - class ResourceHandler { -/** - * General details of resource handler. - * - * @var Item $item - */ + /** @var Item General details of resource handler. */ public $item = null; -/** - * URL of icon. - * - * @var string $icon - */ + + /** @var string URL of icon. */ public $icon = null; -/** - * Required Message objects for resource handler. - * - * @var array $requiredMessages - */ + + /** @var array Required Message objects for resource handler. */ public $requiredMessages = null; -/** - * Optional Message objects for resource handler. - * - * @var array $optionalMessages - */ + + /** @var array Optional Message objects for resource handler. */ public $optionalMessages = null; -/** - * Class constructor. - * - * @param Item $item General details of resource handler - * @param string $icon URL of icon - * @param array $requiredMessages Array of required Message objects for resource handler - * @param array $optionalMessages Array of optional Message objects for resource handler - */ - function __construct($item, $icon, $requiredMessages, $optionalMessages) + /** + * Class constructor. + * + * @param Item $item General details of resource handler. + * @param string $icon URL of icon. + * @param array $requiredMessages Array of required Message objects for resource handler. + * @param array $optionalMessages Array of optional Message objects for resource handler. + */ + public function __construct($item, $icon, $requiredMessages, $optionalMessages) { - $this->item = $item; $this->icon = $icon; $this->requiredMessages = $requiredMessages; $this->optionalMessages = $optionalMessages; - } - } diff --git a/src/Profile/ServiceDefinition.php b/src/Profile/ServiceDefinition.php index b21919e..cbb988e 100644 --- a/src/Profile/ServiceDefinition.php +++ b/src/Profile/ServiceDefinition.php @@ -1,68 +1,47 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ - class ServiceDefinition { -/** - * Media types supported by service. - * - * @var array $formats - */ + /** @var array Media types supported by service. */ public $formats = null; -/** - * HTTP actions accepted by service. - * - * @var array $actions - */ + + /** @var array HTTP actions accepted by service. */ public $actions = null; -/** - * ID of service. - * - * @var string $id - */ + + /** @var string ID of service. */ public $id = null; -/** - * URL for service requests. - * - * @var string $endpoint - */ - public $endpoint = null; -/** - * Class constructor. - * - * @param array $formats Array of media types supported by service - * @param array $actions Array of HTTP actions accepted by service - * @param string $id ID of service (optional) - * @param string $endpoint URL for service requests (optional) - */ + /** @var string URL for service requests. */ + public $endpoint = null; - function __construct($formats, $actions, $id = null, $endpoint = null) + /** + * Class constructor. + * + * @param array $formats Array of media types supported by service. + * @param array $actions Array of HTTP actions accepted by service. + * @param string $id ID of service (optional). + * @param string $endpoint URL for service requests (optional). + */ + public function __construct($formats, $actions, $id = null, $endpoint = null) { - $this->formats = $formats; $this->actions = $actions; $this->id = $id; $this->endpoint = $endpoint; - } - function setId($id) { - + public function setId($id) + { $this->id = $id; - } - } diff --git a/src/ToolProvider/ConsumerNonce.php b/src/ToolProvider/ConsumerNonce.php index e60606c..c43d1d2 100644 --- a/src/ToolProvider/ConsumerNonce.php +++ b/src/ToolProvider/ConsumerNonce.php @@ -1,105 +1,79 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ConsumerNonce { + + /** @var int Maximum age nonce values will be retained for (in minutes). */ + const MAX_NONCE_AGE = 30; -/** - * Maximum age nonce values will be retained for (in minutes). - */ - const MAX_NONCE_AGE = 30; // in minutes - -/** - * Date/time when the nonce value expires. - * - * @var int $expires - */ + /** @var int Date/time when the nonce value expires. */ public $expires = null; -/** - * Tool Consumer to which this nonce applies. - * - * @var ToolConsumer $consumer - */ + /** @var ToolConsumer Tool Consumer to which this nonce applies. */ private $consumer = null; -/** - * Nonce value. - * - * @var string $value - */ + + /** @var string Nonce value. */ private $value = null; -/** - * Class constructor. - * - * @param ToolConsumer $consumer Consumer object - * @param string $value Nonce value (optional, default is null) - */ + /** + * Class constructor. + * + * @param ToolConsumer $consumer Consumer object. + * @param string|null $value Nonce value (optional, default is NULL). + */ public function __construct($consumer, $value = null) { - $this->consumer = $consumer; $this->value = $value; $this->expires = time() + (self::MAX_NONCE_AGE * 60); - } -/** - * Load a nonce value from the database. - * - * @return boolean True if the nonce value was successfully loaded - */ + /** + * Load a nonce value from the database. + * + * @return bool TRUE if the nonce value was successfully loaded + */ public function load() { - return $this->consumer->getDataConnector()->loadConsumerNonce($this); - } -/** - * Save a nonce value in the database. - * - * @return boolean True if the nonce value was successfully saved - */ + /** + * Save a nonce value in the database. + * + * @return bool TRUE if the nonce value was successfully saved + */ public function save() { - return $this->consumer->getDataConnector()->saveConsumerNonce($this); - } -/** - * Get tool consumer. - * - * @return ToolConsumer Consumer for this nonce - */ + /** + * Get tool consumer. + * + * @return ToolConsumer Consumer for this nonce + */ public function getConsumer() { - return $this->consumer; - } -/** - * Get outcome value. - * - * @return string Outcome value - */ + /** + * Get outcome value. + * + * @return string Outcome value + */ public function getValue() { - return $this->value; - } - } diff --git a/src/ToolProvider/ContentItem.php b/src/ToolProvider/ContentItem.php index e1e2f05..a06f324 100644 --- a/src/ToolProvider/ContentItem.php +++ b/src/ToolProvider/ContentItem.php @@ -1,138 +1,128 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ContentItem { - -/** - * Media type for LTI launch links. - */ + + /** @var string Media type for LTI launch links. */ const LTI_LINK_MEDIA_TYPE = 'application/vnd.ims.lti.v1.ltilink'; -/** - * Class constructor. - * - * @param string $type Class type of content-item - * @param ContentItemPlacement $placementAdvice Placement object for item (optional) - * @param string $id URL of content-item (optional) - */ - function __construct($type, $placementAdvice = null, $id = null) + /** + * Class constructor. + * + * @param string $type Class type of content-item. + * @param ContentItemPlacement $placementAdvice Placement object for item (optional). + * @param string $id URL of content-item (optional). + */ + public function __construct($type, $placementAdvice = null, $id = null) { - $this->{'@type'} = $type; + if (is_object($placementAdvice) && (count(get_object_vars($placementAdvice)) > 0)) { $this->placementAdvice = $placementAdvice; } + if (!empty($id)) { $this->{'@id'} = $id; } - } -/** - * Set a URL value for the content-item. - * - * @param string $url URL value - */ + /** + * Set a URL value for the content-item. + * + * @param string $url URL value. + */ public function setUrl($url) { - if (!empty($url)) { $this->url = $url; } else { unset($this->url); } - } -/** - * Set a media type value for the content-item. - * - * @param string $mediaType Media type value - */ + /** + * Set a media type value for the content-item. + * + * @param string $mediaType Media type value. + */ public function setMediaType($mediaType) { - if (!empty($mediaType)) { $this->mediaType = $mediaType; } else { unset($this->mediaType); } - } -/** - * Set a title value for the content-item. - * - * @param string $title Title value - */ + /** + * Set a title value for the content-item. + * + * @param string $title Title value. + */ public function setTitle($title) { - if (!empty($title)) { $this->title = $title; - } else if (isset($this->title)) { + } elseif (isset($this->title)) { unset($this->title); } - } -/** - * Set a link text value for the content-item. - * - * @param string $text Link text value - */ + /** + * Set a link text value for the content-item. + * + * @param string $text Link text value. + */ public function setText($text) { - if (!empty($text)) { $this->text = $text; - } else if (isset($this->text)) { + } elseif (isset($this->text)) { unset($this->text); } - } -/** - * Wrap the content items to form a complete application/vnd.ims.lti.v1.contentitems+json media type instance. - * - * @param mixed $items An array of content items or a single item - * @return string - */ + /** + * Wrap the content items to form a complete application/vnd.ims.lti.v1.contentitems+json media type instance. + * + * @param mixed $items An array of content items or a single item. + * + * @return string + */ public static function toJson($items) { -/* - $data = array(); - if (!is_array($items)) { - $data[] = json_encode($items); - } else { - foreach ($items as $item) { - $data[] = json_encode($item); - } - } - $json = '{ "@context" : "http://purl.imsglobal.org/ctx/lti/v1/ContentItem", "@graph" : [' . implode(", ", $data) . '] }'; -*/ + /* + $data = array(); + + if (!is_array($items)) { + $data[] = json_encode($items); + } else { + foreach ($items as $item) { + $data[] = json_encode($item); + } + } + + $json = '{ "@context" : "http://purl.imsglobal.org/ctx/lti/v1/ContentItem", "@graph" : [' . implode(", ", $data) . '] }'; + */ $obj = new \stdClass(); $obj->{'@context'} = 'http://purl.imsglobal.org/ctx/lti/v1/ContentItem'; + if (!is_array($items)) { - $obj->{'@graph'} = array(); - $obj->{'@graph'}[] = $items; + $obj->{'@graph'} = array(); + $obj->{'@graph'}[] = $items; } else { - $obj->{'@graph'} = $items; + $obj->{'@graph'} = $items; } - + return json_encode($obj); - } - } diff --git a/src/ToolProvider/ContentItemImage.php b/src/ToolProvider/ContentItemImage.php index 8609195..6109284 100644 --- a/src/ToolProvider/ContentItemImage.php +++ b/src/ToolProvider/ContentItemImage.php @@ -1,37 +1,34 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ContentItemImage { -/** - * Class constructor. - * - * @param string $id URL of image - * @param int $height Height of image in pixels (optional) - * @param int $width Width of image in pixels (optional) - */ - function __construct($id, $height = null, $width = null) + /** + * Class constructor. + * + * @param string $id URL of image. + * @param int $height Height of image in pixels (optional). + * @param int $width Width of image in pixels (optional). + */ + public function __construct($id, $height = null, $width = null) { - $this->{'@id'} = $id; + if (!is_null($height)) { $this->height = $height; } + if (!is_null($width)) { $this->width = $width; } - } - } diff --git a/src/ToolProvider/ContentItemPlacement.php b/src/ToolProvider/ContentItemPlacement.php index f9397a4..e9795d9 100644 --- a/src/ToolProvider/ContentItemPlacement.php +++ b/src/ToolProvider/ContentItemPlacement.php @@ -1,43 +1,41 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ContentItemPlacement { -/** - * Class constructor. - * - * @param int $displayWidth Width of item location - * @param int $displayHeight Height of item location - * @param string $documentTarget Location to open content in - * @param string $windowTarget Name of window target - */ - function __construct($displayWidth, $displayHeight, $documentTarget, $windowTarget) + /** + * Class constructor. + * + * @param int $displayWidth Width of item location. + * @param int $displayHeight Height of item location. + * @param string $documentTarget Location to open content in. + * @param string $windowTarget Name of window target. + */ + public function __construct($displayWidth, $displayHeight, $documentTarget, $windowTarget) { - if (!empty($displayWidth)) { $this->displayWidth = $displayWidth; } + if (!empty($displayHeight)) { $this->displayHeight = $displayHeight; } + if (!empty($documentTarget)) { $this->documentTarget = $documentTarget; } + if (!empty($windowTarget)) { $this->windowTarget = $windowTarget; } - } - } diff --git a/src/ToolProvider/Context.php b/src/ToolProvider/Context.php index 6f585ad..ca0ad4e 100644 --- a/src/ToolProvider/Context.php +++ b/src/ToolProvider/Context.php @@ -1,460 +1,382 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class Context { -/** - * Context ID as supplied in the last connection request. - * - * @var string $ltiContextId - */ + /** @var string Context ID as supplied in the last connection request. */ public $ltiContextId = null; -/** - * Context title. - * - * @var string $title - */ + + /** @var string Context title. */ public $title = null; -/** - * Setting values (LTI parameters, custom parameters and local parameters). - * - * @var array $settings - */ + + /** @var array Setting values (LTI parameters, custom parameters and local parameters). */ public $settings = null; -/** - * Date/time when the object was created. - * - * @var int $created - */ + + /** @var int Date/time when the object was created. */ public $created = null; -/** - * Date/time when the object was last updated. - * - * @var int $updated - */ + + /** @var int Date/time when the object was last updated. */ public $updated = null; -/** - * Tool Consumer for this context. - * - * @var ToolConsumer $consumer - */ + /** @var ToolConsumer Tool Consumer for this context. */ private $consumer = null; -/** - * Tool Consumer ID for this context. - * - * @var int $consumerId - */ + + /** @var int Tool Consumer ID for this context. */ private $consumerId = null; -/** - * ID for this context. - * - * @var int $id - */ + + /** @var int ID for this context. */ private $id = null; -/** - * Whether the settings value have changed since last saved. - * - * @var boolean $settingsChanged - */ + + /** @var bool Whether the settings value have changed since last saved. */ private $settingsChanged = false; -/** - * Data connector object or string. - * - * @var mixed $dataConnector - */ + + /** @var mixed Data connector object or string. */ private $dataConnector = null; -/** - * Class constructor. - */ + /** + * Class constructor. + */ public function __construct() { - $this->initialize(); - } -/** - * Initialise the context. - */ + /** + * Initialise the context. + */ public function initialize() { - $this->title = ''; $this->settings = array(); $this->created = null; $this->updated = null; - } -/** - * Initialise the context. - * - * Pseudonym for initialize(). - */ + /** + * Initialise the context. + * + * Pseudonym for initialize(). + */ public function initialise() { - $this->initialize(); - } -/** - * Save the context to the database. - * - * @return boolean True if the context was successfully saved. - */ + /** + * Save the context to the database. + * + * @return boolean True if the context was successfully saved. + */ public function save() { - $ok = $this->getDataConnector()->saveContext($this); + if ($ok) { $this->settingsChanged = false; } - + return $ok; - } -/** - * Delete the context from the database. - * - * @return boolean True if the context was successfully deleted. - */ + /** + * Delete the context from the database. + * + * @return boolean True if the context was successfully deleted. + */ public function delete() { - return $this->getDataConnector()->deleteContext($this); - } -/** - * Get tool consumer. - * - * @return ToolConsumer Tool consumer object for this context. - */ + /** + * Get tool consumer. + * + * @return ToolConsumer Tool consumer object for this context. + */ public function getConsumer() { - if (is_null($this->consumer)) { $this->consumer = ToolConsumer::fromRecordId($this->consumerId, $this->getDataConnector()); } - + return $this->consumer; - } -/** - * Set tool consumer ID. - * - * @param int $consumerId Tool Consumer ID for this resource link. - */ + + /** + * Set tool consumer ID. + * + * @param int $consumerId Tool Consumer ID for this resource link. + */ public function setConsumerId($consumerId) { - $this->consumer = null; $this->consumerId = $consumerId; - } -/** - * Get tool consumer key. - * - * @return string Consumer key value for this context. - */ + /** + * Get tool consumer key. + * + * @return string Consumer key value for this context. + */ public function getKey() { - return $this->getConsumer()->getKey(); - } -/** - * Get context ID. - * - * @return string ID for this context. - */ + /** + * Get context ID. + * + * @return string ID for this context. + */ public function getId() { - return $this->ltiContextId; - } -/** - * Get the context record ID. - * - * @return int Context record ID value - */ + /** + * Get the context record ID. + * + * @return int Context record ID value + */ public function getRecordId() { - return $this->id; - } -/** - * Sets the context record ID. - * - * @return int $id Context record ID value - */ + /** + * Sets the context record ID. + * + * @return int $id Context record ID value + */ public function setRecordId($id) { - $this->id = $id; - } -/** - * Get the data connector. - * - * @return mixed Data connector object or string - */ + /** + * Get the data connector. + * + * @return mixed Data connector object or string + */ public function getDataConnector() { - return $this->dataConnector; - } -/** - * Get a setting value. - * - * @param string $name Name of setting - * @param string $default Value to return if the setting does not exist (optional, default is an empty string) - * - * @return string Setting value - */ + /** + * Get a setting value. + * + * @param string $name Name of setting. + * @param string $default Value to return if the setting does not exist (optional, default is an empty string). + * + * @return string Setting value + */ public function getSetting($name, $default = '') { - if (array_key_exists($name, $this->settings)) { $value = $this->settings[$name]; } else { $value = $default; } - + return $value; - } -/** - * Set a setting value. - * - * @param string $name Name of setting - * @param string $value Value to set, use an empty value to delete a setting (optional, default is null) - */ + /** + * Set a setting value. + * + * @param string $name Name of setting. + * @param string $value Value to set, use an empty value to delete a setting (optional, default is null). + */ public function setSetting($name, $value = null) { - $old_value = $this->getSetting($name); + if ($value !== $old_value) { if (!empty($value)) { $this->settings[$name] = $value; } else { unset($this->settings[$name]); } + $this->settingsChanged = true; } - } -/** - * Get an array of all setting values. - * - * @return array Associative array of setting values - */ + /** + * Get an array of all setting values. + * + * @return array Associative array of setting values + */ public function getSettings() { - return $this->settings; - } -/** - * Set an array of all setting values. - * - * @param array $settings Associative array of setting values - */ + /** + * Set an array of all setting values. + * + * @param array $settings Associative array of setting values. + */ public function setSettings($settings) { - $this->settings = $settings; - } -/** - * Save setting values. - * - * @return boolean True if the settings were successfully saved - */ + /** + * Save setting values. + * + * @return boolean True if the settings were successfully saved + */ public function saveSettings() { - if ($this->settingsChanged) { $ok = $this->save(); } else { $ok = true; } - + return $ok; - } -/** - * Check if the Tool Settings service is supported. - * - * @return boolean True if this context supports the Tool Settings service - */ + /** + * Check if the Tool Settings service is supported. + * + * @return boolean True if this context supports the Tool Settings service + */ public function hasToolSettingsService() { - $url = $this->getSetting('custom_context_setting_url'); - + return !empty($url); - } -/** - * Get Tool Settings. - * - * @param int $mode Mode for request (optional, default is current level only) - * @param boolean $simple True if all the simple media type is to be used (optional, default is true) - * - * @return mixed The array of settings if successful, otherwise false - */ + /** + * Get Tool Settings. + * + * @param int $mode Mode for request (optional, default is current level only). + * @param bool $simple True if all the simple media type is to be used (optional, default is true). + * + * @return mixed The array of settings if successful, otherwise false + */ public function getToolSettings($mode = Service\ToolSettings::MODE_CURRENT_LEVEL, $simple = true) { - $url = $this->getSetting('custom_context_setting_url'); $service = new Service\ToolSettings($this, $url, $simple); $response = $service->get($mode); - + return $response; - } -/** - * Perform a Tool Settings service request. - * - * @param array $settings An associative array of settings (optional, default is none) - * - * @return boolean True if action was successful, otherwise false - */ + /** + * Perform a Tool Settings service request. + * + * @param array $settings An associative array of settings (optional, default is none). + * + * @return boolean True if action was successful, otherwise false + */ public function setToolSettings($settings = array()) { - $url = $this->getSetting('custom_context_setting_url'); $service = new Service\ToolSettings($this, $url); $response = $service->set($settings); - + return $response; - } -/** - * Check if the Membership service is supported. - * - * @return boolean True if this context supports the Membership service - */ + /** + * Check if the Membership service is supported. + * + * @return boolean True if this context supports the Membership service + */ public function hasMembershipService() { - $url = $this->getSetting('custom_context_memberships_url'); - + return !empty($url); - } -/** - * Get Memberships. - * - * @return mixed The array of User objects if successful, otherwise false - */ + /** + * Get Memberships. + * + * @return mixed The array of User objects if successful, otherwise false + */ public function getMembership() { - $url = $this->getSetting('custom_context_memberships_url'); $service = new Service\Membership($this, $url); $response = $service->get(); - + return $response; - } -/** - * Load the context from the database. - * - * @param int $id Record ID of context - * @param DataConnector $dataConnector Database connection object - * - * @return Context Context object - */ + /** + * Load the context from the database. + * + * @param int $id Record ID of context. + * @param DataConnector $dataConnector Database connection object. + * + * @return Context Context object + */ public static function fromRecordId($id, $dataConnector) { - $context = new Context(); $context->dataConnector = $dataConnector; $context->load($id); - + return $context; - } -/** - * Class constructor from consumer. - * - * @param ToolConsumer $consumer Consumer instance - * @param string $ltiContextId LTI Context ID value - * @return Context - */ + /** + * Class constructor from consumer. + * + * @param ToolConsumer $consumer Consumer instance. + * @param string $ltiContextId LTI Context ID value. + * + * @return Context + */ public static function fromConsumer($consumer, $ltiContextId) { - $context = new Context(); $context->consumer = $consumer; $context->dataConnector = $consumer->getDataConnector(); $context->ltiContextId = $ltiContextId; + if (!empty($ltiContextId)) { $context->load(); } - + return $context; - } - -### -### PRIVATE METHODS -### - -/** - * Load the context from the database. - * - * @param int $id Record ID of context (optional, default is null) - * - * @return boolean True if context was successfully loaded - */ + + ### + ### PRIVATE METHODS + ### + + + /** + * Load the context from the database. + * + * @param int $id Record ID of context (optional, default is null). + * + * @return boolean True if context was successfully loaded + */ private function load($id = null) { - $this->initialize(); $this->id = $id; return $this->getDataConnector()->loadContext($this); - } - } diff --git a/src/ToolProvider/DataConnector/DataConnector.php b/src/ToolProvider/DataConnector/DataConnector.php index 9a31d6e..8b61656 100644 --- a/src/ToolProvider/DataConnector/DataConnector.php +++ b/src/ToolProvider/DataConnector/DataConnector.php @@ -1,5 +1,4 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class DataConnector { - -/** - * Default name for database table used to store tool consumers. - */ + + /** + * Default name for database table used to store tool consumers. + */ const CONSUMER_TABLE_NAME = 'lti2_consumer'; -/** - * Default name for database table used to store pending tool proxies. - */ + /** + * Default name for database table used to store pending tool proxies. + */ const TOOL_PROXY_TABLE_NAME = 'lti2_tool_proxy'; -/** - * Default name for database table used to store contexts. - */ + /** + * Default name for database table used to store contexts. + */ const CONTEXT_TABLE_NAME = 'lti2_context'; -/** - * Default name for database table used to store resource links. - */ + /** + * Default name for database table used to store resource links. + */ const RESOURCE_LINK_TABLE_NAME = 'lti2_resource_link'; -/** - * Default name for database table used to store users. - */ + /** + * Default name for database table used to store users. + */ const USER_RESULT_TABLE_NAME = 'lti2_user_result'; -/** - * Default name for database table used to store resource link share keys. - */ + /** + * Default name for database table used to store resource link share keys. + */ const RESOURCE_LINK_SHARE_KEY_TABLE_NAME = 'lti2_share_key'; -/** - * Default name for database table used to store nonce values. - */ + /** + * Default name for database table used to store nonce values. + */ const NONCE_TABLE_NAME = 'lti2_nonce'; -/** - * Database object. - * - * @var object $db - */ + /** @var object Database object. */ protected $db = null; -/** - * Prefix for database table names. - * - * @var string $dbTableNamePrefix - */ + + /** @var string Prefix for database table names. */ protected $dbTableNamePrefix = ''; -/** - * SQL date format (default = 'Y-m-d') - * - * @var string $dateFormat - */ + + /** @var string SQL date format (default = 'Y-m-d'). */ protected $dateFormat = 'Y-m-d'; -/** - * SQL time format (default = 'H:i:s') - * - * @var string $timeFormat - */ + + /** @var string SQL time format (default = 'H:i:s'). */ protected $timeFormat = 'H:i:s'; -/** - * Class constructor - * - * @param object $db Database connection object - * @param string $dbTableNamePrefix Prefix for database table names (optional, default is none) - */ + /** + * Class constructor. + * + * @param object $db Database connection object. + * @param string $dbTableNamePrefix Prefix for database table names (optional, default is none). + */ public function __construct($db, $dbTableNamePrefix = '') { - $this->db = $db; $this->dbTableNamePrefix = $dbTableNamePrefix; - } - -### -### ToolConsumer methods -### - -/** - * Load tool consumer object. - * - * @param ToolConsumer $consumer ToolConsumer object - * - * @return boolean True if the tool consumer object was successfully loaded - */ + + ### + ### ToolConsumer methods + ### + + + /** + * Load tool consumer object. + * + * @param ToolConsumer $consumer ToolConsumer object. + * + * @return bool TRUE if the tool consumer object was successfully loaded + */ public function loadToolConsumer($consumer) { - $consumer->secret = 'secret'; $consumer->enabled = true; $now = time(); $consumer->created = $now; $consumer->updated = $now; - + return true; - } -/** - * Save tool consumer object. - * - * @param ToolConsumer $consumer Consumer object - * - * @return boolean True if the tool consumer object was successfully saved - */ + /** + * Save tool consumer object. + * + * @param ToolConsumer $consumer Consumer object. + * + * @return bool TRUE if the tool consumer object was successfully saved + */ public function saveToolConsumer($consumer) { - $consumer->updated = time(); - + return true; - } -/** - * Delete tool consumer object. - * - * @param ToolConsumer $consumer Consumer object - * - * @return boolean True if the tool consumer object was successfully deleted - */ + /** + * Delete tool consumer object. + * + * @param ToolConsumer $consumer Consumer object. + * + * @return bool TRUE if the tool consumer object was successfully deleted + */ public function deleteToolConsumer($consumer) { - $consumer->initialize(); - + return true; - } -/** - * Load tool consumer objects. - * - * @return array Array of all defined ToolConsumer objects - */ + /** + * Load tool consumer objects. + * + * @return array Array of all defined ToolConsumer objects + */ public function getToolConsumers() { - return array(); - } - - -### -### ToolProxy methods -### - -/** - * Load tool proxy object. - * - * @param ToolProxy $toolProxy ToolProxy object - * - * @return boolean True if the tool proxy object was successfully loaded - */ + + ### + ### ToolProxy methods + ### + + + /** + * Load tool proxy object. + * + * @param ToolProxy $toolProxy ToolProxy object. + * + * @return bool TRUE if the tool proxy object was successfully loaded + */ public function loadToolProxy($toolProxy) { - $now = time(); $toolProxy->created = $now; $toolProxy->updated = $now; - + return true; - } -/** - * Save tool proxy object. - * - * @param ToolProxy $toolProxy ToolProxy object - * - * @return boolean True if the tool proxy object was successfully saved - */ + /** + * Save tool proxy object. + * + * @param ToolProxy $toolProxy ToolProxy object. + * + * @return bool TRUE if the tool proxy object was successfully saved + */ public function saveToolProxy($toolProxy) { - $toolProxy->updated = time(); - + return true; - } -/** - * Delete tool proxy object. - * - * @param ToolProxy $toolProxy ToolProxy object - * - * @return boolean True if the tool proxy object was successfully deleted - */ + /** + * Delete tool proxy object. + * + * @param ToolProxy $toolProxy ToolProxy object. + * + * @return bool TRUE if the tool proxy object was successfully deleted + */ public function deleteToolProxy($toolProxy) { - $toolProxy->initialize(); - + return true; - } - -### -### Context methods -### - -/** - * Load context object. - * - * @param Context $context Context object - * - * @return boolean True if the context object was successfully loaded - */ + + ### + ### Context methods + ### + + + /** + * Load context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the context object was successfully loaded + */ public function loadContext($context) { - $now = time(); $context->created = $now; $context->updated = $now; - + return true; - } -/** - * Save context object. - * - * @param Context $context Context object - * - * @return boolean True if the context object was successfully saved - */ + /** + * Save context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the context object was successfully saved + */ public function saveContext($context) { - $context->updated = time(); - + return true; - } -/** - * Delete context object. - * - * @param Context $context Context object - * - * @return boolean True if the Context object was successfully deleted - */ + /** + * Delete context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the Context object was successfully deleted + */ public function deleteContext($context) { - $context->initialize(); - + return true; - } - -### -### ResourceLink methods -### - -/** - * Load resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully loaded - */ + + ### + ### ResourceLink methods + ### + + + /** + * Load resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully loaded + */ public function loadResourceLink($resourceLink) { - $now = time(); $resourceLink->created = $now; $resourceLink->updated = $now; - + return true; - } -/** - * Save resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully saved - */ + /** + * Save resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully saved + */ public function saveResourceLink($resourceLink) { - $resourceLink->updated = time(); - + return true; - } -/** - * Delete resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully deleted - */ + /** + * Delete resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully deleted + */ public function deleteResourceLink($resourceLink) { - $resourceLink->initialize(); - + return true; - } -/** - * Get array of user objects. - * - * Obtain an array of User objects for users with a result sourcedId. The array may include users from other - * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope. - * - * @param ResourceLink $resourceLink Resource link object - * @param boolean $localOnly True if only users within the resource link are to be returned (excluding users sharing this resource link) - * @param int $idScope Scope value to use for user IDs - * - * @return array Array of User objects - */ + /** + * Get array of user objects. + * + * Obtain an array of User objects for users with a result sourcedId. The array may include users from other + * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope. + * + * @param ResourceLink $resourceLink Resource link object. + * @param bool $localOnly TRUE if only users within the resource link are to be returned (excluding users sharing this resource link). + * @param int $idScope Scope value to use for user IDs. + * + * @return array Array of User objects + */ public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $idScope) { - return array(); - } -/** - * Get array of shares defined for this resource link. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return array Array of ResourceLinkShare objects - */ + /** + * Get array of shares defined for this resource link. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return array Array of ResourceLinkShare objects + */ public function getSharesResourceLink($resourceLink) { - return array(); - } - -### -### ConsumerNonce methods -### - -/** - * Load nonce object. - * - * @param ConsumerNonce $nonce Nonce object - * - * @return boolean True if the nonce object was successfully loaded - */ + + ### + ### ConsumerNonce methods + ### + + + /** + * Load nonce object. + * + * @param ConsumerNonce $nonce Nonce object. + * + * @return bool TRUE if the nonce object was successfully loaded + */ public function loadConsumerNonce($nonce) { - return false; // assume the nonce does not already exist - + return false; // assume the nonce does not already exist } -/** - * Save nonce object. - * - * @param ConsumerNonce $nonce Nonce object - * - * @return boolean True if the nonce object was successfully saved - */ + /** + * Save nonce object. + * + * @param ConsumerNonce $nonce Nonce object. + * + * @return bool TRUE if the nonce object was successfully saved + */ public function saveConsumerNonce($nonce) { - return true; - } - -### -### ResourceLinkShareKey methods -### - -/** - * Load resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource_Link share key object - * - * @return boolean True if the resource link share key object was successfully loaded - */ + + ### + ### ResourceLinkShareKey methods + ### + + + /** + * Load resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource_Link share key object. + * + * @return bool TRUE if the resource link share key object was successfully loaded + */ public function loadResourceLinkShareKey($shareKey) { - return true; - } -/** - * Save resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource link share key object - * - * @return boolean True if the resource link share key object was successfully saved - */ + /** + * Save resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource link share key object. + * + * @return bool TRUE if the resource link share key object was successfully saved + */ public function saveResourceLinkShareKey($shareKey) { - return true; - } -/** - * Delete resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource link share key object - * - * @return boolean True if the resource link share key object was successfully deleted - */ + /** + * Delete resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource link share key object. + * + * @return bool TRUE if the resource link share key object was successfully deleted + */ public function deleteResourceLinkShareKey($shareKey) { - return true; - } - -### -### User methods -### - -/** - * Load user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully loaded - */ + + ### + ### User methods + ### + + + /** + * Load user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully loaded + */ public function loadUser($user) { - $now = time(); $user->created = $now; $user->updated = $now; - + return true; - } -/** - * Save user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully saved - */ + /** + * Save user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully saved + */ public function saveUser($user) { - $user->updated = time(); - + return true; - } -/** - * Delete user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully deleted - */ + /** + * Delete user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully deleted + */ public function deleteUser($user) { - $user->initialize(); - + return true; - } - -### -### Other methods -### - -/** - * Return a hash of a consumer key for values longer than 255 characters. - * - * @param string $key - * @return string - */ + + ### + ### Other methods + ### + + + /** + * Return a hash of a consumer key for values longer than 255 characters. + * + * @param string $key. + * + * @return string + */ protected static function getConsumerKey($key) { - $len = strlen($key); + if ($len > 255) { $key = 'sha512:' . hash('sha512', $key); } - + return $key; - } -/** - * Create data connector object. - * - * A data connector provides access to persistent storage for the different objects. - * - * Names of tables may be given a prefix to allow multiple versions to share the same schema. A separate sub-class is defined for - * each different database connection - the class to use is determined by inspecting the database object passed, but this can be overridden - * (for example, to use a bespoke connector) by specifying a type. If no database is passed then this class is used which acts as a dummy - * connector with no persistence. - * - * @param string $dbTableNamePrefix Prefix for database table names (optional, default is none) - * @param object $db A database connection object or string (optional, default is no persistence) - * @param string $type The type of data connector (optional, default is based on $db parameter) - * - * @return DataConnector Data connector object - */ + /** + * Create data connector object. + * + * A data connector provides access to persistent storage for the different objects. + * + * Names of tables may be given a prefix to allow multiple versions to share the same schema. A separate sub-class is defined for + * each different database connection - the class to use is determined by inspecting the database object passed, but this can be overridden + * (for example, to use a bespoke connector) by specifying a type. If no database is passed then this class is used which acts as a dummy + * connector with no persistence. + * + * @param string $dbTableNamePrefix Prefix for database table names (optional, default is none). + * @param object $db A database connection object or string (optional, default is no persistence). + * @param string $type The type of data connector (optional, default is based on $db parameter). + * + * @return DataConnector Data connector object + */ public static function getDataConnector($dbTableNamePrefix = '', $db = null, $type = '') { - if (is_null($dbTableNamePrefix)) { $dbTableNamePrefix = ''; } + if (!is_null($db) && empty($type)) { if (is_object($db)) { $type = get_class($db); } } + $type = strtolower($type); + if (($type === 'pdo') && ($db->getAttribute(PDO::ATTR_DRIVER_NAME) === 'sqlite')) { $type .= '_sqlite'; } + if (!empty($type)) { - $type ="DataConnector_{$type}"; + $type = "DataConnector_{$type}"; } else { - $type ='DataConnector'; + $type = 'DataConnector'; } + $type = "\\IMSGlobal\\LTI\\ToolProvider\\DataConnector\\{$type}"; $dataConnector = new $type($db, $dbTableNamePrefix); - + return $dataConnector; - } -/** - * Generate a random string. - * - * The generated string will only comprise letters (upper- and lower-case) and digits. - * - * @param int $length Length of string to be generated (optional, default is 8 characters) - * - * @return string Random string - */ - static function getRandomString($length = 8) + /** + * Generate a random string. + * + * The generated string will only comprise letters (upper- and lower-case) and digits. + * + * @param int $length Length of string to be generated (optional, default is 8 characters). + * + * @return string Random string + */ + public static function getRandomString($length = 8) { - $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - + $value = ''; $charsLength = strlen($chars) - 1; - - for ($i = 1 ; $i <= $length; $i++) { + + for ($i = 1; $i <= $length; $i++) { $value .= $chars[rand(0, $charsLength)]; } - + return $value; - } -/** - * Quote a string for use in a database query. - * - * Any single quotes in the value passed will be replaced with two single quotes. If a null value is passed, a string - * of 'null' is returned (which will never be enclosed in quotes irrespective of the value of the $addQuotes parameter. - * - * @param string $value Value to be quoted - * @param bool $addQuotes If true the returned string will be enclosed in single quotes (optional, default is true) - * @return string The quoted string. - */ - static function quoted($value, $addQuotes = true) + /** + * Quote a string for use in a database query. + * + * Any single quotes in the value passed will be replaced with two single quotes. If a null value is passed, a string + * of 'null' is returned (which will never be enclosed in quotes irrespective of the value of the $addQuotes parameter. + * + * @param string $value Value to be quoted. + * @param bool $addQuotes If TRUE the returned string will be enclosed in single quotes (optional, default is TRUE). + * + * @return string The quoted string. + */ + public static function quoted($value, $addQuotes = true) { - if (is_null($value)) { $value = 'null'; } else { $value = str_replace('\'', '\'\'', $value); + if ($addQuotes) { $value = "'{$value}'"; } } - + return $value; - } - } diff --git a/src/ToolProvider/DataConnector/DataConnector_mysql.php b/src/ToolProvider/DataConnector/DataConnector_mysql.php index c0dc1ce..d9c2d7f 100644 --- a/src/ToolProvider/DataConnector/DataConnector_mysql.php +++ b/src/ToolProvider/DataConnector/DataConnector_mysql.php @@ -1,5 +1,4 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ ### # NB This class assumes that a MySQL connection has already been opened to the appropriate schema ### - - class DataConnector_mysql extends DataConnector { - -### -### ToolConsumer methods -### - -/** - * Load tool consumer object. - * - * @param ToolConsumer $consumer ToolConsumer object - * - * @return boolean True if the tool consumer object was successfully loaded - */ + + ### + ### ToolConsumer methods + ### + + + /** + * Load tool consumer object. + * + * @param ToolConsumer $consumer ToolConsumer object. + * + * @return bool TRUE if the tool consumer object was successfully loaded + */ public function loadToolConsumer($consumer) { - $ok = false; + if (!empty($consumer->getRecordId())) { $sql = sprintf('SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' . - 'consumer_name, consumer_version, consumer_guid, ' . - 'profile, tool_proxy, settings, protected, enabled, ' . - 'enable_from, enable_until, last_access, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . - "WHERE consumer_pk = %d", - $consumer->getRecordId()); + 'consumer_name, consumer_version, consumer_guid, ' . + 'profile, tool_proxy, settings, protected, enabled, ' . + 'enable_from, enable_until, last_access, created, updated ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::CONSUMER_TABLE_NAME . ' ' . "WHERE consumer_pk = %d", $consumer->getRecordId()); } else { $key256 = DataConnector::getConsumerKey($consumer->getKey()); $sql = sprintf('SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' . - 'consumer_name, consumer_version, consumer_guid, ' . - 'profile, tool_proxy, settings, protected, enabled, ' . - 'enable_from, enable_until, last_access, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . - "WHERE consumer_key256 = %s", - DataConnector::quoted($key256)); + 'consumer_name, consumer_version, consumer_guid, ' . + 'profile, tool_proxy, settings, protected, enabled, ' . + 'enable_from, enable_until, last_access, created, updated ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::CONSUMER_TABLE_NAME . ' ' . "WHERE consumer_key256 = %s", DataConnector::quoted($key256)); } + $rsConsumer = mysql_query($sql); + if ($rsConsumer) { while ($row = mysql_fetch_object($rsConsumer)) { if (empty($key256) || empty($row->consumer_key) || ($consumer->getKey() === $row->consumer_key)) { @@ -76,228 +71,214 @@ public function loadToolConsumer($consumer) $consumer->profile = json_decode($row->profile); $consumer->toolProxy = $row->tool_proxy; $settings = unserialize($row->settings); + if (!is_array($settings)) { $settings = array(); } + $consumer->setSettings($settings); $consumer->protected = (intval($row->protected) === 1); $consumer->enabled = (intval($row->enabled) === 1); $consumer->enableFrom = null; + if (!is_null($row->enable_from)) { $consumer->enableFrom = strtotime($row->enable_from); } + $consumer->enableUntil = null; + if (!is_null($row->enable_until)) { $consumer->enableUntil = strtotime($row->enable_until); } + $consumer->lastAccess = null; + if (!is_null($row->last_access)) { $consumer->lastAccess = strtotime($row->last_access); } + $consumer->created = strtotime($row->created); $consumer->updated = strtotime($row->updated); $ok = true; break; } } + mysql_free_result($rsConsumer); } - + return $ok; - } -/** - * Save tool consumer object. - * - * @param ToolConsumer $consumer Consumer object - * - * @return boolean True if the tool consumer object was successfully saved - */ + /** + * Save tool consumer object. + * + * @param ToolConsumer $consumer Consumer object. + * + * @return bool TRUE if the tool consumer object was successfully saved + */ public function saveToolConsumer($consumer) { - $id = $consumer->getRecordId(); $key = $consumer->getKey(); $key256 = DataConnector::getConsumerKey($key); + if ($key === $key256) { $key = null; } + $protected = ($consumer->protected) ? 1 : 0; - $enabled = ($consumer->enabled)? 1 : 0; + $enabled = ($consumer->enabled) ? 1 : 0; $profile = (!empty($consumer->profile)) ? json_encode($consumer->profile) : null; $settingsValue = serialize($consumer->getSettings()); $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $from = null; + if (!is_null($consumer->enableFrom)) { $from = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableFrom); } + $until = null; + if (!is_null($consumer->enableUntil)) { $until = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableUntil); } + $last = null; + if (!is_null($consumer->lastAccess)) { $last = date($this->dateFormat, $consumer->lastAccess); } + if (empty($id)) { - $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' (consumer_key256, consumer_key, name, ' . - 'secret, lti_version, consumer_name, consumer_version, consumer_guid, profile, tool_proxy, settings, protected, enabled, ' . - 'enable_from, enable_until, last_access, created, updated) ' . - 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %d, %s, %s, %s, %s, %s)', - DataConnector::quoted($key256), DataConnector::quoted($key), DataConnector::quoted($consumer->name), - DataConnector::quoted($consumer->secret), DataConnector::quoted($consumer->ltiVersion), - DataConnector::quoted($consumer->consumerName), DataConnector::quoted($consumer->consumerVersion), DataConnector::quoted($consumer->consumerGuid), - DataConnector::quoted($profile), DataConnector::quoted($consumer->toolProxy), DataConnector::quoted($settingsValue), - $protected, $enabled, DataConnector::quoted($from), DataConnector::quoted($until), DataConnector::quoted($last), - DataConnector::quoted($now), DataConnector::quoted($now)); + $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . + ' (consumer_key256, consumer_key, name, ' . + 'secret, lti_version, consumer_name, consumer_version, consumer_guid, profile, tool_proxy, settings, protected, enabled, ' . + 'enable_from, enable_until, last_access, created, updated) ' . + 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %d, %s, %s, %s, %s, %s)', DataConnector::quoted($key256), DataConnector::quoted($key), DataConnector::quoted($consumer->name), DataConnector::quoted($consumer->secret), DataConnector::quoted($consumer->ltiVersion), DataConnector::quoted($consumer->consumerName), DataConnector::quoted($consumer->consumerVersion), DataConnector::quoted($consumer->consumerGuid), DataConnector::quoted($profile), DataConnector::quoted($consumer->toolProxy), DataConnector::quoted($settingsValue), $protected, $enabled, DataConnector::quoted($from), DataConnector::quoted($until), DataConnector::quoted($last), DataConnector::quoted($now), DataConnector::quoted($now)); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' SET ' . - 'consumer_key256 = %s, consumer_key = %s, ' . - 'name = %s, secret= %s, lti_version = %s, consumer_name = %s, consumer_version = %s, consumer_guid = %s, ' . - 'profile = %s, tool_proxy = %s, settings = %s, ' . - 'protected = %d, enabled = %d, enable_from = %s, enable_until = %s, last_access = %s, updated = %s ' . - 'WHERE consumer_pk = %d', - DataConnector::quoted($key256), DataConnector::quoted($key), - DataConnector::quoted($consumer->name), - DataConnector::quoted($consumer->secret), DataConnector::quoted($consumer->ltiVersion), - DataConnector::quoted($consumer->consumerName), DataConnector::quoted($consumer->consumerVersion), DataConnector::quoted($consumer->consumerGuid), - DataConnector::quoted($profile), DataConnector::quoted($consumer->toolProxy), DataConnector::quoted($settingsValue), - $protected, $enabled, - DataConnector::quoted($from), DataConnector::quoted($until), DataConnector::quoted($last), - DataConnector::quoted($now), $consumer->getRecordId()); + 'consumer_key256 = %s, consumer_key = %s, ' . + 'name = %s, secret= %s, lti_version = %s, consumer_name = %s, consumer_version = %s, consumer_guid = %s, ' . + 'profile = %s, tool_proxy = %s, settings = %s, ' . + 'protected = %d, enabled = %d, enable_from = %s, enable_until = %s, last_access = %s, updated = %s ' . + 'WHERE consumer_pk = %d', DataConnector::quoted($key256), DataConnector::quoted($key), DataConnector::quoted($consumer->name), DataConnector::quoted($consumer->secret), DataConnector::quoted($consumer->ltiVersion), DataConnector::quoted($consumer->consumerName), DataConnector::quoted($consumer->consumerVersion), DataConnector::quoted($consumer->consumerGuid), DataConnector::quoted($profile), DataConnector::quoted($consumer->toolProxy), DataConnector::quoted($settingsValue), $protected, $enabled, DataConnector::quoted($from), DataConnector::quoted($until), DataConnector::quoted($last), DataConnector::quoted($now), $consumer->getRecordId()); } + $ok = mysql_query($sql); + if ($ok) { if (empty($id)) { $consumer->setRecordId(mysql_insert_id()); $consumer->created = $time; } + $consumer->updated = $time; } - + return $ok; - } -/** - * Delete tool consumer object. - * - * @param ToolConsumer $consumer Consumer object - * - * @return boolean True if the tool consumer object was successfully deleted - */ + /** + * Delete tool consumer object. + * + * @param ToolConsumer $consumer Consumer object. + * + * @return bool TRUE if the tool consumer object was successfully deleted + */ public function deleteToolConsumer($consumer) { - -// Delete any nonce values for this consumer - $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any nonce values for this consumer + $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . + ' WHERE consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Delete any outstanding share keys for resource links for this consumer - $sql = sprintf('DELETE sk ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any outstanding share keys for resource links for this consumer + $sql = sprintf('DELETE sk ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . + 'WHERE rl.consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Delete any outstanding share keys for resource links for contexts in this consumer - $sql = sprintf('DELETE sk ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'WHERE c.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any outstanding share keys for resource links for contexts in this consumer + $sql = sprintf('DELETE sk ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' c ON rl.context_pk = c.context_pk ' . 'WHERE c.consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Delete any users in resource links for this consumer - $sql = sprintf('DELETE u ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any users in resource links for this consumer + $sql = sprintf('DELETE u ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON u.resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Delete any users in resource links for contexts in this consumer - $sql = sprintf('DELETE u ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'WHERE c.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any users in resource links for contexts in this consumer + $sql = sprintf('DELETE u ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON u.resource_link_pk = rl.resource_link_pk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . 'WHERE c.consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Update any resource links for which this consumer is acting as a primary resource link + + // Update any resource links for which this consumer is acting as a primary resource link $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . - 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . - 'WHERE rl.consumer_pk = %d', - $consumer->getRecordId()); + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . + 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . 'WHERE rl.consumer_pk = %d', $consumer->getRecordId()); $ok = mysql_query($sql); - -// Update any resource links for contexts in which this consumer is acting as a primary resource link + + // Update any resource links for contexts in which this consumer is acting as a primary resource link $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . - 'WHERE c.consumer_pk = %d', - $consumer->getRecordId()); + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . + 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . 'WHERE c.consumer_pk = %d', $consumer->getRecordId()); $ok = mysql_query($sql); - -// Delete any resource links for this consumer - $sql = sprintf('DELETE rl ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - 'WHERE rl.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any resource links for this consumer + $sql = sprintf('DELETE rl ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ' . 'WHERE rl.consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Delete any resource links for contexts in this consumer - $sql = sprintf('DELETE rl ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'WHERE c.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any resource links for contexts in this consumer + $sql = sprintf('DELETE rl ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ' . "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' c ON rl.context_pk = c.context_pk ' . 'WHERE c.consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Delete any contexts for this consumer - $sql = sprintf('DELETE c ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . - 'WHERE c.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete any contexts for this consumer + $sql = sprintf('DELETE c ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE c.consumer_pk = %d', $consumer->getRecordId()); mysql_query($sql); - -// Delete consumer - $sql = sprintf('DELETE c ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' c ' . - 'WHERE c.consumer_pk = %d', - $consumer->getRecordId()); + + // Delete consumer + $sql = sprintf('DELETE c ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' c ' . + 'WHERE c.consumer_pk = %d', $consumer->getRecordId()); $ok = mysql_query($sql); - + if ($ok) { $consumer->initialize(); } - + return $ok; - } - -### -# Load all tool consumers from the database -### + + ### + # Load all tool consumers from the database + ### public function getToolConsumers() { - $consumers = array(); - + $sql = 'SELECT consumer_pk, consumer_key, consumer_key, name, secret, lti_version, consumer_name, consumer_version, consumer_guid, ' . - 'profile, tool_proxy, settings, ' . - 'protected, enabled, enable_from, enable_until, last_access, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . - 'ORDER BY name'; + 'profile, tool_proxy, settings, ' . + 'protected, enabled, enable_from, enable_until, last_access, created, updated ' . + "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . 'ORDER BY name'; $rsConsumers = mysql_query($sql); + if ($rsConsumers) { while ($row = mysql_fetch_object($rsConsumers)) { $consumer = new ToolProvider\ToolConsumer($row->consumer_key, $this); @@ -311,439 +292,430 @@ public function getToolConsumers() $consumer->profile = json_decode($row->profile); $consumer->toolProxy = $row->tool_proxy; $settings = unserialize($row->settings); + if (!is_array($settings)) { $settings = array(); } + $consumer->setSettings($settings); $consumer->protected = (intval($row->protected) === 1); $consumer->enabled = (intval($row->enabled) === 1); $consumer->enableFrom = null; + if (!is_null($row->enable_from)) { $consumer->enableFrom = strtotime($row->enable_from); } + $consumer->enableUntil = null; + if (!is_null($row->enable_until)) { $consumer->enableUntil = strtotime($row->enable_until); } + $consumer->lastAccess = null; + if (!is_null($row->last_access)) { $consumer->lastAccess = strtotime($row->last_access); } + $consumer->created = strtotime($row->created); $consumer->updated = strtotime($row->updated); $consumers[] = $consumer; } + mysql_free_result($rsConsumers); } - + return $consumers; - } - -### -### ToolProxy methods -### - -### -# Load the tool proxy from the database -### + + ### + ### ToolProxy methods + ### + + + ### + # Load the tool proxy from the database + ### public function loadToolProxy($toolProxy) { - return false; - } - -### -# Save the tool proxy to the database -### + + ### + # Save the tool proxy to the database + ### public function saveToolProxy($toolProxy) { - return false; - } - -### -# Delete the tool proxy from the database -### + + ### + # Delete the tool proxy from the database + ### public function deleteToolProxy($toolProxy) { - return false; - } - -### -### Context methods -### - -/** - * Load context object. - * - * @param Context $context Context object - * - * @return boolean True if the context object was successfully loaded - */ + + ### + ### Context methods + ### + + + /** + * Load context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the context object was successfully loaded + */ public function loadContext($context) { - $ok = false; + if (!empty($context->getRecordId())) { $sql = sprintf('SELECT context_pk, consumer_pk, lti_context_id, settings, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . - 'WHERE (context_pk = %d)', - $context->getRecordId()); + "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . 'WHERE (context_pk = %d)', $context->getRecordId()); } else { $sql = sprintf('SELECT context_pk, consumer_pk, lti_context_id, settings, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . - 'WHERE (consumer_pk = %d) AND (lti_context_id = %s)', - $context->getConsumer()->getRecordId(), DataConnector::quoted($context->ltiContextId)); + "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . + 'WHERE (consumer_pk = %d) AND (lti_context_id = %s)', $context->getConsumer()->getRecordId(), DataConnector::quoted($context->ltiContextId)); } + $rs_context = mysql_query($sql); + if ($rs_context) { $row = mysql_fetch_object($rs_context); + if ($row) { $context->setRecordId(intval($row->context_pk)); $context->setConsumerId(intval($row->consumer_pk)); $context->ltiContextId = $row->lti_context_id; $settings = unserialize($row->settings); + if (!is_array($settings)) { $settings = array(); } + $context->setSettings($settings); $context->created = strtotime($row->created); $context->updated = strtotime($row->updated); $ok = true; } } - + return $ok; - } -/** - * Save context object. - * - * @param Context $context Context object - * - * @return boolean True if the context object was successfully saved - */ + /** + * Save context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the context object was successfully saved + */ public function saveContext($context) { - $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $settingsValue = serialize($context->getSettings()); $id = $context->getRecordId(); $consumer_pk = $context->getConsumer()->getRecordId(); + if (empty($id)) { - $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' (consumer_pk, lti_context_id, ' . - 'settings, created, updated) ' . - 'VALUES (%d, %s, %s, %s, %s)', - $consumer_pk, DataConnector::quoted($context->ltiContextId), - DataConnector::quoted($settingsValue), - DataConnector::quoted($now), DataConnector::quoted($now)); + $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' (consumer_pk, lti_context_id, ' . 'settings, created, updated) ' . 'VALUES (%d, %s, %s, %s, %s)', $consumer_pk, DataConnector::quoted($context->ltiContextId), DataConnector::quoted($settingsValue), DataConnector::quoted($now), DataConnector::quoted($now)); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' SET ' . - 'lti_context_id = %s, settings = %s, '. - 'updated = %s' . - 'WHERE (consumer_pk = %d) AND (context_pk = %d)', - DataConnector::quoted($context->ltiContextId), DataConnector::quoted($settingsValue), - DataConnector::quoted($now), $consumer_pk, $id); + 'lti_context_id = %s, settings = %s, ' . 'updated = %s' . + 'WHERE (consumer_pk = %d) AND (context_pk = %d)', DataConnector::quoted($context->ltiContextId), DataConnector::quoted($settingsValue), DataConnector::quoted($now), $consumer_pk, $id); } + $ok = mysql_query($sql); + if ($ok) { if (empty($id)) { $context->setRecordId(mysql_insert_id()); $context->created = $time; } + $context->updated = $time; } - + return $ok; - } -/** - * Delete context object. - * - * @param Context $context Context object - * - * @return boolean True if the Context object was successfully deleted - */ + /** + * Delete context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the Context object was successfully deleted + */ public function deleteContext($context) { - -// Delete any outstanding share keys for resource links for this context - $sql = sprintf('DELETE sk ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.context_pk = %d', - $context->getRecordId()); + + // Delete any outstanding share keys for resource links for this context + $sql = sprintf('DELETE sk ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . + 'WHERE rl.context_pk = %d', $context->getRecordId()); mysql_query($sql); - -// Delete any users in resource links for this context - $sql = sprintf('DELETE u ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.context_pk = %d', - $context->getRecordId()); + + // Delete any users in resource links for this context + $sql = sprintf('DELETE u ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON u.resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.context_pk = %d', $context->getRecordId()); mysql_query($sql); - -// Update any resource links for which this consumer is acting as a primary resource link + + // Update any resource links for which this consumer is acting as a primary resource link $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . - 'SET prl.primary_resource_link_pk = null, prl.share_approved = null ' . - 'WHERE rl.context_pk = %d', - $context->getRecordId()); + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . + 'SET prl.primary_resource_link_pk = null, prl.share_approved = null ' . 'WHERE rl.context_pk = %d', $context->getRecordId()); $ok = mysql_query($sql); - -// Delete any resource links for this consumer - $sql = sprintf('DELETE rl ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - 'WHERE rl.context_pk = %d', - $context->getRecordId()); + + // Delete any resource links for this consumer + $sql = sprintf('DELETE rl ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ' . 'WHERE rl.context_pk = %d', $context->getRecordId()); mysql_query($sql); - -// Delete context - $sql = sprintf('DELETE c ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ', - 'WHERE c.context_pk = %d', - $context->getRecordId()); + + // Delete context + $sql = sprintf('DELETE c ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ', 'WHERE c.context_pk = %d', $context->getRecordId()); $ok = mysql_query($sql); + if ($ok) { $context->initialize(); } - + return $ok; - } - -### -### ResourceLink methods -### - -/** - * Load resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully loaded - */ + + ### + ### ResourceLink methods + ### + + + /** + * Load resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully loaded + */ public function loadResourceLink($resourceLink) { - $ok = false; + if (!empty($resourceLink->getRecordId())) { $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = %d)', - $resourceLink->getRecordId()); - } else if (!empty($resourceLink->getContext())) { + "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . + 'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId()); + } elseif (!empty($resourceLink->getContext())) { $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = %d) AND (lti_resource_link_id = %s)', - $resourceLink->getContext()->getRecordId(), DataConnector::quoted($resourceLink->getId())); + "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . + 'WHERE (context_pk = %d) AND (lti_resource_link_id = %s)', $resourceLink->getContext()->getRecordId(), DataConnector::quoted($resourceLink->getId())); } else { $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . - $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME . ' c ON r.context_pk = c.context_pk ' . - ' WHERE ((r.consumer_pk = %d) OR (c.consumer_pk = %d)) AND (lti_resource_link_id = %s)', - $resourceLink->getConsumer()->getRecordId(), $resourceLink->getConsumer()->getRecordId(), DataConnector::quoted($resourceLink->getId())); + "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . + $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME . ' c ON r.context_pk = c.context_pk ' . + ' WHERE ((r.consumer_pk = %d) OR (c.consumer_pk = %d)) AND (lti_resource_link_id = %s)', $resourceLink->getConsumer()->getRecordId(), $resourceLink->getConsumer()->getRecordId(), DataConnector::quoted($resourceLink->getId())); } + $rsContext = mysql_query($sql); + if ($rsContext) { $row = mysql_fetch_object($rsContext); + if ($row) { $resourceLink->setRecordId(intval($row->resource_link_pk)); + if (!is_null($row->context_pk)) { $resourceLink->setContextId(intval($row->context_pk)); } else { $resourceLink->setContextId(null); } + if (!is_null($row->consumer_pk)) { $resourceLink->setConsumerId(intval($row->consumer_pk)); } else { $resourceLink->setConsumerId(null); } + $resourceLink->ltiResourceLinkId = $row->lti_resource_link_id; $settings = unserialize($row->settings); + if (!is_array($settings)) { $settings = array(); } + $resourceLink->setSettings($settings); + if (!is_null($row->primary_resource_link_pk)) { $resourceLink->primaryResourceLinkId = intval($row->primary_resource_link_pk); } else { $resourceLink->primaryResourceLinkId = null; } - $resourceLink->shareApproved = (is_null($row->share_approved)) ? null : (intval($row->share_approved) === 1); + + $resourceLink->shareApproved = (is_null($row->share_approved)) ? null : (intval($row->share_approved) === + 1); $resourceLink->created = strtotime($row->created); $resourceLink->updated = strtotime($row->updated); $ok = true; } } - + return $ok; - } -/** - * Save resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully saved - */ - public function saveResourceLink($resourceLink) { - + /** + * Save resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully saved + */ + public function saveResourceLink($resourceLink) + { if (is_null($resourceLink->shareApproved)) { $approved = 'NULL'; - } else if ($resourceLink->shareApproved) { + } elseif ($resourceLink->shareApproved) { $approved = '1'; } else { $approved = '0'; } + if (empty($resourceLink->primaryResourceLinkId)) { $primaryResourceLinkId = 'NULL'; } else { $primaryResourceLinkId = strval($resourceLink->primaryResourceLinkId); } + $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $settingsValue = serialize($resourceLink->getSettings()); + if (!empty($resourceLink->getContext())) { $consumerId = 'NULL'; $contextId = strval($resourceLink->getContext()->getRecordId()); - } else if (!empty($resourceLink->getContextId())) { + } elseif (!empty($resourceLink->getContextId())) { $consumerId = 'NULL'; $contextId = strval($resourceLink->getContextId()); } else { $consumerId = strval($resourceLink->getConsumer()->getRecordId()); $contextId = 'NULL'; } + $id = $resourceLink->getRecordId(); + if (empty($id)) { - $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' (consumer_pk, context_pk, ' . - 'lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated) ' . - 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', - $consumerId, $contextId, DataConnector::quoted($resourceLink->getId()), - DataConnector::quoted($settingsValue), - $primaryResourceLinkId, $approved, DataConnector::quoted($now), DataConnector::quoted($now)); - } else if ($contextId !== 'NULL') { + $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' (consumer_pk, context_pk, ' . + 'lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated) ' . + 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', $consumerId, $contextId, DataConnector::quoted($resourceLink->getId()), DataConnector::quoted($settingsValue), $primaryResourceLinkId, $approved, DataConnector::quoted($now), DataConnector::quoted($now)); + } elseif ($contextId !== 'NULL') { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'consumer_pk = %s, lti_resource_link_id = %s, settings = %s, '. - 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . - 'WHERE (context_pk = %s) AND (resource_link_pk = %d)', - $consumerId, DataConnector::quoted($resourceLink->getId()), - DataConnector::quoted($settingsValue), $primaryResourceLinkId, $approved, DataConnector::quoted($now), - $contextId, $id); + 'consumer_pk = %s, lti_resource_link_id = %s, settings = %s, ' . + 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . + 'WHERE (context_pk = %s) AND (resource_link_pk = %d)', $consumerId, DataConnector::quoted($resourceLink->getId()), DataConnector::quoted($settingsValue), $primaryResourceLinkId, $approved, DataConnector::quoted($now), $contextId, $id); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = %s, lti_resource_link_id = %s, settings = %s, '. - 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . - 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', - $contextId, DataConnector::quoted($resourceLink->getId()), - DataConnector::quoted($settingsValue), $primaryResourceLinkId, $approved, DataConnector::quoted($now), - $consumerId, $id); + 'context_pk = %s, lti_resource_link_id = %s, settings = %s, ' . + 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . + 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $contextId, DataConnector::quoted($resourceLink->getId()), DataConnector::quoted($settingsValue), $primaryResourceLinkId, $approved, DataConnector::quoted($now), $consumerId, $id); } + $ok = mysql_query($sql); + if ($ok) { if (empty($id)) { $resourceLink->setRecordId(mysql_insert_id()); $resourceLink->created = $time; } + $resourceLink->updated = $time; } - + return $ok; - } -/** - * Delete resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully deleted - */ + /** + * Delete resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully deleted + */ public function deleteResourceLink($resourceLink) { - -// Delete any outstanding share keys for resource links for this consumer - $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = %d)', - $resourceLink->getRecordId()); + + // Delete any outstanding share keys for resource links for this consumer + $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + ' ' . 'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId()); $ok = mysql_query($sql); - -// Delete users + + // Delete users if ($ok) { $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = %d)', - $resourceLink->getRecordId()); + 'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId()); $ok = mysql_query($sql); } - -// Update any resource links for which this is the primary resource link + + // Update any resource links for which this is the primary resource link if ($ok) { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'SET primary_resource_link_pk = NULL ' . - 'WHERE (primary_resource_link_pk = %d)', - $resourceLink->getRecordId()); + 'SET primary_resource_link_pk = NULL ' . 'WHERE (primary_resource_link_pk = %d)', $resourceLink->getRecordId()); $ok = mysql_query($sql); } - -// Delete resource link + + // Delete resource link if ($ok) { $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = %s)', - $resourceLink->getRecordId()); + 'WHERE (resource_link_pk = %s)', $resourceLink->getRecordId()); $ok = mysql_query($sql); } - + if ($ok) { $resourceLink->initialize(); } - + return $ok; - } -/** - * Get array of user objects. - * - * Obtain an array of User objects for users with a result sourcedId. The array may include users from other - * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope. - * - * @param ResourceLink $resourceLink Resource link object - * @param boolean $localOnly True if only users within the resource link are to be returned (excluding users sharing this resource link) - * @param int $idScope Scope value to use for user IDs - * - * @return array Array of User objects - */ + /** + * Get array of user objects. + * + * Obtain an array of User objects for users with a result sourcedId. The array may include users from other + * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope. + * + * @param ResourceLink $resourceLink Resource link object. + * @param bool $localOnly TRUE if only users within the resource link are to be returned (excluding users sharing this resource link). + * @param int $idScope Scope value to use for user IDs. + * + * @return array Array of User objects + */ public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $idScope) { - $users = array(); - + if ($localOnly) { $sql = sprintf('SELECT u.user_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . - 'ON u.resource_link_pk = rl.resource_link_pk ' . - "WHERE (rl.resource_link_pk = %d) AND (rl.primary_resource_link_pk IS NULL)", - $resourceLink->getRecordId()); + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . + 'ON u.resource_link_pk = rl.resource_link_pk ' . + "WHERE (rl.resource_link_pk = %d) AND (rl.primary_resource_link_pk IS NULL)", $resourceLink->getRecordId()); } else { $sql = sprintf('SELECT u.user_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . - 'ON u.resource_link_pk = rl.resource_link_pk ' . - 'WHERE ((rl.resource_link_pk = %d) AND (rl.primary_resource_link_pk IS NULL)) OR ' . - '((rl.primary_resource_link_pk = %d) AND (share_approved = 1))', - $resourceLink->getRecordId(), $resourceLink->getRecordId()); + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . + 'ON u.resource_link_pk = rl.resource_link_pk ' . + 'WHERE ((rl.resource_link_pk = %d) AND (rl.primary_resource_link_pk IS NULL)) OR ' . + '((rl.primary_resource_link_pk = %d) AND (share_approved = 1))', $resourceLink->getRecordId(), $resourceLink->getRecordId()); } + $rsUser = mysql_query($sql); + if ($rsUser) { while ($row = mysql_fetch_object($rsUser)) { $user = ToolProvider\User::fromResourceLink($resourceLink, $row->lti_user_id); @@ -751,6 +723,7 @@ public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $ $user->ltiResultSourcedId = $row->lti_result_sourcedid; $user->created = strtotime($row->created); $user->updated = strtotime($row->updated); + if (is_null($idScope)) { $users[] = $user; } else { @@ -758,29 +731,26 @@ public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $ } } } - + return $users; - } -/** - * Get array of shares defined for this resource link. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return array Array of ResourceLinkShare objects - */ + /** + * Get array of shares defined for this resource link. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return array Array of ResourceLinkShare objects + */ public function getSharesResourceLink($resourceLink) { - $shares = array(); - - $sql = sprintf('SELECT consumer_pk, resource_link_pk, share_approved ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (primary_resource_link_pk = %d) ' . - 'ORDER BY consumer_pk', - $resourceLink->getRecordId()); + + $sql = sprintf('SELECT consumer_pk, resource_link_pk, share_approved ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . 'WHERE (primary_resource_link_pk = %d) ' . + 'ORDER BY consumer_pk', $resourceLink->getRecordId()); $rsShare = mysql_query($sql); + if ($rsShare) { while ($row = mysql_fetch_object($rsShare)) { $share = new ToolProvider\ResourceLinkShare(); @@ -789,188 +759,180 @@ public function getSharesResourceLink($resourceLink) $shares[] = $share; } } - + return $shares; - } - - -### -### ConsumerNonce methods -### - -/** - * Load nonce object. - * - * @param ConsumerNonce $nonce Nonce object - * - * @return boolean True if the nonce object was successfully loaded - */ + + ### + ### ConsumerNonce methods + ### + + + /** + * Load nonce object. + * + * @param ConsumerNonce $nonce Nonce object. + * + * @return bool TRUE if the nonce object was successfully loaded + */ public function loadConsumerNonce($nonce) { - $ok = true; - -// Delete any expired nonce values + + // Delete any expired nonce values $now = date("{$this->dateFormat} {$this->timeFormat}", time()); $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . " WHERE expires <= '{$now}'"; mysql_query($sql); - -// Load the nonce - $sql = sprintf("SELECT value AS T FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE (consumer_pk = %d) AND (value = %s)', - $nonce->getConsumer()->getRecordId(), DataConnector::quoted($nonce->getValue())); + + // Load the nonce + $sql = sprintf("SELECT value AS T FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . + ' WHERE (consumer_pk = %d) AND (value = %s)', $nonce->getConsumer()->getRecordId(), DataConnector::quoted($nonce->getValue())); $rs_nonce = mysql_query($sql); + if ($rs_nonce) { $row = mysql_fetch_object($rs_nonce); + if ($row === false) { $ok = false; } } - + return $ok; - } -/** - * Save nonce object. - * - * @param ConsumerNonce $nonce Nonce object - * - * @return boolean True if the nonce object was successfully saved - */ + /** + * Save nonce object. + * + * @param ConsumerNonce $nonce Nonce object. + * + * @return bool TRUE if the nonce object was successfully saved + */ public function saveConsumerNonce($nonce) { - $expires = date("{$this->dateFormat} {$this->timeFormat}", $nonce->expires); - $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . " (consumer_pk, value, expires) VALUES (%d, %s, %s)", - $nonce->getConsumer()->getRecordId(), DataConnector::quoted($nonce->getValue()), - DataConnector::quoted($expires)); + $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . + " (consumer_pk, value, expires) VALUES (%d, %s, %s)", $nonce->getConsumer()->getRecordId(), DataConnector::quoted($nonce->getValue()), DataConnector::quoted($expires)); $ok = mysql_query($sql); - + return $ok; - } - - -### -### ResourceLinkShareKey methods -### - -/** - * Load resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource_Link share key object - * - * @return boolean True if the resource link share key object was successfully loaded - */ + + ### + ### ResourceLinkShareKey methods + ### + + + /** + * Load resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource_Link share key object. + * + * @return bool TRUE if the resource link share key object was successfully loaded + */ public function loadResourceLinkShareKey($shareKey) { - $ok = false; - -// Clear expired share keys + + // Clear expired share keys $now = date("{$this->dateFormat} {$this->timeFormat}", time()); - $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . " WHERE expires <= '{$now}'"; + $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + " WHERE expires <= '{$now}'"; mysql_query($sql); - -// Load share key + + // Load share key $id = mysql_real_escape_string($shareKey->getId()); - $sql = 'SELECT resource_link_pk, auto_approve, expires ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - "WHERE share_key_id = '{$id}'"; + $sql = 'SELECT resource_link_pk, auto_approve, expires ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . "WHERE share_key_id = '{$id}'"; $rsShareKey = mysql_query($sql); + if ($rsShareKey) { $row = mysql_fetch_object($rsShareKey); + if ($row && (intval($row->resource_link_pk) === $shareKey->resourceLinkId)) { $shareKey->autoApprove = (intval($row->auto_approve) === 1); $shareKey->expires = strtotime($row->expires); $ok = true; } } - + return $ok; - } -/** - * Save resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource link share key object - * - * @return boolean True if the resource link share key object was successfully saved - */ + /** + * Save resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource link share key object. + * + * @return bool TRUE if the resource link share key object was successfully saved + */ public function saveResourceLinkShareKey($shareKey) { - if ($shareKey->autoApprove) { $approve = 1; } else { $approve = 0; } + $expires = date("{$this->dateFormat} {$this->timeFormat}", $shareKey->expires); - $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - '(share_key_id, resource_link_pk, auto_approve, expires) ' . - "VALUES (%s, %d, {$approve}, '{$expires}')", - DataConnector::quoted($shareKey->getId()), $shareKey->resourceLinkId); + $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + ' ' . '(share_key_id, resource_link_pk, auto_approve, expires) ' . + "VALUES (%s, %d, {$approve}, '{$expires}')", DataConnector::quoted($shareKey->getId()), $shareKey->resourceLinkId); $ok = mysql_query($sql); - + return $ok; - } -/** - * Delete resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource link share key object - * - * @return boolean True if the resource link share key object was successfully deleted - */ + /** + * Delete resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource link share key object. + * + * @return bool TRUE if the resource link share key object was successfully deleted + */ public function deleteResourceLinkShareKey($shareKey) { - - $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . " WHERE share_key_id = '{$shareKey->getId()}'"; - + $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + " WHERE share_key_id = '{$shareKey->getId()}'"; + $ok = mysql_query($sql); - + if ($ok) { $shareKey->initialize(); } - + return $ok; - } - - -### -### User methods -### - -/** - * Load user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully loaded - */ + + ### + ### User methods + ### + + + /** + * Load user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully loaded + */ public function loadUser($user) { - $ok = false; + if (!empty($user->getRecordId())) { $sql = sprintf('SELECT user_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (user_pk = %d)', - $user->getRecordId()); + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . 'WHERE (user_pk = %d)', $user->getRecordId()); } else { $sql = sprintf('SELECT user_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = %d) AND (lti_user_id = %s)', - $user->getResourceLink()->getRecordId(), - DataConnector::quoted($user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY))); + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . + 'WHERE (resource_link_pk = %d) AND (lti_user_id = %s)', $user->getResourceLink()->getRecordId(), DataConnector::quoted($user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY))); } + $rsUser = mysql_query($sql); + if ($rsUser) { $row = mysql_fetch_object($rsUser); + if ($row) { $user->setRecordId(intval($row->user_pk)); $user->setResourceLinkId(intval($row->resource_link_pk)); @@ -981,72 +943,62 @@ public function loadUser($user) $ok = true; } } - + return $ok; - } -/** - * Save user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully saved - */ + /** + * Save user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully saved + */ public function saveUser($user) { - $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); + if (is_null($user->created)) { - $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' (resource_link_pk, ' . - 'lti_user_id, lti_result_sourcedid, created, updated) ' . - 'VALUES (%d, %s, %s, %s, %s)', - $user->getResourceLink()->getRecordId(), - DataConnector::quoted($user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY)), DataConnector::quoted($user->ltiResultSourcedId), - DataConnector::quoted($now), DataConnector::quoted($now)); + $sql = sprintf("INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . + ' (resource_link_pk, ' . 'lti_user_id, lti_result_sourcedid, created, updated) ' . + 'VALUES (%d, %s, %s, %s, %s)', $user->getResourceLink()->getRecordId(), DataConnector::quoted($user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY)), DataConnector::quoted($user->ltiResultSourcedId), DataConnector::quoted($now), DataConnector::quoted($now)); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'SET lti_result_sourcedid = %s, updated = %s ' . - 'WHERE (user_pk = %d)', - DataConnector::quoted($user->ltiResultSourcedId), - DataConnector::quoted($now), - $user->getRecordId()); + 'SET lti_result_sourcedid = %s, updated = %s ' . 'WHERE (user_pk = %d)', DataConnector::quoted($user->ltiResultSourcedId), DataConnector::quoted($now), $user->getRecordId()); } + $ok = mysql_query($sql); + if ($ok) { if (is_null($user->created)) { $user->setRecordId(mysql_insert_id()); $user->created = $time; } + $user->updated = $time; } - + return $ok; - } -/** - * Delete user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully deleted - */ + /** + * Delete user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully deleted + */ public function deleteUser($user) { - $sql = sprintf("DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (user_pk = %d)', - $user->getRecordId()); + 'WHERE (user_pk = %d)', $user->getRecordId()); $ok = mysql_query($sql); - + if ($ok) { $user->initialize(); } - + return $ok; - } - } diff --git a/src/ToolProvider/DataConnector/DataConnector_pdo.php b/src/ToolProvider/DataConnector/DataConnector_pdo.php index 3528aca..6a17300 100644 --- a/src/ToolProvider/DataConnector/DataConnector_pdo.php +++ b/src/ToolProvider/DataConnector/DataConnector_pdo.php @@ -1,5 +1,4 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ - - class DataConnector_pdo extends DataConnector { -/** - * Class constructor - * - * @param object $db Database connection object - * @param string $dbTableNamePrefix Prefix for database table names (optional, default is none) - */ + /** + * Class constructor. + * + * @param object $db Database connection object. + * @param string $dbTableNamePrefix Prefix for database table names (optional, default is none). + */ public function __construct($db, $dbTableNamePrefix = '') { - parent::__construct($db, $dbTableNamePrefix); + if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'oci') { $this->date_format = 'd-M-Y'; } - } - -### -### ToolConsumer methods -### - -/** - * Load tool consumer object. - * - * @param ToolConsumer $consumer ToolConsumer object - * - * @return boolean True if the tool consumer object was successfully loaded - */ + + ### + ### ToolConsumer methods + ### + + + /** + * Load tool consumer object. + * + * @param ToolConsumer $consumer ToolConsumer object. + * + * @return bool TRUE if the tool consumer object was successfully loaded + */ public function loadToolConsumer($consumer) { - $ok = false; + if (!empty($consumer->getRecordId())) { $sql = 'SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' . - 'consumer_name, consumer_version, consumer_guid, ' . - 'profile, tool_proxy, settings, protected, enabled, ' . - 'enable_from, enable_until, last_access, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . - 'WHERE consumer_pk = :id'; + 'consumer_name, consumer_version, consumer_guid, ' . + 'profile, tool_proxy, settings, protected, enabled, ' . + 'enable_from, enable_until, last_access, created, updated ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::CONSUMER_TABLE_NAME . ' ' . 'WHERE consumer_pk = :id'; $query = $this->db->prepare($sql); $id = $consumer->getRecordId(); $query->bindValue('id', $id, PDO::PARAM_INT); } else { $sql = 'SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' . - 'consumer_name, consumer_version, consumer_guid, ' . - 'profile, tool_proxy, settings, protected, enabled, ' . - 'enable_from, enable_until, last_access, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . - 'WHERE consumer_key256 = :key256'; + 'consumer_name, consumer_version, consumer_guid, ' . + 'profile, tool_proxy, settings, protected, enabled, ' . + 'enable_from, enable_until, last_access, created, updated ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::CONSUMER_TABLE_NAME . ' ' . 'WHERE consumer_key256 = :key256'; $query = $this->db->prepare($sql); $key256 = DataConnector::getConsumerKey($consumer->getKey()); $query->bindValue('key256', $key256, PDO::PARAM_STR); } - + if ($query->execute()) { while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $row = array_change_key_case($row); + if (empty($key256) || empty($row['consumer_key']) || ($consumer->getKey() === $row['consumer_key'])) { $consumer->setRecordId(intval($row['consumer_pk'])); $consumer->name = $row['name']; @@ -93,24 +88,32 @@ public function loadToolConsumer($consumer) $consumer->profile = json_decode($row['profile']); $consumer->toolProxy = $row['tool_proxy']; $settings = unserialize($row['settings']); + if (!is_array($settings)) { $settings = array(); } + $consumer->setSettings($settings); $consumer->protected = (intval($row['protected']) === 1); $consumer->enabled = (intval($row['enabled']) === 1); $consumer->enableFrom = null; + if (!is_null($row['enable_from'])) { $consumer->enableFrom = strtotime($row['enable_from']); } + $consumer->enableUntil = null; + if (!is_null($row['enable_until'])) { $consumer->enableUntil = strtotime($row['enable_until']); } + $consumer->lastAccess = null; + if (!is_null($row['last_access'])) { $consumer->lastAccess = strtotime($row['last_access']); } + $consumer->created = strtotime($row['created']); $consumer->updated = strtotime($row['updated']); $ok = true; @@ -118,51 +121,58 @@ public function loadToolConsumer($consumer) } } } - + return $ok; - } -/** - * Save tool consumer object. - * - * @param ToolConsumer $consumer Consumer object - * - * @return boolean True if the tool consumer object was successfully saved - */ + /** + * Save tool consumer object. + * + * @param ToolConsumer $consumer Consumer object. + * + * @return bool TRUE if the tool consumer object was successfully saved + */ public function saveToolConsumer($consumer) { - $id = $consumer->getRecordId(); $key = $consumer->getKey(); $key256 = $this->getConsumerKey($key); + if ($key === $key256) { $key = null; } + $protected = ($consumer->protected) ? 1 : 0; - $enabled = ($consumer->enabled)? 1 : 0; + $enabled = ($consumer->enabled) ? 1 : 0; $profile = (!empty($consumer->profile)) ? json_encode($consumer->profile) : null; $settingsValue = serialize($consumer->getSettings()); $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $from = null; + if (!is_null($consumer->enableFrom)) { $from = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableFrom); } + $until = null; + if (!is_null($consumer->enableUntil)) { $until = date("{$this->dateFormat} {$this->timeFormat}", $consumer->enableUntil); } + $last = null; + if (!is_null($consumer->lastAccess)) { $last = date($this->dateFormat, $consumer->lastAccess); } + if (empty($id)) { - $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' (consumer_key256, consumer_key, name, ' . - 'secret, lti_version, consumer_name, consumer_version, consumer_guid, profile, tool_proxy, settings, protected, enabled, ' . - 'enable_from, enable_until, last_access, created, updated) ' . - 'VALUES (:key256, :key, :name, :secret, :lti_version, :consumer_name, :consumer_version, :consumer_guid, :profile, :tool_proxy, :settings, ' . - ':protected, :enabled, :enable_from, :enable_until, :last_access, :created, :updated)'; + $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . + ' (consumer_key256, consumer_key, name, ' . + 'secret, lti_version, consumer_name, consumer_version, consumer_guid, profile, tool_proxy, settings, protected, enabled, ' . + 'enable_from, enable_until, last_access, created, updated) ' . + 'VALUES (:key256, :key, :name, :secret, :lti_version, :consumer_name, :consumer_version, :consumer_guid, :profile, :tool_proxy, :settings, ' . + ':protected, :enabled, :enable_from, :enable_until, :last_access, :created, :updated)'; $query = $this->db->prepare($sql); $query->bindValue('key256', $key256, PDO::PARAM_STR); $query->bindValue('key', $key, PDO::PARAM_STR); @@ -184,11 +194,11 @@ public function saveToolConsumer($consumer) $query->bindValue('updated', $now, PDO::PARAM_STR); } else { $sql = 'UPDATE ' . $this->dbTableNamePrefix . DataConnector::CONSUMER_TABLE_NAME . ' ' . - 'SET consumer_key256 = :key256, consumer_key = :key, name = :name, secret = :secret, lti_version = :lti_version, ' . - 'consumer_name = :consumer_name, consumer_version = :consumer_version, consumer_guid = :consumer_guid, ' . - 'profile = :profile, tool_proxy = :tool_proxy, settings = :settings, ' . - 'protected = :protected, enabled = :enabled, enable_from = :enable_from, enable_until = :enable_until, last_access = :last_access, updated = :updated ' . - 'WHERE consumer_pk = :id'; + 'SET consumer_key256 = :key256, consumer_key = :key, name = :name, secret = :secret, lti_version = :lti_version, ' . + 'consumer_name = :consumer_name, consumer_version = :consumer_version, consumer_guid = :consumer_guid, ' . + 'profile = :profile, tool_proxy = :tool_proxy, settings = :settings, ' . + 'protected = :protected, enabled = :enabled, enable_from = :enable_from, enable_until = :enable_until, last_access = :last_access, updated = :updated ' . + 'WHERE consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('key256', $key256, PDO::PARAM_STR); $query->bindValue('key', $key, PDO::PARAM_STR); @@ -209,156 +219,145 @@ public function saveToolConsumer($consumer) $query->bindValue('updated', $now, PDO::PARAM_STR); $query->bindValue('id', $id, PDO::PARAM_INT); } + $ok = $query->execute(); + if ($ok) { if (empty($id)) { $consumer->setRecordId(intval($this->db->lastInsertId())); $consumer->created = $time; } + $consumer->updated = $time; } - + return $ok; - } -/** - * Delete tool consumer object. - * - * @param ToolConsumer $consumer Consumer object - * - * @return boolean True if the tool consumer object was successfully deleted - */ + /** + * Delete tool consumer object. + * + * @param ToolConsumer $consumer Consumer object. + * + * @return bool TRUE if the tool consumer object was successfully deleted + */ public function deleteToolConsumer($consumer) { - $id = $consumer->getRecordId(); - -// Delete any nonce values for this consumer + + // Delete any nonce values for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any outstanding share keys for resource links for this consumer - $sql = 'DELETE sk ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.consumer_pk = :id'; + + // Delete any outstanding share keys for resource links for this consumer + $sql = 'DELETE sk ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + ' sk ' . "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any outstanding share keys for resource links for contexts in this consumer - $sql = 'DELETE sk ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'WHERE c.consumer_pk = :id'; + + // Delete any outstanding share keys for resource links for contexts in this consumer + $sql = 'DELETE sk ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + ' sk ' . "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . 'WHERE c.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any users in resource links for this consumer - $sql = 'DELETE u ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.consumer_pk = :id'; + + // Delete any users in resource links for this consumer + $sql = 'DELETE u ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON u.resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any users in resource links for contexts in this consumer - $sql = 'DELETE u ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'WHERE c.consumer_pk = :id'; + + // Delete any users in resource links for contexts in this consumer + $sql = 'DELETE u ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON u.resource_link_pk = rl.resource_link_pk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . 'WHERE c.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Update any resource links for which this consumer is acting as a primary resource link + + // Update any resource links for which this consumer is acting as a primary resource link $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . - 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . - 'WHERE rl.consumer_pk = :id'; + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . + 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . 'WHERE rl.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Update any resource links for contexts in which this consumer is acting as a primary resource link + + // Update any resource links for contexts in which this consumer is acting as a primary resource link $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . - 'WHERE c.consumer_pk = :id'; + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . "INNER JOIN {$this->dbTableNamePrefix}" . + DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . + 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . 'WHERE c.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any resource links for this consumer - $sql = 'DELETE rl ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - 'WHERE rl.consumer_pk = :id'; + + // Delete any resource links for this consumer + $sql = 'DELETE rl ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + 'WHERE rl.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any resource links for contexts in this consumer - $sql = 'DELETE rl ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'WHERE c.consumer_pk = :id'; + + // Delete any resource links for contexts in this consumer + $sql = 'DELETE rl ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' c ON rl.context_pk = c.context_pk ' . 'WHERE c.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any contexts for this consumer - $sql = 'DELETE c ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . - 'WHERE c.consumer_pk = :id'; + + // Delete any contexts for this consumer + $sql = 'DELETE c ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE c.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete consumer - $sql = 'DELETE c ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' c ' . - 'WHERE c.consumer_pk = :id'; + + // Delete consumer + $sql = 'DELETE c ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' c ' . + 'WHERE c.consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); - + if ($ok) { $consumer->initialize(); } - + return $ok; - } - -### -# Load all tool consumers from the database -### + + ### + # Load all tool consumers from the database + ### public function getToolConsumers() { - $consumers = array(); - + $sql = 'SELECT consumer_pk, name, consumer_key256, consumer_key, secret, lti_version, ' . - 'consumer_name, consumer_version, consumer_guid, ' . - 'profile, tool_proxy, settings, protected, enabled, ' . - 'enable_from, enable_until, last_access, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . - 'ORDER BY name'; + 'consumer_name, consumer_version, consumer_guid, ' . 'profile, tool_proxy, settings, protected, enabled, ' . + 'enable_from, enable_until, last_access, created, updated ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::CONSUMER_TABLE_NAME . ' ' . 'ORDER BY name'; $query = $this->db->prepare($sql); - $ok = ($query !== FALSE); - + $ok = ($query !== false); + if ($ok) { $ok = $query->execute(); } - + if ($ok) { while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $row = array_change_key_case($row); @@ -374,139 +373,145 @@ public function getToolConsumers() $consumer->profile = json_decode($row['profile']); $consumer->toolProxy = $row['tool_proxy']; $settings = unserialize($row['settings']); + if (!is_array($settings)) { $settings = array(); } + $consumer->setSettings($settings); $consumer->protected = (intval($row['protected']) === 1); $consumer->enabled = (intval($row['enabled']) === 1); $consumer->enableFrom = null; + if (!is_null($row['enable_from'])) { $consumer->enableFrom = strtotime($row['enable_from']); } + $consumer->enableUntil = null; + if (!is_null($row['enable_until'])) { $consumer->enableUntil = strtotime($row['enable_until']); } + $consumer->lastAccess = null; + if (!is_null($row['last_access'])) { $consumer->lastAccess = strtotime($row['last_access']); } + $consumer->created = strtotime($row['created']); $consumer->updated = strtotime($row['updated']); $consumers[] = $consumer; } } - + return $consumers; - } - -### -### ToolProxy methods -### - -### -# Load the tool proxy from the database -### + + ### + ### ToolProxy methods + ### + + + ### + # Load the tool proxy from the database + ### public function loadToolProxy($toolProxy) { - return false; - } - -### -# Save the tool proxy to the database -### + + ### + # Save the tool proxy to the database + ### public function saveToolProxy($toolProxy) { - return false; - } - -### -# Delete the tool proxy from the database -### + + ### + # Delete the tool proxy from the database + ### public function deleteToolProxy($toolProxy) { - return false; - } - -### -### Context methods -### - -/** - * Load context object. - * - * @param Context $context Context object - * - * @return boolean True if the context object was successfully loaded - */ + + ### + ### Context methods + ### + + + /** + * Load context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the context object was successfully loaded + */ public function loadContext($context) { - $ok = false; + if (!empty($context->getRecordId())) { $sql = 'SELECT context_pk, consumer_pk, lti_context_id, settings, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . - 'WHERE (context_pk = :id)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . 'WHERE (context_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $context->getRecordId(), PDO::PARAM_INT); } else { $sql = 'SELECT context_pk, consumer_pk, lti_context_id, settings, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . - 'WHERE (consumer_pk = :cid) AND (lti_context_id = :ctx)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . + 'WHERE (consumer_pk = :cid) AND (lti_context_id = :ctx)'; $query = $this->db->prepare($sql); $query->bindValue('cid', $context->getConsumer()->getRecordId(), PDO::PARAM_INT); $query->bindValue('ctx', $context->ltiContextId, PDO::PARAM_STR); } + $ok = $query->execute(); + if ($ok) { - $row = $query->fetch(PDO::FETCH_ASSOC); - $ok = ($row !== FALSE); + $row = $query->fetch(PDO::FETCH_ASSOC); + $ok = ($row !== false); } + if ($ok) { $row = array_change_key_case($row); $context->setRecordId(intval($row['context_pk'])); $context->setConsumerId(intval($row['consumer_pk'])); $context->ltiContextId = $row['lti_context_id']; $settings = unserialize($row['settings']); + if (!is_array($settings)) { $settings = array(); } + $context->setSettings($settings); $context->created = strtotime($row['created']); $context->updated = strtotime($row['updated']); } - + return $ok; - } -/** - * Save context object. - * - * @param Context $context Context object - * - * @return boolean True if the context object was successfully saved - */ + /** + * Save context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the context object was successfully saved + */ public function saveContext($context) { - $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $settingsValue = serialize($context->getSettings()); $id = $context->getRecordId(); $consumer_pk = $context->getConsumer()->getRecordId(); + if (empty($id)) { - $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' (consumer_pk, lti_context_id, ' . - 'settings, created, updated) ' . - 'VALUES (:cid, :ctx, :settings, :created, :updated)'; + $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' (consumer_pk, lti_context_id, ' . 'settings, created, updated) ' . + 'VALUES (:cid, :ctx, :settings, :created, :updated)'; $query = $this->db->prepare($sql); $query->bindValue('cid', $consumer_pk, PDO::PARAM_INT); $query->bindValue('ctx', $context->ltiContextId, PDO::PARAM_STR); @@ -515,9 +520,8 @@ public function saveContext($context) $query->bindValue('updated', $now, PDO::PARAM_STR); } else { $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' SET ' . - 'lti_context_id = :ctx, settings = :settings, '. - 'updated = :updated ' . - 'WHERE (consumer_pk = :cid) AND (context_pk = :ctxid)'; + 'lti_context_id = :ctx, settings = :settings, ' . 'updated = :updated ' . + 'WHERE (consumer_pk = :cid) AND (context_pk = :ctxid)'; $query = $this->db->prepare($sql); $query->bindValue('ctx', $context->ltiContextId, PDO::PARAM_STR); $query->bindValue('settings', $settingsValue, PDO::PARAM_STR); @@ -525,190 +529,200 @@ public function saveContext($context) $query->bindValue('cid', $consumer_pk, PDO::PARAM_INT); $query->bindValue('ctxid', $id, PDO::PARAM_INT); } + $ok = $query->execute(); + if ($ok) { if (empty($id)) { $context->setRecordId(intval($this->db->lastInsertId())); $context->created = $time; } + $context->updated = $time; } - + return $ok; - } -/** - * Delete context object. - * - * @param Context $context Context object - * - * @return boolean True if the Context object was successfully deleted - */ + /** + * Delete context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the Context object was successfully deleted + */ public function deleteContext($context) { - $id = $context->getRecordId(); - -// Delete any outstanding share keys for resource links for this context - $sql = 'DELETE sk ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' sk ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.context_pk = :id'; + + // Delete any outstanding share keys for resource links for this context + $sql = 'DELETE sk ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + ' sk ' . "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON sk.resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.context_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any users in resource links for this context - $sql = 'DELETE u ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON u.resource_link_pk = rl.resource_link_pk ' . - 'WHERE rl.context_pk = :id'; + + // Delete any users in resource links for this context + $sql = 'DELETE u ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON u.resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.context_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Update any resource links for which this consumer is acting as a primary resource link + + // Update any resource links for which this consumer is acting as a primary resource link $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . - 'SET prl.primary_resource_link_pk = null, prl.share_approved = null ' . - 'WHERE rl.context_pk = :id'; + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . + 'SET prl.primary_resource_link_pk = null, prl.share_approved = null ' . 'WHERE rl.context_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any resource links for this consumer - $sql = 'DELETE rl ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - 'WHERE rl.context_pk = :id'; + + // Delete any resource links for this consumer + $sql = 'DELETE rl ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + 'WHERE rl.context_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete context - $sql = 'DELETE c ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . - 'WHERE c.context_pk = :id'; + + // Delete context + $sql = 'DELETE c ' . "FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE c.context_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); - + if ($ok) { $context->initialize(); } - + return $ok; - } - -### -### ResourceLink methods -### - -/** - * Load resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully loaded - */ + + ### + ### ResourceLink methods + ### + + + /** + * Load resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully loaded + */ public function loadResourceLink($resourceLink) { - if (!empty($resourceLink->getRecordId())) { $sql = 'SELECT resource_link_pk, context_pk, consumer_pk, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = :id)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . + 'WHERE (resource_link_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $resourceLink->getRecordId(), PDO::PARAM_INT); - } else if (!empty($resourceLink->getContext())) { + } elseif (!empty($resourceLink->getContext())) { $sql = 'SELECT resource_link_pk, context_pk, consumer_pk, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = :id) AND (lti_resource_link_id = :rlid)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . + 'WHERE (context_pk = :id) AND (lti_resource_link_id = :rlid)'; $query = $this->db->prepare($sql); $query->bindValue('id', $resourceLink->getContext()->getRecordId(), PDO::PARAM_INT); $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR); } else { $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 ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . - $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME . ' c ON r.context_pk = c.context_pk ' . - ' WHERE ((r.consumer_pk = :id1) OR (c.consumer_pk = :id2)) AND (lti_resource_link_id = :rlid)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . + $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME . ' c ON r.context_pk = c.context_pk ' . + ' WHERE ((r.consumer_pk = :id1) OR (c.consumer_pk = :id2)) AND (lti_resource_link_id = :rlid)'; $query = $this->db->prepare($sql); $query->bindValue('id1', $resourceLink->getConsumer()->getRecordId(), PDO::PARAM_INT); $query->bindValue('id2', $resourceLink->getConsumer()->getRecordId(), PDO::PARAM_INT); $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR); } + $ok = $query->execute(); + if ($ok) { - $row = $query->fetch(PDO::FETCH_ASSOC); - $ok = ($row !== FALSE); + $row = $query->fetch(PDO::FETCH_ASSOC); + $ok = ($row !== false); } - + if ($ok) { $row = array_change_key_case($row); $resourceLink->setRecordId(intval($row['resource_link_pk'])); + if (!is_null($row['context_pk'])) { $resourceLink->setContextId(intval($row['context_pk'])); } else { $resourceLink->setContextId(null); } + if (!is_null($row['consumer_pk'])) { $resourceLink->setConsumerId(intval($row['consumer_pk'])); } else { $resourceLink->setConsumerId(null); } + $resourceLink->ltiResourceLinkId = $row['lti_resource_link_id']; $settings = unserialize($row['settings']); + if (!is_array($settings)) { $settings = array(); } + $resourceLink->setSettings($settings); + if (!is_null($row['primary_resource_link_pk'])) { $resourceLink->primaryResourceLinkId = intval($row['primary_resource_link_pk']); } else { $resourceLink->primaryResourceLinkId = null; } - $resourceLink->shareApproved = (is_null($row['share_approved'])) ? null : (intval($row['share_approved']) === 1); + + $resourceLink->shareApproved = (is_null($row['share_approved'])) ? null : (intval($row['share_approved']) === + 1); $resourceLink->created = strtotime($row['created']); $resourceLink->updated = strtotime($row['updated']); } - + return $ok; - } -/** - * Save resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully saved - */ - public function saveResourceLink($resourceLink) { - + /** + * Save resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully saved + */ + public function saveResourceLink($resourceLink) + { $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $settingsValue = serialize($resourceLink->getSettings()); + if (!empty($resourceLink->getContext())) { $consumerId = null; $contextId = strval($resourceLink->getContext()->getRecordId()); - } else if (!empty($resourceLink->getContextId())) { + } elseif (!empty($resourceLink->getContextId())) { $consumerId = null; $contextId = strval($resourceLink->getContextId()); } else { $consumerId = strval($resourceLink->getConsumer()->getRecordId()); $contextId = null; } + if (empty($resourceLink->primaryResourceLinkId)) { $primaryResourceLinkId = null; } else { $primaryResourceLinkId = $resourceLink->primaryResourceLinkId; } + $id = $resourceLink->getRecordId(); + if (empty($id)) { - $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' (consumer_pk, context_pk, ' . - 'lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated) ' . - 'VALUES (:cid, :ctx, :rlid, :settings, :prlid, :share_approved, :created, :updated)'; + $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + ' (consumer_pk, context_pk, ' . + 'lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated) ' . + 'VALUES (:cid, :ctx, :rlid, :settings, :prlid, :share_approved, :created, :updated)'; $query = $this->db->prepare($sql); $query->bindValue('cid', $consumerId, PDO::PARAM_INT); $query->bindValue('ctx', $contextId, PDO::PARAM_INT); @@ -718,11 +732,11 @@ public function saveResourceLink($resourceLink) { $query->bindValue('share_approved', $resourceLink->shareApproved, PDO::PARAM_INT); $query->bindValue('created', $now, PDO::PARAM_STR); $query->bindValue('updated', $now, PDO::PARAM_STR); - } else if (!is_null($contextId)) { + } elseif (!is_null($contextId)) { $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'consumer_pk = NULL, context_pk = :ctx, lti_resource_link_id = :rlid, settings = :settings, '. - 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' . - 'WHERE (resource_link_pk = :id)'; + 'consumer_pk = NULL, context_pk = :ctx, lti_resource_link_id = :rlid, settings = :settings, ' . + 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' . + 'WHERE (resource_link_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('ctx', $contextId, PDO::PARAM_INT); $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR); @@ -733,9 +747,9 @@ public function saveResourceLink($resourceLink) { $query->bindValue('id', $id, PDO::PARAM_INT); } else { $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = :ctx, lti_resource_link_id = :rlid, settings = :settings, '. - 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' . - 'WHERE (consumer_pk = :cid) AND (resource_link_pk = :id)'; + 'context_pk = :ctx, lti_resource_link_id = :rlid, settings = :settings, ' . + 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' . + 'WHERE (consumer_pk = :cid) AND (resource_link_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('ctx', $contextId, PDO::PARAM_INT); $query->bindValue('rlid', $resourceLink->getId(), PDO::PARAM_STR); @@ -746,115 +760,115 @@ public function saveResourceLink($resourceLink) { $query->bindValue('cid', $consumerId, PDO::PARAM_INT); $query->bindValue('id', $id, PDO::PARAM_INT); } + $ok = $query->execute(); + if ($ok) { if (empty($id)) { $resourceLink->setRecordId(intval($this->db->lastInsertId())); $resourceLink->created = $time; } + $resourceLink->updated = $time; } - + return $ok; - } -/** - * Delete resource link object. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return boolean True if the resource link object was successfully deleted - */ + /** + * Delete resource link object. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return bool TRUE if the resource link object was successfully deleted + */ public function deleteResourceLink($resourceLink) { - $id = $resourceLink->getRecordId(); - -// Delete any outstanding share keys for resource links for this consumer + + // Delete any outstanding share keys for resource links for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = :id)'; + 'WHERE (resource_link_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); - -// Delete users + + // Delete users if ($ok) { $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = :id)'; + 'WHERE (resource_link_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); } - -// Update any resource links for which this is the primary resource link + + // Update any resource links for which this is the primary resource link if ($ok) { $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'SET primary_resource_link_pk = NULL ' . - 'WHERE (primary_resource_link_pk = :id)'; + 'SET primary_resource_link_pk = NULL ' . 'WHERE (primary_resource_link_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); } - -// Delete resource link + + // Delete resource link if ($ok) { $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = :id)'; + 'WHERE (resource_link_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); } - + if ($ok) { $resourceLink->initialize(); } - + return $ok; - } -/** - * Get array of user objects. - * - * Obtain an array of User objects for users with a result sourcedId. The array may include users from other - * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope. - * - * @param ResourceLink $resourceLink Resource link object - * @param boolean $localOnly True if only users within the resource link are to be returned (excluding users sharing this resource link) - * @param int $idScope Scope value to use for user IDs - * - * @return array Array of User objects - */ + /** + * Get array of user objects. + * + * Obtain an array of User objects for users with a result sourcedId. The array may include users from other + * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope. + * + * @param ResourceLink $resourceLink Resource link object. + * @param bool $localOnly TRUE if only users within the resource link are to be returned (excluding users sharing this resource link). + * @param int $idScope Scope value to use for user IDs. + * + * @return array Array of User objects + */ public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $idScope) { - $id = $resourceLink->getRecordId(); $users = array(); - + if ($localOnly) { $sql = 'SELECT u.user_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . - 'ON u.resource_link_pk = rl.resource_link_pk ' . - 'WHERE (rl.resource_link_pk = :id) AND (rl.primary_resource_link_pk IS NULL)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . + 'ON u.resource_link_pk = rl.resource_link_pk ' . + 'WHERE (rl.resource_link_pk = :id) AND (rl.primary_resource_link_pk IS NULL)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); } else { $sql = 'SELECT u.user_pk, u.lti_result_sourcedid, u.lti_user_id, u.created, u.updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . - 'ON u.resource_link_pk = rl.resource_link_pk ' . - 'WHERE ((rl.resource_link_pk = :id) AND (rl.primary_resource_link_pk IS NULL)) OR ' . - '((rl.primary_resource_link_pk = :pid) AND (share_approved = 1))'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' AS u ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' AS rl ' . + 'ON u.resource_link_pk = rl.resource_link_pk ' . + 'WHERE ((rl.resource_link_pk = :id) AND (rl.primary_resource_link_pk IS NULL)) OR ' . + '((rl.primary_resource_link_pk = :pid) AND (share_approved = 1))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->bindValue('pid', $id, PDO::PARAM_INT); } + if ($query->execute()) { while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $row = array_change_key_case($row); $user = ToolProvider\User::fromRecordId($row['user_pk'], $resourceLink->getDataConnector()); + if (is_null($idScope)) { $users[] = $user; } else { @@ -862,31 +876,29 @@ public function getUserResultSourcedIDsResourceLink($resourceLink, $localOnly, $ } } } - + return $users; - } -/** - * Get array of shares defined for this resource link. - * - * @param ResourceLink $resourceLink Resource_Link object - * - * @return array Array of ResourceLinkShare objects - */ + /** + * Get array of shares defined for this resource link. + * + * @param ResourceLink $resourceLink Resource_Link object. + * + * @return array Array of ResourceLinkShare objects + */ public function getSharesResourceLink($resourceLink) { - $id = $resourceLink->getRecordId(); - + $shares = array(); - - $sql = 'SELECT consumer_pk, resource_link_pk, share_approved ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (primary_resource_link_pk = :id) ' . - 'ORDER BY consumer_pk'; + + $sql = 'SELECT consumer_pk, resource_link_pk, share_approved ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . 'WHERE (primary_resource_link_pk = :id) ' . + 'ORDER BY consumer_pk'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); + if ($query->execute()) { while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $row = array_change_key_case($row); @@ -896,113 +908,114 @@ public function getSharesResourceLink($resourceLink) $shares[] = $share; } } - + return $shares; - } - - -### -### ConsumerNonce methods -### - -/** - * Load nonce object. - * - * @param ConsumerNonce $nonce Nonce object - * - * @return boolean True if the nonce object was successfully loaded - */ + + ### + ### ConsumerNonce methods + ### + + + /** + * Load nonce object. + * + * @param ConsumerNonce $nonce Nonce object. + * + * @return bool TRUE if the nonce object was successfully loaded + */ public function loadConsumerNonce($nonce) { - $ok = true; - -// Delete any expired nonce values + + // Delete any expired nonce values $now = date("{$this->dateFormat} {$this->timeFormat}", time()); $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE expires <= :now'; $query = $this->db->prepare($sql); $query->bindValue('now', $now, PDO::PARAM_STR); $query->execute(); - -// Load the nonce + + // Load the nonce $id = $nonce->getConsumer()->getRecordId(); $value = $nonce->getValue(); - $sql = "SELECT value T FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE (consumer_pk = :id) AND (value = :value)'; + $sql = "SELECT value T FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . + ' WHERE (consumer_pk = :id) AND (value = :value)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->bindValue('value', $value, PDO::PARAM_STR); $ok = $query->execute(); + if ($ok) { $row = $query->fetch(PDO::FETCH_ASSOC); + if ($row === false) { $ok = false; } } - + return $ok; - } -/** - * Save nonce object. - * - * @param ConsumerNonce $nonce Nonce object - * - * @return boolean True if the nonce object was successfully saved - */ + /** + * Save nonce object. + * + * @param ConsumerNonce $nonce Nonce object. + * + * @return bool TRUE if the nonce object was successfully saved + */ public function saveConsumerNonce($nonce) { - $id = $nonce->getConsumer()->getRecordId(); $value = $nonce->getValue(); $expires = date("{$this->dateFormat} {$this->timeFormat}", $nonce->expires); - $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' (consumer_pk, value, expires) VALUES (:id, :value, :expires)'; + $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . + ' (consumer_pk, value, expires) VALUES (:id, :value, :expires)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->bindValue('value', $value, PDO::PARAM_STR); $query->bindValue('expires', $expires, PDO::PARAM_STR); $ok = $query->execute(); - + return $ok; - } - - -### -### ResourceLinkShareKey methods -### - -/** - * Load resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource_Link share key object - * - * @return boolean True if the resource link share key object was successfully loaded - */ + + ### + ### ResourceLinkShareKey methods + ### + + + /** + * Load resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource_Link share key object. + * + * @return bool TRUE if the resource link share key object was successfully loaded + */ public function loadResourceLinkShareKey($shareKey) { - $ok = false; - -// Clear expired share keys + + // Clear expired share keys $now = date("{$this->dateFormat} {$this->timeFormat}", time()); - $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' WHERE expires <= :now'; + $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + ' WHERE expires <= :now'; $query = $this->db->prepare($sql); $query->bindValue('now', $now, PDO::PARAM_STR); $query->execute(); - -// Load share key + + // Load share key $id = $shareKey->getId(); - $sql = 'SELECT resource_link_pk, auto_approve, expires ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - 'WHERE share_key_id = :id'; + $sql = 'SELECT resource_link_pk, auto_approve, expires ' . "FROM {$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . 'WHERE share_key_id = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_STR); + if ($query->execute()) { $row = $query->fetch(PDO::FETCH_ASSOC); - if ($row !== FALSE) { + + if ($row !== false) { $row = array_change_key_case($row); + if (intval($row['resource_link_pk']) === $shareKey->resourceLinkId) { $shareKey->autoApprove = ($row['auto_approve'] === 1); $shareKey->expires = strtotime($row['expires']); @@ -1010,96 +1023,93 @@ public function loadResourceLinkShareKey($shareKey) } } } - + return $ok; - } -/** - * Save resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource link share key object - * - * @return boolean True if the resource link share key object was successfully saved - */ + /** + * Save resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource link share key object. + * + * @return bool TRUE if the resource link share key object was successfully saved + */ public function saveResourceLinkShareKey($shareKey) { - $id = $shareKey->getId(); $expires = date("{$this->dateFormat} {$this->timeFormat}", $shareKey->expires); $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - '(share_key_id, resource_link_pk, auto_approve, expires) ' . - 'VALUES (:id, :prlid, :approve, :expires)'; + '(share_key_id, resource_link_pk, auto_approve, expires) ' . 'VALUES (:id, :prlid, :approve, :expires)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_STR); $query->bindValue('prlid', $shareKey->resourceLinkId, PDO::PARAM_INT); $query->bindValue('approve', $shareKey->autoApprove, PDO::PARAM_INT); $query->bindValue('expires', $expires, PDO::PARAM_STR); $ok = $query->execute(); - + return $ok; - } -/** - * Delete resource link share key object. - * - * @param ResourceLinkShareKey $shareKey Resource link share key object - * - * @return boolean True if the resource link share key object was successfully deleted - */ + /** + * Delete resource link share key object. + * + * @param ResourceLinkShareKey $shareKey Resource link share key object. + * + * @return bool TRUE if the resource link share key object was successfully deleted + */ public function deleteResourceLinkShareKey($shareKey) { - $id = $shareKey->getId(); - $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' WHERE share_key_id = :id'; + $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + ' WHERE share_key_id = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_STR); $ok = $query->execute(); - + if ($ok) { $shareKey->initialize(); } - + return $ok; - } - - -### -### User methods -### - -/** - * Load user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully loaded - */ + + ### + ### User methods + ### + + + /** + * Load user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully loaded + */ public function loadUser($user) { - $ok = false; + if (!empty($user->getRecordId())) { $id = $user->getRecordId(); $sql = 'SELECT user_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (user_pk = :id)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . + 'WHERE (user_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); } else { $id = $user->getResourceLink()->getRecordId(); $uid = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY); $sql = 'SELECT user_pk, resource_link_pk, lti_user_id, lti_result_sourcedid, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (resource_link_pk = :id) AND (lti_user_id = :uid)'; + "FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . + 'WHERE (resource_link_pk = :id) AND (lti_user_id = :uid)'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->bindValue('uid', $uid, PDO::PARAM_STR); } + if ($query->execute()) { $row = $query->fetch(PDO::FETCH_ASSOC); + if ($row !== false) { $row = array_change_key_case($row); $user->setRecordId(intval($row['user_pk'])); @@ -1111,27 +1121,26 @@ public function loadUser($user) $ok = true; } } - + return $ok; - } -/** - * Save user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully saved - */ + /** + * Save user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully saved + */ public function saveUser($user) { - $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); + if (is_null($user->created)) { - $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' (resource_link_pk, ' . - 'lti_user_id, lti_result_sourcedid, created, updated) ' . - 'VALUES (:rlid, :uid, :sourcedid, :created, :updated)'; + $sql = "INSERT INTO {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . + ' (resource_link_pk, ' . 'lti_user_id, lti_result_sourcedid, created, updated) ' . + 'VALUES (:rlid, :uid, :sourcedid, :created, :updated)'; $query = $this->db->prepare($sql); $query->bindValue('rlid', $user->getResourceLink()->getRecordId(), PDO::PARAM_INT); $query->bindValue('uid', $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY), PDO::PARAM_STR); @@ -1140,48 +1149,46 @@ public function saveUser($user) $query->bindValue('updated', $now, PDO::PARAM_STR); } else { $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'SET lti_result_sourcedid = :sourcedid, updated = :updated ' . - 'WHERE (user_pk = :id)'; + 'SET lti_result_sourcedid = :sourcedid, updated = :updated ' . 'WHERE (user_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('sourcedid', $user->ltiResultSourcedId, PDO::PARAM_STR); $query->bindValue('updated', $now, PDO::PARAM_STR); $query->bindValue('id', $user->getRecordId(), PDO::PARAM_INT); } + $ok = $query->execute(); + if ($ok) { if (is_null($user->created)) { $user->setRecordId(intval($this->db->lastInsertId())); $user->created = $time; } + $user->updated = $time; } - + return $ok; - } -/** - * Delete user object. - * - * @param User $user User object - * - * @return boolean True if the user object was successfully deleted - */ + /** + * Delete user object. + * + * @param User $user User object. + * + * @return bool TRUE if the user object was successfully deleted + */ public function deleteUser($user) { - $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - 'WHERE (user_pk = :id)'; + 'WHERE (user_pk = :id)'; $query = $this->db->prepare($sql); $query->bindValue('id', $user->getRecordId(), PDO::PARAM_INT); $ok = $query->execute(); - + if ($ok) { $user->initialize(); } - + return $ok; - } - } diff --git a/src/ToolProvider/DataConnector/DataConnector_pdo_sqlite.php b/src/ToolProvider/DataConnector/DataConnector_pdo_sqlite.php index 93f03b3..5abbb30 100644 --- a/src/ToolProvider/DataConnector/DataConnector_pdo_sqlite.php +++ b/src/ToolProvider/DataConnector/DataConnector_pdo_sqlite.php @@ -1,5 +1,4 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ - - class DataConnector_pdo_sqlite extends DataConnector_pdo { - -### -### ToolConsumer methods -### - -/** - * Delete tool consumer object. - * - * @param ToolConsumer $consumer Consumer object - * - * @return boolean True if the tool consumer object was successfully deleted - */ + + ### + ### ToolConsumer methods + ### + + + /** + * Delete tool consumer object. + * + * @param ToolConsumer $consumer Consumer object. + * + * @return bool TRUE if the tool consumer object was successfully deleted + */ public function deleteToolConsumer($consumer) { - $id = $consumer->getRecordId(); - -// Delete any nonce values for this consumer + + // Delete any nonce values for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::NONCE_TABLE_NAME . ' WHERE consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any outstanding share keys for resource links for this consumer + + // Delete any outstanding share keys for resource links for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . '.resource_link_pk = rl.resource_link_pk) AND (rl.consumer_pk = :id))'; + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + '.resource_link_pk = rl.resource_link_pk) AND (rl.consumer_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any outstanding share keys for resource links for contexts in this consumer + + // Delete any outstanding share keys for resource links for contexts in this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . '.resource_link_pk = rl.resource_link_pk) AND (c.consumer_pk = :id))'; + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' c ON rl.context_pk = c.context_pk ' . "WHERE ({$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + '.resource_link_pk = rl.resource_link_pk) AND (c.consumer_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any users in resource links for this consumer + + // Delete any users in resource links for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . '.resource_link_pk = rl.resource_link_pk) AND (rl.consumer_pk = :id))'; + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "WHERE ({$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . + '.resource_link_pk = rl.resource_link_pk) AND (rl.consumer_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any users in resource links for contexts in this consumer + + // Delete any users in resource links for contexts in this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . '.resource_link_pk = rl.resource_link_pk) AND (c.consumer_pk = :id))'; + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' c ON rl.context_pk = c.context_pk ' . "WHERE ({$this->dbTableNamePrefix}" . + DataConnector::USER_RESULT_TABLE_NAME . + '.resource_link_pk = rl.resource_link_pk) AND (c.consumer_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Update any resource links for which this consumer is acting as a primary resource link + + // Update any resource links for which this consumer is acting as a primary resource link $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'SET primary_resource_link_pk = NULL, share_approved = NULL ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . '.primary_resource_link_pk = rl.resource_link_pk) AND (rl.consumer_pk = :id))'; + 'SET primary_resource_link_pk = NULL, share_approved = NULL ' . + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + '.primary_resource_link_pk = rl.resource_link_pk) AND (rl.consumer_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Update any resource links for contexts in which this consumer is acting as a primary resource link + + // Update any resource links for contexts in which this consumer is acting as a primary resource link $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'SET primary_resource_link_pk = NULL, share_approved = NULL ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . '.primary_resource_link_pk = rl.resource_link_pk) AND (c.consumer_pk = :id))'; + 'SET primary_resource_link_pk = NULL, share_approved = NULL ' . + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "INNER JOIN {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . + ' c ON rl.context_pk = c.context_pk ' . "WHERE ({$this->dbTableNamePrefix}" . + DataConnector::RESOURCE_LINK_TABLE_NAME . + '.primary_resource_link_pk = rl.resource_link_pk) AND (c.consumer_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any resource links for this consumer + + // Delete any resource links for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE consumer_pk = :id'; + 'WHERE consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any resource links for contexts in this consumer + + // Delete any resource links for contexts in this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . '.context_pk = c.context_pk) AND (c.consumer_pk = :id))'; + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' c ' . + "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + '.context_pk = c.context_pk) AND (c.consumer_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any contexts for this consumer + + // Delete any contexts for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . - 'WHERE consumer_pk = :id'; + 'WHERE consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete consumer + + // Delete consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::CONSUMER_TABLE_NAME . ' ' . - 'WHERE consumer_pk = :id'; + 'WHERE consumer_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); - + if ($ok) { $consumer->initialize(); } - + return $ok; - } - -### -### Context methods -### - -/** - * Delete context object. - * - * @param Context $context Context object - * - * @return boolean True if the Context object was successfully deleted - */ + + ### + ### Context methods + ### + + + /** + * Delete context object. + * + * @param Context $context Context object. + * + * @return bool TRUE if the Context object was successfully deleted + */ public function deleteContext($context) { - $id = $context->getRecordId(); - -// Delete any outstanding share keys for resource links for this context + + // Delete any outstanding share keys for resource links for this context $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . '.resource_link_pk = rl.resource_link_pk) AND (rl.context_pk = :id))'; + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . + '.resource_link_pk = rl.resource_link_pk) AND (rl.context_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any users in resource links for this context + + // Delete any users in resource links for this context $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . ' ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . '.resource_link_pk = rl.resource_link_pk) AND (rl.context_pk = :id))'; + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "WHERE ({$this->dbTableNamePrefix}" . DataConnector::USER_RESULT_TABLE_NAME . + '.resource_link_pk = rl.resource_link_pk) AND (rl.context_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Update any resource links for which this consumer is acting as a primary resource link + + // Update any resource links for which this consumer is acting as a primary resource link $sql = "UPDATE {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'SET primary_resource_link_pk = null, share_approved = null ' . - "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . - "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . '.primary_resource_link_pk = rl.resource_link_pk) AND (rl.context_pk = :id))'; + 'SET primary_resource_link_pk = null, share_approved = null ' . + "WHERE EXISTS (SELECT * FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' rl ' . + "WHERE ({$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . + '.primary_resource_link_pk = rl.resource_link_pk) AND (rl.context_pk = :id))'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete any resource links for this consumer + + // Delete any resource links for this consumer $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE context_pk = :id'; + 'WHERE context_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $query->execute(); - -// Delete context + + // Delete context $sql = "DELETE FROM {$this->dbTableNamePrefix}" . DataConnector::CONTEXT_TABLE_NAME . ' ' . - 'WHERE context_pk = :id'; + 'WHERE context_pk = :id'; $query = $this->db->prepare($sql); $query->bindValue('id', $id, PDO::PARAM_INT); $ok = $query->execute(); - + if ($ok) { $context->initialize(); } - + return $ok; - } - } diff --git a/src/ToolProvider/MediaType/Message.php b/src/ToolProvider/MediaType/Message.php index 2eb040c..aaceac2 100644 --- a/src/ToolProvider/MediaType/Message.php +++ b/src/ToolProvider/MediaType/Message.php @@ -1,52 +1,51 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 - * @version 3.0.0 - * @license GNU Lesser General Public License, version 3 () + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc + * @version 3.0.0 + * @license Apache-2.0 */ class Message { -/** - * Class constructor. - * - * @param Message $message Message object - * @param array $capabilitiesOffered Capabilities offered - */ - function __construct($message, $capabilitiesOffered) + /** + * Class constructor. + * + * @param Message $message Message object. + * @param array $capabilitiesOffered Capabilities offered. + */ + public function __construct($message, $capabilitiesOffered) { - $this->message_type = $message->type; $this->path = $message->path; $this->enabled_capability = array(); + foreach ($message->capabilities as $capability) { if (in_array($capability, $capabilitiesOffered)) { $this->enabled_capability[] = $capability; } } + $this->parameter = array(); + foreach ($message->constants as $name => $value) { - $parameter = new \stdClass; + $parameter = new \stdClass(); $parameter->name = $name; $parameter->fixed = $value; $this->parameter[] = $parameter; } + foreach ($message->variables as $name => $value) { if (in_array($value, $capabilitiesOffered)) { - $parameter = new \stdClass; + $parameter = new \stdClass(); $parameter->name = $name; $parameter->variable = $value; $this->parameter[] = $parameter; } } - } - } diff --git a/src/ToolProvider/MediaType/ResourceHandler.php b/src/ToolProvider/MediaType/ResourceHandler.php index 9177fcf..d5fc26e 100644 --- a/src/ToolProvider/MediaType/ResourceHandler.php +++ b/src/ToolProvider/MediaType/ResourceHandler.php @@ -1,52 +1,50 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 - * @version 3.0.0 - * @license GNU Lesser General Public License, version 3 () + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc + * @version 3.0.0 + * @license Apache-2.0 */ class ResourceHandler { -/** - * Class constructor. - * - * @param ToolProvider $toolProvider Tool Provider object - * @param ProfileResourceHandler $resourceHandler Resource handler object - */ - function __construct($toolProvider, $resourceHandler) + /** + * Class constructor. + * + * @param ToolProvider $toolProvider Tool Provider object. + * @param ProfileResourceHandler $resourceHandler Resource handler object. + */ + public function __construct($toolProvider, $resourceHandler) { - - $this->resource_type = new \stdClass; + $this->resource_type = new \stdClass(); $this->resource_type->code = $resourceHandler->item->id; - $this->resource_name = new \stdClass; + $this->resource_name = new \stdClass(); $this->resource_name->default_value = $resourceHandler->item->name; $this->resource_name->key = "{$resourceHandler->item->id}.resource.name"; - $this->description = new \stdClass; + $this->description = new \stdClass(); $this->description->default_value = $resourceHandler->item->description; $this->description->key = "{$resourceHandler->item->id}.resource.description"; - $this->icon_info = new \stdClass; - $this->icon_info->default_location = new \stdClass; + $this->icon_info = new \stdClass(); + $this->icon_info->default_location = new \stdClass(); $this->icon_info->default_location->path = $resourceHandler->icon; $this->icon_info->key = "{$resourceHandler->item->id}.icon.path"; $this->message = array(); + foreach ($resourceHandler->requiredMessages as $message) { $this->message[] = new Message($message, $toolProvider->consumer->profile->capability_offered); } + foreach ($resourceHandler->optionalMessages as $message) { if (in_array($message->type, $toolProvider->consumer->profile->capability_offered)) { $this->message[] = new Message($message, $toolProvider->consumer->profile->capability_offered); } } - } - } diff --git a/src/ToolProvider/MediaType/SecurityContract.php b/src/ToolProvider/MediaType/SecurityContract.php index 2632b10..7e9c63e 100644 --- a/src/ToolProvider/MediaType/SecurityContract.php +++ b/src/ToolProvider/MediaType/SecurityContract.php @@ -1,50 +1,53 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 - * @version 3.0.0 - * @license GNU Lesser General Public License, version 3 () + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc + * @version 3.0.0 + * @license Apache-2.0 */ class SecurityContract { -/** - * Class constructor. - * - * @param ToolProvider $toolProvider Tool Provider instance - * @param string $secret Shared secret - */ - function __construct($toolProvider, $secret) + /** + * Class constructor. + * + * @param ToolProvider $toolProvider Tool Provider instance. + * @param string $secret Shared secret. + */ + public function __construct($toolProvider, $secret) { - $tcContexts = array(); + foreach ($toolProvider->consumer->profile->{'@context'} as $context) { - if (is_object($context)) { - $tcContexts = array_merge(get_object_vars($context), $tcContexts); - } + if (is_object($context)) { + $tcContexts = array_merge(get_object_vars($context), $tcContexts); + } } - + $this->shared_secret = $secret; $toolServices = array(); + foreach ($toolProvider->requiredServices as $requiredService) { foreach ($requiredService->formats as $format) { $service = $toolProvider->findService($format, $requiredService->actions); + if (($service !== false) && !array_key_exists($service->{'@id'}, $toolServices)) { $id = $service->{'@id'}; $parts = explode(':', $id, 2); + if (count($parts) > 1) { if (array_key_exists($parts[0], $tcContexts)) { $id = "{$tcContexts[$parts[0]]}{$parts[1]}"; } } - $toolService = new \stdClass; + + $toolService = new \stdClass(); $toolService->{'@type'} = 'RestServiceProfile'; $toolService->service = $id; $toolService->action = $requiredService->actions; @@ -52,18 +55,22 @@ function __construct($toolProvider, $secret) } } } + foreach ($toolProvider->optionalServices as $optionalService) { foreach ($optionalService->formats as $format) { $service = $toolProvider->findService($format, $optionalService->actions); + if (($service !== false) && !array_key_exists($service->{'@id'}, $toolServices)) { $id = $service->{'@id'}; $parts = explode(':', $id, 2); + if (count($parts) > 1) { if (array_key_exists($parts[0], $tcContexts)) { $id = "{$tcContexts[$parts[0]]}{$parts[1]}"; } } - $toolService = new \stdClass; + + $toolService = new \stdClass(); $toolService->{'@type'} = 'RestServiceProfile'; $toolService->service = $id; $toolService->action = $optionalService->actions; @@ -71,8 +78,7 @@ function __construct($toolProvider, $secret) } } } + $this->tool_service = array_values($toolServices); - } - } diff --git a/src/ToolProvider/MediaType/ToolProfile.php b/src/ToolProvider/MediaType/ToolProfile.php index 1981f7d..72267f1 100644 --- a/src/ToolProvider/MediaType/ToolProfile.php +++ b/src/ToolProvider/MediaType/ToolProfile.php @@ -1,89 +1,98 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 - * @version 3.0.0 - * @license GNU Lesser General Public License, version 3 () + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc + * @version 3.0.0 + * @license Apache-2.0 */ class ToolProfile { public $product_instance; -/** - * Class constructor. - * - * @param ToolProvider $toolProvider Tool Provider object - */ - function __construct($toolProvider) + /** + * Class constructor. + * + * @param ToolProvider $toolProvider Tool Provider object. + */ + public function __construct($toolProvider) { - $this->lti_version = 'LTI-2p0'; - + if (!empty($toolProvider->product)) { - $this->product_instance = new \stdClass; + $this->product_instance = new \stdClass(); } + if (!empty($toolProvider->product->id)) { $this->product_instance->guid = $toolProvider->product->id; } + if (!empty($toolProvider->product->name)) { - $this->product_instance->product_info = new \stdClass; - $this->product_instance->product_info->product_name = new \stdClass; + $this->product_instance->product_info = new \stdClass(); + $this->product_instance->product_info->product_name = new \stdClass(); $this->product_instance->product_info->product_name->default_value = $toolProvider->product->name; $this->product_instance->product_info->product_name->key = 'tool.name'; } + if (!empty($toolProvider->product->description)) { - $this->product_instance->product_info->description = new \stdClass; + $this->product_instance->product_info->description = new \stdClass(); $this->product_instance->product_info->description->default_value = $toolProvider->product->description; $this->product_instance->product_info->description->key = 'tool.description'; } + if (!empty($toolProvider->product->url)) { $this->product_instance->guid = $toolProvider->product->url; } + if (!empty($toolProvider->product->version)) { $this->product_instance->product_info->product_version = $toolProvider->product->version; } + if (!empty($toolProvider->vendor)) { - $this->product_instance->product_info->product_family = new \stdClass; - $this->product_instance->product_info->product_family->vendor = new \stdClass; + $this->product_instance->product_info->product_family = new \stdClass(); + $this->product_instance->product_info->product_family->vendor = new \stdClass(); } + if (!empty($toolProvider->vendor->id)) { $this->product_instance->product_info->product_family->vendor->code = $toolProvider->vendor->id; } + if (!empty($toolProvider->vendor->name)) { - $this->product_instance->product_info->product_family->vendor->vendor_name = new \stdClass; + $this->product_instance->product_info->product_family->vendor->vendor_name = new \stdClass(); $this->product_instance->product_info->product_family->vendor->vendor_name->default_value = $toolProvider->vendor->name; $this->product_instance->product_info->product_family->vendor->vendor_name->key = 'tool.vendor.name'; } + if (!empty($toolProvider->vendor->description)) { - $this->product_instance->product_info->product_family->vendor->description = new \stdClass; + $this->product_instance->product_info->product_family->vendor->description = new \stdClass(); $this->product_instance->product_info->product_family->vendor->description->default_value = $toolProvider->vendor->description; $this->product_instance->product_info->product_family->vendor->description->key = 'tool.vendor.description'; } + if (!empty($toolProvider->vendor->url)) { $this->product_instance->product_info->product_family->vendor->website = $toolProvider->vendor->url; } + if (!empty($toolProvider->vendor->timestamp)) { $this->product_instance->product_info->product_family->vendor->timestamp = date('Y-m-d\TH:i:sP', $toolProvider->vendor->timestamp); } - + $this->resource_handler = array(); + foreach ($toolProvider->resourceHandlers as $resourceHandler) { $this->resource_handler[] = new ResourceHandler($toolProvider, $resourceHandler); } + if (!empty($toolProvider->baseUrl)) { $this->base_url_choice = array(); - $this->base_url_choice[] = new \stdClass; + $this->base_url_choice[] = new \stdClass(); $this->base_url_choice[0]->default_base_url = $toolProvider->baseUrl; } - } - } diff --git a/src/ToolProvider/MediaType/ToolProxy.php b/src/ToolProvider/MediaType/ToolProxy.php index 7fa5d3c..6224380 100644 --- a/src/ToolProvider/MediaType/ToolProxy.php +++ b/src/ToolProvider/MediaType/ToolProxy.php @@ -1,42 +1,39 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 - * @version 3.0.0 - * @license GNU Lesser General Public License, version 3 () + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc + * @version 3.0.0 + * @license Apache-2.0 */ class ToolProxy { -/** - * Class constructor. - * - * @param ToolProvider $toolProvider Tool Provider object - * @param ServiceDefinition $toolProxyService Tool Proxy service - * @param string $secret Shared secret - */ - function __construct($toolProvider, $toolProxyService, $secret) + /** + * Class constructor. + * + * @param ToolProvider $toolProvider Tool Provider object. + * @param ServiceDefinition $toolProxyService Tool Proxy service. + * @param string $secret Shared secret. + */ + public function __construct($toolProvider, $toolProxyService, $secret) { - $contexts = array(); - - $this->{'@context'} = array_merge(array('http://purl.imsglobal.org/ctx/lti/v2/ToolProxy'), $contexts); + + $this->{'@context'} = array_merge(array( + 'http://purl.imsglobal.org/ctx/lti/v2/ToolProxy' + ), $contexts); $this->{'@type'} = 'ToolProxy'; $this->{'@id'} = "{$toolProxyService->endpoint}"; $this->lti_version = 'LTI-2p0'; $this->tool_consumer_profile = $toolProvider->consumer->profile->{'@id'}; $this->tool_profile = new ToolProfile($toolProvider); $this->security_contract = new SecurityContract($toolProvider, $secret); - } - } diff --git a/src/ToolProvider/OAuthDataStore.php b/src/ToolProvider/OAuthDataStore.php index 90d59f5..21b2347 100644 --- a/src/ToolProvider/OAuthDataStore.php +++ b/src/ToolProvider/OAuthDataStore.php @@ -1,126 +1,108 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class OAuthDataStore extends OAuth\OAuthDataStore { -/** - * Tool Provider object. - * - * @var ToolProvider $toolProvider - */ + /** @var ToolProvider Tool Provider object. */ private $toolProvider = null; -/** - * Class constructor. - * - * @param ToolProvider $toolProvider Tool_Provider object - */ + /** + * Class constructor. + * + * @param ToolProvider $toolProvider Tool_Provider object. + */ public function __construct($toolProvider) { - $this->toolProvider = $toolProvider; - } -/** - * Create an OAuthConsumer object for the tool consumer. - * - * @param string $consumerKey Consumer key value - * - * @return OAuthConsumer OAuthConsumer object - */ - function lookup_consumer($consumerKey) + /** + * Create an OAuthConsumer object for the tool consumer. + * + * @param string $consumerKey Consumer key value. + * + * @return OAuthConsumer OAuthConsumer object + */ + public function lookup_consumer($consumerKey) { - - return new OAuth\OAuthConsumer($this->toolProvider->consumer->getKey(), - $this->toolProvider->consumer->secret); - + return new OAuth\OAuthConsumer($this->toolProvider->consumer->getKey(), $this->toolProvider->consumer->secret); } -/** - * Create an OAuthToken object for the tool consumer. - * - * @param string $consumer OAuthConsumer object - * @param string $tokenType Token type - * @param string $token Token value - * - * @return OAuthToken OAuthToken object - */ - function lookup_token($consumer, $tokenType, $token) + /** + * Create an OAuthToken object for the tool consumer. + * + * @param string $consumer OAuthConsumer object. + * @param string $tokenType Token type. + * @param string $token Token value. + * + * @return OAuthToken OAuthToken object + */ + public function lookup_token($consumer, $tokenType, $token) { - return new OAuth\OAuthToken($consumer, ''); - } -/** - * Lookup nonce value for the tool consumer. - * - * @param OAuthConsumer $consumer OAuthConsumer object - * @param string $token Token value - * @param string $value Nonce value - * @param string $timestamp Date/time of request - * - * @return boolean True if the nonce value already exists - */ - function lookup_nonce($consumer, $token, $value, $timestamp) + /** + * Lookup nonce value for the tool consumer. + * + * @param OAuthConsumer $consumer OAuthConsumer object. + * @param string $token Token value. + * @param string $value Nonce value. + * @param string $timestamp Date/time of request. + * + * @return bool TRUE if the nonce value already exists + */ + public function lookup_nonce($consumer, $token, $value, $timestamp) { - $nonce = new ConsumerNonce($this->toolProvider->consumer, $value); $ok = !$nonce->load(); + if ($ok) { $ok = $nonce->save(); } + if (!$ok) { $this->toolProvider->reason = 'Invalid nonce.'; } - + return !$ok; - } -/** - * Get new request token. - * - * @param OAuthConsumer $consumer OAuthConsumer object - * @param string $callback Callback URL - * - * @return string Null value - */ - function new_request_token($consumer, $callback = null) + /** + * Get new request token. + * + * @param OAuthConsumer $consumer OAuthConsumer object. + * @param string $callback Callback URL. + * + * @return string NULL value + */ + public function new_request_token($consumer, $callback = null) { - return null; - } -/** - * Get new access token. - * - * @param string $token Token value - * @param OAuthConsumer $consumer OAuthConsumer object - * @param string $verifier Verification code - * - * @return string Null value - */ - function new_access_token($token, $consumer, $verifier = null) + /** + * Get new access token. + * + * @param string $token Token value. + * @param OAuthConsumer $consumer OAuthConsumer object. + * @param string $verifier Verification code. + * + * @return string NULL value + */ + public function new_access_token($token, $consumer, $verifier = null) { - return null; - } - } diff --git a/src/ToolProvider/Outcome.php b/src/ToolProvider/Outcome.php index 77508fd..a4f2359 100644 --- a/src/ToolProvider/Outcome.php +++ b/src/ToolProvider/Outcome.php @@ -1,94 +1,65 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class Outcome { -/** - * Language value. - * - * @var string $language - */ + /** @var string Language value. */ public $language = null; -/** - * Outcome status value. - * - * @var string $status - */ + + /** @var string Outcome status value. */ public $status = null; -/** - * Outcome date value. - * - * @var string $date - */ + + /** @var string Outcome date value. */ public $date = null; -/** - * Outcome type value. - * - * @var string $type - */ + + /** @var string Outcome type value. */ public $type = null; -/** - * Outcome data source value. - * - * @var string $dataSource - */ + + /** @var string Outcome data source value. */ public $dataSource = null; -/** - * Outcome value. - * - * @var string $value - */ + /** @var string Outcome value. */ private $value = null; -/** - * Class constructor. - * - * @param string $value Outcome value (optional, default is none) - */ + /** + * Class constructor. + * + * @param string $value Outcome value (optional, default is none). + */ public function __construct($value = null) { - $this->value = $value; $this->language = 'en-US'; $this->date = gmdate('Y-m-d\TH:i:s\Z', time()); $this->type = 'decimal'; - } -/** - * Get the outcome value. - * - * @return string Outcome value - */ + /** + * Get the outcome value. + * + * @return string Outcome value + */ public function getValue() { - return $this->value; - } -/** - * Set the outcome value. - * - * @param string $value Outcome value - */ + /** + * Set the outcome value. + * + * @param string $value Outcome value. + */ public function setValue($value) { - $this->value = $value; - } - } diff --git a/src/ToolProvider/ResourceLink.php b/src/ToolProvider/ResourceLink.php index f08f11c..3a1a364 100644 --- a/src/ToolProvider/ResourceLink.php +++ b/src/ToolProvider/ResourceLink.php @@ -1,5 +1,4 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ResourceLink { - -/** - * Read action. - */ + + /** + * Read action. + */ const EXT_READ = 1; -/** - * Write (create/update) action. - */ + /** + * Write (create/update) action. + */ const EXT_WRITE = 2; -/** - * Delete action. - */ + /** + * Delete action. + */ const EXT_DELETE = 3; -/** - * Create action. - */ + /** + * Create action. + */ const EXT_CREATE = 4; -/** - * Update action. - */ + /** + * Update action. + */ const EXT_UPDATE = 5; - -/** - * Decimal outcome type. - */ + + /** + * Decimal outcome type. + */ const EXT_TYPE_DECIMAL = 'decimal'; -/** - * Percentage outcome type. - */ + /** + * Percentage outcome type. + */ const EXT_TYPE_PERCENTAGE = 'percentage'; -/** - * Ratio outcome type. - */ + /** + * Ratio outcome type. + */ const EXT_TYPE_RATIO = 'ratio'; -/** - * Letter (A-F) outcome type. - */ + /** + * Letter (A-F) outcome type. + */ const EXT_TYPE_LETTER_AF = 'letteraf'; -/** - * Letter (A-F) with optional +/- outcome type. - */ + /** + * Letter (A-F) with optional +/- outcome type. + */ const EXT_TYPE_LETTER_AF_PLUS = 'letterafplus'; -/** - * Pass/fail outcome type. - */ + /** + * Pass/fail outcome type. + */ const EXT_TYPE_PASS_FAIL = 'passfail'; -/** - * Free text outcome type. - */ + /** + * Free text outcome type. + */ const EXT_TYPE_TEXT = 'freetext'; -/** - * Context title. - * - * @var string $title - */ + /** @var string Context title. */ public $title = null; -/** - * Resource link ID as supplied in the last connection request. - * - * @var string $ltiResourceLinkId - */ + + /** @var string Resource link ID as supplied in the last connection request. */ public $ltiResourceLinkId = null; -/** - * User group sets (null if the consumer does not support the groups enhancement) - * - * @var array $groupSets - */ + + /** @var array User group sets (null if the consumer does not support the groups enhancement). */ public $groupSets = null; -/** - * User groups (null if the consumer does not support the groups enhancement) - * - * @var array $groups - */ + + /** @var array User groups (null if the consumer does not support the groups enhancement). */ public $groups = null; -/** - * Request for last service request. - * - * @var string $extRequest - */ + + /** @var string Request for last service request. */ public $extRequest = null; -/** - * Request headers for last service request. - * - * @var array $extRequestHeaders - */ + + /** @var array Request headers for last service request. */ public $extRequestHeaders = null; -/** - * Response from last service request. - * - * @var string $extResponse - */ + + /** @var string Response from last service request. */ public $extResponse = null; -/** - * Response header from last service request. - * - * @var array $extResponseHeaders - */ + + /** @var array Response header from last service request. */ public $extResponseHeaders = null; -/** - * Consumer key value for resource link being shared (if any). - * - * @var string $primaryResourceLinkId - */ + + /** @var string Consumer key value for resource link being shared (if any). */ public $primaryResourceLinkId = null; -/** - * Whether the sharing request has been approved by the primary resource link. - * - * @var boolean $shareApproved - */ + + /** @var bool Whether the sharing request has been approved by the primary resource link. */ public $shareApproved = null; -/** - * Date/time when the object was created. - * - * @var int $created - */ + + /** @var int Date/time when the object was created. */ public $created = null; -/** - * Date/time when the object was last updated. - * - * @var int $updated - */ + + /** @var int Date/time when the object was last updated. */ public $updated = null; -/** - * Record ID for this resource link. - * - * @var int $id - */ + /** @var int Record ID for this resource link. */ private $id = null; -/** - * Tool Consumer for this resource link. - * - * @var ToolConsumer $consumer - */ + + /** @var ToolConsumer Tool Consumer for this resource link. */ private $consumer = null; -/** - * Tool Consumer ID for this resource link. - * - * @var int $consumerId - */ + + /** @var int Tool Consumer ID for this resource link. */ private $consumerId = null; -/** - * Context for this resource link. - * - * @var Context $context - */ + + /** @var Context Context for this resource link. */ private $context = null; -/** - * Context ID for this resource link. - * - * @var int $contextId - */ + + /** @var int Context ID for this resource link. */ private $contextId = null; -/** - * Setting values (LTI parameters, custom parameters and local parameters). - * - * @var array $settings - */ + + /** @var array Setting values (LTI parameters, custom parameters and local parameters). */ private $settings = null; -/** - * Whether the settings value have changed since last saved. - * - * @var boolean $settingsChanged - */ + + /** @var bool Whether the settings value have changed since last saved. */ private $settingsChanged = false; -/** - * XML document for the last extension service request. - * - * @var string $extDoc - */ + + /** @var string XML document for the last extension service request. */ private $extDoc = null; -/** - * XML node array for the last extension service request. - * - * @var array $extNodes - */ + + /** @var array XML node array for the last extension service request. */ private $extNodes = null; -/** - * Data connector object or string. - * - * @var mixed $dataConnector - */ + + /** @var mixed Data connector object or string. */ private $dataConnector = null; -/** - * Class constructor. - */ + /** + * Class constructor. + */ public function __construct() { - $this->initialize(); - } -/** - * Initialise the resource link. - */ + /** + * Initialise the resource link. + */ public function initialize() { - $this->title = ''; $this->settings = array(); $this->groupSets = null; @@ -229,58 +156,51 @@ public function initialize() $this->shareApproved = null; $this->created = null; $this->updated = null; - } -/** - * Initialise the resource link. - * - * Pseudonym for initialize(). - */ + /** + * Initialise the resource link. + * + * Pseudonym for initialize(). + */ public function initialise() { - $this->initialize(); - } -/** - * Save the resource link to the database. - * - * @return boolean True if the resource link was successfully saved. - */ + /** + * Save the resource link to the database. + * + * @return bool TRUE if the resource link was successfully saved. + */ public function save() { - $ok = $this->getDataConnector()->saveResourceLink($this); + if ($ok) { $this->settingsChanged = false; } - + return $ok; - } -/** - * Delete the resource link from the database. - * - * @return boolean True if the resource link was successfully deleted. - */ + /** + * Delete the resource link from the database. + * + * @return bool TRUE if the resource link was successfully deleted. + */ public function delete() { - return $this->getDataConnector()->deleteResourceLink($this); - } -/** - * Get tool consumer. - * - * @return ToolConsumer Tool consumer object for this resource link. - */ + /** + * Get tool consumer. + * + * @return ToolConsumer Tool consumer object for this resource link. + */ public function getConsumer() { - if (is_null($this->consumer)) { if (!is_null($this->context) || !is_null($this->contextId)) { $this->consumer = $this->getContext()->getConsumer(); @@ -288,308 +208,284 @@ public function getConsumer() $this->consumer = ToolConsumer::fromRecordId($this->consumerId, $this->getDataConnector()); } } - + return $this->consumer; - } -/** - * Set tool consumer ID. - * - * @param int $consumerId Tool Consumer ID for this resource link. - */ + /** + * Set tool consumer ID. + * + * @param int $consumerId Tool Consumer ID for this resource link. + */ public function setConsumerId($consumerId) { - $this->consumer = null; $this->consumerId = $consumerId; - } -/** - * Get context. - * - * @return object LTIContext object for this resource link. - */ + /** + * Get context. + * + * @return object LTIContext object for this resource link. + */ public function getContext() { - if (is_null($this->context) && !is_null($this->contextId)) { $this->context = Context::fromRecordId($this->contextId, $this->getDataConnector()); } - + return $this->context; - } -/** - * Get context record ID. - * - * @return int Context record ID for this resource link. - */ + /** + * Get context record ID. + * + * @return int Context record ID for this resource link. + */ public function getContextId() { - return $this->contextId; - } -/** - * Set context ID. - * - * @param int $contextId Context ID for this resource link. - */ + /** + * Set context ID. + * + * @param int $contextId Context ID for this resource link. + */ public function setContextId($contextId) { - $this->context = null; $this->contextId = $contextId; - } -/** - * Get tool consumer key. - * - * @return string Consumer key value for this resource link. - */ + /** + * Get tool consumer key. + * + * @return string Consumer key value for this resource link. + */ public function getKey() { - return $this->getConsumer()->getKey(); - } -/** - * Get resource link ID. - * - * @return string ID for this resource link. - */ + /** + * Get resource link ID. + * + * @return string ID for this resource link. + */ public function getId() { - return $this->ltiResourceLinkId; - } -/** - * Get resource link record ID. - * - * @return int Record ID for this resource link. - */ + /** + * Get resource link record ID. + * + * @return int Record ID for this resource link. + */ public function getRecordId() { - return $this->id; - } -/** - * Set resource link record ID. - * - * @param int $id Record ID for this resource link. - */ + /** + * Set resource link record ID. + * + * @param int $id Record ID for this resource link. + */ public function setRecordId($id) { - $this->id = $id; + } - } - -/** - * Get the data connector. - * - * @return mixed Data connector object or string - */ + /** + * Get the data connector. + * + * @return mixed Data connector object or string + */ public function getDataConnector() { - return $this->dataConnector; - } -/** - * Get a setting value. - * - * @param string $name Name of setting - * @param string $default Value to return if the setting does not exist (optional, default is an empty string) - * - * @return string Setting value - */ + /** + * Get a setting value. + * + * @param string $name Name of setting. + * @param string $default Value to return if the setting does not exist (optional, default is an empty string). + * + * @return string Setting value + */ public function getSetting($name, $default = '') { - if (array_key_exists($name, $this->settings)) { $value = $this->settings[$name]; } else { $value = $default; } - + return $value; - } -/** - * Set a setting value. - * - * @param string $name Name of setting - * @param string $value Value to set, use an empty value to delete a setting (optional, default is null) - */ + /** + * Set a setting value. + * + * @param string $name Name of setting. + * @param string $value Value to set, use an empty value to delete a setting (optional, default is NULL). + */ public function setSetting($name, $value = null) { - $old_value = $this->getSetting($name); + if ($value !== $old_value) { if (!empty($value)) { $this->settings[$name] = $value; } else { unset($this->settings[$name]); } + $this->settingsChanged = true; } - } -/** - * Get an array of all setting values. - * - * @return array Associative array of setting values - */ + /** + * Get an array of all setting values. + * + * @return array Associative array of setting values + */ public function getSettings() { - return $this->settings; - } -/** - * Set an array of all setting values. - * - * @param array $settings Associative array of setting values - */ + /** + * Set an array of all setting values. + * + * @param array $settings Associative array of setting values. + */ public function setSettings($settings) { - $this->settings = $settings; - } -/** - * Save setting values. - * - * @return boolean True if the settings were successfully saved - */ + /** + * Save setting values. + * + * @return bool TRUE if the settings were successfully saved + */ public function saveSettings() { - if ($this->settingsChanged) { $ok = $this->save(); } else { $ok = true; } - + return $ok; - } -/** - * Check if the Outcomes service is supported. - * - * @return boolean True if this resource link supports the Outcomes service (either the LTI 1.1 or extension service) - */ + /** + * Check if the Outcomes service is supported. + * + * @return bool TRUE if this resource link supports the Outcomes service (either the LTI 1.1 or extension service) + */ public function hasOutcomesService() { - $url = $this->getSetting('ext_ims_lis_basic_outcome_url') . $this->getSetting('lis_outcome_service_url'); - + return !empty($url); - } -/** - * Check if the Memberships extension service is supported. - * - * @return boolean True if this resource link supports the Memberships extension service - */ + /** + * Check if the Memberships extension service is supported. + * + * @return bool TRUE if this resource link supports the Memberships extension service + */ public function hasMembershipsService() { - $url = $this->getSetting('ext_ims_lis_memberships_url'); - + return !empty($url); - } -/** - * Check if the Setting extension service is supported. - * - * @return boolean True if this resource link supports the Setting extension service - */ + /** + * Check if the Setting extension service is supported. + * + * @return bool TRUE if this resource link supports the Setting extension service + */ public function hasSettingService() { - $url = $this->getSetting('ext_ims_lti_tool_setting_url'); - + return !empty($url); - } -/** - * Perform an Outcomes service request. - * - * @param int $action The action type constant - * @param Outcome $ltiOutcome Outcome object - * @param User $user User object - * - * @return boolean True if the request was successfully processed - */ + /** + * Perform an Outcomes service request. + * + * @param int $action The action type constant. + * @param Outcome $ltiOutcome Outcome object. + * @param User $user User object. + * + * @return bool TRUE if the request was successfully processed + */ public function doOutcomesService($action, $ltiOutcome, $user) { - $response = false; $this->extResponse = null; - -// Lookup service details from the source resource link appropriate to the user (in case the destination is being shared) + + // Lookup service details from the source resource link appropriate to the user (in case the destination is being shared) $sourceResourceLink = $user->getResourceLink(); $sourcedId = $user->ltiResultSourcedId; - -// Use LTI 1.1 service in preference to extension service if it is available + + // Use LTI 1.1 service in preference to extension service if it is available $urlLTI11 = $sourceResourceLink->getSetting('lis_outcome_service_url'); $urlExt = $sourceResourceLink->getSetting('ext_ims_lis_basic_outcome_url'); + if ($urlExt || $urlLTI11) { switch ($action) { case self::EXT_READ: if ($urlLTI11 && ($ltiOutcome->type === self::EXT_TYPE_DECIMAL)) { $do = 'readResult'; - } else if ($urlExt) { + } elseif ($urlExt) { $urlLTI11 = null; $do = 'basic-lis-readresult'; } + break; case self::EXT_WRITE: - if ($urlLTI11 && $this->checkValueType($ltiOutcome, array(self::EXT_TYPE_DECIMAL))) { + if ($urlLTI11 && $this->checkValueType($ltiOutcome, array( + self::EXT_TYPE_DECIMAL + ))) { $do = 'replaceResult'; - } else if ($this->checkValueType($ltiOutcome)) { + } elseif ($this->checkValueType($ltiOutcome)) { $urlLTI11 = null; $do = 'basic-lis-updateresult'; } + break; case self::EXT_DELETE: if ($urlLTI11 && ($ltiOutcome->type === self::EXT_TYPE_DECIMAL)) { $do = 'deleteResult'; - } else if ($urlExt) { + } elseif ($urlExt) { $urlLTI11 = null; $do = 'basic-lis-deleteresult'; } + break; } } + if (isset($do)) { $value = $ltiOutcome->getValue(); + if (is_null($value)) { $value = ''; } + if ($urlLTI11) { $xml = ''; + if ($action === self::EXT_WRITE) { $xml = << EOF; } + $sourcedId = htmlentities($sourcedId); $xml = << {$sourcedId} {$xml} + EOF; + if ($this->doLTI11Service($do, $urlLTI11, $xml)) { switch ($action) { case self::EXT_READ: @@ -617,6 +516,8 @@ public function doOutcomesService($action, $ltiOutcome, $user) } else { $ltiOutcome->setValue($this->extNodes['imsx_POXBody']["{$do}Response"]['result']['resultScore']['textString']); } + + // FALL-THROUGH !!! case self::EXT_WRITE: case self::EXT_DELETE: $response = true; @@ -627,27 +528,34 @@ public function doOutcomesService($action, $ltiOutcome, $user) $params = array(); $params['sourcedid'] = $sourcedId; $params['result_resultscore_textstring'] = $value; + if (!empty($ltiOutcome->language)) { $params['result_resultscore_language'] = $ltiOutcome->language; } + if (!empty($ltiOutcome->status)) { $params['result_statusofresult'] = $ltiOutcome->status; } + if (!empty($ltiOutcome->date)) { $params['result_date'] = $ltiOutcome->date; } + if (!empty($ltiOutcome->type)) { $params['result_resultvaluesourcedid'] = $ltiOutcome->type; } + if (!empty($ltiOutcome->data_source)) { $params['result_datasource'] = $ltiOutcome->data_source; } + if ($this->doService($do, $urlExt, $params)) { switch ($action) { case self::EXT_READ: if (isset($this->extNodes['result']['resultscore']['textstring'])) { $response = $this->extNodes['result']['resultscore']['textstring']; } + break; case self::EXT_WRITE: case self::EXT_DELETE: @@ -656,27 +564,26 @@ public function doOutcomesService($action, $ltiOutcome, $user) } } } + if (is_array($response) && (count($response) <= 0)) { $response = ''; } } - + return $response; - } -/** - * Perform a Memberships service request. - * - * The user table is updated with the new list of user objects. - * - * @param boolean $withGroups True is group information is to be requested as well - * - * @return mixed Array of User objects or False if the request was not successful - */ + /** + * Perform a Memberships service request. + * + * The user table is updated with the new list of user objects. + * + * @param bool $withGroups TRUE is group information is to be requested as well. + * + * @return mixed Array of User objects or FALSE if the request was not successful + */ public function doMembershipsService($withGroups = false) { - $users = array(); $oldUsers = $this->getUserResultSourcedIDs(true, ToolProvider::ID_SCOPE_RESOURCE); $this->extResponse = null; @@ -684,115 +591,135 @@ public function doMembershipsService($withGroups = false) $params = array(); $params['id'] = $this->getSetting('ext_ims_lis_memberships_id'); $ok = false; + if ($withGroups) { $ok = $this->doService('basic-lis-readmembershipsforcontextwithgroups', $url, $params); } + if ($ok) { $this->groupSets = array(); $this->groups = array(); } else { $ok = $this->doService('basic-lis-readmembershipsforcontext', $url, $params); } - + if ($ok) { if (!isset($this->extNodes['memberships']['member'])) { $members = array(); - } else if (!isset($this->extNodes['memberships']['member'][0])) { + } elseif (!isset($this->extNodes['memberships']['member'][0])) { $members = array(); $members[0] = $this->extNodes['memberships']['member']; } else { $members = $this->extNodes['memberships']['member']; } - + for ($i = 0; $i < count($members); $i++) { - $user = User::fromResourceLink($this, $members[$i]['user_id']); - -// Set the user name + + // Set the user name $firstname = (isset($members[$i]['person_name_given'])) ? $members[$i]['person_name_given'] : ''; $lastname = (isset($members[$i]['person_name_family'])) ? $members[$i]['person_name_family'] : ''; $fullname = (isset($members[$i]['person_name_full'])) ? $members[$i]['person_name_full'] : ''; $user->setNames($firstname, $lastname, $fullname); - -// Set the user email + + // Set the user email $email = (isset($members[$i]['person_contact_email_primary'])) ? $members[$i]['person_contact_email_primary'] : ''; $user->setEmail($email, $this->getConsumer()->defaultEmail); - -/// Set the user roles + + /// Set the user roles if (isset($members[$i]['roles'])) { $user->roles = ToolProvider::parseRoles($members[$i]['roles']); } - -// Set the user groups + + // Set the user groups if (!isset($members[$i]['groups']['group'])) { $groups = array(); - } else if (!isset($members[$i]['groups']['group'][0])) { + } elseif (!isset($members[$i]['groups']['group'][0])) { $groups = array(); $groups[0] = $members[$i]['groups']['group']; } else { $groups = $members[$i]['groups']['group']; } + for ($j = 0; $j < count($groups); $j++) { $group = $groups[$j]; + if (isset($group['set'])) { $set_id = $group['set']['id']; + if (!isset($this->groupSets[$set_id])) { - $this->groupSets[$set_id] = array('title' => $group['set']['title'], 'groups' => array(), - 'num_members' => 0, 'num_staff' => 0, 'num_learners' => 0); + $this->groupSets[$set_id] = array( + 'title' => $group['set']['title'], + 'groups' => array(), + 'num_members' => 0, + 'num_staff' => 0, + 'num_learners' => 0 + ); } + $this->groupSets[$set_id]['num_members']++; + if ($user->isStaff()) { $this->groupSets[$set_id]['num_staff']++; } + if ($user->isLearner()) { $this->groupSets[$set_id]['num_learners']++; } + if (!in_array($group['id'], $this->groupSets[$set_id]['groups'])) { $this->groupSets[$set_id]['groups'][] = $group['id']; } - $this->groups[$group['id']] = array('title' => $group['title'], 'set' => $set_id); + + $this->groups[$group['id']] = array( + 'title' => $group['title'], + 'set' => $set_id + ); } else { - $this->groups[$group['id']] = array('title' => $group['title']); + $this->groups[$group['id']] = array( + 'title' => $group['title'] + ); } + $user->groups[] = $group['id']; } - -// If a result sourcedid is provided save the user + + // If a result sourcedid is provided save the user if (isset($members[$i]['lis_result_sourcedid'])) { $user->ltiResultSourcedId = $members[$i]['lis_result_sourcedid']; $user->save(); } + $users[] = $user; - -// Remove old user (if it exists) + + // Remove old user (if it exists) unset($oldUsers[$user->getId(ToolProvider::ID_SCOPE_RESOURCE)]); } - -// Delete any old users which were not in the latest list from the tool consumer + + // Delete any old users which were not in the latest list from the tool consumer foreach ($oldUsers as $id => $user) { $user->delete(); } } else { $users = false; } - + return $users; - } -/** - * Perform a Setting service request. - * - * @param int $action The action type constant - * @param string $value The setting value (optional, default is null) - * - * @return mixed The setting value for a read action, true if a write or delete action was successful, otherwise false - */ + /** + * Perform a Setting service request. + * + * @param int $action The action type constant. + * @param string $value The setting value (optional, default is NULL). + * + * @return mixed The setting value for a read action, TRUE if a write or delete action was successful, otherwise FALSE + */ public function doSettingService($action, $value = null) { - $response = false; $this->extResponse = null; + switch ($action) { case self::EXT_READ: $do = 'basic-lti-loadsetting'; @@ -804,25 +731,29 @@ public function doSettingService($action, $value = null) $do = 'basic-lti-deletesetting'; break; } + if (isset($do)) { - $url = $this->getSetting('ext_ims_lti_tool_setting_url'); $params = array(); $params['id'] = $this->getSetting('ext_ims_lti_tool_setting_id'); + if (is_null($value)) { $value = ''; } + $params['setting'] = $value; - + if ($this->doService($do, $url, $params)) { switch ($action) { case self::EXT_READ: if (isset($this->extNodes['setting']['value'])) { $response = $this->extNodes['setting']['value']; + if (is_array($response)) { $response = ''; } } + break; case self::EXT_WRITE: $this->setSetting('ext_ims_lti_tool_setting', $value); @@ -835,289 +766,283 @@ public function doSettingService($action, $value = null) } } } - + return $response; - } -/** - * Check if the Tool Settings service is supported. - * - * @return boolean True if this resource link supports the Tool Settings service - */ + /** + * Check if the Tool Settings service is supported. + * + * @return bool TRUE if this resource link supports the Tool Settings service + */ public function hasToolSettingsService() { - $url = $this->getSetting('custom_link_setting_url'); - + return !empty($url); - } -/** - * Get Tool Settings. - * - * @param int $mode Mode for request (optional, default is current level only) - * @param boolean $simple True if all the simple media type is to be used (optional, default is true) - * - * @return mixed The array of settings if successful, otherwise false - */ + /** + * Get Tool Settings. + * + * @param int $mode Mode for request (optional, default is current level only). + * @param bool $simple TRUE if all the simple media type is to be used (optional, default is TRUE). + * + * @return mixed The array of settings if successful, otherwise FALSE + */ public function getToolSettings($mode = Service\ToolSettings::MODE_CURRENT_LEVEL, $simple = true) { - $url = $this->getSetting('custom_link_setting_url'); $service = new Service\ToolSettings($this, $url, $simple); $response = $service->get($mode); - + return $response; - } -/** - * Perform a Tool Settings service request. - * - * @param array $settings An associative array of settings (optional, default is none) - * - * @return boolean True if action was successful, otherwise false - */ + /** + * Perform a Tool Settings service request. + * + * @param array $settings An associative array of settings (optional, default is none). + * + * @return bool TRUE if action was successful, otherwise FALSE + */ public function setToolSettings($settings = array()) { - $url = $this->getSetting('custom_link_setting_url'); $service = new Service\ToolSettings($this, $url); $response = $service->set($settings); - + return $response; - } -/** - * Check if the Membership service is supported. - * - * @return boolean True if this resource link supports the Membership service - */ + /** + * Check if the Membership service is supported. + * + * @return bool TRUE if this resource link supports the Membership service + */ public function hasMembershipService() { - $has = !empty($this->contextId); + if ($has) { $has = !empty($this->getContext()->getSetting('custom_context_memberships_url')); } - + return $has; - } -/** - * Get Memberships. - * - * @return mixed The array of User objects if successful, otherwise false - */ + /** + * Get Memberships. + * + * @return mixed The array of User objects if successful, otherwise FALSE + */ public function getMembership() { - $response = false; + if (!empty($this->contextId)) { $url = $this->getContext()->getSetting('custom_context_memberships_url'); + if (!empty($url)) { $service = new Service\Membership($this, $url); $response = $service->get(); } } - + return $response; - } -/** - * Obtain an array of User objects for users with a result sourcedId. - * - * The array may include users from other resource links which are sharing this resource link. - * It may also be optionally indexed by the user ID of a specified scope. - * - * @param boolean $localOnly True if only users from this resource link are to be returned, not users from shared resource links (optional, default is false) - * @param int $idScope Scope to use for ID values (optional, default is null for consumer default) - * - * @return array Array of User objects - */ + /** + * Obtain an array of User objects for users with a result sourcedId. + * + * The array may include users from other resource links which are sharing this resource link. + * It may also be optionally indexed by the user ID of a specified scope. + * + * @param bool $localOnly TRUE if only users from this resource link are to be returned, not users from shared resource links (optional, default is FALSE). + * @param int $idScope Scope to use for ID values (optional, default is NULL for consumer default). + * + * @return array Array of User objects + */ public function getUserResultSourcedIDs($localOnly = false, $idScope = null) { - return $this->getDataConnector()->getUserResultSourcedIDsResourceLink($this, $localOnly, $idScope); - } -/** - * Get an array of ResourceLinkShare objects for each resource link which is sharing this context. - * - * @return array Array of ResourceLinkShare objects - */ + /** + * Get an array of ResourceLinkShare objects for each resource link which is sharing this context. + * + * @return array Array of ResourceLinkShare objects + */ public function getShares() { - return $this->getDataConnector()->getSharesResourceLink($this); - } -/** - * Class constructor from consumer. - * - * @param ToolConsumer $consumer Consumer object - * @param string $ltiResourceLinkId Resource link ID value - * @param string $tempId Temporary Resource link ID value (optional, default is null) - * @return ResourceLink - */ + /** + * Class constructor from consumer. + * + * @param ToolConsumer $consumer Consumer object. + * @param string $ltiResourceLinkId Resource link ID value. + * @param string $tempId Temporary Resource link ID value (optional, default is NULL). + * + * @return ResourceLink + */ public static function fromConsumer($consumer, $ltiResourceLinkId, $tempId = null) { - $resourceLink = new ResourceLink(); $resourceLink->consumer = $consumer; $resourceLink->dataConnector = $consumer->getDataConnector(); $resourceLink->ltiResourceLinkId = $ltiResourceLinkId; + if (!empty($ltiResourceLinkId)) { $resourceLink->load(); + if (is_null($resourceLink->id) && !empty($tempId)) { $resourceLink->ltiResourceLinkId = $tempId; $resourceLink->load(); $resourceLink->ltiResourceLinkId = $ltiResourceLinkId; } } - + return $resourceLink; - } -/** - * Class constructor from context. - * - * @param Context $context Context object - * @param string $ltiResourceLinkId Resource link ID value - * @param string $tempId Temporary Resource link ID value (optional, default is null) - * @return ResourceLink - */ + /** + * Class constructor from context. + * + * @param Context $context Context object. + * @param string $ltiResourceLinkId Resource link ID value. + * @param string $tempId Temporary Resource link ID value (optional, default is NULL). + * + * @return ResourceLink + */ public static function fromContext($context, $ltiResourceLinkId, $tempId = null) { - $resourceLink = new ResourceLink(); $resourceLink->setContextId($context->getRecordId()); $resourceLink->context = $context; $resourceLink->dataConnector = $context->getDataConnector(); $resourceLink->ltiResourceLinkId = $ltiResourceLinkId; + if (!empty($ltiResourceLinkId)) { $resourceLink->load(); + if (is_null($resourceLink->id) && !empty($tempId)) { $resourceLink->ltiResourceLinkId = $tempId; $resourceLink->load(); $resourceLink->ltiResourceLinkId = $ltiResourceLinkId; } } - + return $resourceLink; - } -/** - * Load the resource link from the database. - * - * @param int $id Record ID of resource link - * @param DataConnector $dataConnector Database connection object - * - * @return ResourceLink ResourceLink object - */ + /** + * Load the resource link from the database. + * + * @param int $id Record ID of resource link. + * @param DataConnector $dataConnector Database connection object. + * + * @return ResourceLink ResourceLink object + */ public static function fromRecordId($id, $dataConnector) { - $resourceLink = new ResourceLink(); $resourceLink->dataConnector = $dataConnector; $resourceLink->load($id); - + return $resourceLink; - } - -### -### PRIVATE METHODS -### - -/** - * Load the resource link from the database. - * - * @param int $id Record ID of resource link (optional, default is null) - * - * @return boolean True if resource link was successfully loaded - */ + + ### + ### PRIVATE METHODS + ### + + + /** + * Load the resource link from the database. + * + * @param int $id Record ID of resource link (optional, default is NULL). + * + * @return bool TRUE if resource link was successfully loaded + */ private function load($id = null) { - $this->initialize(); $this->id = $id; - + return $this->getDataConnector()->loadResourceLink($this); - } -/** - * Convert data type of value to a supported type if possible. - * - * @param Outcome $ltiOutcome Outcome object - * @param string[] $supportedTypes Array of outcome types to be supported (optional, default is null to use supported types reported in the last launch for this resource link) - * - * @return boolean True if the type/value are valid and supported - */ + /** + * Convert data type of value to a supported type if possible. + * + * @param Outcome $ltiOutcome Outcome object. + * @param string[] $supportedTypes Array of outcome types to be supported (optional, default is NULL to use supported types reported in the last launch for this resource link). + * + * @return bool TRUE if the type/value are valid and supported + */ private function checkValueType($ltiOutcome, $supportedTypes = null) { - if (empty($supportedTypes)) { $supportedTypes = explode(',', str_replace(' ', '', strtolower($this->getSetting('ext_ims_lis_resultvalue_sourcedids', self::EXT_TYPE_DECIMAL)))); } + $type = $ltiOutcome->type; $value = $ltiOutcome->getValue(); -// Check whether the type is supported or there is no value + // Check whether the type is supported or there is no value $ok = in_array($type, $supportedTypes) || (strlen($value) <= 0); + if (!$ok) { -// Convert numeric values to decimal if ($type === self::EXT_TYPE_PERCENTAGE) { + // Convert numeric values to decimal if (substr($value, -1) === '%') { $value = substr($value, 0, -1); } + $ok = is_numeric($value) && ($value >= 0) && ($value <= 100); + if ($ok) { $ltiOutcome->setValue($value / 100); $ltiOutcome->type = self::EXT_TYPE_DECIMAL; } - } else if ($type === self::EXT_TYPE_RATIO) { + } elseif ($type === self::EXT_TYPE_RATIO) { $parts = explode('/', $value, 2); - $ok = (count($parts) === 2) && is_numeric($parts[0]) && is_numeric($parts[1]) && ($parts[0] >= 0) && ($parts[1] > 0); + $ok = (count($parts) === 2) && is_numeric($parts[0]) && is_numeric($parts[1]) && ($parts[0] >= 0) && + ($parts[1] > 0); + if ($ok) { $ltiOutcome->setValue($parts[0] / $parts[1]); $ltiOutcome->type = self::EXT_TYPE_DECIMAL; } -// Convert letter_af to letter_af_plus or text - } else if ($type === self::EXT_TYPE_LETTER_AF) { + } elseif ($type === self::EXT_TYPE_LETTER_AF) { + // Convert letter_af to letter_af_plus or text if (in_array(self::EXT_TYPE_LETTER_AF_PLUS, $supportedTypes)) { $ok = true; $ltiOutcome->type = self::EXT_TYPE_LETTER_AF_PLUS; - } else if (in_array(self::EXT_TYPE_TEXT, $supportedTypes)) { + } elseif (in_array(self::EXT_TYPE_TEXT, $supportedTypes)) { $ok = true; $ltiOutcome->type = self::EXT_TYPE_TEXT; } -// Convert letter_af_plus to letter_af or text - } else if ($type === self::EXT_TYPE_LETTER_AF_PLUS) { + } elseif ($type === self::EXT_TYPE_LETTER_AF_PLUS) { + // Convert letter_af_plus to letter_af or text if (in_array(self::EXT_TYPE_LETTER_AF, $supportedTypes) && (strlen($value) === 1)) { $ok = true; $ltiOutcome->type = self::EXT_TYPE_LETTER_AF; - } else if (in_array(self::EXT_TYPE_TEXT, $supportedTypes)) { + } elseif (in_array(self::EXT_TYPE_TEXT, $supportedTypes)) { $ok = true; $ltiOutcome->type = self::EXT_TYPE_TEXT; } -// Convert text to decimal - } else if ($type === self::EXT_TYPE_TEXT) { - $ok = is_numeric($value) && ($value >= 0) && ($value <=1); + } elseif ($type === self::EXT_TYPE_TEXT) { + // Convert text to decimal + $ok = is_numeric($value) && ($value >= 0) && ($value <= 1); + if ($ok) { $ltiOutcome->type = self::EXT_TYPE_DECIMAL; - } else if (substr($value, -1) === '%') { + } elseif (substr($value, -1) === '%') { $value = substr($value, 0, -1); - $ok = is_numeric($value) && ($value >= 0) && ($value <=100); + $ok = is_numeric($value) && ($value >= 0) && ($value <= 100); + if ($ok) { if (in_array(self::EXT_TYPE_PERCENTAGE, $supportedTypes)) { $ltiOutcome->type = self::EXT_TYPE_PERCENTAGE; @@ -1129,71 +1054,75 @@ private function checkValueType($ltiOutcome, $supportedTypes = null) } } } - + return $ok; - } -/** - * Send a service request to the tool consumer. - * - * @param string $type Message type value - * @param string $url URL to send request to - * @param array $params Associative array of parameter values to be passed - * - * @return boolean True if the request successfully obtained a response - */ + /** + * Send a service request to the tool consumer. + * + * @param string $type Message type value. + * @param string $url URL to send request to. + * @param array $params Associative array of parameter values to be passed. + * + * @return bool TRUE if the request successfully obtained a response + */ private function doService($type, $url, $params) { - $ok = false; $this->extRequest = null; $this->extRequestHeaders = ''; $this->extResponse = null; $this->extResponseHeaders = ''; + if (!empty($url)) { $params = $this->getConsumer()->signParameters($url, $type, $this->getConsumer()->ltiVersion, $params); -// Connect to tool consumer + + // Connect to tool consumer $http = new HTTPMessage($url, 'POST', $params); -// Parse XML response + + // Parse XML response if ($http->send()) { $this->extResponse = $http->response; $this->extResponseHeaders = $http->responseHeaders; + try { $this->extDoc = new DOMDocument(); $this->extDoc->loadXML($http->response); $this->extNodes = $this->domnodeToArray($this->extDoc->documentElement); - if (isset($this->extNodes['statusinfo']['codemajor']) && ($this->extNodes['statusinfo']['codemajor'] === 'Success')) { + + if (isset($this->extNodes['statusinfo']['codemajor']) && + ($this->extNodes['statusinfo']['codemajor'] === 'Success')) { $ok = true; } } catch (\Exception $e) { } } + $this->extRequest = $http->request; $this->extRequestHeaders = $http->requestHeaders; } - + return $ok; - } -/** - * Send a service request to the tool consumer. - * - * @param string $type Message type value - * @param string $url URL to send request to - * @param string $xml XML of message request - * - * @return boolean True if the request successfully obtained a response - */ + /** + * Send a service request to the tool consumer. + * + * @param string $type Message type value. + * @param string $url URL to send request to. + * @param string $xml XML of message request. + * + * @return bool TRUE if the request successfully obtained a response + */ private function doLTI11Service($type, $url, $xml) { - $ok = false; $this->extRequest = null; $this->extRequestHeaders = ''; $this->extResponse = null; $this->extResponseHeaders = ''; + if (!empty($url)) { $id = uniqid(); $xmlRequest = <<< EOD @@ -1208,15 +1137,18 @@ private function doLTI11Service($type, $url, $xml) <{$type}Request> {$xml} + EOD; -// Calculate body hash + // Calculate body hash $hash = base64_encode(sha1($xmlRequest, true)); - $params = array('oauth_body_hash' => $hash); - -// Add OAuth signature + $params = array( + 'oauth_body_hash' => $hash + ); + + // Add OAuth signature $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1(); $consumer = new OAuth\OAuthConsumer($this->getConsumer()->getKey(), $this->getConsumer()->secret, null); $req = OAuth\OAuthRequest::from_consumer_and_token($consumer, null, 'POST', $url, $params); @@ -1224,42 +1156,46 @@ private function doLTI11Service($type, $url, $xml) $params = $req->get_parameters(); $header = $req->to_header(); $header .= "\nContent-Type: application/xml"; -// Connect to tool consumer + + // Connect to tool consumer $http = new HTTPMessage($url, 'POST', $xmlRequest, $header); -// Parse XML response + + // Parse XML response if ($http->send()) { $this->extResponse = $http->response; $this->extResponseHeaders = $http->responseHeaders; + try { $this->extDoc = new DOMDocument(); $this->extDoc->loadXML($http->response); $this->extNodes = $this->domnodeToArray($this->extDoc->documentElement); - if (isset($this->extNodes['imsx_POXHeader']['imsx_POXResponseHeaderInfo']['imsx_statusInfo']['imsx_codeMajor']) && - ($this->extNodes['imsx_POXHeader']['imsx_POXResponseHeaderInfo']['imsx_statusInfo']['imsx_codeMajor'] === 'success')) { + + if (isset($this->extNodes['imsx_POXHeader']['imsx_POXResponseHeaderInfo']['imsx_statusInfo']['imsx_codeMajor']) && ($this->extNodes['imsx_POXHeader']['imsx_POXResponseHeaderInfo']['imsx_statusInfo']['imsx_codeMajor'] === + 'success')) { $ok = true; } } catch (\Exception $e) { } } + $this->extRequest = $http->request; $this->extRequestHeaders = $http->requestHeaders; } - + return $ok; - } -/** - * Convert DOM nodes to array. - * - * @param DOMElement $node XML element - * - * @return array Array of XML document elements - */ + /** + * Convert DOM nodes to array. + * + * @param DOMElement $node XML element. + * + * @return array Array of XML document elements + */ private function domnodeToArray($node) { - $output = ''; + switch ($node->nodeType) { case XML_CDATA_SECTION_NODE: case XML_TEXT_NODE: @@ -1269,38 +1205,45 @@ private function domnodeToArray($node) for ($i = 0; $i < $node->childNodes->length; $i++) { $child = $node->childNodes->item($i); $v = $this->domnodeToArray($child); + if (isset($child->tagName)) { $t = $child->tagName; + if (!isset($output[$t])) { $output[$t] = array(); } + $output[$t][] = $v; } else { $s = (string) $v; + if (strlen($s) > 0) { $output = $s; } } } + if (is_array($output)) { if ($node->attributes->length) { $a = array(); + foreach ($node->attributes as $attrName => $attrNode) { $a[$attrName] = (string) $attrNode->value; } + $output['@attributes'] = $a; } + foreach ($output as $t => $v) { - if (is_array($v) && count($v)==1 && $t!='@attributes') { + if (is_array($v) && count($v) == 1 && $t != '@attributes') { $output[$t] = $v[0]; } } } + break; } - + return $output; - } - } diff --git a/src/ToolProvider/ResourceLinkShare.php b/src/ToolProvider/ResourceLinkShare.php index d275593..32ccb97 100644 --- a/src/ToolProvider/ResourceLinkShare.php +++ b/src/ToolProvider/ResourceLinkShare.php @@ -1,49 +1,33 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ResourceLinkShare { -/** - * Consumer key value. - * - * @var string $consumerKey - */ + /** @var string Consumer key value. */ public $consumerKey = null; -/** - * Resource link ID value. - * - * @var string $resourceLinkId - */ + + /** @var string Resource link ID value. */ public $resourceLinkId = null; -/** - * Title of sharing context. - * - * @var string $title - */ + + /** @var string Title of sharing context. */ public $title = null; -/** - * Whether sharing request is to be automatically approved on first use. - * - * @var boolean $approved - */ + + /** @var bool Whether sharing request is to be automatically approved on first use. */ public $approved = null; -/** - * Class constructor. - */ + /** + * Class constructor. + */ public function __construct() { } - } diff --git a/src/ToolProvider/ResourceLinkShareKey.php b/src/ToolProvider/ResourceLinkShareKey.php index 1946eb4..35986f8 100644 --- a/src/ToolProvider/ResourceLinkShareKey.php +++ b/src/ToolProvider/ResourceLinkShareKey.php @@ -1,196 +1,165 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ResourceLinkShareKey { - -/** - * Maximum permitted life for a share key value. - */ - const MAX_SHARE_KEY_LIFE = 168; // in hours (1 week) -/** - * Default life for a share key value. - */ - const DEFAULT_SHARE_KEY_LIFE = 24; // in hours -/** - * Minimum length for a share key value. - */ + + /** + * Maximum permitted life for a share key value. + */ + const MAX_SHARE_KEY_LIFE = 168; // in hours (1 week) + /** + * Default life for a share key value. + */ + const DEFAULT_SHARE_KEY_LIFE = 24; // in hours + /** + * Minimum length for a share key value. + */ const MIN_SHARE_KEY_LENGTH = 5; -/** - * Maximum length for a share key value. - */ + /** + * Maximum length for a share key value. + */ const MAX_SHARE_KEY_LENGTH = 32; -/** - * ID for resource link being shared. - * - * @var string $resourceLinkId - */ + /** @var string ID for resource link being shared. */ public $resourceLinkId = null; -/** - * Length of share key. - * - * @var int $length - */ + + /** @var int Length of share key. */ public $length = null; -/** - * Life of share key. - * - * @var int $life - */ - public $life = null; // in hours -/** - * Whether the sharing arrangement should be automatically approved when first used. - * - * @var boolean $autoApprove - */ + + /** @var int Life of share key. */ + public $life = null; + // in hours + + + /** @var bool Whether the sharing arrangement should be automatically approved when first used. */ public $autoApprove = false; -/** - * Date/time when the share key expires. - * - * @var int $expires - */ + + /** @var int Date/time when the share key expires. */ public $expires = null; -/** - * Share key value. - * - * @var string $id - */ + /** @var string Share key value. */ private $id = null; -/** - * Data connector. - * - * @var DataConnector $dataConnector - */ + + /** @var DataConnector Data connector. */ private $dataConnector = null; -/** - * Class constructor. - * - * @param ResourceLink $resourceLink Resource_Link object - * @param string $id Value of share key (optional, default is null) - */ + /** + * Class constructor. + * + * @param ResourceLink $resourceLink Resource_Link object. + * @param string $id Value of share key (optional, default is NULL). + */ public function __construct($resourceLink, $id = null) { - $this->initialize(); $this->dataConnector = $resourceLink->getDataConnector(); $this->resourceLinkId = $resourceLink->getRecordId(); $this->id = $id; + if (!empty($id)) { $this->load(); } - } -/** - * Initialise the resource link share key. - */ + /** + * Initialise the resource link share key. + */ public function initialize() { - $this->length = null; $this->life = null; $this->autoApprove = false; $this->expires = null; - } -/** - * Initialise the resource link share key. - * - * Pseudonym for initialize(). - */ + /** + * Initialise the resource link share key. + * + * Pseudonym for initialize(). + */ public function initialise() { - $this->initialize(); - } -/** - * Save the resource link share key to the database. - * - * @return boolean True if the share key was successfully saved - */ + /** + * Save the resource link share key to the database. + * + * @return bool TRUE if the share key was successfully saved + */ public function save() { - if (empty($this->life)) { $this->life = self::DEFAULT_SHARE_KEY_LIFE; } else { $this->life = max(min($this->life, self::MAX_SHARE_KEY_LIFE), 0); } + $this->expires = time() + ($this->life * 60 * 60); + if (empty($this->id)) { if (empty($this->length) || !is_numeric($this->length)) { $this->length = self::MAX_SHARE_KEY_LENGTH; } else { $this->length = max(min($this->length, self::MAX_SHARE_KEY_LENGTH), self::MIN_SHARE_KEY_LENGTH); } + $this->id = DataConnector::getRandomString($this->length); } - + return $this->dataConnector->saveResourceLinkShareKey($this); - } -/** - * Delete the resource link share key from the database. - * - * @return boolean True if the share key was successfully deleted - */ + /** + * Delete the resource link share key from the database. + * + * @return bool TRUE if the share key was successfully deleted + */ public function delete() { - return $this->dataConnector->deleteResourceLinkShareKey($this); - } -/** - * Get share key value. - * - * @return string Share key value - */ + /** + * Get share key value. + * + * @return string Share key value + */ public function getId() { - return $this->id; - } - -### -### PRIVATE METHOD -### - -/** - * Load the resource link share key from the database. - */ + + ### + ### PRIVATE METHOD + ### + + + /** + * Load the resource link share key from the database. + */ private function load() { - $this->initialize(); $this->dataConnector->loadResourceLinkShareKey($this); + if (!is_null($this->id)) { $this->length = strlen($this->id); } + if (!is_null($this->expires)) { $this->life = ($this->expires - time()) / 60 / 60; } - } - } diff --git a/src/ToolProvider/Service/Membership.php b/src/ToolProvider/Service/Membership.php index b718f10..8b8294d 100644 --- a/src/ToolProvider/Service/Membership.php +++ b/src/ToolProvider/Service/Membership.php @@ -1,97 +1,101 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class Membership extends Service { -/** - * The object to which the settings apply (ResourceLink, Context or ToolConsumer). - * - * @var object $source - */ + /** + * The object to which the settings apply (ResourceLink, Context or ToolConsumer). + * + * @var object $source + */ private $source; -/** - * Class constructor. - * - * @param object $source The object to which the memberships apply (ResourceLink or Context) - * @param string $endpoint Service endpoint - */ + /** + * Class constructor. + * + * @param object $source The object to which the memberships apply (ResourceLink or Context). + * @param string $endpoint Service endpoint. + */ public function __construct($source, $endpoint) { - $consumer = $source->getConsumer(); parent::__construct($consumer, $endpoint, 'application/vnd.ims.lis.v2.membershipcontainer+json'); $this->source = $source; - } -/** - * Get the memberships. - * - * @param string $role Role for which memberships are to be requested (optional, default is all roles) - * @param int $limit Limit on the number of memberships to be returned (optional, default is all) - * - * @return mixed The array of User objects if successful, otherwise false - */ - public function get($role = null, $limit = 0) { - + /** + * Get the memberships. + * + * @param string $role Role for which memberships are to be requested (optional, default is all roles). + * @param int $limit Limit on the number of memberships to be returned (optional, default is all). + * + * @return mixed The array of User objects if successful, otherwise FALSE + */ + public function get($role = null, $limit = 0) + { $isLink = is_a($this->source, 'IMSGlobal\LTI\ToolProvider\ResourceLink'); $parameters = array(); + if (!empty($role)) { $parameters['role'] = $role; } + if ($limit > 0) { $parameters['limit'] = strval($limit); } + if ($isLink) { $parameters['rlid'] = $this->source->getId(); } + $http = $this->send('GET', $parameters); + if (!$http->ok) { $users = false; } else { $users = array(); + if ($isLink) { $oldUsers = $this->source->getUserResultSourcedIDs(true, ToolProvider\ToolProvider::ID_SCOPE_RESOURCE); } + foreach ($http->responseJson->pageOf->membershipSubject->membership as $membership) { $member = $membership->member; + if ($isLink) { $user = ToolProvider\User::fromResourceLink($this->source, $member->userId); } else { $user = new ToolProvider\User(); $user->ltiUserId = $member->userId; } - -// Set the user name + + // Set the user name $firstname = (isset($member->givenName)) ? $member->givenName : ''; $lastname = (isset($member->familyName)) ? $member->familyName : ''; $fullname = (isset($member->name)) ? $member->name : ''; $user->setNames($firstname, $lastname, $fullname); - -// Set the user email + + // Set the user email $email = (isset($member->email)) ? $member->email : ''; $user->setEmail($email, $this->source->getConsumer()->defaultEmail); - -// Set the user roles + + // Set the user roles if (isset($membership->role)) { $user->roles = ToolProvider\ToolProvider::parseRoles($membership->role); } - -// If a result sourcedid is provided save the user + + // If a result sourcedid is provided save the user if ($isLink) { if (isset($member->message)) { foreach ($member->message as $message) { @@ -100,29 +104,29 @@ public function get($role = null, $limit = 0) { $user->ltiResultSourcedId = $message->lis_result_sourcedid; $user->save(); } - break; + + break; } } } } + $users[] = $user; - -// Remove old user (if it exists) + + // Remove old user (if it exists) if ($isLink) { unset($oldUsers[$user->getId(ToolProvider\ToolProvider::ID_SCOPE_RESOURCE)]); } } - -// Delete any old users which were not in the latest list from the tool consumer + + // Delete any old users which were not in the latest list from the tool consumer if ($isLink) { foreach ($oldUsers as $id => $user) { $user->delete(); } } } - + return $users; - } - } diff --git a/src/ToolProvider/Service/Service.php b/src/ToolProvider/Service/Service.php index c5cb56c..fb7895f 100644 --- a/src/ToolProvider/Service/Service.php +++ b/src/ToolProvider/Service/Service.php @@ -1,104 +1,86 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class Service { -/** - * Whether service request should be sent unsigned. - * - * @var boolean $unsigned - */ + /** @var bool Whether service request should be sent unsigned. */ public $unsigned = false; -/** - * Service endpoint. - * - * @var string $endpoint - */ + /** @var string Service endpoint. */ protected $endpoint; -/** - * Tool Consumer for this service request. - * - * @var ToolConsumer $consumer - */ + + /** @var ToolConsumer Tool Consumer for this service request. */ private $consumer; -/** - * Media type of message body. - * - * @var string $mediaType - */ + + /** @var string Media type of message body. */ private $mediaType; -/** - * Class constructor. - * - * @param ToolConsumer $consumer Tool consumer object for this service request - * @param string $endpoint Service endpoint - * @param string $mediaType Media type of message body - */ + /** + * Class constructor. + * + * @param ToolConsumer $consumer Tool consumer object for this service request. + * @param string $endpoint Service endpoint. + * @param string $mediaType Media type of message body. + */ public function __construct($consumer, $endpoint, $mediaType) { - $this->consumer = $consumer; $this->endpoint = $endpoint; $this->mediaType = $mediaType; - } -/** - * Send a service request. - * - * @param string $method The action type constant (optional, default is GET) - * @param array $parameters Query parameters to add to endpoint (optional, default is none) - * @param string $body Body of request (optional, default is null) - * - * @return HTTPMessage HTTP object containing request and response details - */ + /** + * Send a service request. + * + * @param string $method The action type constant (optional, default is GET). + * @param array $parameters Query parameters to add to endpoint (optional, default is none). + * @param string $body Body of request (optional, default is NULL). + * + * @return HTTPMessage HTTP object containing request and response details + */ public function send($method, $parameters = array(), $body = null) { - $url = $this->endpoint; + if (!empty($parameters)) { if (strpos($url, '?') === false) { $sep = '?'; } else { $sep = '&'; } + foreach ($parameters as $name => $value) { $url .= $sep . urlencode($name) . '=' . urlencode($value); $sep = '&'; } } + if (!$this->unsigned) { $header = ToolProvider\ToolConsumer::addSignature($url, $this->consumer->getKey(), $this->consumer->secret, $body, $method, $this->mediaType); } else { $header = null; } - -// Connect to tool consumer + + // Connect to tool consumer $http = new HTTPMessage($url, $method, $body, $header); -// Parse JSON response + // Parse JSON response if ($http->send() && !empty($http->response)) { $http->responseJson = json_decode($http->response); $http->ok = !is_null($http->responseJson); } - + return $http; - } - } diff --git a/src/ToolProvider/Service/ToolSettings.php b/src/ToolProvider/Service/ToolSettings.php index 3377cdb..55c48a7 100644 --- a/src/ToolProvider/Service/ToolSettings.php +++ b/src/ToolProvider/Service/ToolSettings.php @@ -1,130 +1,131 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.0 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ToolSettings extends Service { - -/** - * Settings at current level mode. - */ + + /** + * Settings at current level mode. + */ const MODE_CURRENT_LEVEL = 1; -/** - * Settings at all levels mode. - */ + /** + * Settings at all levels mode. + */ const MODE_ALL_LEVELS = 2; -/** - * Settings with distinct names at all levels mode. - */ + /** + * Settings with distinct names at all levels mode. + */ const MODE_DISTINCT_NAMES = 3; -/** - * Names of LTI parameters to be retained in the consumer settings property. - * - * @var array $LEVEL_NAMES - */ - private static $LEVEL_NAMES = array('ToolProxy' => 'system', - 'ToolProxyBinding' => 'context', - 'LtiLink' => 'link'); - -/** - * The object to which the settings apply (ResourceLink, Context or ToolConsumer). - * - * @var object $source - */ + /** @var array Names of LTI parameters to be retained in the consumer settings property. */ + private static $LEVEL_NAMES = array( + 'ToolProxy' => 'system', + 'ToolProxyBinding' => 'context', + 'LtiLink' => 'link' + ); + + /** + * The object to which the settings apply (ResourceLink, Context or ToolConsumer). + * + * @var object $source + */ private $source; -/** - * Whether to use the simple JSON format. - * - * @var boolean $simple - */ + + /** + * Whether to use the simple JSON format. + * + * @var bool $simple + */ private $simple; -/** - * Class constructor. - * - * @param object $source The object to which the settings apply (ResourceLink, Context or ToolConsumer) - * @param string $endpoint Service endpoint - * @param boolean $simple True if the simple media type is to be used (optional, default is true) - */ + /** + * Class constructor. + * + * @param object $source The object to which the settings apply (ResourceLink, Context or ToolConsumer). + * @param string $endpoint Service endpoint. + * @param bool $simple TRUE if the simple media type is to be used (optional, default is TRUE). + */ public function __construct($source, $endpoint, $simple = true) { - if (is_a($source, 'IMSGlobal\LTI\ToolProvider\ToolConsumer')) { $consumer = $source; } else { $consumer = $source->getConsumer(); } + if ($simple) { $mediaType = 'application/vnd.ims.lti.v2.toolsettings.simple+json'; } else { $mediaType = 'application/vnd.ims.lti.v2.toolsettings+json'; } + parent::__construct($consumer, $endpoint, $mediaType); $this->source = $source; $this->simple = $simple; - } -/** - * Get the tool settings. - * - * @param int $mode Mode for request (optional, default is current level only) - * - * @return mixed The array of settings if successful, otherwise false - */ - public function get($mode = self::MODE_CURRENT_LEVEL) { - + /** + * Get the tool settings. + * + * @param int $mode Mode for request (optional, default is current level only). + * + * @return mixed The array of settings if successful, otherwise FALSE + */ + public function get($mode = self::MODE_CURRENT_LEVEL) + { $parameter = array(); + if ($mode === self::MODE_ALL_LEVELS) { $parameter['bubble'] = 'all'; - } else if ($mode === self::MODE_DISTINCT_NAMES) { + } elseif ($mode === self::MODE_DISTINCT_NAMES) { $parameter['bubble'] = 'distinct'; } + $http = $this->send('GET', $parameter); + if (!$http->ok) { $response = false; - } else if ($this->simple) { + } elseif ($this->simple) { $response = json_decode($http->response, true); - } else if (isset($http->responseJson->{'@graph'})) { + } elseif (isset($http->responseJson->{'@graph'})) { $response = array(); + foreach ($http->responseJson->{'@graph'} as $level) { $settings = json_decode(json_encode($level->custom), true); unset($settings['@id']); $response[self::$LEVEL_NAMES[$level->{'@type'}]] = $settings; } } - + return $response; - } -/** - * Set the tool settings. - * - * @param array $settings An associative array of settings (optional, default is null) - * - * @return HTTPMessage HTTP object containing request and response details - */ - public function set($settings) { - + /** + * Set the tool settings. + * + * @param array $settings An associative array of settings (optional, default is NULL). + * + * @return HTTPMessage HTTP object containing request and response details + */ + public function set($settings) + { if (!$this->simple) { if (is_a($this->source, 'ToolConsumer')) { $type = 'ToolProxy'; - } else if (is_a($this->source, 'ToolConsumer')) { + } elseif (is_a($this->source, 'ToolConsumer')) { $type = 'ToolProxyBinding'; } else { $type = 'LtiLink'; } + $obj = new \stdClass(); $obj->{'@context'} = 'http://purl.imsglobal.org/ctx/lti/v2/ToolSettings'; $obj->{'@graph'} = array(); @@ -137,11 +138,9 @@ public function set($settings) { } else { $body = json_encode($settings); } - + $response = parent::send('PUT', null, $body); - + return $response->ok; - } - } diff --git a/src/ToolProvider/ToolConsumer.php b/src/ToolProvider/ToolConsumer.php index aa31793..9e7bf34 100644 --- a/src/ToolProvider/ToolConsumer.php +++ b/src/ToolProvider/ToolConsumer.php @@ -1,5 +1,4 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class ToolConsumer { -/** - * Local name of tool consumer. - * - * @var string $name - */ + /** @var string Local name of tool consumer. */ public $name = null; -/** - * Shared secret. - * - * @var string $secret - */ + + /** @var string Shared secret. */ public $secret = null; -/** - * LTI version (as reported by last tool consumer connection). - * - * @var string $ltiVersion - */ + + /** @var string LTI version (as reported by last tool consumer connection). */ public $ltiVersion = null; -/** - * Name of tool consumer (as reported by last tool consumer connection). - * - * @var string $consumerName - */ + + /** @var string Name of tool consumer (as reported by last tool consumer connection). */ public $consumerName = null; -/** - * Tool consumer version (as reported by last tool consumer connection). - * - * @var string $consumerVersion - */ + + /** @var string Tool consumer version (as reported by last tool consumer connection). */ public $consumerVersion = null; -/** - * Tool consumer GUID (as reported by first tool consumer connection). - * - * @var string $consumerGuid - */ + + /** @var string Tool consumer GUID (as reported by first tool consumer connection). */ public $consumerGuid = null; -/** - * Optional CSS path (as reported by last tool consumer connection). - * - * @var string $cssPath - */ + + /** @var string Optional CSS path (as reported by last tool consumer connection). */ public $cssPath = null; -/** - * Whether the tool consumer instance is protected by matching the consumer_guid value in incoming requests. - * - * @var boolean $protected - */ + + /** @var bool Whether the tool consumer instance is protected by matching the consumer_guid value in incoming requests. */ public $protected = false; -/** - * Whether the tool consumer instance is enabled to accept incoming connection requests. - * - * @var boolean $enabled - */ + + /** @var bool Whether the tool consumer instance is enabled to accept incoming connection requests. */ public $enabled = false; -/** - * Date/time from which the the tool consumer instance is enabled to accept incoming connection requests. - * - * @var int $enableFrom - */ + + /** @var int Date/time from which the the tool consumer instance is enabled to accept incoming connection requests. */ public $enableFrom = null; -/** - * Date/time until which the tool consumer instance is enabled to accept incoming connection requests. - * - * @var int $enableUntil - */ + + /** @var int Date/time until which the tool consumer instance is enabled to accept incoming connection requests. */ public $enableUntil = null; -/** - * Date of last connection from this tool consumer. - * - * @var int $lastAccess - */ + + /** @var int Date of last connection from this tool consumer. */ public $lastAccess = null; -/** - * Default scope to use when generating an Id value for a user. - * - * @var int $idScope - */ + + /** @var int Default scope to use when generating an Id value for a user. */ public $idScope = ToolProvider::ID_SCOPE_ID_ONLY; -/** - * Default email address (or email domain) to use when no email address is provided for a user. - * - * @var string $defaultEmail - */ + + /** @var string Default email address (or email domain) to use when no email address is provided for a user. */ public $defaultEmail = ''; -/** - * Setting values (LTI parameters, custom parameters and local parameters). - * - * @var array $settings - */ + + /** @var array Setting values (LTI parameters, custom parameters and local parameters). */ public $settings = null; -/** - * Date/time when the object was created. - * - * @var int $created - */ + + /** @var int Date/time when the object was created. */ public $created = null; -/** - * Date/time when the object was last updated. - * - * @var int $updated - */ + + /** @var int Date/time when the object was last updated. */ public $updated = null; -/** - * Consumer ID value. - * - * @var int $id - */ + /** @var int Consumer ID value. */ private $id = null; -/** - * Consumer key value. - * - * @var string $key - */ + + /** @var string Consumer key value. */ private $key = null; -/** - * Whether the settings value have changed since last saved. - * - * @var boolean $settingsChanged - */ + + /** @var bool Whether the settings value have changed since last saved. */ private $settingsChanged = false; -/** - * Data connector object or string. - * - * @var mixed $dataConnector - */ + + /** @var mixed Data connector object or string. */ private $dataConnector = null; -/** - * Class constructor. - * - * @param string $key Consumer key - * @param DataConnector $dataConnector A data connector object - * @param boolean $autoEnable true if the tool consumers is to be enabled automatically (optional, default is false) - */ + /** + * Class constructor. + * + * @param string $key Consumer key. + * @param DataConnector $dataConnector A data connector object. + * @param bool $autoEnable TRUE if the tool consumers is to be enabled automatically (optional, default is FALSE). + */ public function __construct($key = null, $dataConnector = null, $autoEnable = false) { - $this->initialize(); + if (empty($dataConnector)) { $dataConnector = DataConnector::getDataConnector(); } + $this->dataConnector = $dataConnector; + if (!empty($key)) { $this->load($key, $autoEnable); } else { $this->secret = DataConnector::getRandomString(32); } - } -/** - * Initialise the tool consumer. - */ + /** + * Initialise the tool consumer. + */ public function initialize() { - $this->id = null; $this->key = null; $this->name = null; @@ -196,451 +129,421 @@ public function initialize() $this->defaultEmail = ''; $this->created = null; $this->updated = null; - } -/** - * Initialise the tool consumer. - * - * Pseudonym for initialize(). - */ + /** + * Initialise the tool consumer. + * + * Pseudonym for initialize(). + */ public function initialise() { - $this->initialize(); - } -/** - * Save the tool consumer to the database. - * - * @return boolean True if the object was successfully saved - */ + /** + * Save the tool consumer to the database. + * + * @return bool TRUE if the object was successfully saved + */ public function save() { - $ok = $this->dataConnector->saveToolConsumer($this); + if ($ok) { $this->settingsChanged = false; } - + return $ok; - } -/** - * Delete the tool consumer from the database. - * - * @return boolean True if the object was successfully deleted - */ + /** + * Delete the tool consumer from the database. + * + * @return bool TRUE if the object was successfully deleted + */ public function delete() { - return $this->dataConnector->deleteToolConsumer($this); - } -/** - * Get the tool consumer record ID. - * - * @return int Consumer record ID value - */ + /** + * Get the tool consumer record ID. + * + * @return int Consumer record ID value + */ public function getRecordId() { - return $this->id; - } -/** - * Sets the tool consumer record ID. - * - * @param int $id Consumer record ID value - */ + /** + * Sets the tool consumer record ID. + * + * @param int $id Consumer record ID value. + */ public function setRecordId($id) { - $this->id = $id; - } -/** - * Get the tool consumer key. - * - * @return string Consumer key value - */ + /** + * Get the tool consumer key. + * + * @return string Consumer key value + */ public function getKey() { - return $this->key; - } -/** - * Set the tool consumer key. - * - * @param string $key Consumer key value - */ + /** + * Set the tool consumer key. + * + * @param string $key Consumer key value. + */ public function setKey($key) { - $this->key = $key; - } -/** - * Get the data connector. - * - * @return mixed Data connector object or string - */ + /** + * Get the data connector. + * + * @return mixed Data connector object or string + */ public function getDataConnector() { - return $this->dataConnector; - } -/** - * Is the consumer key available to accept launch requests? - * - * @return boolean True if the consumer key is enabled and within any date constraints - */ + /** + * Is the consumer key available to accept launch requests? + * + * @return bool TRUE if the consumer key is enabled and within any date constraints + */ public function getIsAvailable() { - $ok = $this->enabled; - + $now = time(); + if ($ok && !is_null($this->enableFrom)) { $ok = $this->enableFrom <= $now; } + if ($ok && !is_null($this->enableUntil)) { $ok = $this->enableUntil > $now; } - + return $ok; - } -/** - * Get a setting value. - * - * @param string $name Name of setting - * @param string $default Value to return if the setting does not exist (optional, default is an empty string) - * - * @return string Setting value - */ + /** + * Get a setting value. + * + * @param string $name Name of setting. + * @param string $default Value to return if the setting does not exist (optional, default is an empty string). + * + * @return string Setting value + */ public function getSetting($name, $default = '') { - if (array_key_exists($name, $this->settings)) { $value = $this->settings[$name]; } else { $value = $default; } - + return $value; - } -/** - * Set a setting value. - * - * @param string $name Name of setting - * @param string $value Value to set, use an empty value to delete a setting (optional, default is null) - */ + /** + * Set a setting value. + * + * @param string $name Name of setting. + * @param string $value Value to set, use an empty value to delete a setting (optional, default is NULL). + */ public function setSetting($name, $value = null) { - $old_value = $this->getSetting($name); + if ($value !== $old_value) { if (!empty($value)) { $this->settings[$name] = $value; } else { unset($this->settings[$name]); } + $this->settingsChanged = true; } - } -/** - * Get an array of all setting values. - * - * @return array Associative array of setting values - */ + /** + * Get an array of all setting values. + * + * @return array Associative array of setting values + */ public function getSettings() { - return $this->settings; - } -/** - * Set an array of all setting values. - * - * @param array $settings Associative array of setting values - */ + /** + * Set an array of all setting values. + * + * @param array $settings Associative array of setting values. + */ public function setSettings($settings) { - $this->settings = $settings; - } -/** - * Save setting values. - * - * @return boolean True if the settings were successfully saved - */ + /** + * Save setting values. + * + * @return bool TRUE if the settings were successfully saved + */ public function saveSettings() { - if ($this->settingsChanged) { $ok = $this->save(); } else { $ok = true; } - + return $ok; - } -/** - * Check if the Tool Settings service is supported. - * - * @return boolean True if this tool consumer supports the Tool Settings service - */ + /** + * Check if the Tool Settings service is supported. + * + * @return bool TRUE if this tool consumer supports the Tool Settings service + */ public function hasToolSettingsService() { - $url = $this->getSetting('custom_system_setting_url'); - + return !empty($url); - } -/** - * Get Tool Settings. - * - * @param boolean $simple True if all the simple media type is to be used (optional, default is true) - * - * @return mixed The array of settings if successful, otherwise false - */ + /** + * Get Tool Settings. + * + * @param bool $simple TRUE if all the simple media type is to be used (optional, default is TRUE). + * + * @return mixed The array of settings if successful, otherwise FALSE + */ public function getToolSettings($simple = true) { - $url = $this->getSetting('custom_system_setting_url'); $service = new Service\ToolSettings($this, $url, $simple); $response = $service->get(); - + return $response; - } -/** - * Perform a Tool Settings service request. - * - * @param array $settings An associative array of settings (optional, default is none) - * - * @return boolean True if action was successful, otherwise false - */ + /** + * Perform a Tool Settings service request. + * + * @param array $settings An associative array of settings (optional, default is none). + * + * @return bool TRUE if action was successful, otherwise FALSE + */ public function setToolSettings($settings = array()) { - $url = $this->getSetting('custom_system_setting_url'); $service = new Service\ToolSettings($this, $url); $response = $service->set($settings); - + return $response; - } -/** - * Add the OAuth signature to an LTI message. - * - * @param string $url URL for message request - * @param string $type LTI message type - * @param string $version LTI version - * @param array $params Message parameters - * - * @return array Array of signed message parameters - */ + /** + * Add the OAuth signature to an LTI message. + * + * @param string $url URL for message request. + * @param string $type LTI message type. + * @param string $version LTI version. + * @param array $params Message parameters. + * + * @return array Array of signed message parameters + */ public function signParameters($url, $type, $version, $params) { - if (!empty($url)) { -// Check for query parameters which need to be included in the signature + // Check for query parameters which need to be included in the signature $queryParams = array(); $queryString = parse_url($url, PHP_URL_QUERY); + if (!is_null($queryString)) { $queryItems = explode('&', $queryString); + foreach ($queryItems as $item) { if (strpos($item, '=') !== false) { - list($name, $value) = explode('=', $item); + list ($name, $value) = explode('=', $item); $queryParams[urldecode($name)] = urldecode($value); } else { $queryParams[urldecode($item)] = ''; } } } + $params = $params + $queryParams; -// Add standard parameters + // Add standard parameters $params['lti_version'] = $version; $params['lti_message_type'] = $type; $params['oauth_callback'] = 'about:blank'; -// Add OAuth signature + // Add OAuth signature $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1(); $consumer = new OAuth\OAuthConsumer($this->getKey(), $this->secret, null); $req = OAuth\OAuthRequest::from_consumer_and_token($consumer, null, 'POST', $url, $params); $req->sign_request($hmacMethod, $consumer, null); $params = $req->get_parameters(); -// Remove parameters being passed on the query string + // Remove parameters being passed on the query string foreach (array_keys($queryParams) as $name) { unset($params[$name]); } } - + return $params; - } -/** - * Add the OAuth signature to an array of message parameters or to a header string. - * - * @return mixed Array of signed message parameters or header string - */ + /** + * Add the OAuth signature to an array of message parameters or to a header string. + * + * @return mixed Array of signed message parameters or header string + */ public static function addSignature($endpoint, $consumerKey, $consumerSecret, $data, $method = 'POST', $type = null) { - $params = array(); + if (is_array($data)) { $params = $data; } -// Check for query parameters which need to be included in the signature + // Check for query parameters which need to be included in the signature $queryParams = array(); $queryString = parse_url($endpoint, PHP_URL_QUERY); + if (!is_null($queryString)) { $queryItems = explode('&', $queryString); + foreach ($queryItems as $item) { if (strpos($item, '=') !== false) { - list($name, $value) = explode('=', $item); + list ($name, $value) = explode('=', $item); $queryParams[urldecode($name)] = urldecode($value); } else { $queryParams[urldecode($item)] = ''; } } + $params = $params + $queryParams; } - + if (!is_array($data)) { -// Calculate body hash + // Calculate body hash $hash = base64_encode(sha1($data, true)); $params['oauth_body_hash'] = $hash; } - -// Add OAuth signature + + // Add OAuth signature $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1(); $oauthConsumer = new OAuth\OAuthConsumer($consumerKey, $consumerSecret, null); $oauthReq = OAuth\OAuthRequest::from_consumer_and_token($oauthConsumer, null, $method, $endpoint, $params); $oauthReq->sign_request($hmacMethod, $oauthConsumer, null); $params = $oauthReq->get_parameters(); -// Remove parameters being passed on the query string + // Remove parameters being passed on the query string foreach (array_keys($queryParams) as $name) { unset($params[$name]); } - + if (!is_array($data)) { $header = $oauthReq->to_header(); + if (empty($data)) { if (!empty($type)) { $header .= "\nAccept: {$type}"; } - } else if (isset($type)) { + } elseif (isset($type)) { $header .= "\nContent-Type: {$type}"; $header .= "\nContent-Length: " . strlen($data); } + return $header; } else { return $params; } - } -/** - * Perform a service request - * - * @param object $service Service object to be executed - * @param string $method HTTP action - * @param string $format Media type - * @param mixed $data Array of parameters or body string - * - * @return HTTPMessage HTTP object containing request and response details - */ + /** + * Perform a service request. + * + * @param object $service Service object to be executed. + * @param string $method HTTP action. + * @param string $format Media type. + * @param mixed $data Array of parameters or body string. + * + * @return HTTPMessage HTTP object containing request and response details + */ public function doServiceRequest($service, $method, $format, $data) { - $header = ToolConsumer::addSignature($service->endpoint, $this->getKey(), $this->secret, $data, $method, $format); - -// Connect to tool consumer + + // Connect to tool consumer $http = new HTTPMessage($service->endpoint, $method, $data, $header); -// Parse JSON response + // Parse JSON response if ($http->send() && !empty($http->response)) { $http->responseJson = json_decode($http->response); $http->ok = !is_null($http->responseJson); } - + return $http; - } -/** - * Load the tool consumer from the database by its record ID. - * - * @param string $id The consumer key record ID - * @param DataConnector $dataConnector Database connection object - * - * @return object ToolConsumer The tool consumer object - */ + /** + * Load the tool consumer from the database by its record ID. + * + * @param string $id The consumer key record ID. + * @param DataConnector $dataConnector Database connection object. + * + * @return object ToolConsumer The tool consumer object + */ public static function fromRecordId($id, $dataConnector) { - $toolConsumer = new ToolConsumer(null, $dataConnector); - + $toolConsumer->initialize(); $toolConsumer->setRecordId($id); + if (!$dataConnector->loadToolConsumer($toolConsumer)) { $toolConsumer->initialize(); } - + return $toolConsumer; - } - - -### -### PRIVATE METHOD -### - -/** - * Load the tool consumer from the database. - * - * @param string $key The consumer key value - * @param boolean $autoEnable True if the consumer should be enabled (optional, default if false) - * - * @return boolean True if the consumer was successfully loaded - */ + + ### + ### PRIVATE METHOD + ### + + + /** + * Load the tool consumer from the database. + * + * @param string $key The consumer key value. + * @param bool $autoEnable TRUE if the consumer should be enabled (optional, default if FALSE). + * + * @return bool TRUE if the consumer was successfully loaded + */ private function load($key, $autoEnable = false) { - $this->key = $key; $ok = $this->dataConnector->loadToolConsumer($this); + if (!$ok) { $this->enabled = $autoEnable; } - + return $ok; - } - } diff --git a/src/ToolProvider/ToolProvider.php b/src/ToolProvider/ToolProvider.php index b78b03e..7ee8add 100644 --- a/src/ToolProvider/ToolProvider.php +++ b/src/ToolProvider/ToolProvider.php @@ -1,5 +1,4 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 - * @version 3.0.2 - * @license GNU Lesser General Public License, version 3 () + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc + * @version 3.0.2 + * @license Apache-2.0 */ class ToolProvider { - -/** - * Default connection error message. - */ + /** @var string Default connection error message. */ const CONNECTION_ERROR_MESSAGE = 'Sorry, there was an error connecting you to the application.'; - -/** - * LTI version 1 for messages. - */ + /** @var string LTI version 1 for messages. */ const LTI_VERSION1 = 'LTI-1p0'; -/** - * LTI version 2 for messages. - */ + /** @var string LTI version 2 for messages. */ const LTI_VERSION2 = 'LTI-2p0'; -/** - * Use ID value only. - */ + /** @var int Use ID value only. */ const ID_SCOPE_ID_ONLY = 0; -/** - * Prefix an ID with the consumer key. - */ + /** @var int Prefix an ID with the consumer key. */ const ID_SCOPE_GLOBAL = 1; -/** - * Prefix the ID with the consumer key and context ID. - */ + /** @var int Prefix the ID with the consumer key and context ID. */ const ID_SCOPE_CONTEXT = 2; -/** - * Prefix the ID with the consumer key and resource ID. - */ + /** @var int Prefix the ID with the consumer key and resource ID. */ const ID_SCOPE_RESOURCE = 3; -/** - * Character used to separate each element of an ID. - */ + /** @var string Character used to separate each element of an ID. */ const ID_SCOPE_SEPARATOR = ':'; -/** - * Permitted LTI versions for messages. - */ - private static $LTI_VERSIONS = array(self::LTI_VERSION1, self::LTI_VERSION2); -/** - * List of supported message types and associated class methods. - */ - private static $MESSAGE_TYPES = array('basic-lti-launch-request' => 'onLaunch', - 'ContentItemSelectionRequest' => 'onContentItem', - 'ToolProxyRegistrationRequest' => 'register'); -/** - * List of supported message types and associated class methods - * - * @var array $METHOD_NAMES - */ - private static $METHOD_NAMES = array('basic-lti-launch-request' => 'onLaunch', - 'ContentItemSelectionRequest' => 'onContentItem', - 'ToolProxyRegistrationRequest' => 'onRegister'); -/** - * Names of LTI parameters to be retained in the consumer settings property. - * - * @var array $LTI_CONSUMER_SETTING_NAMES - */ - private static $LTI_CONSUMER_SETTING_NAMES = array('custom_tc_profile_url', 'custom_system_setting_url'); -/** - * Names of LTI parameters to be retained in the context settings property. - * - * @var array $LTI_CONTEXT_SETTING_NAMES - */ - private static $LTI_CONTEXT_SETTING_NAMES = array('custom_context_setting_url', - 'custom_lineitems_url', 'custom_results_url', - 'custom_context_memberships_url'); -/** - * Names of LTI parameters to be retained in the resource link settings property. - * - * @var array $LTI_RESOURCE_LINK_SETTING_NAMES - */ - private static $LTI_RESOURCE_LINK_SETTING_NAMES = array('lis_result_sourcedid', 'lis_outcome_service_url', - 'ext_ims_lis_basic_outcome_url', 'ext_ims_lis_resultvalue_sourcedids', - 'ext_ims_lis_memberships_id', 'ext_ims_lis_memberships_url', - 'ext_ims_lti_tool_setting', 'ext_ims_lti_tool_setting_id', 'ext_ims_lti_tool_setting_url', - 'custom_link_setting_url', - 'custom_lineitem_url', 'custom_result_url'); -/** - * Names of LTI custom parameter substitution variables (or capabilities) and their associated default message parameter names. - * - * @var array $CUSTOM_SUBSTITUTION_VARIABLES - */ - private static $CUSTOM_SUBSTITUTION_VARIABLES = array('User.id' => 'user_id', - 'User.image' => 'user_image', - 'User.username' => 'username', - 'User.scope.mentor' => 'role_scope_mentor', - 'Membership.role' => 'roles', - 'Person.sourcedId' => 'lis_person_sourcedid', - 'Person.name.full' => 'lis_person_name_full', - 'Person.name.family' => 'lis_person_name_family', - 'Person.name.given' => 'lis_person_name_given', - 'Person.email.primary' => 'lis_person_contact_email_primary', - 'Context.id' => 'context_id', - 'Context.type' => 'context_type', - 'Context.title' => 'context_title', - 'Context.label' => 'context_label', - 'CourseOffering.sourcedId' => 'lis_course_offering_sourcedid', - 'CourseSection.sourcedId' => 'lis_course_section_sourcedid', - 'CourseSection.label' => 'context_label', - 'CourseSection.title' => 'context_title', - 'ResourceLink.id' => 'resource_link_id', - 'ResourceLink.title' => 'resource_link_title', - 'ResourceLink.description' => 'resource_link_description', - 'Result.sourcedId' => 'lis_result_sourcedid', - 'BasicOutcome.url' => 'lis_outcome_service_url', - 'ToolConsumerProfile.url' => 'custom_tc_profile_url', - 'ToolProxy.url' => 'tool_proxy_url', - 'ToolProxy.custom.url' => 'custom_system_setting_url', - 'ToolProxyBinding.custom.url' => 'custom_context_setting_url', - 'LtiLink.custom.url' => 'custom_link_setting_url', - 'LineItems.url' => 'custom_lineitems_url', - 'LineItem.url' => 'custom_lineitem_url', - 'Results.url' => 'custom_results_url', - 'Result.url' => 'custom_result_url', - 'ToolProxyBinding.memberships.url' => 'custom_context_memberships_url'); - - -/** - * True if the last request was successful. - * - * @var boolean $ok - */ + /** @var string[] Permitted LTI versions for messages. */ + private static $LTI_VERSIONS = array( + self::LTI_VERSION1, + self::LTI_VERSION2 + ); + + /** @var string[] List of supported message types and associated class methods. */ + private static $MESSAGE_TYPES = array( + 'basic-lti-launch-request' => 'onLaunch', + 'ContentItemSelectionRequest' => 'onContentItem', + 'ToolProxyRegistrationRequest' => 'register' + ); + + /** @var string[] List of supported message types and associated class methods. */ + private static $METHOD_NAMES = array( + 'basic-lti-launch-request' => 'onLaunch', + 'ContentItemSelectionRequest' => 'onContentItem', + 'ToolProxyRegistrationRequest' => 'onRegister' + ); + + /** @var string[] Names of LTI parameters to be retained in the consumer settings property. */ + private static $LTI_CONSUMER_SETTING_NAMES = array( + 'custom_tc_profile_url', + 'custom_system_setting_url' + ); + + /** @var string[] Names of LTI parameters to be retained in the context settings property. */ + private static $LTI_CONTEXT_SETTING_NAMES = array( + 'custom_context_setting_url', + 'custom_lineitems_url', + 'custom_results_url', + 'custom_context_memberships_url' + ); + + /** @var string[] Names of LTI parameters to be retained in the resource link settings property. */ + private static $LTI_RESOURCE_LINK_SETTING_NAMES = array( + 'lis_result_sourcedid', + 'lis_outcome_service_url', + 'ext_ims_lis_basic_outcome_url', + 'ext_ims_lis_resultvalue_sourcedids', + 'ext_ims_lis_memberships_id', + 'ext_ims_lis_memberships_url', + 'ext_ims_lti_tool_setting', + 'ext_ims_lti_tool_setting_id', + 'ext_ims_lti_tool_setting_url', + 'custom_link_setting_url', + 'custom_lineitem_url', + 'custom_result_url' + ); + + /** @var string[] Names of LTI custom parameter substitution variables (or capabilities) and their associated default message parameter names. */ + private static $CUSTOM_SUBSTITUTION_VARIABLES = array( + 'User.id' => 'user_id', + 'User.image' => 'user_image', + 'User.username' => 'username', + 'User.scope.mentor' => 'role_scope_mentor', + 'Membership.role' => 'roles', + 'Person.sourcedId' => 'lis_person_sourcedid', + 'Person.name.full' => 'lis_person_name_full', + 'Person.name.family' => 'lis_person_name_family', + 'Person.name.given' => 'lis_person_name_given', + 'Person.email.primary' => 'lis_person_contact_email_primary', + 'Context.id' => 'context_id', + 'Context.type' => 'context_type', + 'Context.title' => 'context_title', + 'Context.label' => 'context_label', + 'CourseOffering.sourcedId' => 'lis_course_offering_sourcedid', + 'CourseSection.sourcedId' => 'lis_course_section_sourcedid', + 'CourseSection.label' => 'context_label', + 'CourseSection.title' => 'context_title', + 'ResourceLink.id' => 'resource_link_id', + 'ResourceLink.title' => 'resource_link_title', + 'ResourceLink.description' => 'resource_link_description', + 'Result.sourcedId' => 'lis_result_sourcedid', + 'BasicOutcome.url' => 'lis_outcome_service_url', + 'ToolConsumerProfile.url' => 'custom_tc_profile_url', + 'ToolProxy.url' => 'tool_proxy_url', + 'ToolProxy.custom.url' => 'custom_system_setting_url', + 'ToolProxyBinding.custom.url' => 'custom_context_setting_url', + 'LtiLink.custom.url' => 'custom_link_setting_url', + 'LineItems.url' => 'custom_lineitems_url', + 'LineItem.url' => 'custom_lineitem_url', + 'Results.url' => 'custom_results_url', + 'Result.url' => 'custom_result_url', + 'ToolProxyBinding.memberships.url' => 'custom_context_memberships_url' + ); + + /** @var bool True if the last request was successful. */ public $ok = true; -/** - * Tool Consumer object. - * - * @var ToolConsumer $consumer - */ + + /** @var ToolConsumer Tool Consumer object. */ public $consumer = null; -/** - * Return URL provided by tool consumer. - * - * @var string $returnUrl - */ + + /** @var string Return URL provided by tool consumer. */ public $returnUrl = null; -/** - * User object. - * - * @var User $user - */ + + /** @var User User object. */ public $user = null; -/** - * Resource link object. - * - * @var ResourceLink $resourceLink - */ + + /** @var ResourceLink Resource link object. */ public $resourceLink = null; -/** - * Context object. - * - * @var Context $context - */ + + /** @var Context Context object. */ public $context = null; -/** - * Data connector object. - * - * @var DataConnector $dataConnector - */ + + /** @var DataConnector Data connector object. */ public $dataConnector = null; -/** - * Default email domain. - * - * @var string $defaultEmail - */ + + /** @var string Default email domain. */ public $defaultEmail = ''; -/** - * Scope to use for user IDs. - * - * @var int $idScope - */ + + /** @var int Scope to use for user IDs. */ public $idScope = self::ID_SCOPE_ID_ONLY; -/** - * Whether shared resource link arrangements are permitted. - * - * @var boolean $allowSharing - */ + + /** @var bool Whether shared resource link arrangements are permitted. */ public $allowSharing = false; -/** - * Message for last request processed - * - * @var string $message - */ + + /** @var string Message for last request processed. */ public $message = self::CONNECTION_ERROR_MESSAGE; -/** - * Error message for last request processed. - * - * @var string $reason - */ + + /** @var string Error message for last request processed. */ public $reason = null; -/** - * Details for error message relating to last request processed. - * - * @var array $details - */ + + /** @var array Details for error message relating to last request processed. */ public $details = array(); -/** - * Base URL for tool provider service - * - * @var string $baseUrl - */ - public $baseUrl = null; -/** - * Vendor details - * - * @var Item $vendor - */ - public $vendor = null; -/** - * Product details - * - * @var Item $product - */ - public $product = null; -/** - * Services required by Tool Provider - * - * @var array $requiredServices - */ - public $requiredServices = null; -/** - * Optional services used by Tool Provider - * - * @var array $optionalServices - */ - public $optionalServices = null; -/** - * Resource handlers for Tool Provider - * - * @var array $resourceHandlers - */ - public $resourceHandlers = null; -/** - * URL to redirect user to on successful completion of the request. - * - * @var string $redirectUrl - */ + /** @var string Base URL for tool provider service. */ + public $baseUrl = null; + + /** @var Item Vendor details. */ + public $vendor = null; + + /** @var Item Product details. */ + public $product = null; + + /** @var Service[] Services required by Tool Provider. */ + public $requiredServices = []; + + /** @var Service[] Optional services used by Tool Provider. */ + public $optionalServices = []; + + /** @var ResourceHandler[] Resource handlers for Tool Provider. */ + public $resourceHandlers = []; + + /** @var string URL to redirect user to on successful completion of the request. */ protected $redirectUrl = null; -/** - * URL to redirect user to on successful completion of the request. - * - * @var string $mediaTypes - */ + + /** @var string URL to redirect user to on successful completion of the request. */ protected $mediaTypes = null; -/** - * URL to redirect user to on successful completion of the request. - * - * @var string $documentTargets - */ + + /** @var string URL to redirect user to on successful completion of the request. */ protected $documentTargets = null; -/** - * HTML to be displayed on a successful completion of the request. - * - * @var string $output - */ + + /** @var string HTML to be displayed on a successful completion of the request. */ protected $output = null; -/** - * HTML to be displayed on an unsuccessful completion of the request and no return URL is available. - * - * @var string $errorOutput - */ + + /** @var string HTML to be displayed on an unsuccessful completion of the request and no return URL is available. */ protected $errorOutput = null; -/** - * Whether debug messages explaining the cause of errors are to be returned to the tool consumer. - * - * @var boolean $debugMode - */ + + /** @var bool Whether debug messages explaining the cause of errors are to be returned to the tool consumer. */ protected $debugMode = false; -/** - * Callback functions for handling requests. - * - * @var array $callbackHandler - */ + /** @var array Callback functions for handling requests. */ private $callbackHandler = null; -/** - * LTI parameter constraints for auto validation checks. - * - * @var array $constraints - */ + + /** @var array LTI parameter constraints for auto validation checks. */ private $constraints = null; -/** - * Class constructor - * - * @param DataConnector $dataConnector Object containing a database connection object - */ - function __construct($dataConnector) + /** + * Class constructor. + * + * @param DataConnector $dataConnector Object containing a database connection object. + */ + public function __construct($dataConnector) { - $this->constraints = array(); $this->dataConnector = $dataConnector; $this->ok = !is_null($this->dataConnector); - -// Set debug mode + + // Set debug mode $this->debugMode = isset($_POST['custom_debug']) && (strtolower($_POST['custom_debug']) === 'true'); - -// Set return URL if available + + // Set return URL if available if (isset($_POST['launch_presentation_return_url'])) { $this->returnUrl = $_POST['launch_presentation_return_url']; - } else if (isset($_POST['content_item_return_url'])) { + } elseif (isset($_POST['content_item_return_url'])) { $this->returnUrl = $_POST['content_item_return_url']; } + $this->vendor = new Profile\Item(); $this->product = new Profile\Item(); $this->requiredServices = array(); $this->optionalServices = array(); $this->resourceHandlers = array(); - } -/** - * Process an incoming request - */ + /** + * Process an incoming request + */ public function handleRequest() { - if ($this->ok) { if ($this->authenticate()) { $this->doCallback(); } } + $this->result(); - } -/** - * Add a parameter constraint to be checked on launch - * - * @param string $name Name of parameter to be checked - * @param boolean $required True if parameter is required (optional, default is true) - * @param int $maxLength Maximum permitted length of parameter value (optional, default is null) - * @param array $messageTypes Array of message types to which the constraint applies (optional, default is all) - */ + /** + * Add a parameter constraint to be checked on launch. + * + * @param string $name Name of parameter to be checked. + * @param bool $required TRUE if parameter is required (optional, default is TRUE). + * @param int $maxLength Maximum permitted length of parameter value (optional, default is NULL). + * @param array $messageTypes Array of message types to which the constraint applies (optional, default is all). + */ public function setParameterConstraint($name, $required = true, $maxLength = null, $messageTypes = null) { - $name = trim($name); + if (strlen($name) > 0) { - $this->constraints[$name] = array('required' => $required, 'max_length' => $maxLength, 'messages' => $messageTypes); + $this->constraints[$name] = array( + 'required' => $required, + 'max_length' => $maxLength, + 'messages' => $messageTypes + ); } - } -/** - * Get an array of defined tool consumers - * - * @return array Array of ToolConsumer objects - */ + /** + * Get an array of defined tool consumers. + * + * @return array Array of ToolConsumer objects + */ public function getConsumers() { - return $this->dataConnector->getToolConsumers(); - } -/** - * Find an offered service based on a media type and HTTP action(s) - * - * @param string $format Media type required - * @param array $methods Array of HTTP actions required - * - * @return object The service object - */ + /** + * Find an offered service based on a media type and HTTP action(s) + * + * @param string $format Media type required. + * @param array $methods Array of HTTP actions required. + * + * @return object The service object + */ public function findService($format, $methods) { - $found = false; $services = $this->consumer->profile->service_offered; + if (is_array($services)) { $n = -1; + foreach ($services as $service) { $n++; + if (!is_array($service->format) || !in_array($format, $service->format)) { continue; } + $missing = array(); + foreach ($methods as $method) { if (!is_array($service->action) || !in_array($method, $service->action)) { $missing[] = $method; } } + $methods = $missing; + if (count($methods) <= 0) { $found = $service; break; } } } - + return $found; - } -/** - * Send the tool proxy to the Tool Consumer - * - * @return boolean True if the tool proxy was accepted - */ + /** + * Send the tool proxy to the Tool Consumer. + * + * @return bool TRUE if the tool proxy was accepted + */ public function doToolProxyService() { - -// Create tool proxy - $toolProxyService = $this->findService('application/vnd.ims.lti.v2.toolproxy+json', array('POST')); + // Create tool proxy + $toolProxyService = $this->findService('application/vnd.ims.lti.v2.toolproxy+json', array( + 'POST' + )); $secret = DataConnector::getRandomString(12); $toolProxy = new MediaType\ToolProxy($this, $toolProxyService, $secret); $http = $this->consumer->doServiceRequest($toolProxyService, 'POST', 'application/vnd.ims.lti.v2.toolproxy+json', json_encode($toolProxy)); - $ok = $http->ok && ($http->status == 201) && isset($http->responseJson->tool_proxy_guid) && (strlen($http->responseJson->tool_proxy_guid) > 0); + $ok = $http->ok && ($http->status == 201) && isset($http->responseJson->tool_proxy_guid) && + (strlen($http->responseJson->tool_proxy_guid) > 0); + if ($ok) { $this->consumer->setKey($http->responseJson->tool_proxy_guid); $this->consumer->secret = $toolProxy->security_contract->shared_secret; $this->consumer->toolProxy = json_encode($toolProxy); $this->consumer->save(); } - + return $ok; - } -/** - * Get an array of fully qualified user roles - * - * @param mixed $roles Comma-separated list of roles or array of roles - * - * @return array Array of roles - */ + /** + * Get an array of fully qualified user roles. + * + * @param mixed $roles Comma-separated list of roles or array of roles. + * + * @return array Array of roles + */ public static function parseRoles($roles) { - if (!is_array($roles)) { $roles = explode(',', $roles); } + $parsedRoles = array(); + foreach ($roles as $role) { $role = trim($role); + if (!empty($role)) { if (substr($role, 0, 4) !== 'urn:') { $role = 'urn:lti:role:ims/lis/' . $role; } + $parsedRoles[] = $role; } } - + return $parsedRoles; - } -/** - * Generate a web page containing an auto-submitted form of parameters. - * - * @param string $url URL to which the form should be submitted - * @param array $params Array of form parameters - * @param string $target Name of target (optional) - * @return string - */ + /** + * Generate a web page containing an auto-submitted form of parameters. + * + * @param string $url URL to which the form should be submitted. + * @param array $params Array of form parameters. + * @param string $target Name of target (optional). + * + * @return string + */ public static function sendForm($url, $params, $target = '') { - $page = <<< EOD @@ -497,146 +407,137 @@ function doOnLoad() {
EOD; - - foreach($params as $key => $value ) { + + foreach ($params as $key => $value) { $key = htmlentities($key, ENT_COMPAT | ENT_HTML401, 'UTF-8'); $value = htmlentities($value, ENT_COMPAT | ENT_HTML401, 'UTF-8'); $page .= <<< EOD EOD; - } - + $page .= <<< EOD
EOD; - + return $page; - } -### -### PROTECTED METHODS -### - -/** - * Process a valid launch request - * - * @return boolean True if no error - */ + /** + * Process a valid launch request. + * + * @return bool TRUE if no error + */ protected function onLaunch() { - $this->onError(); - } -/** - * Process a valid content-item request - * - * @return boolean True if no error - */ + /** + * Process a valid content-item request. + * + * @return bool TRUE if no error + */ protected function onContentItem() { - $this->onError(); - } -/** - * Process a valid tool proxy registration request - * - * @return boolean True if no error - */ - protected function onRegister() { - + /** + * Process a valid tool proxy registration request. + * + * @return bool TRUE if no error + */ + protected function onRegister() + { $this->onError(); - } -/** - * Process a response to an invalid request - * - * @return boolean True if no further error processing required - */ + /** + * Process a response to an invalid request. + * + * @return bool TRUE if no further error processing required + */ protected function onError() { - $this->doCallback('onError'); - } -### -### PRIVATE METHODS -### - -/** - * Call any callback function for the requested action. - * - * This function may set the redirect_url and output properties. - * - * @return boolean True if no error reported - */ + /** + * Call any callback function for the requested action. + * + * This function may set the redirect_url and output properties. + * + * @return bool TRUE if no error reported + */ private function doCallback($method = null) { - $callback = $method; + if (is_null($callback)) { $callback = self::$METHOD_NAMES[$_POST['lti_message_type']]; } + if (method_exists($this, $callback)) { $result = $this->$callback(); - } else if (is_null($method) && $this->ok) { + } elseif (is_null($method) && $this->ok) { $this->ok = false; $this->reason = "Message type not supported: {$_POST['lti_message_type']}"; } + if ($this->ok && ($_POST['lti_message_type'] == 'ToolProxyRegistrationRequest')) { $this->consumer->save(); } - } -/** - * Perform the result of an action. - * - * This function may redirect the user to another URL rather than returning a value. - * - * @return string Output to be displayed (redirection, or display HTML or message) - */ + /** + * Perform the result of an action. + * + * This function may redirect the user to another URL rather than returning a value. + * + * @return string Output to be displayed (redirection, or display HTML or message) + */ private function result() { - $ok = false; + if (!$this->ok) { $ok = $this->onError(); } + if (!$ok) { if (!$this->ok) { - -// If not valid, return an error message to the tool consumer if a return URL is provided + // If not valid, return an error message to the tool consumer if a return URL is provided if (!empty($this->returnUrl)) { $errorUrl = $this->returnUrl; + if (strpos($errorUrl, '?') === false) { $errorUrl .= '?'; } else { $errorUrl .= '&'; } + if ($this->debugMode && !is_null($this->reason)) { $errorUrl .= 'lti_errormsg=' . urlencode("Debug error: $this->reason"); } else { $errorUrl .= 'lti_errormsg=' . urlencode($this->message); + if (!is_null($this->reason)) { $errorUrl .= '<i_errorlog=' . urlencode("Debug error: $this->reason"); } } - if (!is_null($this->consumer) && isset($_POST['lti_message_type']) && ($_POST['lti_message_type'] === 'ContentItemSelectionRequest')) { + + if (!is_null($this->consumer) && isset($_POST['lti_message_type']) && + ($_POST['lti_message_type'] === 'ContentItemSelectionRequest')) { $formParams = array(); + if (isset($_POST['data'])) { $formParams['data'] = $_POST['data']; } + $version = (isset($_POST['lti_version'])) ? $_POST['lti_version'] : self::LTI_VERSION1; $formParams = $this->consumer->signParameters($errorUrl, 'ContentItemSelection', $version, $formParams); $page = self::sendForm($errorUrl, $formParams); @@ -644,60 +545,68 @@ private function result() } else { header("Location: {$errorUrl}"); } - exit; + + exit(); } else { if (!is_null($this->errorOutput)) { echo $this->errorOutput; - } else if ($this->debugMode && !empty($this->reason)) { + } elseif ($this->debugMode && !empty($this->reason)) { echo "Debug error: {$this->reason}"; } else { echo "Error: {$this->message}"; } } - } else if (!is_null($this->redirectUrl)) { + } elseif (!is_null($this->redirectUrl)) { header("Location: {$this->redirectUrl}"); - exit; - } else if (!is_null($this->output)) { + exit(); + } elseif (!is_null($this->output)) { echo $this->output; } } - } -/** - * Check the authenticity of the LTI launch request. - * - * The consumer, resource link and user objects will be initialised if the request is valid. - * - * @return boolean True if the request has been successfully validated. - */ + /** + * Check the authenticity of the LTI launch request. + * + * The consumer, resource link and user objects will be initialised if the request is valid. + * + * @return bool TRUE if the request has been successfully validated. + */ private function authenticate() { - -// Get the consumer + + // Get the consumer $doSaveConsumer = false; -// Check all required launch parameters - $this->ok = isset($_POST['lti_message_type']) && array_key_exists($_POST['lti_message_type'], self::$MESSAGE_TYPES); + + // Check all required launch parameters + $this->ok = isset($_POST['lti_message_type']) && + array_key_exists($_POST['lti_message_type'], self::$MESSAGE_TYPES); + if (!$this->ok) { $this->reason = 'Invalid or missing lti_message_type parameter.'; } + if ($this->ok) { $this->ok = isset($_POST['lti_version']) && in_array($_POST['lti_version'], self::$LTI_VERSIONS); + if (!$this->ok) { $this->reason = 'Invalid or missing lti_version parameter.'; } } + if ($this->ok) { if ($_POST['lti_message_type'] === 'basic-lti-launch-request') { $this->ok = isset($_POST['resource_link_id']) && (strlen(trim($_POST['resource_link_id'])) > 0); + if (!$this->ok) { $this->reason = 'Missing resource link ID.'; } - } else if ($_POST['lti_message_type'] === 'ContentItemSelectionRequest') { + } elseif ($_POST['lti_message_type'] === 'ContentItemSelectionRequest') { if (isset($_POST['accept_media_types']) && (strlen(trim($_POST['accept_media_types'])) > 0)) { $mediaTypes = array_filter(explode(',', str_replace(' ', '', $_POST['accept_media_types'])), 'strlen'); $mediaTypes = array_unique($mediaTypes); $this->ok = count($mediaTypes) > 0; + if (!$this->ok) { $this->reason = 'No accept_media_types found.'; } else { @@ -706,20 +615,32 @@ private function authenticate() } else { $this->ok = false; } - if ($this->ok && isset($_POST['accept_presentation_document_targets']) && (strlen(trim($_POST['accept_presentation_document_targets'])) > 0)) { + + if ($this->ok && isset($_POST['accept_presentation_document_targets']) && + (strlen(trim($_POST['accept_presentation_document_targets'])) > 0)) { $documentTargets = array_filter(explode(',', str_replace(' ', '', $_POST['accept_presentation_document_targets'])), 'strlen'); $documentTargets = array_unique($documentTargets); $this->ok = count($documentTargets) > 0; + if (!$this->ok) { $this->reason = 'Missing or empty accept_presentation_document_targets parameter.'; } else { foreach ($documentTargets as $documentTarget) { - $this->ok = $this->checkValue($documentTarget, array('embed', 'frame', 'iframe', 'window', 'popup', 'overlay', 'none'), - 'Invalid value in accept_presentation_document_targets parameter: %s.'); + $this->ok = $this->checkValue($documentTarget, array( + 'embed', + 'frame', + 'iframe', + 'window', + 'popup', + 'overlay', + 'none' + ), 'Invalid value in accept_presentation_document_targets parameter: %s.'); + if (!$this->ok) { break; } } + if ($this->ok) { $this->documentTargets = $documentTargets; } @@ -727,45 +648,58 @@ private function authenticate() } else { $this->ok = false; } + if ($this->ok) { - $this->ok = isset($_POST['content_item_return_url']) && (strlen(trim($_POST['content_item_return_url'])) > 0); + $this->ok = isset($_POST['content_item_return_url']) && + (strlen(trim($_POST['content_item_return_url'])) > 0); + if (!$this->ok) { $this->reason = 'Missing content_item_return_url parameter.'; } } - } else if ($_POST['lti_message_type'] == 'ToolProxyRegistrationRequest') { + } elseif ($_POST['lti_message_type'] == 'ToolProxyRegistrationRequest') { $this->ok = ((isset($_POST['reg_key']) && (strlen(trim($_POST['reg_key'])) > 0)) && - (isset($_POST['reg_password']) && (strlen(trim($_POST['reg_password'])) > 0)) && - (isset($_POST['tc_profile_url']) && (strlen(trim($_POST['tc_profile_url'])) > 0)) && - (isset($_POST['launch_presentation_return_url']) && (strlen(trim($_POST['launch_presentation_return_url'])) > 0))); + (isset($_POST['reg_password']) && (strlen(trim($_POST['reg_password'])) > 0)) && + (isset($_POST['tc_profile_url']) && (strlen(trim($_POST['tc_profile_url'])) > 0)) && (isset($_POST['launch_presentation_return_url']) && + (strlen(trim($_POST['launch_presentation_return_url'])) > 0))); + if ($this->debugMode && !$this->ok) { $this->reason = 'Missing message parameters.'; } } } + $now = time(); -// Check consumer key + + // Check consumer key if ($this->ok && ($_POST['lti_message_type'] != 'ToolProxyRegistrationRequest')) { $this->ok = isset($_POST['oauth_consumer_key']); + if (!$this->ok) { $this->reason = 'Missing consumer key.'; } + if ($this->ok) { $this->consumer = new ToolConsumer($_POST['oauth_consumer_key'], $this->dataConnector); $this->ok = !is_null($this->consumer->created); + if (!$this->ok) { $this->reason = 'Invalid consumer key.'; } } + if ($this->ok) { $today = date('Y-m-d', $now); + if (is_null($this->consumer->lastAccess)) { $doSaveConsumer = true; } else { $last = date('Y-m-d', $this->consumer->lastAccess); $doSaveConsumer = $doSaveConsumer || ($last !== $today); } + $this->consumer->last_access = $now; + try { $store = new OAuthDataStore($this); $server = new OAuth\OAuthServer($store); @@ -775,14 +709,17 @@ private function authenticate() $res = $server->verify_request($request); } catch (\Exception $e) { $this->ok = false; + if (empty($this->reason)) { if ($this->debugMode) { $consumer = new OAuth\OAuthConsumer($this->consumer->getKey(), $this->consumer->secret); $signature = $request->build_signature($method, $consumer, false); $this->reason = $e->getMessage(); + if (empty($this->reason)) { $this->reason = 'OAuth exception'; } + $this->details[] = 'Timestamp: ' . time(); $this->details[] = "Signature: {$signature}"; $this->details[] = "Base string: {$request->base_string}]"; @@ -792,39 +729,50 @@ private function authenticate() } } } + if ($this->ok) { $today = date('Y-m-d', $now); + if (is_null($this->consumer->lastAccess)) { $doSaveConsumer = true; } else { $last = date('Y-m-d', $this->consumer->lastAccess); $doSaveConsumer = $doSaveConsumer || ($last !== $today); } + $this->consumer->last_access = $now; + if ($this->consumer->protected) { if (!is_null($this->consumer->consumerGuid)) { $this->ok = empty($_POST['tool_consumer_instance_guid']) || ($this->consumer->consumerGuid === $_POST['tool_consumer_instance_guid']); + if (!$this->ok) { $this->reason = 'Request is from an invalid tool consumer.'; } } else { $this->ok = isset($_POST['tool_consumer_instance_guid']); + if (!$this->ok) { $this->reason = 'A tool consumer GUID must be included in the launch request.'; } } } + if ($this->ok) { $this->ok = $this->consumer->enabled; + if (!$this->ok) { $this->reason = 'Tool consumer has not been enabled by the tool provider.'; } } + if ($this->ok) { $this->ok = is_null($this->consumer->enableFrom) || ($this->consumer->enableFrom <= $now); + if ($this->ok) { $this->ok = is_null($this->consumer->enableUntil) || ($this->consumer->enableUntil > $now); + if (!$this->ok) { $this->reason = 'Tool consumer access has expired.'; } @@ -833,56 +781,87 @@ private function authenticate() } } } - -// Validate other message parameter values + + // Validate other message parameter values if ($this->ok) { if ($_POST['lti_message_type'] === 'ContentItemSelectionRequest') { if (isset($_POST['accept_unsigned'])) { - $this->ok = $this->checkValue($_POST['accept_unsigned'], array('true', 'false'), 'Invalid value for accept_unsigned parameter: %s.'); + $this->ok = $this->checkValue($_POST['accept_unsigned'], array( + 'true', + 'false' + ), 'Invalid value for accept_unsigned parameter: %s.'); } + if ($this->ok && isset($_POST['accept_multiple'])) { - $this->ok = $this->checkValue($_POST['accept_multiple'], array('true', 'false'), 'Invalid value for accept_multiple parameter: %s.'); + $this->ok = $this->checkValue($_POST['accept_multiple'], array( + 'true', + 'false' + ), 'Invalid value for accept_multiple parameter: %s.'); } + if ($this->ok && isset($_POST['accept_copy_advice'])) { - $this->ok = $this->checkValue($_POST['accept_copy_advice'], array('true', 'false'), 'Invalid value for accept_copy_advice parameter: %s.'); + $this->ok = $this->checkValue($_POST['accept_copy_advice'], array( + 'true', + 'false' + ), 'Invalid value for accept_copy_advice parameter: %s.'); } + if ($this->ok && isset($_POST['auto_create'])) { - $this->ok = $this->checkValue($_POST['auto_create'], array('true', 'false'), 'Invalid value for auto_create parameter: %s.'); + $this->ok = $this->checkValue($_POST['auto_create'], array( + 'true', + 'false' + ), 'Invalid value for auto_create parameter: %s.'); } + if ($this->ok && isset($_POST['can_confirm'])) { - $this->ok = $this->checkValue($_POST['can_confirm'], array('true', 'false'), 'Invalid value for can_confirm parameter: %s.'); + $this->ok = $this->checkValue($_POST['can_confirm'], array( + 'true', + 'false' + ), 'Invalid value for can_confirm parameter: %s.'); } - } else if (isset($_POST['launch_presentation_document_target'])) { - $this->ok = $this->checkValue($_POST['launch_presentation_document_target'], array('embed', 'frame', 'iframe', 'window', 'popup', 'overlay'), - 'Invalid value for launch_presentation_document_target parameter: %s.'); + } elseif (isset($_POST['launch_presentation_document_target'])) { + $this->ok = $this->checkValue($_POST['launch_presentation_document_target'], array( + 'embed', + 'frame', + 'iframe', + 'window', + 'popup', + 'overlay' + ), 'Invalid value for launch_presentation_document_target parameter: %s.'); } } } - + if ($this->ok && ($_POST['lti_message_type'] === 'ToolProxyRegistrationRequest')) { $this->ok = $_POST['lti_version'] == self::LTI_VERSION2; + if (!$this->ok) { $this->reason = 'Invalid lti_version parameter'; } + if ($this->ok) { $http = new HTTPMessage($_POST['tc_profile_url'], 'GET', null, 'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json'); $this->ok = $http->send(); + if (!$this->ok) { $this->reason = 'Tool consumer profile not accessible.'; } else { $tcProfile = json_decode($http->response); $this->ok = !is_null($tcProfile); + if (!$this->ok) { $this->reason = 'Invalid JSON in tool consumer profile.'; } } } -// Check for required capabilities + + // Check for required capabilities if ($this->ok) { $this->consumer = new ToolConsumer($_POST['reg_key'], $this->dataConnector); $this->consumer->profile = $tcProfile; $capabilities = $this->consumer->profile->capability_offered; $missing = array(); + foreach ($this->resourceHandlers as $resourceHandler) { foreach ($resourceHandler->requiredMessages as $message) { if (!in_array($message->type, $capabilities)) { @@ -890,6 +869,7 @@ private function authenticate() } } } + foreach ($this->constraints as $name => $constraint) { if ($constraint['required']) { if (!in_array($name, $capabilities) && !in_array($name, array_flip($capabilities))) { @@ -897,13 +877,16 @@ private function authenticate() } } } + if (!empty($missing)) { ksort($missing); - $this->reason = 'Required capability not offered - \'' . implode('\', \'', array_keys($missing)) . '\''; + $this->reason = 'Required capability not offered - \'' . implode('\', \'', array_keys($missing)) . + '\''; $this->ok = false; } } -// Check for required services + + // Check for required services if ($this->ok) { foreach ($this->requiredServices as $service) { foreach ($service->formats as $format) { @@ -914,11 +897,13 @@ private function authenticate() } else { $this->reason .= ', '; } + $this->reason .= "'{$format}' [" . implode(', ', $service->actions) . ']'; } } } } + if ($this->ok) { if ($_POST['lti_message_type'] === 'ToolProxyRegistrationRequest') { $this->consumer->profile = $tcProfile; @@ -933,29 +918,34 @@ private function authenticate() $doSaveConsumer = true; } } - } else if ($this->ok && !empty($_POST['custom_tc_profile_url']) && empty($this->consumer->profile)) { + } elseif ($this->ok && !empty($_POST['custom_tc_profile_url']) && empty($this->consumer->profile)) { $http = new HTTPMessage($_POST['custom_tc_profile_url'], 'GET', null, 'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json'); + if ($http->send()) { $tcProfile = json_decode($http->response); + if (!is_null($tcProfile)) { $this->consumer->profile = $tcProfile; $doSaveConsumer = true; } } } - -// Validate message parameter constraints + + // Validate message parameter constraints if ($this->ok) { $invalidParameters = array(); + foreach ($this->constraints as $name => $constraint) { if (empty($constraint['messages']) || in_array($_POST['lti_message_type'], $constraint['messages'])) { $ok = true; + if ($constraint['required']) { if (!isset($_POST[$name]) || (strlen(trim($_POST[$name])) <= 0)) { $invalidParameters[] = "{$name} (missing)"; $ok = false; } } + if ($ok && !is_null($constraint['max_length']) && isset($_POST[$name])) { if (strlen(trim($_POST[$name])) > $constraint['max_length']) { $invalidParameters[] = "{$name} (too long)"; @@ -963,54 +953,67 @@ private function authenticate() } } } + if (count($invalidParameters) > 0) { $this->ok = false; + if (empty($this->reason)) { $this->reason = 'Invalid parameter(s): ' . implode(', ', $invalidParameters) . '.'; } } } - + if ($this->ok) { - -// Set the request context + // Set the request context if (isset($_POST['context_id'])) { $this->context = Context::fromConsumer($this->consumer, trim($_POST['context_id'])); $title = ''; + if (isset($_POST['context_title'])) { $title = trim($_POST['context_title']); } + if (empty($title)) { $title = "Course {$this->context->getId()}"; } + $this->context->title = $title; } - -// Set the request resource link + + // Set the request resource link if (isset($_POST['resource_link_id'])) { $contentItemId = ''; + if (isset($_POST['custom_content_item_id'])) { $contentItemId = $_POST['custom_content_item_id']; } + $this->resourceLink = ResourceLink::fromConsumer($this->consumer, trim($_POST['resource_link_id']), $contentItemId); + if (!empty($this->context)) { $this->resourceLink->setContextId($this->context->getRecordId()); } + $title = ''; + if (isset($_POST['resource_link_title'])) { $title = trim($_POST['resource_link_title']); } + if (empty($title)) { $title = "Resource {$this->resourceLink->getId()}"; } + $this->resourceLink->title = $title; -// Delete any existing custom parameters + + // Delete any existing custom parameters foreach ($this->consumer->getSettings() as $name => $value) { if (strpos($name, 'custom_') === 0) { $this->consumer->setSetting($name); $doSaveConsumer = true; } } + if (!empty($this->context)) { foreach ($this->context->getSettings() as $name => $value) { if (strpos($name, 'custom_') === 0) { @@ -1018,12 +1021,14 @@ private function authenticate() } } } + foreach ($this->resourceLink->getSettings() as $name => $value) { if (strpos($name, 'custom_') === 0) { $this->resourceLink->setSetting($name); } } -// Save LTI parameters + + // Save LTI parameters foreach (self::$LTI_CONSUMER_SETTING_NAMES as $name) { if (isset($_POST[$name])) { $this->consumer->setSetting($name, $_POST[$name]); @@ -1031,6 +1036,7 @@ private function authenticate() $this->consumer->setSetting($name); } } + if (!empty($this->context)) { foreach (self::$LTI_CONTEXT_SETTING_NAMES as $name) { if (isset($_POST[$name])) { @@ -1040,6 +1046,7 @@ private function authenticate() } } } + foreach (self::$LTI_RESOURCE_LINK_SETTING_NAMES as $name) { if (isset($_POST[$name])) { $this->resourceLink->setSetting($name, $_POST[$name]); @@ -1047,164 +1054,178 @@ private function authenticate() $this->resourceLink->setSetting($name); } } -// Save other custom parameters + + // Save other custom parameters foreach ($_POST as $name => $value) { if ((strpos($name, 'custom_') === 0) && - !in_array($name, array_merge(self::$LTI_CONSUMER_SETTING_NAMES, self::$LTI_CONTEXT_SETTING_NAMES, self::$LTI_RESOURCE_LINK_SETTING_NAMES))) { + !in_array($name, array_merge(self::$LTI_CONSUMER_SETTING_NAMES, self::$LTI_CONTEXT_SETTING_NAMES, self::$LTI_RESOURCE_LINK_SETTING_NAMES))) { $this->resourceLink->setSetting($name, $value); } } } - -// Set the user instance + + // Set the user instance $userId = ''; + if (isset($_POST['user_id'])) { $userId = trim($_POST['user_id']); } - + $this->user = User::fromResourceLink($this->resourceLink, $userId); - -// Set the user name + + // Set the user name $firstname = (isset($_POST['lis_person_name_given'])) ? $_POST['lis_person_name_given'] : ''; $lastname = (isset($_POST['lis_person_name_family'])) ? $_POST['lis_person_name_family'] : ''; $fullname = (isset($_POST['lis_person_name_full'])) ? $_POST['lis_person_name_full'] : ''; $this->user->setNames($firstname, $lastname, $fullname); - -// Set the user email + + // Set the user email $email = (isset($_POST['lis_person_contact_email_primary'])) ? $_POST['lis_person_contact_email_primary'] : ''; $this->user->setEmail($email, $this->defaultEmail); - -// Set the user image URI + + // Set the user image URI if (isset($_POST['user_image'])) { $this->user->image = $_POST['user_image']; } - -// Set the user roles + + // Set the user roles if (isset($_POST['roles'])) { $this->user->roles = self::parseRoles($_POST['roles']); } - -// Initialise the consumer and check for changes + + // Initialise the consumer and check for changes $this->consumer->defaultEmail = $this->defaultEmail; + if ($this->consumer->ltiVersion !== $_POST['lti_version']) { $this->consumer->ltiVersion = $_POST['lti_version']; $doSaveConsumer = true; } + if (isset($_POST['tool_consumer_instance_name'])) { if ($this->consumer->consumerName !== $_POST['tool_consumer_instance_name']) { $this->consumer->consumerName = $_POST['tool_consumer_instance_name']; $doSaveConsumer = true; } } + if (isset($_POST['tool_consumer_info_product_family_code'])) { $version = $_POST['tool_consumer_info_product_family_code']; + if (isset($_POST['tool_consumer_info_version'])) { $version .= "-{$_POST['tool_consumer_info_version']}"; } -// do not delete any existing consumer version if none is passed + + // do not delete any existing consumer version if none is passed if ($this->consumer->consumerVersion !== $version) { $this->consumer->consumerVersion = $version; $doSaveConsumer = true; } - } else if (isset($_POST['ext_lms']) && ($this->consumer->consumerName !== $_POST['ext_lms'])) { + } elseif (isset($_POST['ext_lms']) && ($this->consumer->consumerName !== $_POST['ext_lms'])) { $this->consumer->consumerVersion = $_POST['ext_lms']; $doSaveConsumer = true; } + if (isset($_POST['tool_consumer_instance_guid'])) { if (is_null($this->consumer->consumerGuid)) { $this->consumer->consumerGuid = $_POST['tool_consumer_instance_guid']; $doSaveConsumer = true; - } else if (!$this->consumer->protected) { + } elseif (!$this->consumer->protected) { $doSaveConsumer = ($this->consumer->consumerGuid !== $_POST['tool_consumer_instance_guid']); + if ($doSaveConsumer) { $this->consumer->consumerGuid = $_POST['tool_consumer_instance_guid']; } } } + if (isset($_POST['launch_presentation_css_url'])) { if ($this->consumer->cssPath !== $_POST['launch_presentation_css_url']) { $this->consumer->cssPath = $_POST['launch_presentation_css_url']; $doSaveConsumer = true; } - } else if (isset($_POST['ext_launch_presentation_css_url']) && + } elseif (isset($_POST['ext_launch_presentation_css_url']) && ($this->consumer->cssPath !== $_POST['ext_launch_presentation_css_url'])) { $this->consumer->cssPath = $_POST['ext_launch_presentation_css_url']; $doSaveConsumer = true; - } else if (!empty($this->consumer->cssPath)) { + } elseif (!empty($this->consumer->cssPath)) { $this->consumer->cssPath = null; $doSaveConsumer = true; } } - -// Persist changes to consumer + + // Persist changes to consumer if ($doSaveConsumer) { $this->consumer->save(); } + if ($this->ok && isset($this->context)) { $this->context->save(); } + if ($this->ok && isset($this->resourceLink)) { - -// Check if a share arrangement is in place for this resource link + // Check if a share arrangement is in place for this resource link $this->ok = $this->checkForShare(); - -// Persist changes to resource link + + // Persist changes to resource link $this->resourceLink->save(); - -// Save the user instance + + // Save the user instance if (isset($_POST['lis_result_sourcedid'])) { if ($this->user->ltiResultSourcedId !== $_POST['lis_result_sourcedid']) { $this->user->ltiResultSourcedId = $_POST['lis_result_sourcedid']; $this->user->save(); } - } else if (!empty($this->user->ltiResultSourcedId)) { + } elseif (!empty($this->user->ltiResultSourcedId)) { $this->user->ltiResultSourcedId = ''; $this->user->save(); } } - + return $this->ok; - } -/** - * Check if a share arrangement is in place. - * - * @return boolean True if no error is reported - */ + /** + * Check if a share arrangement is in place. + * + * @return bool TRUE if no error is reported + */ private function checkForShare() { - $ok = true; $doSaveResourceLink = true; - + $id = $this->resourceLink->primaryResourceLinkId; - + $shareRequest = isset($_POST['custom_share_key']) && !empty($_POST['custom_share_key']); + if ($shareRequest) { if (!$this->allowSharing) { $ok = false; $this->reason = 'Your sharing request has been refused because sharing is not being permitted.'; } else { -// Check if this is a new share key + // Check if this is a new share key $shareKey = new ResourceLinkShareKey($this->resourceLink, $_POST['custom_share_key']); + if (!is_null($shareKey->primaryConsumerKey) && !is_null($shareKey->primaryResourceLinkId)) { -// Update resource link with sharing primary resource link details + // Update resource link with sharing primary resource link details $key = $shareKey->primaryConsumerKey; $id = $shareKey->primaryResourceLinkId; $ok = ($key !== $this->consumer->getKey()) || ($id != $this->resourceLink->getId()); + if ($ok) { $this->resourceLink->primaryConsumerKey = $key; $this->resourceLink->primaryResourceLinkId = $id; $this->resourceLink->shareApproved = $shareKey->autoApprove; $ok = $this->resourceLink->save(); + if ($ok) { $doSaveResourceLink = false; $this->user->getResourceLink()->primaryConsumerKey = $key; $this->user->getResourceLink()->primaryResourceLinkId = $id; $this->user->getResourceLink()->shareApproved = $shareKey->autoApprove; $this->user->getResourceLink()->updated = time(); -// Remove share key + + // Remove share key $shareKey->delete(); } else { $this->reason = 'An error occurred initialising your share arrangement.'; @@ -1213,12 +1234,16 @@ private function checkForShare() $this->reason = 'It is not possible to share your resource link with yourself.'; } } + if ($ok) { $ok = !is_null($key); + if (!$ok) { $this->reason = 'You have requested to share a resource link but none is available.'; } else { - $ok = (!is_null($this->user->getResourceLink()->shareApproved) && $this->user->getResourceLink()->shareApproved); + $ok = (!is_null($this->user->getResourceLink()->shareApproved) && + $this->user->getResourceLink()->shareApproved); + if (!$ok) { $this->reason = 'Your share request is waiting to be approved.'; } @@ -1226,50 +1251,51 @@ private function checkForShare() } } } else { -// Check no share is in place + // Check no share is in place $ok = is_null($id); + if (!$ok) { $this->reason = 'You have not requested to share a resource link but an arrangement is currently in place.'; } } - -// Look up primary resource link + + // Look up primary resource link if ($ok && !is_null($id)) { $consumer = new ToolConsumer($key, $this->dataConnector); $ok = !is_null($consumer->created); + if ($ok) { $resourceLink = ResourceLink::fromConsumer($consumer, $id); $ok = !is_null($resourceLink->created); } + if ($ok) { if ($doSaveResourceLink) { $this->resourceLink->save(); } + $this->resourceLink = $resourceLink; } else { $this->reason = 'Unable to load resource link being shared.'; } } - + return $ok; - } -/** - * Validate a parameter value from an array of permitted values. - * - * @return boolean True if value is valid - */ + /** + * Validate a parameter value from an array of permitted values. + * + * @return bool TRUE if value is valid + */ private function checkValue($value, $values, $reason) { - $ok = in_array($value, $values); + if (!$ok && !empty($reason)) { $this->reason = sprintf($reason, $value); } - + return $ok; - } - } diff --git a/src/ToolProvider/ToolProxy.php b/src/ToolProvider/ToolProxy.php index 7a1dcfa..997ba85 100644 --- a/src/ToolProvider/ToolProxy.php +++ b/src/ToolProvider/ToolProxy.php @@ -1,194 +1,155 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 - * @version 3.0.2 - * @license GNU Lesser General Public License, version 3 () + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc + * @version 3.0.2 + * @license Apache-2.0 */ class ToolProxy { -/** - * Local id of tool consumer. - * - * @var string $id - */ + /** @var string Local id of tool consumer. */ public $id = null; -/** - * Tool Consumer for this tool proxy. - * - * @var ToolConsumer $consumer - */ + /** @var ToolConsumer Tool Consumer for this tool proxy. */ private $consumer = null; -/** - * Tool Consumer ID for this tool proxy. - * - * @var int $consumerId - */ + + /** @var int Tool Consumer ID for this tool proxy. */ private $consumerId = null; -/** - * Consumer ID value. - * - * @var int $id - */ + + /** @var int Consumer ID value. */ private $recordId = null; -/** - * Data connector object. - * - * @var DataConnector $dataConnector - */ + + /** @var DataConnector Data connector object. */ private $dataConnector = null; -/** - * Tool Proxy document. - * - * @var MediaType\ToolProxy $toolProxy - */ + + /** @var MediaType\ToolProxy Tool Proxy document. */ private $toolProxy = null; -/** - * Class constructor. - * - * @param DataConnector $dataConnector Data connector - * @param string $id Tool Proxy ID (optional, default is null) - */ + /** + * Class constructor. + * + * @param DataConnector $dataConnector Data connector. + * @param string $id Tool Proxy ID (optional, default is NULL). + */ public function __construct($dataConnector, $id = null) { - $this->initialize(); $this->dataConnector = $dataConnector; + if (!empty($id)) { $this->load($id); } else { $this->recordId = DataConnector::getRandomString(32); } - } -/** - * Initialise the tool proxy. - */ + /** + * Initialise the tool proxy. + */ public function initialize() { - $this->id = null; $this->recordId = null; $this->toolProxy = null; $this->created = null; $this->updated = null; - } -/** - * Initialise the tool proxy. - * - * Pseudonym for initialize(). - */ + /** + * Initialise the tool proxy. + * + * Pseudonym for initialize(). + */ public function initialise() { - $this->initialize(); - } -/** - * Get the tool proxy record ID. - * - * @return int Tool Proxy record ID value - */ + /** + * Get the tool proxy record ID. + * + * @return int Tool Proxy record ID value + */ public function getRecordId() { - return $this->recordId; - } -/** - * Sets the tool proxy record ID. - * - * @param int $recordId Tool Proxy record ID value - */ + /** + * Sets the tool proxy record ID. + * + * @param int $recordId Tool Proxy record ID value. + */ public function setRecordId($recordId) { - $this->recordId = $recordId; - } -/** - * Get tool consumer. - * - * @return ToolConsumer Tool consumer object for this context. - */ + /** + * Get tool consumer. + * + * @return ToolConsumer Tool consumer object for this context. + */ public function getConsumer() { - if (is_null($this->consumer)) { $this->consumer = ToolConsumer::fromRecordId($this->consumerId, $this->getDataConnector()); } - + return $this->consumer; - } -/** - * Set tool consumer ID. - * - * @param int $consumerId Tool Consumer ID for this resource link. - */ + /** + * Set tool consumer ID. + * + * @param int $consumerId Tool Consumer ID for this resource link. + */ public function setConsumerId($consumerId) { - $this->consumer = null; $this->consumerId = $consumerId; - } -/** - * Get the data connector. - * - * @return DataConnector Data connector object - */ + /** + * Get the data connector. + * + * @return DataConnector Data connector object + */ public function getDataConnector() { - return $this->dataConnector; - } - - -### -### PRIVATE METHOD -### - -/** - * Load the tool proxy from the database. - * - * @param string $id The tool proxy id value - * - * @return boolean True if the tool proxy was successfully loaded - */ + + ### + ### PRIVATE METHOD + ### + + + /** + * Load the tool proxy from the database. + * + * @param string $id The tool proxy id value. + * + * @return bool TRUE if the tool proxy was successfully loaded + */ private function load($id) { - $this->initialize(); $this->id = $id; $ok = $this->dataConnector->loadToolProxy($this); + if (!$ok) { $this->enabled = $autoEnable; } - + return $ok; - } - } diff --git a/src/ToolProvider/User.php b/src/ToolProvider/User.php index 64632dd..34cf8c0 100644 --- a/src/ToolProvider/User.php +++ b/src/ToolProvider/User.php @@ -1,128 +1,77 @@ - * @copyright IMS Global Learning Consortium Inc - * @date 2016 + * @author Stephen P Vickers + * @copyright 2016 IMS Global Learning Consortium Inc * @version 3.0.2 - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @license Apache-2.0 */ class User { -/** - * User's first name. - * - * @var string $firstname - */ + /** @var string User's first name. */ public $firstname = ''; -/** - * User's last name (surname or family name). - * - * @var string $lastname - */ + + /** @var string User's last name (surname or family name). */ public $lastname = ''; -/** - * User's fullname. - * - * @var string $fullname - */ + + /** @var string User's fullname. */ public $fullname = ''; -/** - * User's email address. - * - * @var string $email - */ + + /** @var string User's email address. */ public $email = ''; -/** - * User's image URI. - * - * @var string $image - */ + + /** @var string User's image URI. */ public $image = ''; -/** - * Roles for user. - * - * @var array $roles - */ + + /** @var array Roles for user. */ public $roles = array(); -/** - * Groups for user. - * - * @var array $groups - */ + + /** @var array Groups for user. */ public $groups = array(); -/** - * User's result sourcedid. - * - * @var string $ltiResultSourcedId - */ + + /** @var string User's result sourcedid. */ public $ltiResultSourcedId = null; -/** - * Date/time the record was created. - * - * @var object $created - */ + + /** @var object Date/time the record was created. */ public $created = null; -/** - * Date/time the record was last updated. - * - * @var object $updated - */ + + /** @var object Date/time the record was last updated. */ public $updated = null; -/** - * Resource link object. - * - * @var ResourceLink $resourceLink - */ + /** @var ResourceLink Resource link object. */ private $resourceLink = null; -/** - * Resource link record ID. - * - * @var int $resourceLinkId - */ + + /** @var int Resource link record ID. */ private $resourceLinkId = null; -/** - * User record ID value. - * - * @var string $id - */ + + /** @var string User record ID value. */ private $id = null; -/** - * user ID as supplied in the last connection request. - * - * @var string $ltiUserId - */ + + /** @var string user ID as supplied in the last connection request. */ public $ltiUserId = null; -/** - * Data connector object or string. - * - * @var mixed $dataConnector - */ + + /** @var mixed Data connector object or string. */ private $dataConnector = null; -/** - * Class constructor. - */ + /** + * Class constructor. + */ public function __construct() { - $this->initialize(); - } -/** - * Initialise the user. - */ + /** + * Initialise the user. + */ public function initialize() { - $this->firstname = ''; $this->lastname = ''; $this->fullname = ''; @@ -133,127 +82,109 @@ public function initialize() $this->ltiResultSourcedId = null; $this->created = null; $this->updated = null; - } -/** - * Initialise the user. - * - * Pseudonym for initialize(). - */ + /** + * Initialise the user. + * + * Pseudonym for initialize(). + */ public function initialise() { - $this->initialize(); - } -/** - * Save the user to the database. - * - * @return boolean True if the user object was successfully saved - */ + /** + * Save the user to the database. + * + * @return bool TRUE if the user object was successfully saved + */ public function save() { - if (!empty($this->ltiResultSourcedId) && !is_null($this->resourceLinkId)) { $ok = $this->getDataConnector()->saveUser($this); } else { $ok = true; } - + return $ok; - } -/** - * Delete the user from the database. - * - * @return boolean True if the user object was successfully deleted - */ + /** + * Delete the user from the database. + * + * @return bool TRUE if the user object was successfully deleted + */ public function delete() { - $ok = $this->getDataConnector()->deleteUser($this); - + return $ok; - } -/** - * Get resource link. - * - * @return ResourceLink Resource link object - */ + /** + * Get resource link. + * + * @return ResourceLink Resource link object + */ public function getResourceLink() { - if (is_null($this->resourceLink) && !is_null($this->resourceLinkId)) { $this->resourceLink = ResourceLink::fromRecordId($this->resourceLinkId, $this->getDataConnector()); } - + return $this->resourceLink; - } -/** - * Get record ID of user. - * - * @return int Record ID of user - */ + /** + * Get record ID of user. + * + * @return int Record ID of user + */ public function getRecordId() { - return $this->id; - } -/** - * Set record ID of user. - * - * @param int $id Record ID of user - */ + /** + * Set record ID of user. + * + * @param int $id Record ID of user. + */ public function setRecordId($id) { - $this->id = $id; - } -/** - * Set resource link ID of user. - * - * @param int $resourceLinkId Resource link ID of user - */ + /** + * Set resource link ID of user. + * + * @param int $resourceLinkId Resource link ID of user. + */ public function setResourceLinkId($resourceLinkId) { - $this->resourceLinkId = $resourceLinkId; - } -/** - * Get the data connector. - * - * @return mixed Data connector object or string - */ + /** + * Get the data connector. + * + * @return mixed Data connector object or string + */ public function getDataConnector() { - return $this->dataConnector; - } -/** - * Get the user ID (which may be a compound of the tool consumer and resource link IDs). - * - * @param int $idScope Scope to use for user ID (optional, default is null for consumer default setting) - * - * @return string User ID value - */ + /** + * Get the user ID (which may be a compound of the tool consumer and resource link IDs). + * + * @param int $idScope Scope to use for user ID (optional, default is NULL for consumer default setting). + * + * @return string User ID value + */ public function getId($idScope = null) { - if (empty($idScope)) { if (!is_null($this->resourceLink)) { $idScope = $this->resourceLink->getConsumer()->idScope; @@ -261,213 +192,214 @@ public function getId($idScope = null) $idScope = ToolProvider::ID_SCOPE_ID_ONLY; } } + switch ($idScope) { case ToolProvider::ID_SCOPE_GLOBAL: $id = $this->getResourceLink()->getKey() . ToolProvider::ID_SCOPE_SEPARATOR . $this->ltiUserId; break; case ToolProvider::ID_SCOPE_CONTEXT: $id = $this->getResourceLink()->getKey(); + if ($this->resourceLink->ltiContextId) { $id .= ToolProvider::ID_SCOPE_SEPARATOR . $this->resourceLink->ltiContextId; } + $id .= ToolProvider::ID_SCOPE_SEPARATOR . $this->ltiUserId; break; case ToolProvider::ID_SCOPE_RESOURCE: $id = $this->getResourceLink()->getKey(); + if ($this->resourceLink->ltiResourceLinkId) { $id .= ToolProvider::ID_SCOPE_SEPARATOR . $this->resourceLink->ltiResourceLinkId; } + $id .= ToolProvider::ID_SCOPE_SEPARATOR . $this->ltiUserId; break; default: $id = $this->ltiUserId; break; } - + return $id; - } -/** - * Set the user's name. - * - * @param string $firstname User's first name. - * @param string $lastname User's last name. - * @param string $fullname User's full name. - */ + /** + * Set the user's name. + * + * @param string $firstname User's first name. + * @param string $lastname User's last name. + * @param string $fullname User's full name. + */ public function setNames($firstname, $lastname, $fullname) { - - $names = array(0 => '', 1 => ''); + $names = array( + 0 => '', + 1 => '' + ); + if (!empty($fullname)) { $this->fullname = trim($fullname); $names = preg_split("/[\s]+/", $this->fullname, 2); } + if (!empty($firstname)) { $this->firstname = trim($firstname); $names[0] = $this->firstname; - } else if (!empty($names[0])) { + } elseif (!empty($names[0])) { $this->firstname = $names[0]; } else { $this->firstname = 'User'; } + if (!empty($lastname)) { $this->lastname = trim($lastname); $names[1] = $this->lastname; - } else if (!empty($names[1])) { + } elseif (!empty($names[1])) { $this->lastname = $names[1]; } else { $this->lastname = $this->ltiUserId; } + if (empty($this->fullname)) { $this->fullname = "{$this->firstname} {$this->lastname}"; } - } -/** - * Set the user's email address. - * - * @param string $email Email address value - * @param string $defaultEmail Value to use if no email is provided (optional, default is none) - */ + /** + * Set the user's email address. + * + * @param string $email Email address value. + * @param string $defaultEmail Value to use if no email is provided (optional, default is none). + */ public function setEmail($email, $defaultEmail = null) { - - if (!empty($email)) { - $this->email = $email; - } else if (!empty($defaultEmail)) { - $this->email = $defaultEmail; - if (substr($this->email, 0, 1) === '@') { - $this->email = $this->getId() . $this->email; - } - } else { - $this->email = ''; - } - + if (!empty($email)) { + $this->email = $email; + } elseif (!empty($defaultEmail)) { + $this->email = $defaultEmail; + + if (substr($this->email, 0, 1) === '@') { + $this->email = $this->getId() . $this->email; + } + } else { + $this->email = ''; + } } -/** - * Check if the user is an administrator (at any of the system, institution or context levels). - * - * @return boolean True if the user has a role of administrator - */ + /** + * Check if the user is an administrator (at any of the system, institution or context levels). + * + * @return bool TRUE if the user has a role of administrator + */ public function isAdmin() { - return $this->hasRole('Administrator') || $this->hasRole('urn:lti:sysrole:ims/lis/SysAdmin') || - $this->hasRole('urn:lti:sysrole:ims/lis/Administrator') || $this->hasRole('urn:lti:instrole:ims/lis/Administrator'); - + $this->hasRole('urn:lti:sysrole:ims/lis/Administrator') || + $this->hasRole('urn:lti:instrole:ims/lis/Administrator'); } -/** - * Check if the user is staff. - * - * @return boolean True if the user has a role of instructor, contentdeveloper or teachingassistant - */ + /** + * Check if the user is staff. + * + * @return bool TRUE if the user has a role of instructor, contentdeveloper or teachingassistant + */ public function isStaff() { - return ($this->hasRole('Instructor') || $this->hasRole('ContentDeveloper') || $this->hasRole('TeachingAssistant')); - } -/** - * Check if the user is a learner. - * - * @return boolean True if the user has a role of learner - */ + /** + * Check if the user is a learner. + * + * @return bool TRUE if the user has a role of learner + */ public function isLearner() { - return $this->hasRole('Learner'); - } -/** - * Load the user from the database. - * - * @param int $id Record ID of user - * @param DataConnector $dataConnector Database connection object - * - * @return User User object - */ + /** + * Load the user from the database. + * + * @param int $id Record ID of user. + * @param DataConnector $dataConnector Database connection object. + * + * @return User User object + */ public static function fromRecordId($id, $dataConnector) { - $user = new User(); $user->dataConnector = $dataConnector; $user->load($id); - + return $user; - } -/** - * Class constructor from resource link. - * - * @param ResourceLink $resourceLink Resource_Link object - * @param string $ltiUserId User ID value - * @return User - */ + /** + * Class constructor from resource link. + * + * @param ResourceLink $resourceLink Resource_Link object. + * @param string $ltiUserId User ID value. + * + * @return User + */ public static function fromResourceLink($resourceLink, $ltiUserId) { - $user = new User(); $user->resourceLink = $resourceLink; + if (!is_null($resourceLink)) { $user->resourceLinkId = $resourceLink->getRecordId(); $user->dataConnector = $resourceLink->getDataConnector(); } + $user->ltiUserId = $ltiUserId; + if (!empty($ltiUserId)) { $user->load(); } - + return $user; - } - -### -### PRIVATE METHODS -### - -/** - * Check whether the user has a specified role name. - * - * @param string $role Name of role - * - * @return boolean True if the user has the specified role - */ - private function hasRole($role) { - - if (substr($role, 0, 4) !== 'urn:') - { + + ### + ### PRIVATE METHODS + ### + + + /** + * Check whether the user has a specified role name. + * + * @param string $role Name of role. + * + * @return bool TRUE if the user has the specified role + */ + private function hasRole($role) + { + if (substr($role, 0, 4) !== 'urn:') { $role = 'urn:lti:role:ims/lis/' . $role; } - + return in_array($role, $this->roles); - } -/** - * Load the user from the database. - * - * @param int $id Record ID of user (optional, default is null) - * - * @return boolean True if the user object was successfully loaded - */ + /** + * Load the user from the database. + * + * @param int $id Record ID of user (optional, default is NULL). + * + * @return bool TRUE if the user object was successfully loaded + */ private function load($id = null) { - $this->initialize(); $this->id = $id; $dataConnector = $this->getDataConnector(); + if (!is_null($dataConnector)) { return $dataConnector->loadUser($this); } - + return false; } - }