ILIAS  release_8 Revision v8.24
ilCmiXapiLaunchGUI Class Reference
+ Collaboration diagram for ilCmiXapiLaunchGUI:

Public Member Functions

 __construct (ilObjCmiXapi $object, ?int $launchedByRefId=null)
 
 executeCommand ()
 

Data Fields

const XAPI_PROXY_ENDPOINT = 'Modules/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
 
int $launchedByRefId
 

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,
?int  $launchedByRefId = null 
)

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

47 {
48 $this->object = $object;
49 $this->launchedByRefId = $launchedByRefId;
50 }

References $launchedByRefId, and $object.

Member Function Documentation

◆ buildAuthTokenFetchParam()

ilCmiXapiLaunchGUI::buildAuthTokenFetchParam ( )
protected
Exceptions
ilCmiXapiException

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

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

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 72 of file class.ilCmiXapiLaunchGUI.php.

72 : string
73 {
74 $launchLink = "";
75
76 if ($this->object->getSourceType() == ilObjCmiXapi::SRC_TYPE_REMOTE) {
77 $launchLink = $this->object->getLaunchUrl();
78 } elseif ($this->object->getSourceType() == ilObjCmiXapi::SRC_TYPE_LOCAL) {
79 if (preg_match("/^(https?:\/\/)/", $this->object->getLaunchUrl()) == 1) {
80 $launchLink = $this->object->getLaunchUrl();
81 } else {
82 $launchLink = implode('/', [
83 ILIAS_HTTP_PATH,
86 ]);
87
88 $launchLink .= DIRECTORY_SEPARATOR . $this->object->getLaunchUrl();
89 }
90 }
91
92 foreach ($this->getLaunchParameters($token) as $paramName => $paramValue) {
93 $launchLink = ilUtil::appendUrlParameterString($launchLink, "{$paramName}={$paramValue}");
94 }
95
96 return $launchLink;
97 }
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 226 of file class.ilCmiXapiLaunchGUI.php.

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

References $client, 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 52 of file class.ilCmiXapiLaunchGUI.php.

52 : void
53 {
54 global $DIC;
55 $this->user = $DIC->user();
56 $this->ctrl = $DIC->ctrl();
57 $this->launchCmd();
58 }
global $DIC
Definition: feed.php:28

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 143 of file class.ilCmiXapiLaunchGUI.php.

143 : string
144 {
145 $link = implode('/', [
146 ILIAS_HTTP_PATH, 'Modules', 'CmiXapi', 'xapitoken.php'
147 ]);
148
150
151 return iLUtil::appendUrlParameterString($link, "param={$param}");
152 }
$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 208 of file class.ilCmiXapiLaunchGUI.php.

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

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 102 of file class.ilCmiXapiLaunchGUI.php.

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

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 176 of file class.ilCmiXapiLaunchGUI.php.

176 : string
177 {
179 $this->user->getId(),
180 $this->object->getRefId(),
181 $this->object->getId(),
182 $this->object->getLrsType()->getTypeId()
183 );
184 return $token;
185 }
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 187 of file class.ilCmiXapiLaunchGUI.php.

187 : void
188 {
189 $this->cmixUser = new ilCmiXapiUser($this->object->getId(), $this->user->getId(), $this->object->getPrivacyIdent());
190 $user_ident = $this->cmixUser->getUsrIdent();
191 if ($user_ident == '' || $user_ident == null) {
192 $user_ident = ilCmiXapiUser::getIdent($this->object->getPrivacyIdent(), $this->user);
193 $this->cmixUser->setUsrIdent($user_ident);
194
195 if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5) {
196 $this->cmixUser->setRegistration((string) ilCmiXapiUser::generateCMI5Registration($this->object->getId(), $this->user->getId()));
197 }
198 $this->cmixUser->save();
199 if (!ilObjUser::_isAnonymous($this->user->getId())) {
200 ilLPStatusWrapper::_updateStatus($this->object->getId(), $this->user->getId());
201 }
202 }
203 }
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 60 of file class.ilCmiXapiLaunchGUI.php.

60 : void
61 {
62 $this->initCmixUser();
63 $token = $this->getValidToken();
64 if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5) {
65 $ret = $this->CMI5preLaunch($token);
66 $token = $ret['token'];
67 }
68 $launchLink = $this->buildLaunchLink($token);
69 $this->ctrl->redirectToURL($launchLink);
70 }
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 400 of file class.ilCmiXapiLaunchGUI.php.

400 : ilLogger
401 {
402 if ($this->plugin) {
403 global $log;
404 return $log;
405 } else {
406 return \ilLoggerFactory::getLogger('cmix');
407 }
408 }
Component logger with individual log levels by component id.
$log
Definition: result.php:33

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.

◆ $launchedByRefId

int ilCmiXapiLaunchGUI::$launchedByRefId
protected

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

Referenced by __construct().

◆ $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 = 'Modules/CmiXapi/xapiproxy.php'

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


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