External tool source
LTI Source Plugins
The External tool supports sub plugins that live under the mod/lti/source directory with the plugin type of ltisource. The purpose of a LTI source plugin is to extend the functionality of the External Tool activity.
The LTI source plugins support the following standard plugin features:
- Language file: mod/lti/source/pluginname/lang/en/ltisource_pluginname.php
- Plugin upgrade API under the mod/lti/source/pluginname/db directory.
Extending the LTI protocol
The most powerful extension that the LTI source plugins can perform is to extend the LTI services provided by the External Tool activity. All incoming requests are handled by mod/lti/service.php and all standard LTI requests are automatically handled. But, if the request is non-standard, then a LTI source plugin can have an opportunity to handle the request.
The request is routed to the LTI source plugin by using the message type. For example, let's say this request was sent to the External Tool:
<?xml version="1.0" encoding="UTF-8"?>
<imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
<imsx_POXHeader>
<imsx_POXRequestHeaderInfo>
<imsx_version>V1.0</imsx_version>
<imsx_messageIdentifier>999998123</imsx_messageIdentifier>
</imsx_POXRequestHeaderInfo>
</imsx_POXHeader>
<imsx_POXBody>
<myCustomRequest><!-- LOOK HERE! -->
<myRecord><!-- This can be named whatever you want -->
<sourcedGUID>
<sourcedId>3124567</sourcedId>
</sourcedGUID>
<!-- You custom data in XML format -->
</myRecord>
</myCustomRequest>
</imsx_POXBody>
</imsx_POXEnvelopeRequest>
In the above request, the message type is myCustomRequest. Since this is not a standard request, a LTI source plugin can handle it. We can do this by adding a LTI source plugin and for this example, we will call it widget. Then, in our ltisource_widget plugin, we must define a specific function In order to handle the request. The function name takes on the form of component_messageType. So, for our above request example we would create mod/lti/source/widget/lib.php and add this function to the file:
/**
* Handle a custom widget request.
*
* @param object $data The LTI request details
*/
function ltisource_widget_myCustomRequest($data) {
$data->body; // The raw LTI request XML body.
$data->xml; // A SimpleXMLElement of the XML body.
$data->messageid; // The value of the <imsx_messageIdentifier> element in the request.
$data->messagetype; // The message type.
$data->consumerkey; // OAuth consumer key.
$data->sharedsecret; // The shared secret used to verify the request body.
// Do your custom work here.
// Throw exceptions on error, they will be sent back appropriately.
// When done, echo out your response XML.
$responsexml = lti_get_response_xml(
'success',
'Widget handled',
$data->messageid,
$data->messagetype
);
echo $responsexml->asXML();
}
Word of warning: If more than one LTI source plugins implement a function for handling the myCustomRequest message, then an exception will be thrown. So, when coming up with names for your message types, try to keep them unique and perhaps prefix them with something unique about your service.
And that's about it! With this extension point, you can build deep integrations with external services all while communicating through the LTI protocol.
Overall, the following has a narrow use case, but it might be expanded in the future.
A LTI source plugin can add itself to the add activities menu by implementing a component_get_types function in its lib.php file. So, for example, if our LTI source plugin was widget, then in mod/lti/source/widget/lib.php we would add the following function:
function ltisource_widget_get_types() {
$types = array();
$types[] = (object) array(
'modclass' => MOD_CLASS_ACTIVITY,
'type' => 'lti&type=widget',
'typestr' => get_string('addwidget', 'ltisource_widget'),
'help' => get_string('addwidget_help', 'ltisource_widget'),
);
return $types;
}
But, this on its own doesn't actually do much at the moment. You must also add another callback that gets called from the External Tool add instance form. The callback takes on the form of component_add_instance_hook. So, also add this function to mod/lti/source/widget/lib.php:
function ltisource_widget_add_instance_hook() {
// Do custom work here.
}
At this point, the most common use case is to redirect to an external site to browse widget-like content. Then the Extending the LTI protocol section can be used to create widget-like content in Moodle.