ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
ilCmiXapiLaunchGUI Class Reference
+ Collaboration diagram for ilCmiXapiLaunchGUI:

Public Member Functions

 __construct (ilObjCmiXapi $object)
 
 executeCommand ()
 

Data Fields

const XAPI_PROXY_ENDPOINT = 'components/ILIAS/CmiXapi/xapiproxy.php'
 

Protected Member Functions

 launchCmd ()
 
 buildLaunchLink (string $token)
 
 getLaunchParameters (string $token)
 
 getAuthTokenFetchLink ()
 
 buildAuthTokenFetchParam ()
 
 getValidToken ()
 
 initCmixUser ()
 
 getCmi5LearnerPreferences ()
 
 CMI5preLaunch (string $token)
 Prelaunch post cmi5LearnerPreference (agent profile) post LMS.LaunchData. More...
 

Protected Attributes

ilObjCmiXapi $object
 
ilCmiXapiUser $cmixUser
 
bool $plugin = false
 

Private Member Functions

 log ()
 

Private Attributes

ilObjUser $user
 
ilCtrlInterface $ctrl
 

Detailed Description

Definition at line 30 of file class.ilCmiXapiLaunchGUI.php.

Constructor & Destructor Documentation

◆ __construct()

ilCmiXapiLaunchGUI::__construct ( ilObjCmiXapi  $object)

Definition at line 44 of file class.ilCmiXapiLaunchGUI.php.

45 {
46 $this->object = $object;
47 }

References $object.

Member Function Documentation

◆ buildAuthTokenFetchParam()

ilCmiXapiLaunchGUI::buildAuthTokenFetchParam ( )
protected
Exceptions
ilCmiXapiException

Definition at line 154 of file class.ilCmiXapiLaunchGUI.php.

154 : string
155 {
156 $params = [
157 session_name() => session_id(),
158 'obj_id' => $this->object->getId(),
159 'ref_id' => $this->object->getRefId(),
160 'ilClientId' => CLIENT_ID
161 ];
162
163 $encryptionKey = ilCmiXapiAuthToken::getWacSalt();
164 return urlencode(base64_encode(openssl_encrypt(
165 json_encode($params),
167 $encryptionKey,
168 0,
170 )));
171 }
const CLIENT_ID
Definition: constants.php:41
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:31

References $params, CLIENT_ID, ilCmiXapiAuthToken\getWacSalt(), ilCmiXapiAuthToken\OPENSSL_ENCRYPTION_METHOD, and ilCmiXapiAuthToken\OPENSSL_IV.

Referenced by getAuthTokenFetchLink().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildLaunchLink()

ilCmiXapiLaunchGUI::buildLaunchLink ( string  $token)
protected

Definition at line 69 of file class.ilCmiXapiLaunchGUI.php.

69 : string
70 {
71 $launchLink = "";
72
73 if ($this->object->getSourceType() == ilObjCmiXapi::SRC_TYPE_REMOTE) {
74 $launchLink = $this->object->getLaunchUrl();
75 } elseif ($this->object->getSourceType() == ilObjCmiXapi::SRC_TYPE_LOCAL) {
76 if (preg_match("/^(https?:\/\/)/", $this->object->getLaunchUrl()) == 1) {
77 $launchLink = $this->object->getLaunchUrl();
78 } else {
79 $launchLink = implode('/', [
80 ILIAS_HTTP_PATH,
83 ]);
84
85 $launchLink .= DIRECTORY_SEPARATOR . $this->object->getLaunchUrl();
86 }
87 }
88
89 foreach ($this->getLaunchParameters($token) as $paramName => $paramValue) {
90 $launchLink = ilUtil::appendUrlParameterString($launchLink, "{$paramName}={$paramValue}");
91 }
92
93 return $launchLink;
94 }
getLaunchParameters(string $token)
static getWebspaceDir(string $mode="filesystem")
get webspace directory
static appendUrlParameterString(string $a_url, string $a_par, bool $xml_style=false)
$token
Definition: xapitoken.php:70

References ilUtil\appendUrlParameterString(), getLaunchParameters(), ilFileUtils\getWebspaceDir(), ILIAS\Repository\object(), ilCmiXapiContentUploadImporter\RELATIVE_CONTENT_DIRECTORY_NAMEBASE, ilObjCmiXapi\SRC_TYPE_LOCAL, and ilObjCmiXapi\SRC_TYPE_REMOTE.

Referenced by launchCmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ CMI5preLaunch()

ilCmiXapiLaunchGUI::CMI5preLaunch ( string  $token)
protected

Prelaunch post cmi5LearnerPreference (agent profile) post LMS.LaunchData.

Returns
array<string, mixed>
Exceptions
ilCmiXapiException
ilDateTimeException

Definition at line 223 of file class.ilCmiXapiLaunchGUI.php.

223 : array
224 {
225 $duration = '';
226 $lrsType = $this->object->getLrsType();
227 $defaultLrs = $lrsType->getLrsEndpoint();
228 //$fallbackLrs = $lrsType->getLrsFallbackEndpoint();
229 $defaultBasicAuth = $lrsType->getBasicAuth();
230 //$fallbackBasicAuth = $lrsType->getFallbackBasicAuth();
231 $defaultHeaders = [
232 'X-Experience-API-Version' => '1.0.3',
233 'Authorization' => $defaultBasicAuth,
234 'Content-Type' => 'application/json;charset=utf-8',
235 'Cache-Control' => 'no-cache, no-store, must-revalidate'
236 ];
237
238 $registration = $this->cmixUser->getRegistration();
239 // for old CMI5 Content after switch commit but before cmi5 bugfix
240 if ($registration == '') {
241 $registration = ilCmiXapiUser::generateRegistration($this->object, $this->user);
242 }
243
244 $activityId = $this->object->getActivityId();
245
246 // profile
247 $profileParams = [];
248 $defaultAgentProfileUrl = $defaultLrs . "/agents/profile";
249 $profileParams['agent'] = json_encode($this->object->getStatementActor($this->cmixUser));
250 $profileParams['profileId'] = 'cmi5LearnerPreferences';
251 $defaultProfileUrl = $defaultAgentProfileUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($profileParams);
252
253 // launchData
254 $launchDataParams = [];
255 $defaultStateUrl = $defaultLrs . "/activities/state";
256 //$launchDataParams['agent'] = $this->buildCmi5ActorParameter();
257 $launchDataParams['agent'] = json_encode($this->object->getStatementActor($this->cmixUser));
258 $launchDataParams['activityId'] = $activityId;
259 $launchDataParams['activity_id'] = $activityId;
260 $launchDataParams['registration'] = $registration;
261 $launchDataParams['stateId'] = 'LMS.LaunchData';
262 $defaultLaunchDataUrl = $defaultStateUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($launchDataParams);
263 $cmi5LearnerPreferencesObj = $this->getCmi5LearnerPreferences();
264 $cmi5LearnerPreferences = json_encode($cmi5LearnerPreferencesObj);
265 $lang = $cmi5LearnerPreferencesObj['languagePreference'];
266 $cmi5_session = ilObjCmiXapi::guidv4();
268 $oldSession = $tokenObject->getCmi5Session();
269 $oldSessionLaunchedTimestamp = '';
270 $abandoned = false;
271 // cmi5_session already exists?
272 if ($oldSession != null && !empty($oldSession)) {
273 $oldSessionData = json_decode($tokenObject->getCmi5SessionData());
274 $oldSessionLaunchedTimestamp = $oldSessionData->launchedTimestamp;
275 $tokenObject->delete();
276 $token = $this->getValidToken();
278 $lastStatement = $this->object->getLastStatement($oldSession);
279 // should never be 'terminated', because terminated statement is sniffed from proxy -> token delete
280 if (isset($lastStatement[0]['statement']['verb']['id']) && $lastStatement[0]['statement']['verb']['id'] != ilCmiXapiVerbList::getInstance()->getVerbUri('terminated')) {
281 $abandoned = true;
282 $start = new DateTime($oldSessionLaunchedTimestamp);
283 $end = new DateTime($lastStatement[0]['statement']['timestamp']);
284 $diff = $end->diff($start);
286 }
287 }
288 // satisfied on launch?
289 // see: https://github.com/AICC/CMI-5_Spec_Current/blob/quartz/cmi5_spec.md#moveon
290 // https://aicc.github.io/CMI-5_Spec_Current/samples/
291 // Session that includes the absolute minimum data, and is associated with a NotApplicable Move On criteria
292 // which results in immediate satisfaction of the course upon registration creation. Includes Satisfied Statement.
293 $satisfied = false;
294 $lpMode = $this->object->getLPMode();
295 // only do this, if we decide to map the moveOn NotApplicable to ilLPObjSettings::LP_MODE_DEACTIVATED on import and settings editing
296 // and what about user result status?
297 if ($lpMode === ilLPObjSettings::LP_MODE_DEACTIVATED) {
298 $satisfied = true;
299 }
300
301 $tokenObject->setCmi5Session($cmi5_session);
302 $sessionData = array();
303 $sessionData['cmi5LearnerPreferences'] = $cmi5LearnerPreferencesObj;
304 //https://www.php.net/manual/de/class.dateinterval.php
305 $now = new ilCmiXapiDateTime(time(), IL_CAL_UNIX);
306 $sessionData['launchedTimestamp'] = $now->toXapiTimestamp(); // required for abandoned statement duration, don't want another roundtrip to lrs ...puhhh
307 $tokenObject->setCmi5SessionData(json_encode($sessionData));
308 $tokenObject->update();
309 $defaultStatementsUrl = $defaultLrs . "/statements";
310
311 // launchedStatement
312 $launchData = json_encode($this->object->getLaunchData($this->cmixUser, $lang));
313 $launchedStatement = $this->object->getLaunchedStatement($this->cmixUser);
314 $launchedStatementParams = [];
315 $launchedStatementParams['statementId'] = $launchedStatement['id'];
316 $defaultLaunchedStatementUrl = $defaultStatementsUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($launchedStatementParams);
317
318 // abandonedStatement
319 if ($abandoned) {
320 $abandonedStatement = $this->object->getAbandonedStatement($oldSession, $duration, $this->cmixUser);
321 $abandonedStatementParams = [];
322 $abandonedStatementParams['statementId'] = $abandonedStatement['id'];
323 $defaultAbandonedStatementUrl = $defaultStatementsUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($abandonedStatementParams);
324 }
325 // abandonedStatement
326 if ($satisfied) {
327 $satisfiedStatement = $this->object->getSatisfiedStatement($this->cmixUser);
328 $satisfiedStatementParams = [];
329 $satisfiedStatementParams['statementId'] = $satisfiedStatement['id'];
330 $defaultSatisfiedStatementUrl = $defaultStatementsUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($satisfiedStatementParams);
331 }
332 $client = new GuzzleHttp\Client();
333 $req_opts = array(
334 GuzzleHttp\RequestOptions::VERIFY => true,
335 GuzzleHttp\RequestOptions::CONNECT_TIMEOUT => 10,
336 GuzzleHttp\RequestOptions::HTTP_ERRORS => false
337 );
338 $defaultProfileRequest = new GuzzleHttp\Psr7\Request(
339 'POST',
340 $defaultProfileUrl,
341 $defaultHeaders,
342 $cmi5LearnerPreferences
343 );
344 $defaultLaunchDataRequest = new GuzzleHttp\Psr7\Request(
345 'PUT',
346 $defaultLaunchDataUrl,
347 $defaultHeaders,
348 $launchData
349 );
350 $defaultLaunchedStatementRequest = new GuzzleHttp\Psr7\Request(
351 'PUT',
352 $defaultLaunchedStatementUrl,
353 $defaultHeaders,
354 json_encode($launchedStatement)
355 );
356 if ($abandoned) {
357 $defaultAbandonedStatementRequest = new GuzzleHttp\Psr7\Request(
358 'PUT',
359 $defaultAbandonedStatementUrl,
360 $defaultHeaders,
361 json_encode($abandonedStatement)
362 );
363 }
364 if ($satisfied) {
365 $defaultSatisfiedStatementRequest = new GuzzleHttp\Psr7\Request(
366 'PUT',
367 $defaultSatisfiedStatementUrl,
368 $defaultHeaders,
369 json_encode($satisfiedStatement)
370 );
371 }
372 $promises = array();
373 $promises['defaultProfile'] = $client->sendAsync($defaultProfileRequest, $req_opts);
374 $promises['defaultLaunchData'] = $client->sendAsync($defaultLaunchDataRequest, $req_opts);
375 $promises['defaultLaunchedStatement'] = $client->sendAsync($defaultLaunchedStatementRequest, $req_opts);
376 if ($abandoned) {
377 $promises['defaultAbandonedStatement'] = $client->sendAsync($defaultAbandonedStatementRequest, $req_opts);
378 }
379 if ($satisfied) {
380 $promises['defaultSatisfiedStatement'] = $client->sendAsync($defaultSatisfiedStatementRequest, $req_opts);
381 }
382 try {
383 $responses = GuzzleHttp\Promise\Utils::settle($promises)->wait();
384 $body = '';
385 foreach ($responses as $response) {
387 }
388 } catch (Exception $e) {
389 $this->log()->error('error:' . $e->getMessage());
390 }
391 return array('cmi5_session' => $cmi5_session, 'token' => $token);
392 }
$duration
const IL_CAL_UNIX
static buildQuery(array $params, $encoding=PHP_QUERY_RFC3986)
static checkResponse(array $response, &$body, array $allowedStatus=[200, 204])
static getInstanceByToken(string $token)
static dateIntervalToISO860Duration(\DateInterval $d)
static generateRegistration(ilObjCmiXapi $obj, ilObjUser $user)
static guidv4(?string $data=null)
$client
$lang
Definition: xapiexit.php:25
$response
Definition: xapitoken.php:93

References $client, $duration, Vendor\Package\$e, $lang, $response, $token, ilCmiXapiAbstractRequest\buildQuery(), ilCmiXapiAbstractRequest\checkResponse(), ilCmiXapiDateTime\dateIntervalToISO860Duration(), ilCmiXapiUser\generateRegistration(), getCmi5LearnerPreferences(), ilCmiXapiVerbList\getInstance(), ilCmiXapiAuthToken\getInstanceByToken(), getValidToken(), ilObjCmiXapi\guidv4(), IL_CAL_UNIX, log(), ilLPObjSettings\LP_MODE_DEACTIVATED, ILIAS\Repository\object(), and ILIAS\Repository\user().

Referenced by launchCmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ executeCommand()

ilCmiXapiLaunchGUI::executeCommand ( )

Definition at line 49 of file class.ilCmiXapiLaunchGUI.php.

49 : void
50 {
51 global $DIC;
52 $this->user = $DIC->user();
53 $this->ctrl = $DIC->ctrl();
54 $this->launchCmd();
55 }
global $DIC
Definition: shib_login.php:26

References $DIC, ILIAS\Repository\ctrl(), launchCmd(), and ILIAS\Repository\user().

+ Here is the call graph for this function:

◆ getAuthTokenFetchLink()

ilCmiXapiLaunchGUI::getAuthTokenFetchLink ( )
protected
Exceptions
ilCmiXapiException

Definition at line 140 of file class.ilCmiXapiLaunchGUI.php.

140 : string
141 {
142 $link = implode('/', [
143 ILIAS_HTTP_PATH, 'components/ILIAS', 'CmiXapi', 'xapitoken.php'
144 ]);
145
147
148 return iLUtil::appendUrlParameterString($link, "param={$param}");
149 }
$param
Definition: xapitoken.php:46

References $param, and buildAuthTokenFetchParam().

Referenced by getLaunchParameters().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getCmi5LearnerPreferences()

ilCmiXapiLaunchGUI::getCmi5LearnerPreferences ( )
protected
Returns
array<string, string>

Definition at line 205 of file class.ilCmiXapiLaunchGUI.php.

205 : array
206 {
207 $language = $this->user->getLanguage();
208 $audio = "on";
209 return [
210 "languagePreference" => "{$language}",
211 "audioPreference" => "{$audio}"
212 ];
213 }

References ILIAS\Repository\user().

Referenced by CMI5preLaunch().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getLaunchParameters()

ilCmiXapiLaunchGUI::getLaunchParameters ( string  $token)
protected
Returns
array<string, mixed>

Definition at line 99 of file class.ilCmiXapiLaunchGUI.php.

99 : array
100 {
101 $params = [];
102
103 if ($this->object->isBypassProxyEnabled()) {
104 $params['endpoint'] = urlencode(rtrim($this->object->getLrsType()->getLrsEndpoint(), '/') . '/');
105 } else {
106 $params['endpoint'] = urlencode(rtrim(ILIAS_HTTP_PATH . '/' . self::XAPI_PROXY_ENDPOINT, '/') . '/');
107 }
108
109 if ($this->object->isAuthFetchUrlEnabled()) {
110 $params['fetch'] = urlencode($this->getAuthTokenFetchLink());
111 } else {
112 if ($this->object->isBypassProxyEnabled()) {
113 $params['auth'] = urlencode($this->object->getLrsType()->getBasicAuth());
114 } else {
115 $params['auth'] = urlencode('Basic ' . base64_encode(
116 CLIENT_ID . ':' . $token
117 ));
118 }
119 }
120
121 $params['activity_id'] = urlencode($this->object->getActivityId());
122 $params['activityId'] = urlencode($this->object->getActivityId());
123 $params['actor'] = urlencode(json_encode($this->object->getStatementActor($this->cmixUser)));
124 if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5) {
125 $registration = $this->cmixUser->getRegistration();
126 // for old CMI5 Content after switch commit but before cmi5 bugfix
127 if ($registration == '') {
128 $registration = ilCmiXapiUser::generateRegistration($this->object, $this->user);
129 }
130 $params['registration'] = $registration;
131 } else {
132 $params['registration'] = urlencode((string) ilCmiXapiUser::generateRegistration($this->object, $this->user));
133 }
134 return $params;
135 }

References $params, $token, CLIENT_ID, ilObjCmiXapi\CONT_TYPE_CMI5, ilCmiXapiUser\generateRegistration(), getAuthTokenFetchLink(), ILIAS\Repository\object(), and ILIAS\Repository\user().

Referenced by buildLaunchLink().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getValidToken()

ilCmiXapiLaunchGUI::getValidToken ( )
protected

Definition at line 173 of file class.ilCmiXapiLaunchGUI.php.

173 : string
174 {
176 $this->user->getId(),
177 $this->object->getRefId(),
178 $this->object->getId(),
179 $this->object->getLrsType()->getTypeId()
180 );
181 return $token;
182 }
static fillToken(int $usrId, int $refId, int $objId, int $lrsTypeId=0)

References $token, ilCmiXapiAuthToken\fillToken(), and ILIAS\Repository\user().

Referenced by CMI5preLaunch(), and launchCmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ initCmixUser()

ilCmiXapiLaunchGUI::initCmixUser ( )
protected

Definition at line 184 of file class.ilCmiXapiLaunchGUI.php.

184 : void
185 {
186 $this->cmixUser = new ilCmiXapiUser($this->object->getId(), $this->user->getId(), $this->object->getPrivacyIdent());
187 $user_ident = $this->cmixUser->getUsrIdent();
188 if ($user_ident == '' || $user_ident == null) {
189 $user_ident = ilCmiXapiUser::getIdent($this->object->getPrivacyIdent(), $this->user);
190 $this->cmixUser->setUsrIdent($user_ident);
191
192 if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5) {
193 $this->cmixUser->setRegistration((string) ilCmiXapiUser::generateCMI5Registration($this->object->getId(), $this->user->getId()));
194 }
195 $this->cmixUser->save();
196 if (!ilObjUser::_isAnonymous($this->user->getId())) {
197 ilLPStatusWrapper::_updateStatus($this->object->getId(), $this->user->getId());
198 }
199 }
200 }
static getIdent(int $userIdentMode, ilObjUser $user)
static generateCMI5Registration(int $objId, int $usrId)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
static _isAnonymous(int $usr_id)

References ilObjUser\_isAnonymous(), ilLPStatusWrapper\_updateStatus(), ilObjCmiXapi\CONT_TYPE_CMI5, ilCmiXapiUser\generateCMI5Registration(), ilCmiXapiUser\getIdent(), ILIAS\Repository\object(), and ILIAS\Repository\user().

Referenced by launchCmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ launchCmd()

ilCmiXapiLaunchGUI::launchCmd ( )
protected

Definition at line 57 of file class.ilCmiXapiLaunchGUI.php.

57 : void
58 {
59 $this->initCmixUser();
60 $token = $this->getValidToken();
61 if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5) {
62 $ret = $this->CMI5preLaunch($token);
63 $token = $ret['token'];
64 }
65 $launchLink = $this->buildLaunchLink($token);
66 $this->ctrl->redirectToURL($launchLink);
67 }
CMI5preLaunch(string $token)
Prelaunch post cmi5LearnerPreference (agent profile) post LMS.LaunchData.

References $token, buildLaunchLink(), CMI5preLaunch(), ilObjCmiXapi\CONT_TYPE_CMI5, ILIAS\Repository\ctrl(), getValidToken(), initCmixUser(), and ILIAS\Repository\object().

Referenced by executeCommand().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ log()

ilCmiXapiLaunchGUI::log ( )
private
Returns
ilLogger

Definition at line 397 of file class.ilCmiXapiLaunchGUI.php.

397 : ilLogger
398 {
399 if ($this->plugin) {
400 global $log;
401 return $log;
402 } else {
403 return \ilLoggerFactory::getLogger('cmix');
404 }
405 }
Component logger with individual log levels by component id.
$log
Definition: ltiresult.php:34

References $log.

Referenced by CMI5preLaunch().

+ Here is the caller graph for this function:

Field Documentation

◆ $cmixUser

ilCmiXapiUser ilCmiXapiLaunchGUI::$cmixUser
protected

Definition at line 36 of file class.ilCmiXapiLaunchGUI.php.

◆ $ctrl

ilCtrlInterface ilCmiXapiLaunchGUI::$ctrl
private

Definition at line 42 of file class.ilCmiXapiLaunchGUI.php.

◆ $object

ilObjCmiXapi ilCmiXapiLaunchGUI::$object
protected

Definition at line 34 of file class.ilCmiXapiLaunchGUI.php.

Referenced by __construct().

◆ $plugin

bool ilCmiXapiLaunchGUI::$plugin = false
protected

Definition at line 38 of file class.ilCmiXapiLaunchGUI.php.

◆ $user

ilObjUser ilCmiXapiLaunchGUI::$user
private

Definition at line 40 of file class.ilCmiXapiLaunchGUI.php.

◆ XAPI_PROXY_ENDPOINT

const ilCmiXapiLaunchGUI::XAPI_PROXY_ENDPOINT = 'components/ILIAS/CmiXapi/xapiproxy.php'

Definition at line 32 of file class.ilCmiXapiLaunchGUI.php.


The documentation for this class was generated from the following file: