From 53d3cf06a8c33219ef7e7ac879741971febbbc42 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 09:59:50 -0600 Subject: [PATCH 01/27] Implement some changes --- src/Lti1p1Key.php | 4 ++-- src/LtiAbstractService.php | 2 +- src/LtiDeepLink.php | 4 ++-- src/LtiDeepLinkDateTimeInterval.php | 4 ++-- src/LtiDeepLinkResourceIcon.php | 4 ++-- src/LtiDeepLinkResourceIframe.php | 4 ++-- src/LtiDeepLinkResourceWindow.php | 4 ++-- src/LtiOidcLogin.php | 10 +++++----- src/ServiceRequest.php | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Lti1p1Key.php b/src/Lti1p1Key.php index 4abd70bf..091f9fc5 100644 --- a/src/Lti1p1Key.php +++ b/src/Lti1p1Key.php @@ -23,7 +23,7 @@ public function getKey(): ?string return $this->key; } - public function setKey(string $key) + public function setKey(string $key): self { $this->key = $key; @@ -35,7 +35,7 @@ public function getSecret(): ?string return $this->secret; } - public function setSecret(string $secret) + public function setSecret(string $secret): self { $this->secret = $secret; diff --git a/src/LtiAbstractService.php b/src/LtiAbstractService.php index 56f28d06..d0614ba4 100644 --- a/src/LtiAbstractService.php +++ b/src/LtiAbstractService.php @@ -32,7 +32,7 @@ abstract public function getScope(): array; protected function validateScopes(array $scopes): void { if (empty(array_intersect($scopes, $this->getScope()))) { - throw new LtiException('Missing required scope', 1); + throw new LtiException('Missing required scope'); } } diff --git a/src/LtiDeepLink.php b/src/LtiDeepLink.php index 7fbdbc15..a1fae707 100644 --- a/src/LtiDeepLink.php +++ b/src/LtiDeepLink.php @@ -10,8 +10,8 @@ class LtiDeepLink public function __construct( private ILtiRegistration $registration, private string $deployment_id, - private array $deep_link_settings) - { + private array $deep_link_settings + ) { } public function getResponseJwt(array $resources): string diff --git a/src/LtiDeepLinkDateTimeInterval.php b/src/LtiDeepLinkDateTimeInterval.php index f1dad280..e0b4f9e6 100644 --- a/src/LtiDeepLinkDateTimeInterval.php +++ b/src/LtiDeepLinkDateTimeInterval.php @@ -8,8 +8,8 @@ class LtiDeepLinkDateTimeInterval { public function __construct( private ?DateTime $start = null, - private ?DateTime $end = null) - { + private ?DateTime $end = null + ) { if ($start !== null && $end !== null && $end < $start) { throw new LtiException('Interval start time cannot be greater than end time'); } diff --git a/src/LtiDeepLinkResourceIcon.php b/src/LtiDeepLinkResourceIcon.php index 18b2a42f..65eae1cc 100644 --- a/src/LtiDeepLinkResourceIcon.php +++ b/src/LtiDeepLinkResourceIcon.php @@ -7,8 +7,8 @@ class LtiDeepLinkResourceIcon public function __construct( private string $url, private int $width, - private int $height) - { + private int $height + ) { } public static function new(string $url, int $width, int $height): LtiDeepLinkResourceIcon diff --git a/src/LtiDeepLinkResourceIframe.php b/src/LtiDeepLinkResourceIframe.php index bb16c667..11676fbc 100644 --- a/src/LtiDeepLinkResourceIframe.php +++ b/src/LtiDeepLinkResourceIframe.php @@ -7,8 +7,8 @@ class LtiDeepLinkResourceIframe public function __construct( private ?int $width = null, private ?int $height = null, - private ?string $src = null) - { + private ?string $src = null + ) { } public static function new(): LtiDeepLinkResourceIframe diff --git a/src/LtiDeepLinkResourceWindow.php b/src/LtiDeepLinkResourceWindow.php index f69bf55b..52fff1c9 100644 --- a/src/LtiDeepLinkResourceWindow.php +++ b/src/LtiDeepLinkResourceWindow.php @@ -8,8 +8,8 @@ public function __construct( private ?string $target_name = null, private ?int $width = null, private ?int $height = null, - private ?string $window_features = null) - { + private ?string $window_features = null + ) { } public static function new(): LtiDeepLinkResourceWindow diff --git a/src/LtiOidcLogin.php b/src/LtiOidcLogin.php index 393927c6..58cee775 100644 --- a/src/LtiOidcLogin.php +++ b/src/LtiOidcLogin.php @@ -18,8 +18,8 @@ class LtiOidcLogin public function __construct( public IDatabase $db, public ICache $cache, - public ICookie $cookie) - { + public ICookie $cookie + ) { } /** @@ -81,12 +81,12 @@ public function validateOidcLogin(array $request): ILtiRegistration { // Validate Issuer. if (empty($request['iss'])) { - throw new OidcException(static::ERROR_MSG_ISSUER, 1); + throw new OidcException(static::ERROR_MSG_ISSUER); } // Validate Login Hint. if (empty($request['login_hint'])) { - throw new OidcException(static::ERROR_MSG_LOGIN_HINT, 1); + throw new OidcException(static::ERROR_MSG_LOGIN_HINT); } // Fetch Registration Details. @@ -97,7 +97,7 @@ public function validateOidcLogin(array $request): ILtiRegistration if (empty($registration)) { $errorMsg = LtiMessageLaunch::getMissingRegistrationErrorMsg($request['iss'], $clientId); - throw new OidcException($errorMsg, 1); + throw new OidcException($errorMsg); } // Return Registration. diff --git a/src/ServiceRequest.php b/src/ServiceRequest.php index 8c8edffd..7aebaa03 100644 --- a/src/ServiceRequest.php +++ b/src/ServiceRequest.php @@ -46,8 +46,8 @@ class ServiceRequest implements IServiceRequest public function __construct( private string $method, private string $url, - private $type = self::TYPE_UNSUPPORTED) - { + private $type = self::TYPE_UNSUPPORTED + ) { } public function getMethod(): string From 9590f428c06226a760b556cf66e0ceefdb988a0b Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 10:53:44 -0600 Subject: [PATCH 02/27] Change a few more things --- src/LtiDeepLinkDateTimeInterval.php | 2 +- src/LtiDeepLinkResource.php | 26 +++++++++++++------------- src/LtiMessageLaunch.php | 14 ++++++-------- src/LtiOidcLogin.php | 6 +++--- src/LtiRegistration.php | 2 +- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/LtiDeepLinkDateTimeInterval.php b/src/LtiDeepLinkDateTimeInterval.php index e0b4f9e6..d6c50b20 100644 --- a/src/LtiDeepLinkDateTimeInterval.php +++ b/src/LtiDeepLinkDateTimeInterval.php @@ -10,7 +10,7 @@ public function __construct( private ?DateTime $start = null, private ?DateTime $end = null ) { - if ($start !== null && $end !== null && $end < $start) { + if (isset($start) && isset($end) && $end < $start) { throw new LtiException('Interval start time cannot be greater than end time'); } } diff --git a/src/LtiDeepLinkResource.php b/src/LtiDeepLinkResource.php index a39ba5b9..1b5f6a91 100644 --- a/src/LtiDeepLinkResource.php +++ b/src/LtiDeepLinkResource.php @@ -18,7 +18,7 @@ class LtiDeepLinkResource private ?LtiDeepLinkDateTimeInterval $availability_interval = null; private ?LtiDeepLinkDateTimeInterval $submission_interval = null; - public static function new(): LtiDeepLinkResource + public static function new(): self { return new LtiDeepLinkResource(); } @@ -28,7 +28,7 @@ public function getType(): string return $this->type; } - public function setType(string $value): LtiDeepLinkResource + public function setType(string $value): self { $this->type = $value; @@ -40,7 +40,7 @@ public function getTitle(): ?string return $this->title; } - public function setTitle(?string $value): LtiDeepLinkResource + public function setTitle(?string $value): self { $this->title = $value; @@ -52,7 +52,7 @@ public function getText(): ?string return $this->text; } - public function setText(?string $value): LtiDeepLinkResource + public function setText(?string $value): self { $this->text = $value; @@ -64,7 +64,7 @@ public function getUrl(): ?string return $this->url; } - public function setUrl(?string $value): LtiDeepLinkResource + public function setUrl(?string $value): self { $this->url = $value; @@ -76,14 +76,14 @@ public function getLineItem(): ?LtiLineitem return $this->line_item; } - public function setLineItem(?LtiLineitem $value): LtiDeepLinkResource + public function setLineItem(?LtiLineitem $value): self { $this->line_item = $value; return $this; } - public function setIcon(?LtiDeepLinkResourceIcon $icon): LtiDeepLinkResource + public function setIcon(?LtiDeepLinkResourceIcon $icon): self { $this->icon = $icon; @@ -95,7 +95,7 @@ public function getIcon(): ?LtiDeepLinkResourceIcon return $this->icon; } - public function setThumbnail(?LtiDeepLinkResourceIcon $thumbnail): LtiDeepLinkResource + public function setThumbnail(?LtiDeepLinkResourceIcon $thumbnail): self { $this->thumbnail = $thumbnail; @@ -112,7 +112,7 @@ public function getCustomParams(): array return $this->custom_params; } - public function setCustomParams(array $value): LtiDeepLinkResource + public function setCustomParams(array $value): self { $this->custom_params = $value; @@ -124,7 +124,7 @@ public function getIframe(): ?LtiDeepLinkResourceIframe return $this->iframe; } - public function setIframe(?LtiDeepLinkResourceIframe $iframe): LtiDeepLinkResource + public function setIframe(?LtiDeepLinkResourceIframe $iframe): self { $this->iframe = $iframe; @@ -136,7 +136,7 @@ public function getWindow(): ?LtiDeepLinkResourceWindow return $this->window; } - public function setWindow(?LtiDeepLinkResourceWindow $window): LtiDeepLinkResource + public function setWindow(?LtiDeepLinkResourceWindow $window): self { $this->window = $window; @@ -148,7 +148,7 @@ public function getAvailabilityInterval(): ?LtiDeepLinkDateTimeInterval return $this->availability_interval; } - public function setAvailabilityInterval(?LtiDeepLinkDateTimeInterval $availabilityInterval): LtiDeepLinkResource + public function setAvailabilityInterval(?LtiDeepLinkDateTimeInterval $availabilityInterval): self { $this->availability_interval = $availabilityInterval; @@ -160,7 +160,7 @@ public function getSubmissionInterval(): ?LtiDeepLinkDateTimeInterval return $this->submission_interval; } - public function setSubmissionInterval(?LtiDeepLinkDateTimeInterval $submissionInterval): LtiDeepLinkResource + public function setSubmissionInterval(?LtiDeepLinkDateTimeInterval $submissionInterval): self { $this->submission_interval = $submissionInterval; diff --git a/src/LtiMessageLaunch.php b/src/LtiMessageLaunch.php index e6f8ae32..019506f2 100644 --- a/src/LtiMessageLaunch.php +++ b/src/LtiMessageLaunch.php @@ -169,7 +169,7 @@ public function cacheLaunchData(): self */ public function hasNrps(): bool { - return !empty($this->jwt['body'][LtiConstants::NRPS_CLAIM_SERVICE]['context_memberships_url']); + return isset($this->jwt['body'][LtiConstants::NRPS_CLAIM_SERVICE]['context_memberships_url']); } /** @@ -189,7 +189,7 @@ public function getNrps(): LtiNamesRolesProvisioningService */ public function hasGs(): bool { - return !empty($this->jwt['body'][LtiConstants::GS_CLAIM_SERVICE]['context_groups_url']); + return isset($this->jwt['body'][LtiConstants::GS_CLAIM_SERVICE]['context_groups_url']); } /** @@ -209,7 +209,7 @@ public function getGs(): LtiCourseGroupsService */ public function hasAgs(): bool { - return !empty($this->jwt['body'][LtiConstants::AGS_CLAIM_ENDPOINT]); + return isset($this->jwt['body'][LtiConstants::AGS_CLAIM_ENDPOINT]); } /** @@ -375,14 +375,12 @@ protected function validateState(): self protected function validateJwtFormat(): self { - $jwt = $this->request['id_token'] ?? null; - - if (empty($jwt)) { + if (!isset($this->request['id_token'])) { throw new LtiException(static::ERR_MISSING_ID_TOKEN); } // Get parts of JWT. - $jwt_parts = explode('.', $jwt); + $jwt_parts = explode('.', $this->request['id_token']); if (count($jwt_parts) !== 3) { // Invalid number of parts in JWT. @@ -469,7 +467,7 @@ protected function validateDeployment(): self protected function validateMessage(): self { - if (empty($this->jwt['body'][LtiConstants::MESSAGE_TYPE])) { + if (!isset($this->jwt['body'][LtiConstants::MESSAGE_TYPE])) { // Unable to identify message type. throw new LtiException(static::ERR_INVALID_MESSAGE_TYPE); } diff --git a/src/LtiOidcLogin.php b/src/LtiOidcLogin.php index 58cee775..1bca40ad 100644 --- a/src/LtiOidcLogin.php +++ b/src/LtiOidcLogin.php @@ -80,12 +80,12 @@ public function getRedirectUrl(string $launchUrl, array $request): string public function validateOidcLogin(array $request): ILtiRegistration { // Validate Issuer. - if (empty($request['iss'])) { + if (!isset($request['iss'])) { throw new OidcException(static::ERROR_MSG_ISSUER); } // Validate Login Hint. - if (empty($request['login_hint'])) { + if (!isset($request['login_hint'])) { throw new OidcException(static::ERROR_MSG_LOGIN_HINT); } @@ -94,7 +94,7 @@ public function validateOidcLogin(array $request): ILtiRegistration $registration = $this->db->findRegistrationByIssuer($request['iss'], $clientId); // Check we got something. - if (empty($registration)) { + if (!isset($registration)) { $errorMsg = LtiMessageLaunch::getMissingRegistrationErrorMsg($request['iss'], $clientId); throw new OidcException($errorMsg); diff --git a/src/LtiRegistration.php b/src/LtiRegistration.php index 1e31868b..0ae8717b 100644 --- a/src/LtiRegistration.php +++ b/src/LtiRegistration.php @@ -94,7 +94,7 @@ public function setAuthLoginUrl($authLoginUrl): self public function getAuthServer() { - return empty($this->authServer) ? $this->authTokenUrl : $this->authServer; + return $this->authServer ?? $this->authTokenUrl; } public function setAuthServer($authServer): self From 2aa70748ea5f8646c81983271aee96ecb16d341f Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 10:57:55 -0600 Subject: [PATCH 03/27] Type a few things --- src/LtiDeepLinkDateTimeInterval.php | 6 +++--- src/LtiDeepLinkResourceIcon.php | 8 ++++---- src/LtiDeepLinkResourceIframe.php | 8 ++++---- src/LtiDeepLinkResourceWindow.php | 10 +++++----- src/LtiDeployment.php | 2 +- src/LtiMessageLaunch.php | 4 ++-- src/LtiOidcLogin.php | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/LtiDeepLinkDateTimeInterval.php b/src/LtiDeepLinkDateTimeInterval.php index d6c50b20..b756c429 100644 --- a/src/LtiDeepLinkDateTimeInterval.php +++ b/src/LtiDeepLinkDateTimeInterval.php @@ -15,12 +15,12 @@ public function __construct( } } - public static function new(): LtiDeepLinkDateTimeInterval + public static function new(): self { return new LtiDeepLinkDateTimeInterval(); } - public function setStart(?DateTime $start): LtiDeepLinkDateTimeInterval + public function setStart(?DateTime $start): self { $this->start = $start; @@ -32,7 +32,7 @@ public function getStart(): ?DateTime return $this->start; } - public function setEnd(?DateTime $end): LtiDeepLinkDateTimeInterval + public function setEnd(?DateTime $end): self { $this->end = $end; diff --git a/src/LtiDeepLinkResourceIcon.php b/src/LtiDeepLinkResourceIcon.php index 65eae1cc..90c37b79 100644 --- a/src/LtiDeepLinkResourceIcon.php +++ b/src/LtiDeepLinkResourceIcon.php @@ -11,12 +11,12 @@ public function __construct( ) { } - public static function new(string $url, int $width, int $height): LtiDeepLinkResourceIcon + public static function new(string $url, int $width, int $height): self { return new LtiDeepLinkResourceIcon($url, $width, $height); } - public function setUrl(string $url): LtiDeepLinkResourceIcon + public function setUrl(string $url): self { $this->url = $url; @@ -28,7 +28,7 @@ public function getUrl(): string return $this->url; } - public function setWidth(int $width): LtiDeepLinkResourceIcon + public function setWidth(int $width): self { $this->width = $width; @@ -40,7 +40,7 @@ public function getWidth(): int return $this->width; } - public function setHeight(int $height): LtiDeepLinkResourceIcon + public function setHeight(int $height): self { $this->height = $height; diff --git a/src/LtiDeepLinkResourceIframe.php b/src/LtiDeepLinkResourceIframe.php index 11676fbc..7152f0a2 100644 --- a/src/LtiDeepLinkResourceIframe.php +++ b/src/LtiDeepLinkResourceIframe.php @@ -11,12 +11,12 @@ public function __construct( ) { } - public static function new(): LtiDeepLinkResourceIframe + public static function new(): self { return new LtiDeepLinkResourceIframe(); } - public function setWidth(?int $width): LtiDeepLinkResourceIframe + public function setWidth(?int $width): self { $this->width = $width; @@ -28,7 +28,7 @@ public function getWidth(): ?int return $this->width; } - public function setHeight(?int $height): LtiDeepLinkResourceIframe + public function setHeight(?int $height): self { $this->height = $height; @@ -40,7 +40,7 @@ public function getHeight(): ?int return $this->height; } - public function setSrc(?string $src): LtiDeepLinkResourceIframe + public function setSrc(?string $src): self { $this->src = $src; diff --git a/src/LtiDeepLinkResourceWindow.php b/src/LtiDeepLinkResourceWindow.php index 52fff1c9..45f9e8bf 100644 --- a/src/LtiDeepLinkResourceWindow.php +++ b/src/LtiDeepLinkResourceWindow.php @@ -12,12 +12,12 @@ public function __construct( ) { } - public static function new(): LtiDeepLinkResourceWindow + public static function new(): self { return new LtiDeepLinkResourceWindow(); } - public function setTargetName(?string $targetName): LtiDeepLinkResourceWindow + public function setTargetName(?string $targetName): self { $this->target_name = $targetName; @@ -29,7 +29,7 @@ public function getTargetName(): ?string return $this->target_name; } - public function setWidth(?int $width): LtiDeepLinkResourceWindow + public function setWidth(?int $width): self { $this->width = $width; @@ -41,7 +41,7 @@ public function getWidth(): ?int return $this->width; } - public function setHeight(?int $height): LtiDeepLinkResourceWindow + public function setHeight(?int $height): self { $this->height = $height; @@ -53,7 +53,7 @@ public function getHeight(): ?int return $this->height; } - public function setWindowFeatures(?string $windowFeatures): LtiDeepLinkResourceWindow + public function setWindowFeatures(?string $windowFeatures): self { $this->window_features = $windowFeatures; diff --git a/src/LtiDeployment.php b/src/LtiDeployment.php index 09caacbf..24110252 100644 --- a/src/LtiDeployment.php +++ b/src/LtiDeployment.php @@ -21,7 +21,7 @@ public function getDeploymentId() return $this->deployment_id; } - public function setDeploymentId($deployment_id): LtiDeployment + public function setDeploymentId($deployment_id): self { $this->deployment_id = $deployment_id; diff --git a/src/LtiMessageLaunch.php b/src/LtiMessageLaunch.php index 019506f2..7414f969 100644 --- a/src/LtiMessageLaunch.php +++ b/src/LtiMessageLaunch.php @@ -84,7 +84,7 @@ public static function new( ICache $cache, ICookie $cookie, ILtiServiceConnector $serviceConnector - ) { + ): self { return new LtiMessageLaunch($db, $cache, $cookie, $serviceConnector); } @@ -99,7 +99,7 @@ public static function fromCache( ICache $cache, ICookie $cookie, ILtiServiceConnector $serviceConnector - ) { + ): self { $new = new LtiMessageLaunch($db, $cache, $cookie, $serviceConnector); $new->launch_id = $launch_id; $new->jwt = ['body' => $new->cache->getLaunchData($launch_id)]; diff --git a/src/LtiOidcLogin.php b/src/LtiOidcLogin.php index 1bca40ad..aa607835 100644 --- a/src/LtiOidcLogin.php +++ b/src/LtiOidcLogin.php @@ -25,7 +25,7 @@ public function __construct( /** * Static function to allow for method chaining without having to assign to a variable first. */ - public static function new(IDatabase $db, ?ICache $cache = null, ?ICookie $cookie = null) + public static function new(IDatabase $db, ?ICache $cache = null, ?ICookie $cookie = null): self { return new LtiOidcLogin($db, $cache, $cookie); } From c83e288eeefb3274a0246ed1c44e1ab9a5fb8e0a Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 11:16:40 -0600 Subject: [PATCH 04/27] A few more chagnes --- src/LtiOidcLogin.php | 74 +++++++++++++++++--------------------- src/ServiceRequest.php | 2 +- tests/LtiOidcLoginTest.php | 36 +++++++++++++++++-- 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/LtiOidcLogin.php b/src/LtiOidcLogin.php index aa607835..c86968c3 100644 --- a/src/LtiOidcLogin.php +++ b/src/LtiOidcLogin.php @@ -32,78 +32,70 @@ public static function new(IDatabase $db, ?ICache $cache = null, ?ICookie $cooki /** * Calculate the redirect location to return to based on an OIDC third party initiated login request. - * - * @param string $launchUrl URL to redirect back to after the OIDC login. This URL must match exactly a URL white listed in the platform. - * @param array $request An array of request parameters. - * @return string returns the fully formed OIDC login URL */ public function getRedirectUrl(string $launchUrl, array $request): string { - // Validate Request Data. + // Validate request data. $registration = $this->validateOidcLogin($request); - /* - * Build OIDC Auth Response. - */ - - // Generate State. - // Set cookie (short lived) - $state = static::secureRandomString('state-'); - $this->cookie->setCookie(static::COOKIE_PREFIX.$state, $state, 60); - - // Generate Nonce. - $nonce = static::secureRandomString('nonce-'); - $this->cache->cacheNonce($nonce, $state); - - // Build Response. - $authParams = [ - 'scope' => 'openid', // OIDC Scope. - 'response_type' => 'id_token', // OIDC response is always an id token. - 'response_mode' => 'form_post', // OIDC response is always a form post. - 'prompt' => 'none', // Don't prompt user on redirect. - 'client_id' => $registration->getClientId(), // Registered client id. - 'redirect_uri' => $launchUrl, // URL to return to after login. - 'state' => $state, // State to identify browser session. - 'nonce' => $nonce, // Prevent replay attacks. - 'login_hint' => $request['login_hint'], // Login hint to identify platform session. - ]; - - // Pass back LTI message hint if we have it. - if (isset($request['lti_message_hint'])) { - // LTI message hint to identify LTI context within the platform. - $authParams['lti_message_hint'] = $request['lti_message_hint']; - } + // Build OIDC Auth response. + $authParams = $this->getAuthParams($launchUrl, $registration->getClientId(), $request); return Helpers::buildUrlWithQueryParams($registration->getAuthLoginUrl(), $authParams); } public function validateOidcLogin(array $request): ILtiRegistration { - // Validate Issuer. if (!isset($request['iss'])) { throw new OidcException(static::ERROR_MSG_ISSUER); } - // Validate Login Hint. if (!isset($request['login_hint'])) { throw new OidcException(static::ERROR_MSG_LOGIN_HINT); } - // Fetch Registration Details. + // Fetch registration $clientId = $request['client_id'] ?? null; $registration = $this->db->findRegistrationByIssuer($request['iss'], $clientId); - // Check we got something. if (!isset($registration)) { $errorMsg = LtiMessageLaunch::getMissingRegistrationErrorMsg($request['iss'], $clientId); throw new OidcException($errorMsg); } - // Return Registration. return $registration; } + public function getAuthParams(string $launchUrl, string $clientId, array $request): array + { + // Set cookie (short lived) + $state = static::secureRandomString('state-'); + $this->cookie->setCookie(static::COOKIE_PREFIX.$state, $state, 60); + + $nonce = static::secureRandomString('nonce-'); + $this->cache->cacheNonce($nonce, $state); + + $authParams = [ + 'scope' => 'openid', // OIDC Scope. + 'response_type' => 'id_token', // OIDC response is always an id token. + 'response_mode' => 'form_post', // OIDC response is always a form post. + 'prompt' => 'none', // Don't prompt user on redirect. + 'client_id' => $clientId, // Registered client id. + 'redirect_uri' => $launchUrl, // URL to return to after login. + 'state' => $state, // State to identify browser session. + 'nonce' => $nonce, // Prevent replay attacks. + 'login_hint' => $request['login_hint'], // Login hint to identify platform session. + ]; + + if (isset($request['lti_message_hint'])) { + // LTI message hint to identify LTI context within the platform. + $authParams['lti_message_hint'] = $request['lti_message_hint']; + } + + return $authParams; + } + public static function secureRandomString(string $prefix = ''): string { return $prefix.hash('sha256', random_bytes(64)); diff --git a/src/ServiceRequest.php b/src/ServiceRequest.php index 7aebaa03..044d3eb5 100644 --- a/src/ServiceRequest.php +++ b/src/ServiceRequest.php @@ -46,7 +46,7 @@ class ServiceRequest implements IServiceRequest public function __construct( private string $method, private string $url, - private $type = self::TYPE_UNSUPPORTED + private string $type = self::TYPE_UNSUPPORTED ) { } diff --git a/tests/LtiOidcLoginTest.php b/tests/LtiOidcLoginTest.php index 42b8ca26..805878e9 100644 --- a/tests/LtiOidcLoginTest.php +++ b/tests/LtiOidcLoginTest.php @@ -112,7 +112,37 @@ public function testValidatesFailsIfRegistrationNotFound() $this->oidcLogin->validateOidcLogin($request); } - /* - * @todo Finish testing - */ + public function testGetAuthParams() + { + $this->cookie->shouldReceive('setCookie') + ->once(); + $this->cache->shouldReceive('cacheNonce') + ->once(); + + $launchUrl = 'https://example.com/launch'; + $clientId = 'ClientId'; + $expected = [ + 'scope' => 'openid', + 'response_type' => 'id_token', + 'response_mode' => 'form_post', + 'prompt' => 'none', + 'client_id' => $clientId, + 'redirect_uri' => $launchUrl, + 'login_hint' => 'LoginHint', + 'lti_message_hint' => 'LtiMessageHint', + ]; + $request = [ + 'login_hint' => 'LoginHint', + 'lti_message_hint' => 'LtiMessageHint', + ]; + + $result = $this->oidcLogin->getAuthParams($launchUrl, $clientId, $request); + + // These are cryptographically random, so just assert they exist + $this->assertArrayHasKey('state', $result); + $this->assertArrayHasKey('nonce', $result); + // No remove them and check equality + unset($result['state'], $result['nonce']); + $this->assertEquals($expected, $result); + } } From 881b66cc64255638740900756facae3fde24d74f Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 13:46:58 -0600 Subject: [PATCH 05/27] Add code coverage --- .github/workflows/run_tests.yml | 8 ++++++-- .gitignore | 1 + composer.json | 8 +++++--- phpunit.xml.dist | 10 ++++++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 8fa9b4f5..18ebb7d6 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -32,5 +32,9 @@ jobs: with: dependency-versions: "${{ matrix.dependencies }}" composer-options: "${{ matrix.composer-options }}" - - name: Run tests - run: composer test + - uses: paambaati/codeclimate-action@v5.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + with: + coverageCommand: composer test + debug: true diff --git a/.gitignore b/.gitignore index e884cd37..243ffc0b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ tests/_support/_generated/* vendor # ignore the coverage folders +**/.phpunit.cache **/coverage diff --git a/composer.json b/composer.json index d35c7b61..dea9cabe 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "mockery/mockery": "^1.4", "nesbot/carbon": "^2.43", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^10.0" }, "autoload": { "psr-4": { @@ -44,10 +44,12 @@ }, "scripts": { "test": [ - "phpunit", + "phpunit" + ], + "lint": [ + "php-cs-fixer fix -v --dry-run", "phpstan analyse" ], - "lint": "php-cs-fixer fix -v --dry-run", "lint-fix": "php-cs-fixer fix -v" } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index daa8b21a..1fff419b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,9 +1,6 @@ - + - - src/ - @@ -18,4 +15,9 @@ + + + src/ + + From e8e18db4d8958e58bee65b867a54596fd7d399dc Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 13:48:33 -0600 Subject: [PATCH 06/27] Bump phpunit version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index dea9cabe..2b5669e6 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "mockery/mockery": "^1.4", "nesbot/carbon": "^2.43", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^9.0|^10.0" }, "autoload": { "psr-4": { From 7eaafac133c93bdda778a6beb938a7b3da657406 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 13:52:10 -0600 Subject: [PATCH 07/27] Use xdebug maybe --- .github/workflows/run_tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 18ebb7d6..48a084c7 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -35,6 +35,8 @@ jobs: - uses: paambaati/codeclimate-action@v5.0.0 env: CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + XDEBUG_MODE: coverage + XDEBUG_COVERAGE: true with: coverageCommand: composer test debug: true From df33cce6cf7d00be0e3b1d221a5b8921e3fbdb32 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 13:54:27 -0600 Subject: [PATCH 08/27] Separate test --- .github/workflows/run_tests.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 48a084c7..28e6bdbf 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -23,6 +23,25 @@ jobs: php: - "8.0" - "latest" + steps: + - uses: "actions/checkout@v3" + - uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php }}" + - uses: "ramsey/composer-install@v2" + with: + dependency-versions: "${{ matrix.dependencies }}" + composer-options: "${{ matrix.composer-options }}" + - name: Run tests + run: composer test + + coverage: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + php: + - "latest" steps: - uses: "actions/checkout@v3" - uses: "shivammathur/setup-php@v2" From ec64318030e5c1e124bf0a1b1a509e00f77ac8c6 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 13:59:18 -0600 Subject: [PATCH 09/27] Simplify it --- .github/workflows/run_tests.yml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 28e6bdbf..4fa3544f 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -36,26 +36,18 @@ jobs: run: composer test coverage: - name: Test + name: Code coverage runs-on: ubuntu-latest - strategy: - matrix: - php: - - "latest" steps: - uses: "actions/checkout@v3" - uses: "shivammathur/setup-php@v2" with: - php-version: "${{ matrix.php }}" + php-version: lastest + coverage: xdebug - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "${{ matrix.dependencies }}" - composer-options: "${{ matrix.composer-options }}" - uses: paambaati/codeclimate-action@v5.0.0 env: CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} - XDEBUG_MODE: coverage - XDEBUG_COVERAGE: true with: coverageCommand: composer test debug: true From d248598ed01c1862b1e5d8ed8fe19178376f0cdf Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 14:00:48 -0600 Subject: [PATCH 10/27] Typo --- .github/workflows/run_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 4fa3544f..a345952b 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -42,7 +42,7 @@ jobs: - uses: "actions/checkout@v3" - uses: "shivammathur/setup-php@v2" with: - php-version: lastest + php-version: latest coverage: xdebug - uses: "ramsey/composer-install@v2" - uses: paambaati/codeclimate-action@v5.0.0 From 7394ef1e4c327954c49c042fb79660887e07e6e2 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 14:03:16 -0600 Subject: [PATCH 11/27] Don't use debug mode --- .github/workflows/run_tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index a345952b..3eebcbe1 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -50,4 +50,3 @@ jobs: CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} with: coverageCommand: composer test - debug: true From 1503f82bbc0d12008797a64b23e5553629740b99 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 14:13:02 -0600 Subject: [PATCH 12/27] Add badges --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index db1fb320..44b6b444 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ ![Test status](https://github.com/packbackbooks/lti-1-3-php-library/actions/workflows/run_tests.yml/badge.svg?branch=master) +[![Maintainability](https://api.codeclimate.com/v1/badges/16055e83ea04ad95a2f9/maintainability)](https://codeclimate.com/github/packbackbooks/lti-1-3-php-library/maintainability) + +[![Test Coverage](https://api.codeclimate.com/v1/badges/16055e83ea04ad95a2f9/test_coverage)](https://codeclimate.com/github/packbackbooks/lti-1-3-php-library/test_coverage) + A library used for building IMS-certified LTI 1.3 tool providers in PHP. This library allows a tool provider (your app) to receive LTI launches from a tool consumer (i.e. LMS). It validates LTI launches and lets an application interact with services like the Names Roles Provisioning Service (to fetch a roster for an LMS course) and Assignment Grades Service (to update grades for students in a course in the LMS). From ab54c4729eda1f2d6434e3ff00ee0bb99e2df4c6 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 14:13:53 -0600 Subject: [PATCH 13/27] On one line --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 44b6b444..5dd75511 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ # LTI 1.3 Tool Library -![Test status](https://github.com/packbackbooks/lti-1-3-php-library/actions/workflows/run_tests.yml/badge.svg?branch=master) - -[![Maintainability](https://api.codeclimate.com/v1/badges/16055e83ea04ad95a2f9/maintainability)](https://codeclimate.com/github/packbackbooks/lti-1-3-php-library/maintainability) - -[![Test Coverage](https://api.codeclimate.com/v1/badges/16055e83ea04ad95a2f9/test_coverage)](https://codeclimate.com/github/packbackbooks/lti-1-3-php-library/test_coverage) +![Test status](https://github.com/packbackbooks/lti-1-3-php-library/actions/workflows/run_tests.yml/badge.svg?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/16055e83ea04ad95a2f9/maintainability)](https://codeclimate.com/github/packbackbooks/lti-1-3-php-library/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/16055e83ea04ad95a2f9/test_coverage)](https://codeclimate.com/github/packbackbooks/lti-1-3-php-library/test_coverage) A library used for building IMS-certified LTI 1.3 tool providers in PHP. From eeddd3a511b554866bb3dc4ef0013655f8b8e1d3 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 15:10:54 -0600 Subject: [PATCH 14/27] Run tests weekly --- .github/workflows/run_tests.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 3eebcbe1..cac3bf82 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -1,10 +1,13 @@ -name: Tests & style checks +name: Tests & Style Checks on: - # Trigger on any PR being opened, or on a merge to master (to update the badge) + # Trigger on any PR being opened pull_request: + # Or weekly and on a merge to master (to update the badge) push: branches: - master + schedule: + - cron: 0 0 * * 0 jobs: lint: name: Lint @@ -36,7 +39,7 @@ jobs: run: composer test coverage: - name: Code coverage + name: Code Coverage runs-on: ubuntu-latest steps: - uses: "actions/checkout@v3" From 759e469230585da73142f8ffe3bc98f90c30b33a Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 15:44:50 -0600 Subject: [PATCH 15/27] Abstract stuff --- UPGRADES.md | 16 +++++++++++++ src/LtiDeepLinkDateTimeInterval.php | 20 ++++++++++------ src/LtiDeepLinkResourceIcon.php | 28 ++++------------------ src/LtiDeepLinkResourceIframe.php | 32 +++++-------------------- src/LtiDeepLinkResourceWindow.php | 28 ++++------------------ tests/LtiDeepLinkResourceIframeTest.php | 13 ++++++---- 6 files changed, 52 insertions(+), 85 deletions(-) diff --git a/UPGRADES.md b/UPGRADES.md index 65dc35ed..070e9c85 100644 --- a/UPGRADES.md +++ b/UPGRADES.md @@ -33,6 +33,22 @@ All arguments and returns are now strictly typed. This includes changes to the ` This library now requires PHP 8 and firebase/php-jwt 6. +### `LtiDeepLinkResourceIframe` constructor arguments changed order + +To make the interface consistent with other deep link resources, `src` is now the first argument in the constructor: + +```php +class LtiDeepLinkResourceIframe +{ + public function __construct( + private ?string $src = null, + private ?int $width = null, + private ?int $height = null + ) { + } +} +``` + ### Removed `ImsStorage` classes Everything in the `Packback\Lti1p3\ImsStorage` namespace has been removed, specifically the `Packback\Lti1p3\ImsStorage\ImsCache` and `Packback\Lti1p3\ImsStorage\ImsCookie`. If you were using these classes, you will need to implement your own custom storage services. See the [Laravel Implementation Guide](https://github.com/packbackbooks/lti-1-3-php-library/wiki/Laravel-Implementation-Guide#sample-data-store-implementations) for an example. diff --git a/src/LtiDeepLinkDateTimeInterval.php b/src/LtiDeepLinkDateTimeInterval.php index b756c429..207d0987 100644 --- a/src/LtiDeepLinkDateTimeInterval.php +++ b/src/LtiDeepLinkDateTimeInterval.php @@ -6,13 +6,14 @@ class LtiDeepLinkDateTimeInterval { + public const ERROR_NO_START_OR_END = 'Either a start or end time must be specified.'; + public const ERROR_START_GT_END = 'The start time cannot be greater than end time.'; + public function __construct( private ?DateTime $start = null, private ?DateTime $end = null ) { - if (isset($start) && isset($end) && $end < $start) { - throw new LtiException('Interval start time cannot be greater than end time'); - } + $this->validateStartAndEnd(); } public static function new(): self @@ -47,12 +48,10 @@ public function getEnd(): ?DateTime public function toArray(): array { if (!isset($this->start) && !isset($this->end)) { - throw new LtiException('At least one of the interval bounds must be specified on the object instance'); + throw new LtiException(self::ERROR_NO_START_OR_END); } - if ($this->start !== null && $this->end !== null && $this->end < $this->start) { - throw new LtiException('Interval start time cannot be greater than end time'); - } + $this->validateStartAndEnd(); $dateTimeInterval = []; @@ -65,4 +64,11 @@ public function toArray(): array return $dateTimeInterval; } + + private function validateStartAndEnd(): void + { + if (isset($this->start) && isset($this->end) && $this->start > $this->end) { + throw new LtiException(self::ERROR_START_GT_END); + } + } } diff --git a/src/LtiDeepLinkResourceIcon.php b/src/LtiDeepLinkResourceIcon.php index 90c37b79..69cd8f90 100644 --- a/src/LtiDeepLinkResourceIcon.php +++ b/src/LtiDeepLinkResourceIcon.php @@ -2,8 +2,12 @@ namespace Packback\Lti1p3; +use Packback\Lti1p3\Helpers\HasDimensions; + class LtiDeepLinkResourceIcon { + use HasDimensions; + public function __construct( private string $url, private int $width, @@ -28,30 +32,6 @@ public function getUrl(): string return $this->url; } - public function setWidth(int $width): self - { - $this->width = $width; - - return $this; - } - - public function getWidth(): int - { - return $this->width; - } - - public function setHeight(int $height): self - { - $this->height = $height; - - return $this; - } - - public function getHeight(): int - { - return $this->height; - } - public function toArray(): array { return [ diff --git a/src/LtiDeepLinkResourceIframe.php b/src/LtiDeepLinkResourceIframe.php index 7152f0a2..d98845dc 100644 --- a/src/LtiDeepLinkResourceIframe.php +++ b/src/LtiDeepLinkResourceIframe.php @@ -2,12 +2,16 @@ namespace Packback\Lti1p3; +use Packback\Lti1p3\Helpers\HasDimensions; + class LtiDeepLinkResourceIframe { + use HasDimensions; + public function __construct( + private ?string $src = null, private ?int $width = null, - private ?int $height = null, - private ?string $src = null + private ?int $height = null ) { } @@ -16,30 +20,6 @@ public static function new(): self return new LtiDeepLinkResourceIframe(); } - public function setWidth(?int $width): self - { - $this->width = $width; - - return $this; - } - - public function getWidth(): ?int - { - return $this->width; - } - - public function setHeight(?int $height): self - { - $this->height = $height; - - return $this; - } - - public function getHeight(): ?int - { - return $this->height; - } - public function setSrc(?string $src): self { $this->src = $src; diff --git a/src/LtiDeepLinkResourceWindow.php b/src/LtiDeepLinkResourceWindow.php index 45f9e8bf..15353a47 100644 --- a/src/LtiDeepLinkResourceWindow.php +++ b/src/LtiDeepLinkResourceWindow.php @@ -2,8 +2,12 @@ namespace Packback\Lti1p3; +use Packback\Lti1p3\Helpers\HasDimensions; + class LtiDeepLinkResourceWindow { + use HasDimensions; + public function __construct( private ?string $target_name = null, private ?int $width = null, @@ -29,30 +33,6 @@ public function getTargetName(): ?string return $this->target_name; } - public function setWidth(?int $width): self - { - $this->width = $width; - - return $this; - } - - public function getWidth(): ?int - { - return $this->width; - } - - public function setHeight(?int $height): self - { - $this->height = $height; - - return $this; - } - - public function getHeight(): ?int - { - return $this->height; - } - public function setWindowFeatures(?string $windowFeatures): self { $this->window_features = $windowFeatures; diff --git a/tests/LtiDeepLinkResourceIframeTest.php b/tests/LtiDeepLinkResourceIframeTest.php index 5fc75716..4d9cec5c 100644 --- a/tests/LtiDeepLinkResourceIframeTest.php +++ b/tests/LtiDeepLinkResourceIframeTest.php @@ -6,13 +6,18 @@ class LtiDeepLinkResourceIframeTest extends TestCase { + public const INITIAL_SRC = 'https://example.com'; public const INITIAL_WIDTH = 1; public const INITIAL_HEIGHT = 2; private LtiDeepLinkResourceIframe $ltiDeepLinkResourceIframe; public function setUp(): void { - $this->ltiDeepLinkResourceIframe = new LtiDeepLinkResourceIframe(self::INITIAL_WIDTH, self::INITIAL_HEIGHT); + $this->ltiDeepLinkResourceIframe = new LtiDeepLinkResourceIframe( + self::INITIAL_SRC, + self::INITIAL_WIDTH, + self::INITIAL_HEIGHT + ); } public function testItInstantiates() @@ -65,12 +70,12 @@ public function testItGetsSrc() { $result = $this->ltiDeepLinkResourceIframe->getSrc(); - $this->assertNull($result); + $this->assertEquals(self::INITIAL_SRC, $result); } public function testItSetsSrc() { - $expected = 'https://example.com'; + $expected = 'https://example.com/foo/bar'; $result = $this->ltiDeepLinkResourceIframe->setSrc($expected); @@ -94,7 +99,7 @@ public function testItCreatesArrayWithDefinedOptionalProperties() $expected = [ 'width' => 100, 'height' => 200, - 'src' => 'https://example.com', + 'src' => 'https://example.com/foo/bar', ]; $this->ltiDeepLinkResourceIframe->setWidth($expected['width']); From 8679ca047398b314dbf84e463d9ef7b8a44edffa Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 15:44:55 -0600 Subject: [PATCH 16/27] Abstract stuff --- src/Helpers/HasDimensions.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/Helpers/HasDimensions.php diff --git a/src/Helpers/HasDimensions.php b/src/Helpers/HasDimensions.php new file mode 100644 index 00000000..1e245b78 --- /dev/null +++ b/src/Helpers/HasDimensions.php @@ -0,0 +1,30 @@ +width = $width; + + return $this; + } + + public function getWidth(): ?int + { + return $this->width; + } + + public function setHeight(?int $height): self + { + $this->height = $height; + + return $this; + } + + public function getHeight(): ?int + { + return $this->height; + } +} From 46e9f7ed3431252662eed8a80fba1bf4babdd7de Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 16:02:50 -0600 Subject: [PATCH 17/27] Move deep link stuff --- .../DateTimeInterval.php} | 7 +- .../Icon.php} | 6 +- .../Iframe.php} | 6 +- .../Resource.php} | 45 +-- .../Window.php} | 6 +- .../DeepLinkResource/DateTimeIntervalTest.php | 106 +++++++ tests/DeepLinkResource/IconTest.php | 91 ++++++ tests/DeepLinkResource/IframeTest.php | 113 ++++++++ tests/DeepLinkResource/ResourceTest.php | 261 ++++++++++++++++++ tests/DeepLinkResource/WindowTest.php | 119 ++++++++ tests/LtiDeepLinkDateTimeIntervalTest.php | 106 ------- tests/LtiDeepLinkResourceIconTest.php | 91 ------ tests/LtiDeepLinkResourceIframeTest.php | 113 -------- tests/LtiDeepLinkResourceTest.php | 261 ------------------ tests/LtiDeepLinkResourceWindowTest.php | 119 -------- tests/LtiDeepLinkTest.php | 4 +- 16 files changed, 729 insertions(+), 725 deletions(-) rename src/{LtiDeepLinkDateTimeInterval.php => DeepLinkResource/DateTimeInterval.php} (91%) rename src/{LtiDeepLinkResourceIcon.php => DeepLinkResource/Icon.php} (84%) rename src/{LtiDeepLinkResourceIframe.php => DeepLinkResource/Iframe.php} (88%) rename src/{LtiDeepLinkResource.php => DeepLinkResource/Resource.php} (75%) rename src/{LtiDeepLinkResourceWindow.php => DeepLinkResource/Window.php} (92%) create mode 100644 tests/DeepLinkResource/DateTimeIntervalTest.php create mode 100644 tests/DeepLinkResource/IconTest.php create mode 100644 tests/DeepLinkResource/IframeTest.php create mode 100644 tests/DeepLinkResource/ResourceTest.php create mode 100644 tests/DeepLinkResource/WindowTest.php delete mode 100644 tests/LtiDeepLinkDateTimeIntervalTest.php delete mode 100644 tests/LtiDeepLinkResourceIconTest.php delete mode 100644 tests/LtiDeepLinkResourceIframeTest.php delete mode 100644 tests/LtiDeepLinkResourceTest.php delete mode 100644 tests/LtiDeepLinkResourceWindowTest.php diff --git a/src/LtiDeepLinkDateTimeInterval.php b/src/DeepLinkResource/DateTimeInterval.php similarity index 91% rename from src/LtiDeepLinkDateTimeInterval.php rename to src/DeepLinkResource/DateTimeInterval.php index 207d0987..dbd9b5ff 100644 --- a/src/LtiDeepLinkDateTimeInterval.php +++ b/src/DeepLinkResource/DateTimeInterval.php @@ -1,10 +1,11 @@ icon = $icon; return $this; } - public function getIcon(): ?LtiDeepLinkResourceIcon + public function getIcon(): ?Icon { return $this->icon; } - public function setThumbnail(?LtiDeepLinkResourceIcon $thumbnail): self + public function setThumbnail(?Icon $thumbnail): self { $this->thumbnail = $thumbnail; return $this; } - public function getThumbnail(): ?LtiDeepLinkResourceIcon + public function getThumbnail(): ?Icon { return $this->thumbnail; } @@ -119,48 +122,48 @@ public function setCustomParams(array $value): self return $this; } - public function getIframe(): ?LtiDeepLinkResourceIframe + public function getIframe(): ?Iframe { return $this->iframe; } - public function setIframe(?LtiDeepLinkResourceIframe $iframe): self + public function setIframe(?Iframe $iframe): self { $this->iframe = $iframe; return $this; } - public function getWindow(): ?LtiDeepLinkResourceWindow + public function getWindow(): ?Window { return $this->window; } - public function setWindow(?LtiDeepLinkResourceWindow $window): self + public function setWindow(?Window $window): self { $this->window = $window; return $this; } - public function getAvailabilityInterval(): ?LtiDeepLinkDateTimeInterval + public function getAvailabilityInterval(): ?DateTimeInterval { return $this->availability_interval; } - public function setAvailabilityInterval(?LtiDeepLinkDateTimeInterval $availabilityInterval): self + public function setAvailabilityInterval(?DateTimeInterval $availabilityInterval): self { $this->availability_interval = $availabilityInterval; return $this; } - public function getSubmissionInterval(): ?LtiDeepLinkDateTimeInterval + public function getSubmissionInterval(): ?DateTimeInterval { return $this->submission_interval; } - public function setSubmissionInterval(?LtiDeepLinkDateTimeInterval $submissionInterval): self + public function setSubmissionInterval(?DateTimeInterval $submissionInterval): self { $this->submission_interval = $submissionInterval; diff --git a/src/LtiDeepLinkResourceWindow.php b/src/DeepLinkResource/Window.php similarity index 92% rename from src/LtiDeepLinkResourceWindow.php rename to src/DeepLinkResource/Window.php index 15353a47..48f80237 100644 --- a/src/LtiDeepLinkResourceWindow.php +++ b/src/DeepLinkResource/Window.php @@ -1,10 +1,10 @@ initialStart = date_create(); + $this->initialEnd = date_create(); + $this->dateTimeInterval = new DateTimeInterval($this->initialStart, $this->initialEnd); + } + + public function testItInstantiates() + { + $this->assertInstanceOf(DateTimeInterval::class, $this->dateTimeInterval); + } + + public function testItCreatesANewInstance() + { + $deepLinkResource = DateTimeInterval::new(); + + $this->assertInstanceOf(DateTimeInterval::class, $deepLinkResource); + } + + public function testItGetsStart() + { + $result = $this->dateTimeInterval->getStart(); + + $this->assertEquals($this->initialStart, $result); + } + + public function testItSetsStart() + { + $expected = date_create('+1 day'); + + $result = $this->dateTimeInterval->setStart($expected); + + $this->assertSame($this->dateTimeInterval, $result); + $this->assertEquals($expected, $this->dateTimeInterval->getStart()); + } + + public function testItGetsEnd() + { + $result = $this->dateTimeInterval->getEnd(); + + $this->assertEquals($this->initialEnd, $result); + } + + public function testItSetsEnd() + { + $expected = date_create('+1 day'); + + $result = $this->dateTimeInterval->setEnd($expected); + + $this->assertSame($this->dateTimeInterval, $result); + $this->assertEquals($expected, $this->dateTimeInterval->getEnd()); + } + + public function testItThrowsExceptionWhenCreatingArrayWithBothPropertiesNull() + { + $this->dateTimeInterval->setStart(null); + $this->dateTimeInterval->setEnd(null); + + $this->expectException(LtiException::class); + $this->expectExceptionMessage(DateTimeInterval::ERROR_NO_START_OR_END); + + $this->dateTimeInterval->toArray(); + } + + public function testItThrowsExceptionWhenCreatingArrayWithInvalidTimeInterval() + { + $this->dateTimeInterval->setStart(date_create()); + $this->dateTimeInterval->setEnd(date_create('-1 day')); + + $this->expectException(LtiException::class); + $this->expectExceptionMessage(DateTimeInterval::ERROR_START_GT_END); + + $this->dateTimeInterval->toArray(); + } + + public function testItCreatesArrayWithDefinedOptionalProperties() + { + $expectedStart = date_create('+1 day'); + $expectedEnd = date_create('+2 days'); + $expected = [ + 'startDateTime' => $expectedStart->format(DateTime::ATOM), + 'endDateTime' => $expectedEnd->format(DateTime::ATOM), + ]; + + $this->dateTimeInterval->setStart($expectedStart); + $this->dateTimeInterval->setEnd($expectedEnd); + + $result = $this->dateTimeInterval->toArray(); + + $this->assertEquals($expected, $result); + } +} diff --git a/tests/DeepLinkResource/IconTest.php b/tests/DeepLinkResource/IconTest.php new file mode 100644 index 00000000..033edbed --- /dev/null +++ b/tests/DeepLinkResource/IconTest.php @@ -0,0 +1,91 @@ +imageUrl = 'https://example.com/image.png'; + $this->icon = new Icon($this->imageUrl, 1, 2); + } + + public function testItInstantiates() + { + $this->assertInstanceOf(Icon::class, $this->icon); + } + + public function testItCreatesANewInstance() + { + $deepLinkResource = Icon::new($this->imageUrl, 100, 200); + + $this->assertInstanceOf(Icon::class, $deepLinkResource); + } + + public function testItGetsUrl() + { + $result = $this->icon->getUrl(); + + $this->assertEquals($this->imageUrl, $result); + } + + public function testItSetsUrl() + { + $expected = 'expected'; + + $this->icon->setUrl($expected); + + $this->assertEquals($expected, $this->icon->getUrl()); + } + + public function testItGetsWidth() + { + $result = $this->icon->getWidth(); + + $this->assertEquals(1, $result); + } + + public function testItSetsWidth() + { + $expected = 300; + + $this->icon->setWidth($expected); + + $this->assertEquals($expected, $this->icon->getWidth()); + } + + public function testItGetsHeight() + { + $result = $this->icon->getHeight(); + + $this->assertEquals(2, $result); + } + + public function testItSetsHeight() + { + $expected = 400; + + $this->icon->setHeight($expected); + + $this->assertEquals($expected, $this->icon->getHeight()); + } + + public function testItCreatesArray() + { + $expected = [ + 'url' => $this->imageUrl, + 'width' => 100, + 'height' => 200, + ]; + + $this->icon->setUrl($expected['url']); + $this->icon->setWidth($expected['width']); + $this->icon->setHeight($expected['height']); + + $result = $this->icon->toArray(); + + $this->assertEquals($expected, $result); + } +} diff --git a/tests/DeepLinkResource/IframeTest.php b/tests/DeepLinkResource/IframeTest.php new file mode 100644 index 00000000..a82d0f70 --- /dev/null +++ b/tests/DeepLinkResource/IframeTest.php @@ -0,0 +1,113 @@ +iframe = new Iframe( + self::INITIAL_SRC, + self::INITIAL_WIDTH, + self::INITIAL_HEIGHT + ); + } + + public function testItInstantiates() + { + $this->assertInstanceOf(Iframe::class, $this->iframe); + } + + public function testItCreatesANewInstance() + { + $deepLinkResource = Iframe::new(); + + $this->assertInstanceOf(Iframe::class, $deepLinkResource); + } + + public function testItGetsWidth() + { + $result = $this->iframe->getWidth(); + + $this->assertEquals(self::INITIAL_WIDTH, $result); + } + + public function testItSetsWidth() + { + $expected = 300; + + $result = $this->iframe->setWidth($expected); + + $this->assertSame($this->iframe, $result); + $this->assertEquals($expected, $this->iframe->getWidth()); + } + + public function testItGetsHeight() + { + $result = $this->iframe->getHeight(); + + $this->assertEquals(self::INITIAL_HEIGHT, $result); + } + + public function testItSetsHeight() + { + $expected = 400; + + $result = $this->iframe->setHeight($expected); + + $this->assertSame($this->iframe, $result); + $this->assertEquals($expected, $this->iframe->getHeight()); + } + + public function testItGetsSrc() + { + $result = $this->iframe->getSrc(); + + $this->assertEquals(self::INITIAL_SRC, $result); + } + + public function testItSetsSrc() + { + $expected = 'https://example.com/foo/bar'; + + $result = $this->iframe->setSrc($expected); + + $this->assertSame($this->iframe, $result); + $this->assertEquals($expected, $this->iframe->getSrc()); + } + + public function testItCreatesArrayWithoutOptionalProperties() + { + $this->iframe->setWidth(null); + $this->iframe->setHeight(null); + $this->iframe->setSrc(null); + + $result = $this->iframe->toArray(); + + $this->assertEquals([], $result); + } + + public function testItCreatesArrayWithDefinedOptionalProperties() + { + $expected = [ + 'width' => 100, + 'height' => 200, + 'src' => 'https://example.com/foo/bar', + ]; + + $this->iframe->setWidth($expected['width']); + $this->iframe->setHeight($expected['height']); + $this->iframe->setSrc($expected['src']); + + $result = $this->iframe->toArray(); + + $this->assertEquals($expected, $result); + } +} diff --git a/tests/DeepLinkResource/ResourceTest.php b/tests/DeepLinkResource/ResourceTest.php new file mode 100644 index 00000000..0417e175 --- /dev/null +++ b/tests/DeepLinkResource/ResourceTest.php @@ -0,0 +1,261 @@ +resource = new Resource(); + } + + public function testItInstantiates() + { + $this->assertInstanceOf(Resource::class, $this->resource); + } + + public function testItCreatesANewInstance() + { + $resource = Resource::new(); + + $this->assertInstanceOf(Resource::class, $resource); + } + + public function testItGetsType() + { + $result = $this->resource->getType(); + + $this->assertEquals('ltiResourceLink', $result); + } + + public function testItSetsType() + { + $expected = 'expected'; + + $result = $this->resource->setType($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getType()); + } + + public function testItGetsTitle() + { + $result = $this->resource->getTitle(); + + $this->assertNull($result); + } + + public function testItSetsTitle() + { + $expected = 'expected'; + + $result = $this->resource->setTitle($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getTitle()); + } + + public function testItGetsText() + { + $result = $this->resource->getText(); + + $this->assertNull($result); + } + + public function testItSetsText() + { + $expected = 'expected'; + + $result = $this->resource->setText($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getText()); + } + + public function testItGetsUrl() + { + $result = $this->resource->getUrl(); + + $this->assertNull($result); + } + + public function testItSetsUrl() + { + $expected = 'expected'; + + $result = $this->resource->setUrl($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getUrl()); + } + + public function testItGetsLineitem() + { + $result = $this->resource->getLineItem(); + + $this->assertNull($result); + } + + public function testItSetsLineitem() + { + $expected = Mockery::mock(LtiLineitem::class); + + $result = $this->resource->setLineItem($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getLineItem()); + } + + public function testItGetsIcon() + { + $result = $this->resource->getIcon(); + + $this->assertNull($result); + } + + public function testItSetsIcon() + { + $expected = Mockery::mock(Icon::class); + + $result = $this->resource->setIcon($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getIcon()); + } + + public function testItGetsThumbnail() + { + $result = $this->resource->getThumbnail(); + + $this->assertNull($result); + } + + public function testItSetsThumbnail() + { + $expected = Mockery::mock(Icon::class); + + $result = $this->resource->setThumbnail($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getThumbnail()); + } + + public function testItGetsCustomParams() + { + $result = $this->resource->getCustomParams(); + + $this->assertEquals([], $result); + } + + public function testItSetsCustomParams() + { + $expected = ['a_key' => 'a_value']; + + $result = $this->resource->setCustomParams($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getCustomParams()); + } + + public function testItGetsIframe() + { + $result = $this->resource->getIframe(); + + $this->assertEquals(null, $result); + } + + public function testItSetsIframe() + { + $expected = new Iframe(); + + $result = $this->resource->setIframe($expected); + + $this->assertSame($this->resource, $result); + $this->assertEquals($expected, $this->resource->getIframe()); + } + + public function testItCreatesArrayWithoutOptionalProperties() + { + $expected = [ + 'type' => LtiConstants::DL_RESOURCE_LINK_TYPE, + 'presentation' => [ + 'documentTarget' => 'iframe', + ], + ]; + + $result = $this->resource->toArray(); + + $this->assertEquals($expected, $result); + } + + public function testItCreatesArrayWithDefinedOptionalProperties() + { + $icon = Icon::new('https://example.com/image.png', 100, 200); + $Iframe = new Iframe(); + $window = new Window(); + $dateTimeInterval = new DateTimeInterval(date_create()); + + $expected = [ + 'type' => LtiConstants::DL_RESOURCE_LINK_TYPE, + 'title' => 'a_title', + 'text' => 'a_text', + 'url' => 'a_url', + 'icon' => [ + 'url' => $icon->getUrl(), + 'width' => $icon->getWidth(), + 'height' => $icon->getHeight(), + ], + 'thumbnail' => [ + 'url' => $icon->getUrl(), + 'width' => $icon->getWidth(), + 'height' => $icon->getHeight(), + ], + 'lineItem' => [ + 'scoreMaximum' => 80, + 'label' => 'lineitem_label', + ], + 'iframe' => $Iframe->toArray(), + 'window' => $window->toArray(), + 'available' => $dateTimeInterval->toArray(), + 'submission' => $dateTimeInterval->toArray(), + ]; + + $lineitem = Mockery::mock(LtiLineitem::class); + $lineitem->shouldReceive('getScoreMaximum') + ->twice()->andReturn($expected['lineItem']['scoreMaximum']); + $lineitem->shouldReceive('getLabel') + ->twice()->andReturn($expected['lineItem']['label']); + + $this->resource->setTitle($expected['title']); + $this->resource->setText($expected['text']); + $this->resource->setUrl($expected['url']); + $this->resource->setIcon($icon); + $this->resource->setThumbnail($icon); + $this->resource->setLineItem($lineitem); + $this->resource->setIframe($Iframe); + $this->resource->setWindow($window); + $this->resource->setAvailabilityInterval($dateTimeInterval); + $this->resource->setSubmissionInterval($dateTimeInterval); + + $result = $this->resource->toArray(); + + $this->assertEquals($expected, $result); + + // Test again with custom params + $expected['custom'] = ['a_key' => 'a_value']; + $this->resource->setCustomParams(['a_key' => 'a_value']); + $result = $this->resource->toArray(); + $this->assertEquals($expected, $result); + } +} diff --git a/tests/DeepLinkResource/WindowTest.php b/tests/DeepLinkResource/WindowTest.php new file mode 100644 index 00000000..2150d2b9 --- /dev/null +++ b/tests/DeepLinkResource/WindowTest.php @@ -0,0 +1,119 @@ +window = new Window(self::INITIAL_TARGET_NAME, + self::INITIAL_WIDTH, self::INITIAL_HEIGHT, self::INITIAL_WINDOW_FEATURES); + } + + public function testItInstantiates() + { + $this->assertInstanceOf(Window::class, $this->window); + } + + public function testItCreatesANewInstance() + { + $deepLinkResource = Window::new(); + + $this->assertInstanceOf(Window::class, $deepLinkResource); + } + + public function testItGetsTargetName() + { + $result = $this->window->getTargetName(); + + $this->assertEquals(self::INITIAL_TARGET_NAME, $result); + } + + public function testItSetsTargetName() + { + $expected = 'expected'; + + $result = $this->window->setTargetName($expected); + + $this->assertSame($this->window, $result); + $this->assertEquals($expected, $this->window->getTargetName()); + } + + public function testItGetsWidth() + { + $result = $this->window->getWidth(); + + $this->assertEquals(self::INITIAL_WIDTH, $result); + } + + public function testItSetsWidth() + { + $expected = 300; + + $result = $this->window->setWidth($expected); + + $this->assertSame($this->window, $result); + $this->assertEquals($expected, $this->window->getWidth()); + } + + public function testItGetsHeight() + { + $result = $this->window->getHeight(); + + $this->assertEquals(self::INITIAL_HEIGHT, $result); + } + + public function testItSetsHeight() + { + $expected = 400; + + $result = $this->window->setHeight($expected); + + $this->assertSame($this->window, $result); + $this->assertEquals($expected, $this->window->getHeight()); + } + + public function testItGetsWindowFeatures() + { + $result = $this->window->getWindowFeatures(); + + $this->assertEquals(self::INITIAL_WINDOW_FEATURES, $result); + } + + public function testItSetsWindowFeatures() + { + $expected = 'first-feature=value,second-feature'; + + $result = $this->window->setWindowFeatures($expected); + + $this->assertSame($this->window, $result); + $this->assertEquals($expected, $this->window->getWindowFeatures()); + } + + public function testItCreatesArray() + { + $expected = [ + 'targetName' => 'target-name', + 'width' => 100, + 'height' => 200, + 'windowFeatures' => 'first-feature=value,second-feature', + ]; + + $this->window->setTargetName($expected['targetName']); + $this->window->setWidth($expected['width']); + $this->window->setHeight($expected['height']); + $this->window->setWindowFeatures($expected['windowFeatures']); + + $result = $this->window->toArray(); + + $this->assertEquals($expected, $result); + } +} diff --git a/tests/LtiDeepLinkDateTimeIntervalTest.php b/tests/LtiDeepLinkDateTimeIntervalTest.php deleted file mode 100644 index daf50544..00000000 --- a/tests/LtiDeepLinkDateTimeIntervalTest.php +++ /dev/null @@ -1,106 +0,0 @@ -initialStart = date_create(); - $this->initialEnd = date_create(); - $this->ltiDeepLinkDateTimeInterval = new LtiDeepLinkDateTimeInterval($this->initialStart, $this->initialEnd); - } - - public function testItInstantiates() - { - $this->assertInstanceOf(LtiDeepLinkDateTimeInterval::class, $this->ltiDeepLinkDateTimeInterval); - } - - public function testItCreatesANewInstance() - { - $deepLinkResource = LtiDeepLinkDateTimeInterval::new(); - - $this->assertInstanceOf(LtiDeepLinkDateTimeInterval::class, $deepLinkResource); - } - - public function testItGetsStart() - { - $result = $this->ltiDeepLinkDateTimeInterval->getStart(); - - $this->assertEquals($this->initialStart, $result); - } - - public function testItSetsStart() - { - $expected = date_create('+1 day'); - - $result = $this->ltiDeepLinkDateTimeInterval->setStart($expected); - - $this->assertSame($this->ltiDeepLinkDateTimeInterval, $result); - $this->assertEquals($expected, $this->ltiDeepLinkDateTimeInterval->getStart()); - } - - public function testItGetsEnd() - { - $result = $this->ltiDeepLinkDateTimeInterval->getEnd(); - - $this->assertEquals($this->initialEnd, $result); - } - - public function testItSetsEnd() - { - $expected = date_create('+1 day'); - - $result = $this->ltiDeepLinkDateTimeInterval->setEnd($expected); - - $this->assertSame($this->ltiDeepLinkDateTimeInterval, $result); - $this->assertEquals($expected, $this->ltiDeepLinkDateTimeInterval->getEnd()); - } - - public function testItThrowsExceptionWhenCreatingArrayWithBothPropertiesNull() - { - $this->ltiDeepLinkDateTimeInterval->setStart(null); - $this->ltiDeepLinkDateTimeInterval->setEnd(null); - - $this->expectException(LtiException::class); - $this->expectExceptionMessage('At least one of the interval bounds must be specified on the object instance'); - - $this->ltiDeepLinkDateTimeInterval->toArray(); - } - - public function testItThrowsExceptionWhenCreatingArrayWithInvalidTimeInterval() - { - $this->ltiDeepLinkDateTimeInterval->setStart(date_create()); - $this->ltiDeepLinkDateTimeInterval->setEnd(date_create('-1 day')); - - $this->expectException(LtiException::class); - $this->expectExceptionMessage('Interval start time cannot be greater than end time'); - - $this->ltiDeepLinkDateTimeInterval->toArray(); - } - - public function testItCreatesArrayWithDefinedOptionalProperties() - { - $expectedStart = date_create('+1 day'); - $expectedEnd = date_create('+2 days'); - $expected = [ - 'startDateTime' => $expectedStart->format(DateTime::ATOM), - 'endDateTime' => $expectedEnd->format(DateTime::ATOM), - ]; - - $this->ltiDeepLinkDateTimeInterval->setStart($expectedStart); - $this->ltiDeepLinkDateTimeInterval->setEnd($expectedEnd); - - $result = $this->ltiDeepLinkDateTimeInterval->toArray(); - - $this->assertEquals($expected, $result); - } -} diff --git a/tests/LtiDeepLinkResourceIconTest.php b/tests/LtiDeepLinkResourceIconTest.php deleted file mode 100644 index 80675515..00000000 --- a/tests/LtiDeepLinkResourceIconTest.php +++ /dev/null @@ -1,91 +0,0 @@ -imageUrl = 'https://example.com/image.png'; - $this->deepLinkResourceIcon = new LtiDeepLinkResourceIcon($this->imageUrl, 1, 2); - } - - public function testItInstantiates() - { - $this->assertInstanceOf(LtiDeepLinkResourceIcon::class, $this->deepLinkResourceIcon); - } - - public function testItCreatesANewInstance() - { - $deepLinkResource = LtiDeepLinkResourceIcon::new($this->imageUrl, 100, 200); - - $this->assertInstanceOf(LtiDeepLinkResourceIcon::class, $deepLinkResource); - } - - public function testItGetsUrl() - { - $result = $this->deepLinkResourceIcon->getUrl(); - - $this->assertEquals($this->imageUrl, $result); - } - - public function testItSetsUrl() - { - $expected = 'expected'; - - $this->deepLinkResourceIcon->setUrl($expected); - - $this->assertEquals($expected, $this->deepLinkResourceIcon->getUrl()); - } - - public function testItGetsWidth() - { - $result = $this->deepLinkResourceIcon->getWidth(); - - $this->assertEquals(1, $result); - } - - public function testItSetsWidth() - { - $expected = 300; - - $this->deepLinkResourceIcon->setWidth($expected); - - $this->assertEquals($expected, $this->deepLinkResourceIcon->getWidth()); - } - - public function testItGetsHeight() - { - $result = $this->deepLinkResourceIcon->getHeight(); - - $this->assertEquals(2, $result); - } - - public function testItSetsHeight() - { - $expected = 400; - - $this->deepLinkResourceIcon->setHeight($expected); - - $this->assertEquals($expected, $this->deepLinkResourceIcon->getHeight()); - } - - public function testItCreatesArray() - { - $expected = [ - 'url' => $this->imageUrl, - 'width' => 100, - 'height' => 200, - ]; - - $this->deepLinkResourceIcon->setUrl($expected['url']); - $this->deepLinkResourceIcon->setWidth($expected['width']); - $this->deepLinkResourceIcon->setHeight($expected['height']); - - $result = $this->deepLinkResourceIcon->toArray(); - - $this->assertEquals($expected, $result); - } -} diff --git a/tests/LtiDeepLinkResourceIframeTest.php b/tests/LtiDeepLinkResourceIframeTest.php deleted file mode 100644 index 4d9cec5c..00000000 --- a/tests/LtiDeepLinkResourceIframeTest.php +++ /dev/null @@ -1,113 +0,0 @@ -ltiDeepLinkResourceIframe = new LtiDeepLinkResourceIframe( - self::INITIAL_SRC, - self::INITIAL_WIDTH, - self::INITIAL_HEIGHT - ); - } - - public function testItInstantiates() - { - $this->assertInstanceOf(LtiDeepLinkResourceIframe::class, $this->ltiDeepLinkResourceIframe); - } - - public function testItCreatesANewInstance() - { - $deepLinkResource = LtiDeepLinkResourceIframe::new(); - - $this->assertInstanceOf(LtiDeepLinkResourceIframe::class, $deepLinkResource); - } - - public function testItGetsWidth() - { - $result = $this->ltiDeepLinkResourceIframe->getWidth(); - - $this->assertEquals(self::INITIAL_WIDTH, $result); - } - - public function testItSetsWidth() - { - $expected = 300; - - $result = $this->ltiDeepLinkResourceIframe->setWidth($expected); - - $this->assertSame($this->ltiDeepLinkResourceIframe, $result); - $this->assertEquals($expected, $this->ltiDeepLinkResourceIframe->getWidth()); - } - - public function testItGetsHeight() - { - $result = $this->ltiDeepLinkResourceIframe->getHeight(); - - $this->assertEquals(self::INITIAL_HEIGHT, $result); - } - - public function testItSetsHeight() - { - $expected = 400; - - $result = $this->ltiDeepLinkResourceIframe->setHeight($expected); - - $this->assertSame($this->ltiDeepLinkResourceIframe, $result); - $this->assertEquals($expected, $this->ltiDeepLinkResourceIframe->getHeight()); - } - - public function testItGetsSrc() - { - $result = $this->ltiDeepLinkResourceIframe->getSrc(); - - $this->assertEquals(self::INITIAL_SRC, $result); - } - - public function testItSetsSrc() - { - $expected = 'https://example.com/foo/bar'; - - $result = $this->ltiDeepLinkResourceIframe->setSrc($expected); - - $this->assertSame($this->ltiDeepLinkResourceIframe, $result); - $this->assertEquals($expected, $this->ltiDeepLinkResourceIframe->getSrc()); - } - - public function testItCreatesArrayWithoutOptionalProperties() - { - $this->ltiDeepLinkResourceIframe->setWidth(null); - $this->ltiDeepLinkResourceIframe->setHeight(null); - $this->ltiDeepLinkResourceIframe->setSrc(null); - - $result = $this->ltiDeepLinkResourceIframe->toArray(); - - $this->assertEquals([], $result); - } - - public function testItCreatesArrayWithDefinedOptionalProperties() - { - $expected = [ - 'width' => 100, - 'height' => 200, - 'src' => 'https://example.com/foo/bar', - ]; - - $this->ltiDeepLinkResourceIframe->setWidth($expected['width']); - $this->ltiDeepLinkResourceIframe->setHeight($expected['height']); - $this->ltiDeepLinkResourceIframe->setSrc($expected['src']); - - $result = $this->ltiDeepLinkResourceIframe->toArray(); - - $this->assertEquals($expected, $result); - } -} diff --git a/tests/LtiDeepLinkResourceTest.php b/tests/LtiDeepLinkResourceTest.php deleted file mode 100644 index 4045f47e..00000000 --- a/tests/LtiDeepLinkResourceTest.php +++ /dev/null @@ -1,261 +0,0 @@ -deepLinkResource = new LtiDeepLinkResource(); - } - - public function testItInstantiates() - { - $this->assertInstanceOf(LtiDeepLinkResource::class, $this->deepLinkResource); - } - - public function testItCreatesANewInstance() - { - $deepLinkResource = LtiDeepLinkResource::new(); - - $this->assertInstanceOf(LtiDeepLinkResource::class, $deepLinkResource); - } - - public function testItGetsType() - { - $result = $this->deepLinkResource->getType(); - - $this->assertEquals('ltiResourceLink', $result); - } - - public function testItSetsType() - { - $expected = 'expected'; - - $result = $this->deepLinkResource->setType($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getType()); - } - - public function testItGetsTitle() - { - $result = $this->deepLinkResource->getTitle(); - - $this->assertNull($result); - } - - public function testItSetsTitle() - { - $expected = 'expected'; - - $result = $this->deepLinkResource->setTitle($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getTitle()); - } - - public function testItGetsText() - { - $result = $this->deepLinkResource->getText(); - - $this->assertNull($result); - } - - public function testItSetsText() - { - $expected = 'expected'; - - $result = $this->deepLinkResource->setText($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getText()); - } - - public function testItGetsUrl() - { - $result = $this->deepLinkResource->getUrl(); - - $this->assertNull($result); - } - - public function testItSetsUrl() - { - $expected = 'expected'; - - $result = $this->deepLinkResource->setUrl($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getUrl()); - } - - public function testItGetsLineitem() - { - $result = $this->deepLinkResource->getLineItem(); - - $this->assertNull($result); - } - - public function testItSetsLineitem() - { - $expected = Mockery::mock(LtiLineitem::class); - - $result = $this->deepLinkResource->setLineItem($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getLineItem()); - } - - public function testItGetsIcon() - { - $result = $this->deepLinkResource->getIcon(); - - $this->assertNull($result); - } - - public function testItSetsIcon() - { - $expected = Mockery::mock(LtiDeepLinkResourceIcon::class); - - $result = $this->deepLinkResource->setIcon($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getIcon()); - } - - public function testItGetsThumbnail() - { - $result = $this->deepLinkResource->getThumbnail(); - - $this->assertNull($result); - } - - public function testItSetsThumbnail() - { - $expected = Mockery::mock(LtiDeepLinkResourceIcon::class); - - $result = $this->deepLinkResource->setThumbnail($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getThumbnail()); - } - - public function testItGetsCustomParams() - { - $result = $this->deepLinkResource->getCustomParams(); - - $this->assertEquals([], $result); - } - - public function testItSetsCustomParams() - { - $expected = ['a_key' => 'a_value']; - - $result = $this->deepLinkResource->setCustomParams($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getCustomParams()); - } - - public function testItGetsIframe() - { - $result = $this->deepLinkResource->getIframe(); - - $this->assertEquals(null, $result); - } - - public function testItSetsIframe() - { - $expected = new LtiDeepLinkResourceIframe(); - - $result = $this->deepLinkResource->setIframe($expected); - - $this->assertSame($this->deepLinkResource, $result); - $this->assertEquals($expected, $this->deepLinkResource->getIframe()); - } - - public function testItCreatesArrayWithoutOptionalProperties() - { - $expected = [ - 'type' => LtiConstants::DL_RESOURCE_LINK_TYPE, - 'presentation' => [ - 'documentTarget' => 'iframe', - ], - ]; - - $result = $this->deepLinkResource->toArray(); - - $this->assertEquals($expected, $result); - } - - public function testItCreatesArrayWithDefinedOptionalProperties() - { - $icon = LtiDeepLinkResourceIcon::new('https://example.com/image.png', 100, 200); - $resourceIframe = new LtiDeepLinkResourceIframe(); - $resourceWindow = new LtiDeepLinkResourceWindow(); - $resourceDateTimeInterval = new LtiDeepLinkDateTimeInterval(date_create()); - - $expected = [ - 'type' => LtiConstants::DL_RESOURCE_LINK_TYPE, - 'title' => 'a_title', - 'text' => 'a_text', - 'url' => 'a_url', - 'icon' => [ - 'url' => $icon->getUrl(), - 'width' => $icon->getWidth(), - 'height' => $icon->getHeight(), - ], - 'thumbnail' => [ - 'url' => $icon->getUrl(), - 'width' => $icon->getWidth(), - 'height' => $icon->getHeight(), - ], - 'lineItem' => [ - 'scoreMaximum' => 80, - 'label' => 'lineitem_label', - ], - 'iframe' => $resourceIframe->toArray(), - 'window' => $resourceWindow->toArray(), - 'available' => $resourceDateTimeInterval->toArray(), - 'submission' => $resourceDateTimeInterval->toArray(), - ]; - - $lineitem = Mockery::mock(LtiLineitem::class); - $lineitem->shouldReceive('getScoreMaximum') - ->twice()->andReturn($expected['lineItem']['scoreMaximum']); - $lineitem->shouldReceive('getLabel') - ->twice()->andReturn($expected['lineItem']['label']); - - $this->deepLinkResource->setTitle($expected['title']); - $this->deepLinkResource->setText($expected['text']); - $this->deepLinkResource->setUrl($expected['url']); - $this->deepLinkResource->setIcon($icon); - $this->deepLinkResource->setThumbnail($icon); - $this->deepLinkResource->setLineItem($lineitem); - $this->deepLinkResource->setIframe($resourceIframe); - $this->deepLinkResource->setWindow($resourceWindow); - $this->deepLinkResource->setAvailabilityInterval($resourceDateTimeInterval); - $this->deepLinkResource->setSubmissionInterval($resourceDateTimeInterval); - - $result = $this->deepLinkResource->toArray(); - - $this->assertEquals($expected, $result); - - // Test again with custom params - $expected['custom'] = ['a_key' => 'a_value']; - $this->deepLinkResource->setCustomParams(['a_key' => 'a_value']); - $result = $this->deepLinkResource->toArray(); - $this->assertEquals($expected, $result); - } -} diff --git a/tests/LtiDeepLinkResourceWindowTest.php b/tests/LtiDeepLinkResourceWindowTest.php deleted file mode 100644 index dcbe8214..00000000 --- a/tests/LtiDeepLinkResourceWindowTest.php +++ /dev/null @@ -1,119 +0,0 @@ -ltiDeepLinkResourceWindow = new LtiDeepLinkResourceWindow(self::INITIAL_TARGET_NAME, - self::INITIAL_WIDTH, self::INITIAL_HEIGHT, self::INITIAL_WINDOW_FEATURES); - } - - public function testItInstantiates() - { - $this->assertInstanceOf(LtiDeepLinkResourceWindow::class, $this->ltiDeepLinkResourceWindow); - } - - public function testItCreatesANewInstance() - { - $deepLinkResource = LtiDeepLinkResourceWindow::new(); - - $this->assertInstanceOf(LtiDeepLinkResourceWindow::class, $deepLinkResource); - } - - public function testItGetsTargetName() - { - $result = $this->ltiDeepLinkResourceWindow->getTargetName(); - - $this->assertEquals(self::INITIAL_TARGET_NAME, $result); - } - - public function testItSetsTargetName() - { - $expected = 'expected'; - - $result = $this->ltiDeepLinkResourceWindow->setTargetName($expected); - - $this->assertSame($this->ltiDeepLinkResourceWindow, $result); - $this->assertEquals($expected, $this->ltiDeepLinkResourceWindow->getTargetName()); - } - - public function testItGetsWidth() - { - $result = $this->ltiDeepLinkResourceWindow->getWidth(); - - $this->assertEquals(self::INITIAL_WIDTH, $result); - } - - public function testItSetsWidth() - { - $expected = 300; - - $result = $this->ltiDeepLinkResourceWindow->setWidth($expected); - - $this->assertSame($this->ltiDeepLinkResourceWindow, $result); - $this->assertEquals($expected, $this->ltiDeepLinkResourceWindow->getWidth()); - } - - public function testItGetsHeight() - { - $result = $this->ltiDeepLinkResourceWindow->getHeight(); - - $this->assertEquals(self::INITIAL_HEIGHT, $result); - } - - public function testItSetsHeight() - { - $expected = 400; - - $result = $this->ltiDeepLinkResourceWindow->setHeight($expected); - - $this->assertSame($this->ltiDeepLinkResourceWindow, $result); - $this->assertEquals($expected, $this->ltiDeepLinkResourceWindow->getHeight()); - } - - public function testItGetsWindowFeatures() - { - $result = $this->ltiDeepLinkResourceWindow->getWindowFeatures(); - - $this->assertEquals(self::INITIAL_WINDOW_FEATURES, $result); - } - - public function testItSetsWindowFeatures() - { - $expected = 'first-feature=value,second-feature'; - - $result = $this->ltiDeepLinkResourceWindow->setWindowFeatures($expected); - - $this->assertSame($this->ltiDeepLinkResourceWindow, $result); - $this->assertEquals($expected, $this->ltiDeepLinkResourceWindow->getWindowFeatures()); - } - - public function testItCreatesArray() - { - $expected = [ - 'targetName' => 'target-name', - 'width' => 100, - 'height' => 200, - 'windowFeatures' => 'first-feature=value,second-feature', - ]; - - $this->ltiDeepLinkResourceWindow->setTargetName($expected['targetName']); - $this->ltiDeepLinkResourceWindow->setWidth($expected['width']); - $this->ltiDeepLinkResourceWindow->setHeight($expected['height']); - $this->ltiDeepLinkResourceWindow->setWindowFeatures($expected['windowFeatures']); - - $result = $this->ltiDeepLinkResourceWindow->toArray(); - - $this->assertEquals($expected, $result); - } -} diff --git a/tests/LtiDeepLinkTest.php b/tests/LtiDeepLinkTest.php index 56a10c3e..c11ff7b8 100644 --- a/tests/LtiDeepLinkTest.php +++ b/tests/LtiDeepLinkTest.php @@ -5,10 +5,10 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; use Mockery; +use Packback\Lti1p3\DeepLinkResource\Resource; use Packback\Lti1p3\Interfaces\ILtiRegistration; use Packback\Lti1p3\LtiConstants; use Packback\Lti1p3\LtiDeepLink; -use Packback\Lti1p3\LtiDeepLinkResource; class LtiDeepLinkTest extends TestCase { @@ -22,7 +22,7 @@ class LtiDeepLinkTest extends TestCase protected function setUp(): void { $this->registrationMock = Mockery::mock(ILtiRegistration::class); - $this->ltiResourceMock = Mockery::mock(LtiDeepLinkResource::class); + $this->ltiResourceMock = Mockery::mock(Resource::class); } public function testItInstantiates() From 92ff67f475eb50b2cabcdffe970df295815822d8 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 18 Dec 2023 16:04:22 -0600 Subject: [PATCH 18/27] Move has dimensions --- src/{Helpers => DeepLinkResource}/HasDimensions.php | 2 +- src/DeepLinkResource/Icon.php | 2 -- src/DeepLinkResource/Iframe.php | 2 -- src/DeepLinkResource/Window.php | 2 -- 4 files changed, 1 insertion(+), 7 deletions(-) rename src/{Helpers => DeepLinkResource}/HasDimensions.php (90%) diff --git a/src/Helpers/HasDimensions.php b/src/DeepLinkResource/HasDimensions.php similarity index 90% rename from src/Helpers/HasDimensions.php rename to src/DeepLinkResource/HasDimensions.php index 1e245b78..6b774d46 100644 --- a/src/Helpers/HasDimensions.php +++ b/src/DeepLinkResource/HasDimensions.php @@ -1,6 +1,6 @@ Date: Tue, 19 Dec 2023 09:33:27 -0600 Subject: [PATCH 19/27] Move objects again --- UPGRADES.md | 18 ++++++++++++++---- .../DateTimeInterval.php | 2 +- .../HasDimensions.php | 2 +- .../Icon.php | 2 +- .../Iframe.php | 2 +- .../Resource.php | 2 +- .../Window.php | 2 +- .../DateTimeIntervalTest.php | 9 +++++---- .../IconTest.php | 9 +++++---- .../IframeTest.php | 9 +++++---- .../ResourceTest.php | 13 +++++++------ .../WindowTest.php | 9 +++++---- tests/LtiDeepLinkTest.php | 2 +- 13 files changed, 48 insertions(+), 33 deletions(-) rename src/{DeepLinkResource => DeepLinkResources}/DateTimeInterval.php (97%) rename src/{DeepLinkResource => DeepLinkResources}/HasDimensions.php (90%) rename src/{DeepLinkResource => DeepLinkResources}/Icon.php (93%) rename src/{DeepLinkResource => DeepLinkResources}/Iframe.php (94%) rename src/{DeepLinkResource => DeepLinkResources}/Resource.php (99%) rename src/{DeepLinkResource => DeepLinkResources}/Window.php (96%) rename tests/{DeepLinkResource => DeepLinkResources}/DateTimeIntervalTest.php (92%) rename tests/{DeepLinkResource => DeepLinkResources}/IconTest.php (88%) rename tests/{DeepLinkResource => DeepLinkResources}/IframeTest.php (92%) rename tests/{DeepLinkResource => DeepLinkResources}/ResourceTest.php (95%) rename tests/{DeepLinkResource => DeepLinkResources}/WindowTest.php (93%) diff --git a/UPGRADES.md b/UPGRADES.md index 1e30dc4e..4505cc61 100644 --- a/UPGRADES.md +++ b/UPGRADES.md @@ -45,12 +45,22 @@ Packback\Lti1p3\Interfaces\IMigrationDatabase This library now requires PHP 8 and firebase/php-jwt 6. -### `LtiDeepLinkResourceIframe` constructor arguments changed order +### `Packback\Lti1p3\DeepLinkResource*` objects moved to their own namespace + +Objects named `DeepLinkResource*` have been moved to their own namespace: `Packback\Lti1p3\DeepLinkResources`. The following classes have been moved: + +- `Packback\Lti1p3\DeepLinkResourceDateTimeInterval` is now `Packback\Lti1p3\DeepLinkResources\DateTimeInterval` +- `Packback\Lti1p3\DeepLinkResourceIcon` is now `Packback\Lti1p3\DeepLinkResources\Icon` +- `Packback\Lti1p3\DeepLinkResourceIframe` is now `Packback\Lti1p3\DeepLinkResources\Iframe` +- `Packback\Lti1p3\DeepLinkResource` is now `Packback\Lti1p3\DeepLinkResources\Resource` +- `Packback\Lti1p3\DeepLinkResourceWindow` is now `Packback\Lti1p3\DeepLinkResources\Window` + +### `Packback\Lti1p3\DeepLinkResources\Iframe` constructor arguments changed order To make the interface consistent with other deep link resources, `src` is now the first argument in the constructor: ```php -class LtiDeepLinkResourceIframe +class Iframe { public function __construct( private ?string $src = null, @@ -77,8 +87,8 @@ The following methods have been removed: * `Packback\Lti1p3\JwksEndpoint::outputJwks()` - use `getPublicJwks()` to build your own output * `Packback\Lti1p3\LtiDeepLink::outputResponseForm()` - use `getResponseJwt()` to build your own output -* `Packback\Lti1p3\LtiDeepLinkResource::getTarget()` - consider using `getIframe()` or `getWindow()` instead -* `Packback\Lti1p3\LtiDeepLinkResource::setTarget()` - consider using `setIframe()` or `setWindow()` instead +* `Packback\Lti1p3\LtiDeepLinkResources\Resource::getTarget()` - consider using `getIframe()` or `getWindow()` instead +* `Packback\Lti1p3\LtiDeepLinkResources\Resource::setTarget()` - consider using `setIframe()` or `setWindow()` instead * `Packback\Lti1p3\Redirect::doHybridRedirect()` * `Packback\Lti1p3\Redirect::getRedirectUrl()` diff --git a/src/DeepLinkResource/DateTimeInterval.php b/src/DeepLinkResources/DateTimeInterval.php similarity index 97% rename from src/DeepLinkResource/DateTimeInterval.php rename to src/DeepLinkResources/DateTimeInterval.php index dbd9b5ff..82b1aa6e 100644 --- a/src/DeepLinkResource/DateTimeInterval.php +++ b/src/DeepLinkResources/DateTimeInterval.php @@ -1,6 +1,6 @@ assertInstanceOf(DateTimeInterval::class, $deepLinkResource); + $this->assertInstanceOf(DateTimeInterval::class, $DeepLinkResources); } public function testItGetsStart() diff --git a/tests/DeepLinkResource/IconTest.php b/tests/DeepLinkResources/IconTest.php similarity index 88% rename from tests/DeepLinkResource/IconTest.php rename to tests/DeepLinkResources/IconTest.php index 033edbed..8d6d643f 100644 --- a/tests/DeepLinkResource/IconTest.php +++ b/tests/DeepLinkResources/IconTest.php @@ -1,8 +1,9 @@ imageUrl, 100, 200); + $DeepLinkResources = Icon::new($this->imageUrl, 100, 200); - $this->assertInstanceOf(Icon::class, $deepLinkResource); + $this->assertInstanceOf(Icon::class, $DeepLinkResources); } public function testItGetsUrl() diff --git a/tests/DeepLinkResource/IframeTest.php b/tests/DeepLinkResources/IframeTest.php similarity index 92% rename from tests/DeepLinkResource/IframeTest.php rename to tests/DeepLinkResources/IframeTest.php index a82d0f70..1c4fd9db 100644 --- a/tests/DeepLinkResource/IframeTest.php +++ b/tests/DeepLinkResources/IframeTest.php @@ -1,8 +1,9 @@ assertInstanceOf(Iframe::class, $deepLinkResource); + $this->assertInstanceOf(Iframe::class, $DeepLinkResources); } public function testItGetsWidth() diff --git a/tests/DeepLinkResource/ResourceTest.php b/tests/DeepLinkResources/ResourceTest.php similarity index 95% rename from tests/DeepLinkResource/ResourceTest.php rename to tests/DeepLinkResources/ResourceTest.php index 0417e175..d79eedbf 100644 --- a/tests/DeepLinkResource/ResourceTest.php +++ b/tests/DeepLinkResources/ResourceTest.php @@ -1,15 +1,16 @@ assertInstanceOf(Window::class, $deepLinkResource); + $this->assertInstanceOf(Window::class, $DeepLinkResources); } public function testItGetsTargetName() diff --git a/tests/LtiDeepLinkTest.php b/tests/LtiDeepLinkTest.php index c11ff7b8..6d8562c4 100644 --- a/tests/LtiDeepLinkTest.php +++ b/tests/LtiDeepLinkTest.php @@ -5,7 +5,7 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; use Mockery; -use Packback\Lti1p3\DeepLinkResource\Resource; +use Packback\Lti1p3\DeepLinkResources\Resource; use Packback\Lti1p3\Interfaces\ILtiRegistration; use Packback\Lti1p3\LtiConstants; use Packback\Lti1p3\LtiDeepLink; From b8e7f33f54da1ff9bc167f0e413e07255f27e818 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 12:01:34 -0600 Subject: [PATCH 20/27] Add a helper to clean up arrayable --- src/DeepLinkResources/DateTimeInterval.php | 18 ++++----- src/DeepLinkResources/Iframe.php | 22 +++++------ src/DeepLinkResources/Resource.php | 43 +++++++--------------- src/Helpers/Helpers.php | 5 +++ 4 files changed, 36 insertions(+), 52 deletions(-) diff --git a/src/DeepLinkResources/DateTimeInterval.php b/src/DeepLinkResources/DateTimeInterval.php index 82b1aa6e..705276ea 100644 --- a/src/DeepLinkResources/DateTimeInterval.php +++ b/src/DeepLinkResources/DateTimeInterval.php @@ -3,6 +3,7 @@ namespace Packback\Lti1p3\DeepLinkResources; use DateTime; +use Packback\Lti1p3\Helpers\Helpers; use Packback\Lti1p3\LtiException; class DateTimeInterval @@ -54,18 +55,17 @@ public function toArray(): array $this->validateStartAndEnd(); - $dateTimeInterval = []; + $dateTimeInterval = [ + 'startDateTime' => $this->start?->format(DateTime::ATOM) ?? null, + 'endDateTime' => $this->end?->format(DateTime::ATOM) ?? null, + ]; - if (isset($this->start)) { - $dateTimeInterval['startDateTime'] = $this->start->format(DateTime::ATOM); - } - if (isset($this->end)) { - $dateTimeInterval['endDateTime'] = $this->end->format(DateTime::ATOM); - } - - return $dateTimeInterval; + return Helpers::filterOutNulls($dateTimeInterval); } + /** + * @throws LtiException + */ private function validateStartAndEnd(): void { if (isset($this->start) && isset($this->end) && $this->start > $this->end) { diff --git a/src/DeepLinkResources/Iframe.php b/src/DeepLinkResources/Iframe.php index 8120f2fa..0b4a2813 100644 --- a/src/DeepLinkResources/Iframe.php +++ b/src/DeepLinkResources/Iframe.php @@ -2,6 +2,8 @@ namespace Packback\Lti1p3\DeepLinkResources; +use Packback\Lti1p3\Helpers\Helpers; + class Iframe { use HasDimensions; @@ -32,18 +34,12 @@ public function getSrc(): ?string public function toArray(): array { - $iframe = []; - - if (isset($this->width)) { - $iframe['width'] = $this->width; - } - if (isset($this->height)) { - $iframe['height'] = $this->height; - } - if (isset($this->src)) { - $iframe['src'] = $this->src; - } - - return $iframe; + $iframe = [ + 'width' => $this->width ?? null, + 'height' => $this->height ?? null, + 'src' => $this->src ?? null, + ]; + + return Helpers::filterOutNulls($iframe); } } diff --git a/src/DeepLinkResources/Resource.php b/src/DeepLinkResources/Resource.php index 9bfc7802..b2d4ebc4 100644 --- a/src/DeepLinkResources/Resource.php +++ b/src/DeepLinkResources/Resource.php @@ -2,6 +2,7 @@ namespace Packback\Lti1p3\DeepLinkResources; +use Packback\Lti1p3\Helpers\Helpers; use Packback\Lti1p3\LtiConstants; use Packback\Lti1p3\LtiLineitem; @@ -174,27 +175,22 @@ public function toArray(): array { $resource = [ 'type' => $this->type, + 'title' => $this->title ?? null, + 'text' => $this->text ?? null, + 'url' => $this->url ?? null, + 'icon' => $this->icon?->toArray() ?? null, + 'thumbnail' => $this->thumbnail?->toArray() ?? null, + 'iframe' => $this->iframe?->toArray() ?? null, + 'window' => $this->window?->toArray() ?? null, + 'available' => $this->availability_interval?->toArray() ?? null, + 'submission' => $this->submission_interval?->toArray() ?? null, ]; - if (isset($this->title)) { - $resource['title'] = $this->title; - } - if (isset($this->text)) { - $resource['text'] = $this->text; - } - if (isset($this->url)) { - $resource['url'] = $this->url; - } if (!empty($this->custom_params)) { $resource['custom'] = $this->custom_params; } - if (isset($this->icon)) { - $resource['icon'] = $this->icon->toArray(); - } - if (isset($this->thumbnail)) { - $resource['thumbnail'] = $this->thumbnail->toArray(); - } - if ($this->line_item !== null) { + + if (isset($this->line_item)) { $resource['lineItem'] = [ 'scoreMaximum' => $this->line_item->getScoreMaximum(), 'label' => $this->line_item->getLabel(), @@ -208,19 +204,6 @@ public function toArray(): array ]; } - if (isset($this->iframe)) { - $resource['iframe'] = $this->iframe->toArray(); - } - if (isset($this->window)) { - $resource['window'] = $this->window->toArray(); - } - if (isset($this->availability_interval)) { - $resource['available'] = $this->availability_interval->toArray(); - } - if (isset($this->submission_interval)) { - $resource['submission'] = $this->submission_interval->toArray(); - } - - return $resource; + return Helpers::filterOutNulls($resource); } } diff --git a/src/Helpers/Helpers.php b/src/Helpers/Helpers.php index 39fb9611..20763a8a 100644 --- a/src/Helpers/Helpers.php +++ b/src/Helpers/Helpers.php @@ -9,6 +9,11 @@ public static function checkIfNullValue($value): bool return !is_null($value); } + public static function filterOutNulls(array $array): array + { + return array_filter($array, '\Packback\Lti1p3\Helpers\Helpers::checkIfNullValue'); + } + public static function buildUrlWithQueryParams(string $url, array $params = []): string { if (empty($params)) { From d7482d733b30fdf6187b1c49fda90a2a9a7b4237 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 12:52:07 -0600 Subject: [PATCH 21/27] Abstract null array filter --- src/DeepLinkResources/DateTimeInterval.php | 4 ++-- src/DeepLinkResources/Iframe.php | 6 ++--- src/DeepLinkResources/Resource.php | 18 +++++++-------- src/DeepLinkResources/Window.php | 26 +++++++++------------- src/LtiGrade.php | 6 +++-- src/LtiGradeSubmissionReview.php | 6 +++-- src/LtiLineitem.php | 6 +++-- 7 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/DeepLinkResources/DateTimeInterval.php b/src/DeepLinkResources/DateTimeInterval.php index 705276ea..6d7d7566 100644 --- a/src/DeepLinkResources/DateTimeInterval.php +++ b/src/DeepLinkResources/DateTimeInterval.php @@ -56,8 +56,8 @@ public function toArray(): array $this->validateStartAndEnd(); $dateTimeInterval = [ - 'startDateTime' => $this->start?->format(DateTime::ATOM) ?? null, - 'endDateTime' => $this->end?->format(DateTime::ATOM) ?? null, + 'startDateTime' => $this->start?->format(DateTime::ATOM), + 'endDateTime' => $this->end?->format(DateTime::ATOM), ]; return Helpers::filterOutNulls($dateTimeInterval); diff --git a/src/DeepLinkResources/Iframe.php b/src/DeepLinkResources/Iframe.php index 0b4a2813..d5f5bc6c 100644 --- a/src/DeepLinkResources/Iframe.php +++ b/src/DeepLinkResources/Iframe.php @@ -35,9 +35,9 @@ public function getSrc(): ?string public function toArray(): array { $iframe = [ - 'width' => $this->width ?? null, - 'height' => $this->height ?? null, - 'src' => $this->src ?? null, + 'width' => $this->width, + 'height' => $this->height, + 'src' => $this->src, ]; return Helpers::filterOutNulls($iframe); diff --git a/src/DeepLinkResources/Resource.php b/src/DeepLinkResources/Resource.php index b2d4ebc4..c7f62c3f 100644 --- a/src/DeepLinkResources/Resource.php +++ b/src/DeepLinkResources/Resource.php @@ -175,15 +175,15 @@ public function toArray(): array { $resource = [ 'type' => $this->type, - 'title' => $this->title ?? null, - 'text' => $this->text ?? null, - 'url' => $this->url ?? null, - 'icon' => $this->icon?->toArray() ?? null, - 'thumbnail' => $this->thumbnail?->toArray() ?? null, - 'iframe' => $this->iframe?->toArray() ?? null, - 'window' => $this->window?->toArray() ?? null, - 'available' => $this->availability_interval?->toArray() ?? null, - 'submission' => $this->submission_interval?->toArray() ?? null, + 'title' => $this->title, + 'text' => $this->text, + 'url' => $this->url, + 'icon' => $this->icon?->toArray(), + 'thumbnail' => $this->thumbnail?->toArray(), + 'iframe' => $this->iframe?->toArray(), + 'window' => $this->window?->toArray(), + 'available' => $this->availability_interval?->toArray(), + 'submission' => $this->submission_interval?->toArray(), ]; if (!empty($this->custom_params)) { diff --git a/src/DeepLinkResources/Window.php b/src/DeepLinkResources/Window.php index 3ba8831a..c30dbe2c 100644 --- a/src/DeepLinkResources/Window.php +++ b/src/DeepLinkResources/Window.php @@ -2,6 +2,8 @@ namespace Packback\Lti1p3\DeepLinkResources; +use Packback\Lti1p3\Helpers\Helpers; + class Window { use HasDimensions; @@ -45,21 +47,13 @@ public function getWindowFeatures(): ?string public function toArray(): array { - $window = []; - - if (isset($this->target_name)) { - $window['targetName'] = $this->target_name; - } - if (isset($this->width)) { - $window['width'] = $this->width; - } - if (isset($this->height)) { - $window['height'] = $this->height; - } - if (isset($this->window_features)) { - $window['windowFeatures'] = $this->window_features; - } - - return $window; + $window = [ + 'targetName' => $this->target_name, + 'width' => $this->width, + 'height' => $this->height, + 'windowFeatures' => $this->window_features, + ]; + + return Helpers::filterOutNulls($window); } } diff --git a/src/LtiGrade.php b/src/LtiGrade.php index 67654420..50cb35fd 100644 --- a/src/LtiGrade.php +++ b/src/LtiGrade.php @@ -2,6 +2,8 @@ namespace Packback\Lti1p3; +use Packback\Lti1p3\Helpers\Helpers; + class LtiGrade { private $score_given; @@ -30,7 +32,7 @@ public function __construct(?array $grade = null) public function __toString(): string { // Additionally, includes the call back to filter out only NULL values - $request = array_filter([ + $request = Helpers::filterOutNulls([ 'scoreGiven' => $this->score_given, 'scoreMaximum' => $this->score_maximum, 'comment' => $this->comment, @@ -40,7 +42,7 @@ public function __toString(): string 'userId' => $this->user_id, 'submissionReview' => $this->submission_review, 'https://canvas.instructure.com/lti/submission' => $this->canvas_extension, - ], '\Packback\Lti1p3\Helpers\Helpers::checkIfNullValue'); + ]); return json_encode($request); } diff --git a/src/LtiGradeSubmissionReview.php b/src/LtiGradeSubmissionReview.php index b4f0b7cd..bf92db52 100644 --- a/src/LtiGradeSubmissionReview.php +++ b/src/LtiGradeSubmissionReview.php @@ -2,6 +2,8 @@ namespace Packback\Lti1p3; +use Packback\Lti1p3\Helpers\Helpers; + class LtiGradeSubmissionReview { private $reviewable_status; @@ -20,12 +22,12 @@ public function __construct(?array $gradeSubmission = null) public function __toString(): string { // Additionally, includes the call back to filter out only NULL values - return json_encode(array_filter([ + return json_encode(Helpers::filterOutNulls([ 'reviewableStatus' => $this->reviewable_status, 'label' => $this->label, 'url' => $this->url, 'custom' => $this->custom, - ], '\Packback\Lti1p3\Helpers\Helpers::checkIfNullValue')); + ])); } /** diff --git a/src/LtiLineitem.php b/src/LtiLineitem.php index 0f2485d9..8cc9333b 100644 --- a/src/LtiLineitem.php +++ b/src/LtiLineitem.php @@ -2,6 +2,8 @@ namespace Packback\Lti1p3; +use Packback\Lti1p3\Helpers\Helpers; + class LtiLineitem { private $id; @@ -30,7 +32,7 @@ public function __construct(?array $lineitem = null) public function __toString(): string { // Additionally, includes the call back to filter out only NULL values - return json_encode(array_filter([ + return json_encode(Helpers::filterOutNulls([ 'id' => $this->id, 'scoreMaximum' => $this->score_maximum, 'label' => $this->label, @@ -40,7 +42,7 @@ public function __toString(): string 'startDateTime' => $this->start_date_time, 'endDateTime' => $this->end_date_time, 'gradesReleased' => $this->grades_released, - ], '\Packback\Lti1p3\Helpers\Helpers::checkIfNullValue')); + ])); } /** From d81abc8e60ee79da5e5f5e2f25de36bf585d0d7a Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 13:27:39 -0600 Subject: [PATCH 22/27] Make Arrayable and Jsonable concerns --- src/Concerns/Arrayable.php | 15 +++++++++++++++ src/Concerns/JsonStringable.php | 13 +++++++++++++ src/DeepLinkResources/DateTimeInterval.php | 9 ++++----- src/DeepLinkResources/Icon.php | 6 ++++-- src/DeepLinkResources/Iframe.php | 10 ++++------ src/DeepLinkResources/Resource.php | 7 ++++--- src/DeepLinkResources/Window.php | 10 ++++------ src/Helpers/Helpers.php | 7 +------ src/LtiGrade.php | 12 +++++------- src/LtiGradeSubmissionReview.php | 10 +++++----- src/LtiLineitem.php | 10 +++++----- 11 files changed, 64 insertions(+), 45 deletions(-) create mode 100644 src/Concerns/Arrayable.php create mode 100644 src/Concerns/JsonStringable.php diff --git a/src/Concerns/Arrayable.php b/src/Concerns/Arrayable.php new file mode 100644 index 00000000..c83f345e --- /dev/null +++ b/src/Concerns/Arrayable.php @@ -0,0 +1,15 @@ +getArray()); + } +} diff --git a/src/Concerns/JsonStringable.php b/src/Concerns/JsonStringable.php new file mode 100644 index 00000000..29242827 --- /dev/null +++ b/src/Concerns/JsonStringable.php @@ -0,0 +1,13 @@ +toArray()); + } +} diff --git a/src/DeepLinkResources/DateTimeInterval.php b/src/DeepLinkResources/DateTimeInterval.php index 6d7d7566..3cb9033d 100644 --- a/src/DeepLinkResources/DateTimeInterval.php +++ b/src/DeepLinkResources/DateTimeInterval.php @@ -3,11 +3,12 @@ namespace Packback\Lti1p3\DeepLinkResources; use DateTime; -use Packback\Lti1p3\Helpers\Helpers; +use Packback\Lti1p3\Concerns\Arrayable; use Packback\Lti1p3\LtiException; class DateTimeInterval { + use Arrayable; public const ERROR_NO_START_OR_END = 'Either a start or end time must be specified.'; public const ERROR_START_GT_END = 'The start time cannot be greater than end time.'; @@ -47,7 +48,7 @@ public function getEnd(): ?DateTime return $this->end; } - public function toArray(): array + public function getArray(): array { if (!isset($this->start) && !isset($this->end)) { throw new LtiException(self::ERROR_NO_START_OR_END); @@ -55,12 +56,10 @@ public function toArray(): array $this->validateStartAndEnd(); - $dateTimeInterval = [ + return [ 'startDateTime' => $this->start?->format(DateTime::ATOM), 'endDateTime' => $this->end?->format(DateTime::ATOM), ]; - - return Helpers::filterOutNulls($dateTimeInterval); } /** diff --git a/src/DeepLinkResources/Icon.php b/src/DeepLinkResources/Icon.php index 84ae4e16..6a7c5696 100644 --- a/src/DeepLinkResources/Icon.php +++ b/src/DeepLinkResources/Icon.php @@ -2,9 +2,11 @@ namespace Packback\Lti1p3\DeepLinkResources; +use Packback\Lti1p3\Concerns\Arrayable; + class Icon { - use HasDimensions; + use Arrayable, HasDimensions; public function __construct( private string $url, @@ -30,7 +32,7 @@ public function getUrl(): string return $this->url; } - public function toArray(): array + public function getArray(): array { return [ 'url' => $this->url, diff --git a/src/DeepLinkResources/Iframe.php b/src/DeepLinkResources/Iframe.php index d5f5bc6c..ac12d247 100644 --- a/src/DeepLinkResources/Iframe.php +++ b/src/DeepLinkResources/Iframe.php @@ -2,11 +2,11 @@ namespace Packback\Lti1p3\DeepLinkResources; -use Packback\Lti1p3\Helpers\Helpers; +use Packback\Lti1p3\Concerns\Arrayable; class Iframe { - use HasDimensions; + use Arrayable, HasDimensions; public function __construct( private ?string $src = null, @@ -32,14 +32,12 @@ public function getSrc(): ?string return $this->src; } - public function toArray(): array + public function getArray(): array { - $iframe = [ + return [ 'width' => $this->width, 'height' => $this->height, 'src' => $this->src, ]; - - return Helpers::filterOutNulls($iframe); } } diff --git a/src/DeepLinkResources/Resource.php b/src/DeepLinkResources/Resource.php index c7f62c3f..3f907067 100644 --- a/src/DeepLinkResources/Resource.php +++ b/src/DeepLinkResources/Resource.php @@ -2,12 +2,13 @@ namespace Packback\Lti1p3\DeepLinkResources; -use Packback\Lti1p3\Helpers\Helpers; +use Packback\Lti1p3\Concerns\Arrayable; use Packback\Lti1p3\LtiConstants; use Packback\Lti1p3\LtiLineitem; class Resource { + use Arrayable; private string $type = LtiConstants::DL_RESOURCE_LINK_TYPE; private ?string $title = null; private ?string $text = null; @@ -171,7 +172,7 @@ public function setSubmissionInterval(?DateTimeInterval $submissionInterval): se return $this; } - public function toArray(): array + public function getArray(): array { $resource = [ 'type' => $this->type, @@ -204,6 +205,6 @@ public function toArray(): array ]; } - return Helpers::filterOutNulls($resource); + return $resource; } } diff --git a/src/DeepLinkResources/Window.php b/src/DeepLinkResources/Window.php index c30dbe2c..ce968289 100644 --- a/src/DeepLinkResources/Window.php +++ b/src/DeepLinkResources/Window.php @@ -2,11 +2,11 @@ namespace Packback\Lti1p3\DeepLinkResources; -use Packback\Lti1p3\Helpers\Helpers; +use Packback\Lti1p3\Concerns\Arrayable; class Window { - use HasDimensions; + use Arrayable, HasDimensions; public function __construct( private ?string $target_name = null, @@ -45,15 +45,13 @@ public function getWindowFeatures(): ?string return $this->window_features; } - public function toArray(): array + public function getArray(): array { - $window = [ + return [ 'targetName' => $this->target_name, 'width' => $this->width, 'height' => $this->height, 'windowFeatures' => $this->window_features, ]; - - return Helpers::filterOutNulls($window); } } diff --git a/src/Helpers/Helpers.php b/src/Helpers/Helpers.php index 20763a8a..ad64d43f 100644 --- a/src/Helpers/Helpers.php +++ b/src/Helpers/Helpers.php @@ -4,14 +4,9 @@ class Helpers { - public static function checkIfNullValue($value): bool - { - return !is_null($value); - } - public static function filterOutNulls(array $array): array { - return array_filter($array, '\Packback\Lti1p3\Helpers\Helpers::checkIfNullValue'); + return array_filter($array, fn ($value) => !is_null($value)); } public static function buildUrlWithQueryParams(string $url, array $params = []): string diff --git a/src/LtiGrade.php b/src/LtiGrade.php index 50cb35fd..bd673b4e 100644 --- a/src/LtiGrade.php +++ b/src/LtiGrade.php @@ -2,10 +2,11 @@ namespace Packback\Lti1p3; -use Packback\Lti1p3\Helpers\Helpers; +use Packback\Lti1p3\Concerns\JsonStringable; class LtiGrade { + use JsonStringable; private $score_given; private $score_maximum; private $comment; @@ -29,10 +30,9 @@ public function __construct(?array $grade = null) $this->canvas_extension = $grade['https://canvas.instructure.com/lti/submission'] ?? null; } - public function __toString(): string + public function getArray(): array { - // Additionally, includes the call back to filter out only NULL values - $request = Helpers::filterOutNulls([ + return [ 'scoreGiven' => $this->score_given, 'scoreMaximum' => $this->score_maximum, 'comment' => $this->comment, @@ -42,9 +42,7 @@ public function __toString(): string 'userId' => $this->user_id, 'submissionReview' => $this->submission_review, 'https://canvas.instructure.com/lti/submission' => $this->canvas_extension, - ]); - - return json_encode($request); + ]; } /** diff --git a/src/LtiGradeSubmissionReview.php b/src/LtiGradeSubmissionReview.php index bf92db52..4732d784 100644 --- a/src/LtiGradeSubmissionReview.php +++ b/src/LtiGradeSubmissionReview.php @@ -2,10 +2,11 @@ namespace Packback\Lti1p3; -use Packback\Lti1p3\Helpers\Helpers; +use Packback\Lti1p3\Concerns\JsonStringable; class LtiGradeSubmissionReview { + use JsonStringable; private $reviewable_status; private $label; private $url; @@ -19,15 +20,14 @@ public function __construct(?array $gradeSubmission = null) $this->custom = $gradeSubmission['custom'] ?? null; } - public function __toString(): string + public function getArray(): array { - // Additionally, includes the call back to filter out only NULL values - return json_encode(Helpers::filterOutNulls([ + return [ 'reviewableStatus' => $this->reviewable_status, 'label' => $this->label, 'url' => $this->url, 'custom' => $this->custom, - ])); + ]; } /** diff --git a/src/LtiLineitem.php b/src/LtiLineitem.php index 8cc9333b..26f8581b 100644 --- a/src/LtiLineitem.php +++ b/src/LtiLineitem.php @@ -2,10 +2,11 @@ namespace Packback\Lti1p3; -use Packback\Lti1p3\Helpers\Helpers; +use Packback\Lti1p3\Concerns\JsonStringable; class LtiLineitem { + use JsonStringable; private $id; private $score_maximum; private $label; @@ -29,10 +30,9 @@ public function __construct(?array $lineitem = null) $this->grades_released = $lineitem['gradesReleased'] ?? null; } - public function __toString(): string + public function getArray(): array { - // Additionally, includes the call back to filter out only NULL values - return json_encode(Helpers::filterOutNulls([ + return [ 'id' => $this->id, 'scoreMaximum' => $this->score_maximum, 'label' => $this->label, @@ -42,7 +42,7 @@ public function __toString(): string 'startDateTime' => $this->start_date_time, 'endDateTime' => $this->end_date_time, 'gradesReleased' => $this->grades_released, - ])); + ]; } /** From 2df843da72814dbd39158647c8716882fcfe54a7 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 14:32:28 -0600 Subject: [PATCH 23/27] reorder methods --- src/DeepLinkResources/DateTimeInterval.php | 28 ++++----- src/DeepLinkResources/Icon.php | 18 +++--- src/DeepLinkResources/Iframe.php | 18 +++--- src/DeepLinkResources/Resource.php | 72 +++++++++++----------- src/DeepLinkResources/Window.php | 20 +++--- 5 files changed, 78 insertions(+), 78 deletions(-) diff --git a/src/DeepLinkResources/DateTimeInterval.php b/src/DeepLinkResources/DateTimeInterval.php index 3cb9033d..e3b2cef2 100644 --- a/src/DeepLinkResources/DateTimeInterval.php +++ b/src/DeepLinkResources/DateTimeInterval.php @@ -24,6 +24,20 @@ public static function new(): self return new DateTimeInterval(); } + public function getArray(): array + { + if (!isset($this->start) && !isset($this->end)) { + throw new LtiException(self::ERROR_NO_START_OR_END); + } + + $this->validateStartAndEnd(); + + return [ + 'startDateTime' => $this->start?->format(DateTime::ATOM), + 'endDateTime' => $this->end?->format(DateTime::ATOM), + ]; + } + public function setStart(?DateTime $start): self { $this->start = $start; @@ -48,20 +62,6 @@ public function getEnd(): ?DateTime return $this->end; } - public function getArray(): array - { - if (!isset($this->start) && !isset($this->end)) { - throw new LtiException(self::ERROR_NO_START_OR_END); - } - - $this->validateStartAndEnd(); - - return [ - 'startDateTime' => $this->start?->format(DateTime::ATOM), - 'endDateTime' => $this->end?->format(DateTime::ATOM), - ]; - } - /** * @throws LtiException */ diff --git a/src/DeepLinkResources/Icon.php b/src/DeepLinkResources/Icon.php index 6a7c5696..267c983f 100644 --- a/src/DeepLinkResources/Icon.php +++ b/src/DeepLinkResources/Icon.php @@ -20,6 +20,15 @@ public static function new(string $url, int $width, int $height): self return new Icon($url, $width, $height); } + public function getArray(): array + { + return [ + 'url' => $this->url, + 'width' => $this->width, + 'height' => $this->height, + ]; + } + public function setUrl(string $url): self { $this->url = $url; @@ -31,13 +40,4 @@ public function getUrl(): string { return $this->url; } - - public function getArray(): array - { - return [ - 'url' => $this->url, - 'width' => $this->width, - 'height' => $this->height, - ]; - } } diff --git a/src/DeepLinkResources/Iframe.php b/src/DeepLinkResources/Iframe.php index ac12d247..039ea8eb 100644 --- a/src/DeepLinkResources/Iframe.php +++ b/src/DeepLinkResources/Iframe.php @@ -20,6 +20,15 @@ public static function new(): self return new Iframe(); } + public function getArray(): array + { + return [ + 'width' => $this->width, + 'height' => $this->height, + 'src' => $this->src, + ]; + } + public function setSrc(?string $src): self { $this->src = $src; @@ -31,13 +40,4 @@ public function getSrc(): ?string { return $this->src; } - - public function getArray(): array - { - return [ - 'width' => $this->width, - 'height' => $this->height, - 'src' => $this->src, - ]; - } } diff --git a/src/DeepLinkResources/Resource.php b/src/DeepLinkResources/Resource.php index 3f907067..5cbb4b2b 100644 --- a/src/DeepLinkResources/Resource.php +++ b/src/DeepLinkResources/Resource.php @@ -28,6 +28,42 @@ public static function new(): self return new Resource(); } + public function getArray(): array + { + $resource = [ + 'type' => $this->type, + 'title' => $this->title, + 'text' => $this->text, + 'url' => $this->url, + 'icon' => $this->icon?->toArray(), + 'thumbnail' => $this->thumbnail?->toArray(), + 'iframe' => $this->iframe?->toArray(), + 'window' => $this->window?->toArray(), + 'available' => $this->availability_interval?->toArray(), + 'submission' => $this->submission_interval?->toArray(), + ]; + + if (!empty($this->custom_params)) { + $resource['custom'] = $this->custom_params; + } + + if (isset($this->line_item)) { + $resource['lineItem'] = [ + 'scoreMaximum' => $this->line_item->getScoreMaximum(), + 'label' => $this->line_item->getLabel(), + ]; + } + + // Kept for backwards compatibility + if (!isset($this->iframe) && !isset($this->window)) { + $resource['presentation'] = [ + 'documentTarget' => $this->target, + ]; + } + + return $resource; + } + public function getType(): string { return $this->type; @@ -171,40 +207,4 @@ public function setSubmissionInterval(?DateTimeInterval $submissionInterval): se return $this; } - - public function getArray(): array - { - $resource = [ - 'type' => $this->type, - 'title' => $this->title, - 'text' => $this->text, - 'url' => $this->url, - 'icon' => $this->icon?->toArray(), - 'thumbnail' => $this->thumbnail?->toArray(), - 'iframe' => $this->iframe?->toArray(), - 'window' => $this->window?->toArray(), - 'available' => $this->availability_interval?->toArray(), - 'submission' => $this->submission_interval?->toArray(), - ]; - - if (!empty($this->custom_params)) { - $resource['custom'] = $this->custom_params; - } - - if (isset($this->line_item)) { - $resource['lineItem'] = [ - 'scoreMaximum' => $this->line_item->getScoreMaximum(), - 'label' => $this->line_item->getLabel(), - ]; - } - - // Kept for backwards compatibility - if (!isset($this->iframe) && !isset($this->window)) { - $resource['presentation'] = [ - 'documentTarget' => $this->target, - ]; - } - - return $resource; - } } diff --git a/src/DeepLinkResources/Window.php b/src/DeepLinkResources/Window.php index ce968289..7ee30ba0 100644 --- a/src/DeepLinkResources/Window.php +++ b/src/DeepLinkResources/Window.php @@ -21,6 +21,16 @@ public static function new(): self return new Window(); } + public function getArray(): array + { + return [ + 'targetName' => $this->target_name, + 'width' => $this->width, + 'height' => $this->height, + 'windowFeatures' => $this->window_features, + ]; + } + public function setTargetName(?string $targetName): self { $this->target_name = $targetName; @@ -44,14 +54,4 @@ public function getWindowFeatures(): ?string { return $this->window_features; } - - public function getArray(): array - { - return [ - 'targetName' => $this->target_name, - 'width' => $this->width, - 'height' => $this->height, - 'windowFeatures' => $this->window_features, - ]; - } } From d486058a39d1d018e314191df19fc8d1c8275a8b Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 15:02:16 -0600 Subject: [PATCH 24/27] Resolve some issues --- composer.json | 2 +- src/Interfaces/ILtiServiceConnector.php | 10 ++++++---- src/LtiDeployment.php | 2 +- src/LtiLineitem.php | 16 ++++++++-------- src/LtiMessageLaunch.php | 2 +- src/LtiServiceConnector.php | 5 +++-- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index ee8f8d13..1e8a691f 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "scripts": { "test": "phpunit", "lint": [ - "pint -v --test", + "pint --test", "phpstan analyse" ], "lint-fix": "pint -v" diff --git a/src/Interfaces/ILtiServiceConnector.php b/src/Interfaces/ILtiServiceConnector.php index cb3d073b..b77293b2 100644 --- a/src/Interfaces/ILtiServiceConnector.php +++ b/src/Interfaces/ILtiServiceConnector.php @@ -2,16 +2,18 @@ namespace Packback\Lti1p3\Interfaces; -use GuzzleHttp\Psr7\Response; +use Psr\Http\Message\ResponseInterface; /** @internal */ interface ILtiServiceConnector { - public function getAccessToken(ILtiRegistration $registration, array $scopes); + public function getAccessToken(ILtiRegistration $registration, array $scopes): string; - public function makeRequest(IServiceRequest $request); + public function makeRequest(IServiceRequest $request): ResponseInterface; - public function getResponseBody(Response $request): ?array; + public function getResponseBody(ResponseInterface $request): ?array; + + public function getResponseHeaders(ResponseInterface $response): ?array; public function makeServiceRequest( ILtiRegistration $registration, diff --git a/src/LtiDeployment.php b/src/LtiDeployment.php index 24110252..7ac23989 100644 --- a/src/LtiDeployment.php +++ b/src/LtiDeployment.php @@ -11,7 +11,7 @@ public function __construct( ) { } - public static function new($deployment_id) + public static function new($deployment_id): self { return new LtiDeployment($deployment_id); } diff --git a/src/LtiLineitem.php b/src/LtiLineitem.php index 26f8581b..c8e662ed 100644 --- a/src/LtiLineitem.php +++ b/src/LtiLineitem.php @@ -30,6 +30,14 @@ public function __construct(?array $lineitem = null) $this->grades_released = $lineitem['gradesReleased'] ?? null; } + /** + * Static function to allow for method chaining without having to assign to a variable first. + */ + public static function new(?array $lineItem = null): self + { + return new LtiLineitem($lineItem); + } + public function getArray(): array { return [ @@ -45,14 +53,6 @@ public function getArray(): array ]; } - /** - * Static function to allow for method chaining without having to assign to a variable first. - */ - public static function new(?array $lineItem = null): self - { - return new LtiLineitem($lineItem); - } - public function getId() { return $this->id; diff --git a/src/LtiMessageLaunch.php b/src/LtiMessageLaunch.php index 7414f969..ac179b5a 100644 --- a/src/LtiMessageLaunch.php +++ b/src/LtiMessageLaunch.php @@ -414,7 +414,7 @@ protected function validateRegistration(): self $issuerUrl = $this->jwt['body']['iss']; $this->registration = $this->db->findRegistrationByIssuer($issuerUrl, $clientId); - if (empty($this->registration)) { + if (!isset($this->registration)) { throw new LtiException($this->getMissingRegistrationErrorMsg($issuerUrl, $clientId)); } diff --git a/src/LtiServiceConnector.php b/src/LtiServiceConnector.php index e9d76fca..1987dc19 100644 --- a/src/LtiServiceConnector.php +++ b/src/LtiServiceConnector.php @@ -36,7 +36,8 @@ public function getAccessToken(ILtiRegistration $registration, array $scopes): s $accessTokenKey = $this->getAccessTokenCacheKey($registration, $scopes); // Get access token from cache if it exists $accessToken = $this->cache->getAccessToken($accessTokenKey); - if ($accessToken) { + + if (isset($accessToken)) { return $accessToken; } @@ -195,7 +196,7 @@ public static function getLogMessage( $requestBody = $request->getPayload()['body'] ?? null; - if (!empty($requestBody)) { + if (isset($requestBody)) { $contextArray['request_body'] = $requestBody; } From 1a86e9e627af0a9d2843ff3967bd3ee197515196 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 15:06:01 -0600 Subject: [PATCH 25/27] Fix name --- src/Interfaces/ILtiServiceConnector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Interfaces/ILtiServiceConnector.php b/src/Interfaces/ILtiServiceConnector.php index b77293b2..9983d658 100644 --- a/src/Interfaces/ILtiServiceConnector.php +++ b/src/Interfaces/ILtiServiceConnector.php @@ -11,7 +11,7 @@ public function getAccessToken(ILtiRegistration $registration, array $scopes): s public function makeRequest(IServiceRequest $request): ResponseInterface; - public function getResponseBody(ResponseInterface $request): ?array; + public function getResponseBody(ResponseInterface $response): ?array; public function getResponseHeaders(ResponseInterface $response): ?array; From 08bb46e07bdbce8786bc5b969e739b6c202f104e Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 15:31:58 -0600 Subject: [PATCH 26/27] Fix if --- src/LtiServiceConnector.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/LtiServiceConnector.php b/src/LtiServiceConnector.php index 1987dc19..0a73553b 100644 --- a/src/LtiServiceConnector.php +++ b/src/LtiServiceConnector.php @@ -165,7 +165,12 @@ public function getAll( while ($nextUrl) { $response = $this->makeServiceRequest($registration, $scopes, $request); - $page_results = $key === null ? ($response['body'] ?? []) : ($response['body'][$key] ?? []); + if (isset($key)) { + $page_results = $response['body'][$key] ?? []; + } else { + $page_results = $response['body'] ?? []; + } + $results = array_merge($results, $page_results); $nextUrl = $this->getNextUrl($response['headers']); From 9dea6df61581cb91fae975f90060097120080727 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 19 Dec 2023 16:12:43 -0600 Subject: [PATCH 27/27] Add missing interface method --- src/Interfaces/IServiceRequest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Interfaces/IServiceRequest.php b/src/Interfaces/IServiceRequest.php index 6404ce03..d619b159 100644 --- a/src/Interfaces/IServiceRequest.php +++ b/src/Interfaces/IServiceRequest.php @@ -17,6 +17,8 @@ public function setAccessToken(string $accessToken): IServiceRequest; public function setBody(string $body): IServiceRequest; + public function setPayload(array $payload): IServiceRequest; + public function setAccept(string $accept): IServiceRequest; public function setContentType(string $contentType): IServiceRequest;