From c8e61afd00bd2aed6989a7b903169da31fc872d2 Mon Sep 17 00:00:00 2001 From: Christian Einvik Date: Thu, 16 Jan 2025 15:52:55 +0100 Subject: [PATCH] Support adding custom parameters --- src/Lti/Lti11/Context/DeepLinkingProps.php | 10 ++++++++++ src/Lti/Lti11/Mapper/DeepLinking/ContentItemMapper.php | 4 ++-- .../Serializer/DeepLinking/LtiLinkItemSerializer.php | 9 +++++---- src/Lti/Message/DeepLinking/LtiLinkItem.php | 4 ++-- tests/Lti/Lti11/Mapper/ContentItemsMapperTest.php | 9 +++++++++ .../Lti11/Serializer/ContentItemsSerializerTest.php | 8 ++++++++ 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Lti/Lti11/Context/DeepLinkingProps.php b/src/Lti/Lti11/Context/DeepLinkingProps.php index fcb8361..135f514 100644 --- a/src/Lti/Lti11/Context/DeepLinkingProps.php +++ b/src/Lti/Lti11/Context/DeepLinkingProps.php @@ -6,6 +6,7 @@ use Cerpus\EdlibResourceKit\Lti\Message\DeepLinking\PresentationDocumentTarget; use DateTimeImmutable; + use function array_filter; use function array_map; use function preg_replace; @@ -15,6 +16,7 @@ final class DeepLinkingProps public const JSONLD_VOCAB = 'http://purl.imsglobal.org/ctx/lti/v1/ContentItem'; public const COPY_ADVICE = 'copyAdvice'; + public const CUSTOM = 'custom'; public const EXPIRES_AT = 'expiresAt'; public const DISPLAY_HEIGHT = 'displayHeight'; public const DISPLAY_WIDTH = 'displayWidth'; @@ -41,6 +43,7 @@ final class DeepLinkingProps public const TYPE_FLOAT = 'http://www.w3.org/2001/XMLSchema#float'; public const TYPE_INTEGER = 'http://www.w3.org/2001/XMLSchema#integer'; public const TYPE_NORMALIZED_STRING = 'http://www.w3.org/2001/XMLSchema#normalizedString'; + public const TYPE_STRING = 'http://www.w3.org/2001/XMLSchema#string'; public static function getCopyAdvice(array $data): bool|null { @@ -116,6 +119,13 @@ public static function getWindowTarget(array $data): string|null return self::getOfType($data, self::WINDOW_TARGET, self::TYPE_NORMALIZED_STRING); } + public static function getCustom(array $data): array|null + { + $custom = self::getArrayOfType($data, self::CUSTOM, self::TYPE_STRING); + + return empty($custom) ? null : $custom; + } + public static function getOfType(array $data, string $prop, string $type): mixed { $value = $data[$prop] ?? null; diff --git a/src/Lti/Lti11/Mapper/DeepLinking/ContentItemMapper.php b/src/Lti/Lti11/Mapper/DeepLinking/ContentItemMapper.php index 3dff828..33594bd 100644 --- a/src/Lti/Lti11/Mapper/DeepLinking/ContentItemMapper.php +++ b/src/Lti/Lti11/Mapper/DeepLinking/ContentItemMapper.php @@ -42,8 +42,8 @@ public function map(array $data): ContentItem $thumbnail, Prop::getTitle($data), Prop::getUrl($data), - custom: [], // TODO - lineItem: $lineItem, + Prop::getCustom($data), + $lineItem, ); } diff --git a/src/Lti/Lti11/Serializer/DeepLinking/LtiLinkItemSerializer.php b/src/Lti/Lti11/Serializer/DeepLinking/LtiLinkItemSerializer.php index cd5e12e..a5409b9 100644 --- a/src/Lti/Lti11/Serializer/DeepLinking/LtiLinkItemSerializer.php +++ b/src/Lti/Lti11/Serializer/DeepLinking/LtiLinkItemSerializer.php @@ -10,14 +10,11 @@ final readonly class LtiLinkItemSerializer implements LtiLinkItemSerializerInterface { public function __construct( - private ContentItemSerializer $serializer = new ContentItemSerializer(), + private ContentItemSerializerInterface $serializer = new ContentItemSerializer(), private LineItemSerializerInterface $lineItemSerializer = new LineItemSerializer(), ) { } - /** - * @todo Handle the "custom" property - */ public function serialize(LtiLinkItem $item): array { $serialized = [ @@ -31,6 +28,10 @@ public function serialize(LtiLinkItem $item): array ->serialize($item->getLineItem()); } + if (!empty($item->getCustom())) { + $serialized[Prop::CUSTOM] = $item->getCustom(); + } + return $serialized; } } diff --git a/src/Lti/Message/DeepLinking/LtiLinkItem.php b/src/Lti/Message/DeepLinking/LtiLinkItem.php index 6e22fcc..74493c4 100644 --- a/src/Lti/Message/DeepLinking/LtiLinkItem.php +++ b/src/Lti/Message/DeepLinking/LtiLinkItem.php @@ -17,7 +17,7 @@ public function __construct( Image|null $thumbnail = null, string|null $title = null, string|null $url = null, - private readonly array $custom = [], + private readonly array|null $custom = null, private readonly LineItem|null $lineItem = null, ) { parent::__construct( @@ -31,7 +31,7 @@ public function __construct( ); } - public function getCustom(): array + public function getCustom(): array|null { return $this->custom; } diff --git a/tests/Lti/Lti11/Mapper/ContentItemsMapperTest.php b/tests/Lti/Lti11/Mapper/ContentItemsMapperTest.php index 9d7e2c9..c353e02 100644 --- a/tests/Lti/Lti11/Mapper/ContentItemsMapperTest.php +++ b/tests/Lti/Lti11/Mapper/ContentItemsMapperTest.php @@ -60,6 +60,10 @@ public function testItMapsAllTheStuff(): void 'totalMaximum' => 42.0, ], ], + 'custom' => [ + 'level' => 'expert', + 'numericLevel' => 42, + ], ], [ '@type' => 'FileItem', @@ -105,6 +109,11 @@ public function testItMapsAllTheStuff(): void $this->assertSame(39.5, $score->getNormalMaximum()); $this->assertSame(2.5, $score->getExtraCreditMaximum()); $this->assertSame(42.0, $score->getTotalMaximum()); + + $custom = $contentItems[0]->getCustom(); + $this->assertIsArray($custom); + $this->assertSame('expert', $custom['level']); + $this->assertSame(42, $custom['numericLevel']); } public function testMapsDataWithAdditionalJsonldContexts(): void diff --git a/tests/Lti/Lti11/Serializer/ContentItemsSerializerTest.php b/tests/Lti/Lti11/Serializer/ContentItemsSerializerTest.php index e17d098..9cc7ccf 100644 --- a/tests/Lti/Lti11/Serializer/ContentItemsSerializerTest.php +++ b/tests/Lti/Lti11/Serializer/ContentItemsSerializerTest.php @@ -70,6 +70,10 @@ public function testSerializesContentItems(): array text: 'A cool text description of my cool content', title: 'My Cool Content', url: 'https://example.com/lti', + custom: [ + 'level' => 'expert', + 'numericLevel' => 42, + ], lineItem: new LineItem( new ScoreConstraints(39.5, 2.5) ), @@ -118,6 +122,10 @@ public function testSerializesContentItems(): array 'totalMaximum' => 42.0, ], ], + 'custom' => [ + 'level' => 'expert', + 'numericLevel' => 42, + ], ], [ '@type' => 'FileItem',