Last active
September 13, 2023 14:30
-
-
Save lsloan/3a0895cc97bff7373737e7c6b8c6bdad to your computer and use it in GitHub Desktop.
Caliper: An example of using caliper-php to send an event with custom action and context.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require_once 'vendor/autoload.php'; | |
use IMSGlobal\Caliper\actions\Action; | |
use IMSGlobal\Caliper\Client; | |
use IMSGlobal\Caliper\context\Context; | |
use IMSGlobal\Caliper\entities\agent\Person; | |
use IMSGlobal\Caliper\entities\agent\SoftwareApplication; | |
use IMSGlobal\Caliper\entities\media\MediaLocation; | |
use IMSGlobal\Caliper\entities\media\VideoObject; | |
use IMSGlobal\Caliper\events\MediaEvent; | |
use IMSGlobal\Caliper\Options; | |
use IMSGlobal\Caliper\request\HttpRequestor; | |
use IMSGlobal\Caliper\Sensor; | |
use IMSGlobal\Caliper\util; | |
class CustomAction extends Action { | |
const | |
STREAMED_TO_TIME = 'StreamedToTime'; | |
} | |
// In order for UDP to accept a custom action, a custom context must be used. | |
// NOTE: If an array of context URIs is used, the serialization code in | |
// caliper-php gives warnings, like… | |
// `PHP Warning: Array to string conversion in /umich-caliper-php/src/util/BasicEnum.php on line 104` | |
// These are harmless, but annoying. This will be addressed in a future | |
// release of caliper-php. | |
// As a workaround to avoid warnings, use a single URI instead of | |
// multiple. A single, non-standard URI is good enough to indicate to UDP | |
// that this event is special and UDP will accept the custom action. | |
// Technically, the multiple context should be used here. | |
class CustomContext extends Context { | |
const | |
SINGLE = 'http://example.edu/caliper/context/v1p1_custom.json', | |
MULTIPLE = [ | |
parent::CONTEXT, | |
self::SINGLE], | |
__default = self::SINGLE; | |
} | |
date_default_timezone_set( | |
DateTimeZone::listIdentifiers(DateTimeZone::UTC)[0]); | |
$sensorId = 'umich_caliper_example'; | |
$options = (new Options()) | |
->setApiKey('super_secret_key') | |
->setDebug(true) | |
->setHost('https://lti.tools/caliper/event?key=' . $sensorId); | |
$sensor = (new Sensor($sensorId)) | |
->registerClient('http', | |
new Client('clientId', | |
$options)); | |
$video = (new VideoObject('https://example.edu/videos/' . | |
util\UuidUtil::makeUuidV4())) | |
->setDuration('PT59M59S') | |
->setName('A Highly Important Instructional Video') | |
->setDateCreated(new DateTime('2016-05-19')); | |
// Current minute and seconds as pseudorandom video time | |
$currentVideoTime = date('\P\Ti\Ms\S'); | |
$event = (new MediaEvent()) | |
// Using a subclass of Context seems like a complicated way to set context. | |
// Ideally, the context of events should be based on the context(s) | |
// of their entities. | |
->setContext(new CustomContext()) | |
// Example of using multiple contexts. | |
// ->setContext(new CustomContext(CustomContext::MULTIPLE)) | |
// Ideally, caliper-php should also set context on actions, but it | |
// doesn't. If it did, the event context could be based on the action | |
// context, as described above. | |
->setAction(new CustomAction(CustomAction::STREAMED_TO_TIME)) | |
->setActor(new Person('https://example.edu/user/' . | |
get_current_user())) | |
->setEventTime(util\TimestampUtil::makeDateTimeWithSecondsFraction()) | |
->setObject($video) | |
// The intent of the `StreamedToTime` custom action is to mark when | |
// the media playback reaches a quartile. There aren't any Caliper | |
// media entities which encode the percentage of playback (yet), | |
// so it can be encoded in an `extensions` property of an appropriate | |
// entity for now. | |
->setTarget( | |
(new MediaLocation($video->getId() . '#currentTime=' . $currentVideoTime)) | |
->setIsPartOf($video->makeReference()) | |
->setCurrentTime($currentVideoTime) | |
->setExtensions([ | |
'percentage' => 0.25, | |
]) | |
) | |
->setEdApp((new SoftwareApplication('https://example.edu/video_player')) | |
->setVersion('1.2') | |
->setDateCreated(new DateTime('2015-02-09T12:25')) | |
); | |
/* | |
* NOTE: The next few blocks of code are for debugging and demonstration | |
* purposes. It is not necessary for sending events. | |
*/ | |
// Makes JSON for event, but includes attributes without values | |
// print json_encode($event->jsonSerialize(), | |
// $options->getJsonEncodeOptions()) . PHP_EOL; | |
// Requestor-based serialization removes attributes without values and | |
// includes an envelope. | |
$requestor = new HttpRequestor($options); | |
$envelope = $requestor->createEnvelope($sensor, $event); | |
// Using `@` here suppresses warnings about context array instead of string. | |
// However, all other warnings are also suppressed, so be careful. | |
// It may be better to use a single string context instead of an array. | |
$payload = $requestor->serializeData($envelope); | |
print $payload . PHP_EOL; | |
/* | |
* End of debugging and demonstration code. | |
*/ | |
// As above, `@` suppresses warnings about multiple contexts. Caveat emptor. | |
try { | |
@$sensor->send($sensor, $event); | |
} catch (\RuntimeException $sendException) { | |
echo 'Error sending event: ' . $sendException->getMessage() . PHP_EOL; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment