ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilBadgeHandler.php
Go to the documentation of this file.
1<?php
2
24
30{
31 public const GENERAL_INFO = 'inform_about_badges';
32
34 protected ilDBInterface $db;
35 protected ilTree $tree;
36 protected ilLanguage $lng;
38 protected static ?ilBadgeHandler $instance = null;
39
40 protected function __construct()
41 {
42 global $DIC;
43
44 if (isset($DIC['component.repository'])) {
45 $this->component_repository = $DIC['component.repository'];
46 }
47 $this->db = $DIC->database();
48 if (isset($DIC['tree'])) {
49 $this->tree = $DIC->repositoryTree();
50 }
51 $this->settings = new ilSetting('bdga');
52 }
53
54 public static function getInstance(): self
55 {
56 if (!self::$instance) {
57 self::$instance = new self();
58 }
59 return self::$instance;
60 }
61
62
63 //
64 // setter/getter
65 //
66
67 public function isActive(): bool
68 {
69 return (bool) $this->settings->get('active', '');
70 }
71
72 public function setActive(bool $a_value): void
73 {
74 $this->settings->set('active', (string) $a_value);
75 }
76
80 public function getComponents(): array
81 {
82 $components = $this->settings->get('components', null);
83 if ($components) {
84 return unserialize($components, ['allowed_classes' => false]);
85 }
86
87 return [];
88 }
89
90
94 public function setComponents(?array $a_components = null): void
95 {
96 if (isset($a_components) && count($a_components) === 0) {
97 $a_components = null;
98 }
99 $this->settings->set(
100 'components',
101 $a_components !== null
102 ? serialize(array_unique($a_components))
103 : ''
104 );
105 }
106
107
108 //
109 // component handling
110 //
111
112 protected function getComponent(string $a_id): ?array
113 {
114 if (!$this->component_repository->hasComponentId($a_id)) {
115 return null;
116 }
117 $component = $this->component_repository->getComponentById($a_id);
118 return [
119 'type' => $component->getType(),
120 'name' => $component->getName()
121 ];
122 }
123
124 public function getProviderInstance(string $a_component_id): ?ilBadgeProvider
125 {
126 $comp = $this->getComponent($a_component_id);
127 if ($comp) {
128 $class = 'il' . $comp['name'] . 'BadgeProvider';
129 $file = '../' . $comp['type'] . '/' . $comp['name'] . '/classes/class.' . $class . '.php';
130 if (file_exists($file)) {
131 $obj = new $class();
132 if ($obj instanceof ilBadgeProvider) {
133 return $obj;
134 }
135 }
136 }
137 return null;
138 }
139
140 public function getComponentCaption(string $a_component_id): string
141 {
142 $comp = $this->getComponent($a_component_id);
143 if ($comp) {
144 return $comp['type'] . '/' . $comp['name'];
145 }
146 return '';
147 }
148
149 //
150 // types
151 //
152
153 public function getUniqueTypeId(
154 string $a_component_id,
155 ilBadgeType $a_badge
156 ): string {
157 return $a_component_id . '/' . $a_badge->getId();
158 }
159
164 string $a_id
165 ): ?ilBadgeType {
166 $parts = explode('/', $a_id);
167 $comp_id = $parts[0];
168 $type_id = $parts[1];
169
170 $provider = $this->getProviderInstance($comp_id);
171 if ($provider) {
172 foreach ($provider->getBadgeTypes() as $type) {
173 if ($type->getId() === $type_id) {
174 return $type;
175 }
176 }
177 }
178 return null;
179 }
180
184 public function getInactiveTypes(): array
185 {
186 $types = $this->settings->get('inactive_types', null);
187 if ($types) {
188 return unserialize($types, ['allowed_classes' => false]);
189 }
190
191 return [];
192 }
193
197 public function setInactiveTypes(?array $a_types = null): void
198 {
199 if (is_array($a_types) &&
200 !count($a_types)) {
201 $a_types = null;
202 }
203 $this->settings->set(
204 'inactive_types',
205 $a_types !== null
206 ? serialize(array_unique($a_types))
207 : ''
208 );
209 }
210
215 public function getAvailableTypes(bool $exclude_inactive = true): array
216 {
217 $res = [];
218
219 $inactive = $this->getInactiveTypes();
220 foreach ($this->getComponents() as $component_id) {
221 $provider = $this->getProviderInstance($component_id);
222 if ($provider) {
223 foreach ($provider->getBadgeTypes() as $type) {
224 $id = $this->getUniqueTypeId($component_id, $type);
225 if (!$exclude_inactive || !in_array($id, $inactive, true)) {
226 $res[$id] = $type;
227 }
228 }
229 }
230 }
231
232 return $res;
233 }
234
239 public function getAvailableTypesForObjType(string $a_object_type): array
240 {
241 $res = [];
242
243 foreach ($this->getAvailableTypes() as $id => $type) {
244 if (in_array($a_object_type, $type->getValidObjectTypes(), true)) {
245 $res[$id] = $type;
246 }
247 }
248
249 return $res;
250 }
251
257 int $a_parent_obj_id,
258 ?string $a_parent_obj_type = null
259 ): array {
260 $res = [];
261
262 if (!$a_parent_obj_type) {
263 $a_parent_obj_type = ilObject::_lookupType($a_parent_obj_id);
264 }
265
266 $badges = ilBadge::getInstancesByParentId($a_parent_obj_id);
267 foreach (self::getInstance()->getAvailableTypesForObjType($a_parent_obj_type) as $type_id => $type) {
268 if (!$type instanceof ilBadgeAuto) {
269 foreach ($badges as $badge) {
270 if ($badge->getTypeId() === $type_id &&
271 $badge->isActive()) {
272 $res[$badge->getId()] = $badge->getTitle();
273 }
274 }
275 }
276 }
277
278 asort($res);
279 return $res;
280 }
281
282
283
284 //
285 // service/module definition
286 //
287
291 public static function updateFromXML(string $a_component_id): void
292 {
293 $handler = self::getInstance();
294 $components = $handler->getComponents();
295 $components[] = $a_component_id;
296 $handler->setComponents($components);
297 }
298
302 public static function clearFromXML(string $a_component_id): void
303 {
304 $handler = self::getInstance();
305 $components = $handler->getComponents();
306 foreach ($components as $idx => $component) {
307 if ($component === $a_component_id) {
308 unset($components[$idx]);
309 }
310 }
311 $handler->setComponents($components);
312 }
313
314
315 //
316 // helper
317 //
318
319 public function isObjectActive(
320 int $a_obj_id,
321 ?string $a_obj_type = null
322 ): bool {
323 if (!$this->isActive()) {
324 return false;
325 }
326
327 if (!$a_obj_type) {
328 $a_obj_type = ilObject::_lookupType($a_obj_id);
329 }
330
331 if ($a_obj_type !== 'bdga' && !ilContainer::_lookupContainerSetting(
332 $a_obj_id,
334 false
335 )) {
336 return false;
337 }
338
339 return true;
340 }
341
342 public function triggerEvaluation(
343 string $a_type_id,
344 int $a_user_id,
345 ?array $a_params = null
346 ): void {
347 if (!$this->isActive() || in_array($a_type_id, $this->getInactiveTypes(), true)) {
348 return;
349 }
350
351 $type = $this->getTypeInstanceByUniqueId($a_type_id);
352 if (!$type instanceof ilBadgeAuto) {
353 return;
354 }
355
356 $new_badges = [];
357 foreach (ilBadge::getInstancesByType($a_type_id) as $badge) {
358 if ($badge->isActive()) {
359 // already assigned?
360 if (!ilBadgeAssignment::exists($badge->getId(), $a_user_id)) {
361 if ($type->evaluate($a_user_id, (array) $a_params, $badge->getConfiguration())) {
362 $ass = new ilBadgeAssignment($badge->getId(), $a_user_id);
363 $ass->store();
364
365 $new_badges[$a_user_id][] = $badge->getId();
366 }
367 }
368 }
369 }
370
371 $this->sendNotification($new_badges);
372 }
373
379 public function getUserIds(
380 int $a_parent_ref_id,
381 ?int $a_parent_obj_id = null,
382 ?string $a_parent_type = null
383 ): array {
384 $tree = $this->tree;
385
386 if (!$a_parent_obj_id) {
387 $a_parent_obj_id = ilObject::_lookupObjectId($a_parent_ref_id);
388 }
389 if (!$a_parent_type) {
390 $a_parent_type = ilObject::_lookupType($a_parent_obj_id);
391 }
392
393 // try to get participants from (parent) course/group
394 switch ($a_parent_type) {
395 case 'crs':
396 $member_obj = ilCourseParticipants::_getInstanceByObjId($a_parent_obj_id);
397 return $member_obj->getMembers();
398
399 case 'grp':
400 $member_obj = ilGroupParticipants::_getInstanceByObjId($a_parent_obj_id);
401 return $member_obj->getMembers();
402
403 default:
404 // walk path to find course or group object and use members of that object
405 /* this does not work since getParticipantsForObject does not exist
406 $path = $tree->getPathId($a_parent_ref_id);
407 array_pop($path);
408 foreach (array_reverse($path) as $path_ref_id) {
409 $type = ilObject::_lookupType($path_ref_id, true);
410 if ($type == "crs" || $type == "grp") {
411 return $this->getParticipantsForObject($path_ref_id, null, $type);
412 }
413 }*/
414 break;
415 }
416 return [];
417 }
418
419
420 //
421 // PATH HANDLING (PUBLISHING)
422 //
423
424 protected function getBasePath(): string
425 {
426 return ilFileUtils::getWebspaceDir() . '/pub_badges/';
427 }
428
429 public function getInstancePath(ilBadgeAssignment $a_ass): string
430 {
431 $hash = md5($a_ass->getBadgeId() . '_' . $a_ass->getUserId());
432
433 $path = $this->getBasePath() . 'instances/' .
434 $a_ass->getBadgeId() . '/' .
435 floor($a_ass->getUserId() / 1000) . '/';
436
438
439 $path .= $hash . '.json';
440
441 return $path;
442 }
443
444 public function countStaticBadgeInstances(ilBadge $a_badge): int
445 {
446 $path = $this->getBasePath() . 'instances/' . $a_badge->getId();
447 $cnt = 0;
448 if (is_dir($path)) {
449 $this->countStaticBadgeInstancesHelper($cnt, $path);
450 }
451 return $cnt;
452 }
453
455 int &$a_cnt,
456 string $a_path
457 ): void {
458 foreach (glob($a_path . '/*') as $item) {
459 if (is_dir($item)) {
460 $this->countStaticBadgeInstancesHelper($a_cnt, $item);
461 } elseif (str_ends_with($item, '.json')) {
462 $a_cnt++;
463 }
464 }
465 }
466
467 public function getBadgePath(ilBadge $a_badge): string
468 {
469 $hash = md5($a_badge->getId());
470
471 $path = $this->getBasePath() . 'badges/' .
472 floor($a_badge->getId() / 100) . '/' .
473 $hash . '/';
474
476
477 return $path;
478 }
479
480
481 //
482 // notification
483 //
484
485 public function sendNotification(
486 array $a_user_map,
487 ?int $a_parent_ref_id = null
488 ): void {
489 $badges = [];
490
491 foreach ($a_user_map as $user_id => $badge_ids) {
492 $user_badges = [];
493
494 foreach ($badge_ids as $badge_id) {
495 // making extra sure
496 if (!ilBadgeAssignment::exists($badge_id, $user_id)) {
497 continue;
498 }
499
500 if (!array_key_exists($badge_id, $badges)) {
501 $badges[$badge_id] = new ilBadge($badge_id);
502 }
503
504 $badge = $badges[$badge_id];
505
506 $user_badges[] = $badge->getTitle();
507 }
508
509 if (count($user_badges)) {
510 // compose and send mail
511
512 $ntf = new ilSystemNotification(false);
513 $ntf->setLangModules(['badge']);
514
515 if (isset($a_parent_ref_id)) {
516 $ntf->setRefId($a_parent_ref_id);
517 }
518 $ntf->setGotoLangId('badge_notification_parent_goto');
519
520 // user specific language
521 $lng = $ntf->getUserLanguage($user_id);
522
523 $ntf->setIntroductionLangId('badge_notification_body');
524
525 $ntf->addAdditionalInfo('badge_notification_badges', implode("\n", $user_badges), true);
526
527 $url = ilLink::_getLink($user_id, 'usr', [], '_bdg');
528 $ntf->addAdditionalInfo('badge_notification_badges_goto', $url);
529
530 $ntf->setReasonLangId('badge_notification_reason');
531
532 // force email
533 $mail = new ilMail(ANONYMOUS_USER_ID);
534 $mail->enqueue(
536 '',
537 '',
538 $lng->txt('badge_notification_subject'),
539 $ntf->composeAndGetMessage($user_id, null, 'read', true),
540 []
541 );
542
543
544 // osd
545 // bug #24562
546 if (ilContext::hasHTML()) {
547 $url = new ilNotificationLink(new ilNotificationParameter('badge_notification_badges_goto', [], 'badge'), $url);
548 $osd_params = ['badge_list' => implode(', ', $user_badges)];
549
550 $notification = new ilNotificationConfig(BadgeNotificationProvider::NOTIFICATION_TYPE);
551 $notification->setTitleVar('badge_notification_subject', [], 'badge');
552 $notification->setShortDescriptionVar('badge_notification_osd', $osd_params, 'badge');
553 $notification->setLongDescriptionVar('');
554 $notification->setLinks([$url]);
555 $notification->setIconPath(ilUtil::getImagePath('standard/icon_bdga.svg'));
556 $notification->setValidForSeconds(ilNotificationConfig::TTL_SHORT);
557 $notification->setVisibleForSeconds(ilNotificationConfig::DEFAULT_TTS);
558 $notification->setIdentification(new NotificationIdentification(
559 BadgeNotificationProvider::NOTIFICATION_TYPE,
560 self::GENERAL_INFO
561 ));
562 $notification->notifyByUsers([$user_id]);
563 }
564 }
565 }
566 }
567}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$components
description of a localized parameter this information is used locate translations while processing no...
return true
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static exists(int $a_badge_id, int $a_user_id)
Class ilBadgeHandler.
static ilBadgeHandler $instance
getAvailableTypes(bool $exclude_inactive=true)
Get badges types.
getUniqueTypeId(string $a_component_id, ilBadgeType $a_badge)
static updateFromXML(string $a_component_id)
Import component definition.
setComponents(?array $a_components=null)
getProviderInstance(string $a_component_id)
setActive(bool $a_value)
getComponent(string $a_id)
getUserIds(int $a_parent_ref_id, ?int $a_parent_obj_id=null, ?string $a_parent_type=null)
sendNotification(array $a_user_map, ?int $a_parent_ref_id=null)
static clearFromXML(string $a_component_id)
Remove component definition.
triggerEvaluation(string $a_type_id, int $a_user_id, ?array $a_params=null)
getAvailableManualBadges(int $a_parent_obj_id, ?string $a_parent_obj_type=null)
Get available manual badges for object id.
getInstancePath(ilBadgeAssignment $a_ass)
getTypeInstanceByUniqueId(string $a_id)
Get type instance by unique id (component, type)
getBadgePath(ilBadge $a_badge)
getAvailableTypesForObjType(string $a_object_type)
Get valid badges types for object type.
ilComponentRepository $component_repository
countStaticBadgeInstances(ilBadge $a_badge)
isObjectActive(int $a_obj_id, ?string $a_obj_type=null)
countStaticBadgeInstancesHelper(int &$a_cnt, string $a_path)
getComponentCaption(string $a_component_id)
setInactiveTypes(?array $a_types=null)
static getInstancesByType(string $a_type_id)
static getInstancesByParentId(int $a_parent_id, ?array $a_filter=null)
static _lookupContainerSetting(int $a_id, string $a_keyword, ?string $a_default_value=null)
static hasHTML()
Has HTML output.
static _getInstanceByObjId(int $a_obj_id)
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static getWebspaceDir(string $mode="filesystem")
get webspace directory
static _getInstanceByObjId(int $a_obj_id)
Get singleton instance.
language handling
static _lookupEmail(int $a_user_id)
static _lookupObjectId(int $ref_id)
static _lookupType(int $id, bool $reference=false)
ILIAS Setting Class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
const ANONYMOUS_USER_ID
Definition: constants.php:27
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Readable part of repository interface to ilComponentDataDB.
Interface ilDBInterface.
$path
Definition: ltiservices.php:30
$res
Definition: ltiservices.php:69
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:61
$provider
Definition: ltitoken.php:80
$handler
Definition: oai.php:29
global $lng
Definition: privfeed.php:31
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:68