ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilTimingsUser.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=0);
26{
27 private static array $instances = array();
28
29 private int $container_obj_id = 0;
30 private int $container_ref_id = 0;
31
32 private bool $initialized = false;
33 private array $item_ids = array();
34
35 protected ilTree $tree;
36 protected ilDBInterface $db;
37
41 protected function __construct(int $a_container_obj_id)
42 {
43 global $DIC;
44
45 $this->tree = $DIC->repositoryTree();
46 $this->db = $DIC->database();
47
48 $this->container_obj_id = $a_container_obj_id;
49 $refs = ilObject::_getAllReferences($a_container_obj_id);
50 $this->container_ref_id = end($refs);
51 }
52
53 public static function getInstanceByContainerId(int $a_container_obj_id): self
54 {
55 if (array_key_exists($a_container_obj_id, self::$instances)) {
56 return self::$instances[$a_container_obj_id];
57 }
58 return self::$instances[$a_container_obj_id] = new self($a_container_obj_id);
59 }
60
61 public function getContainerObjId(): int
62 {
64 }
65
66 public function getContainerRefId(): int
67 {
69 }
70
71 public function getItemIds(): array
72 {
73 return $this->item_ids;
74 }
75
76 public function init(): void
77 {
78 if ($this->initialized) {
79 return;
80 }
81 $this->item_ids = $this->tree->getSubTreeIds($this->getContainerRefId());
82 ilObjectActivation::preloadData($this->item_ids);
83 $this->initialized = true;
84 }
85
86 public function handleNewMembership(int $a_usr_id, ilDateTime $sub_date): void
87 {
88 foreach ($this->getItemIds() as $item_ref_id) {
89 $item = ilObjectActivation::getItem($item_ref_id);
90
91 if ($item['timing_type'] != ilObjectActivation::TIMINGS_PRESETTING) {
92 continue;
93 }
94 $user_item = new ilTimingUser($item['obj_id'], $a_usr_id);
95 $user_start = clone $sub_date;
96 $user_start->increment(IL_CAL_DAY, $item['suggestion_start_rel']);
97 $user_item->getStart()->setDate($user_start->get(IL_CAL_UNIX), IL_CAL_UNIX);
98 $user_end = clone $sub_date;
99 $user_end->increment(IL_CAL_DAY, $item['suggestion_end_rel']);
100 $user_item->getEnd()->setDate($user_end->get(IL_CAL_UNIX), IL_CAL_UNIX);
101 $user_item->update();
102 }
103 }
104
105 public function handleUnsubscribe(int $a_usr_id): void
106 {
107 $query = 'DELETE FROM crs_timings_user WHERE ' . $this->db->in(
108 'ref_id',
109 $this->item_ids,
110 false,
111 'integer'
112 ) . ' ' .
113 'AND usr_id = ' . $this->db->quote($a_usr_id, 'integer');
114 $this->db->manipulate($query);
115 }
116
121 public static function lookupTimingsExceededByUser(array $a_user_ids): array
122 {
123 $res = array();
124
125 $meta = [];
126 foreach (self::lookupTimings($a_user_ids, $meta, true) as $user_ids) {
127 foreach ($user_ids as $user_id) {
129 }
130 }
131 return array_values($res);
132 }
133
139 public static function lookupTimings(array $a_user_ids, ?array &$a_meta = null, bool $a_only_exceeded = true): array
140 {
141 global $DIC;
142
143 $ilDB = $DIC->database();
144 $logger = $DIC->logger()->crs();
145
146 $res = array();
147 $now = time();
148
149 // get all relevant courses
150 $course_members_map = ilParticipants::getUserMembershipAssignmentsByType($a_user_ids, ['crs'], true);
151 $logger->debug('Course membership assignments');
152 $logger->dump($course_members_map, \ilLogLevel::DEBUG);
153
154 // lookup (course) timing settings
155 $query = 'SELECT crsi.obj_id sub_ref_id, oref.ref_id, oref.obj_id, crsi.suggestion_start' .
156 ',crsi.suggestion_end,crsi.changeable, crss.timing_mode' .
157 ' FROM crs_settings crss' .
158 ' JOIN object_reference oref ON (oref.obj_id = crss.obj_id AND oref.deleted IS NULL) ' .
159 ' JOIN crs_items crsi ON (crsi.parent_id = oref.ref_id)' .
160 ' JOIN object_reference iref ON (crsi.obj_id = iref.ref_id AND iref.deleted IS NULL) ' .
161 ' WHERE crss.view_mode = ' . $ilDB->quote(ilCourseConstants::IL_CRS_VIEW_TIMING, 'integer') .
162 ' AND ' . $ilDB->in('crss.obj_id', array_keys($course_members_map), false, 'integer') .
163 ' AND crsi.timing_type = ' . $ilDB->quote(ilObjectActivation::TIMINGS_PRESETTING, 'integer');
164
165 $logger->debug($query);
166
167 $set = $ilDB->query($query);
168 $user_relevant = $course_map = $course_parent_map = [];
169 while ($row = $ilDB->fetchAssoc($set)) {
170 $obj_id = (int) $row['obj_id'];
171 $sub_ref_id = (int) $row['sub_ref_id'];
172 $mode = (int) $row['timing_mode'];
173
174 // needed for course_map-lookup for user-relevant data (see below)
175 $course_parent_map[(int) $row['sub_ref_id']] = (int) $row['obj_id'];
176 $course_map[(int) $row['obj_id']] = (int) $row['ref_id'];
177
178 // gather meta data
179 if (is_array($a_meta)) {
180 foreach ($a_user_ids as $user_id) {
181 // only if course member
182 if (in_array($user_id, $course_members_map[$obj_id])) {
183 $a_meta[$user_id][$sub_ref_id] = array(
184 'parent' => $row['ref_id']
185 );
186 }
187 }
188 }
189
190 // preset all users with object setting
192 // gather meta data
193 if (is_array($a_meta)) {
194 foreach ($a_user_ids as $user_id) {
195 // only if course member
196 if (in_array($user_id, $course_members_map[$obj_id])) {
197 $a_meta[$user_id][$sub_ref_id]['start'] = (int) $row['suggestion_start'];
198 $a_meta[$user_id][$sub_ref_id]['end'] = (int) $row['suggestion_end'];
199 }
200 }
201 }
202
203 if (
204 ($a_only_exceeded && ((int) $row['suggestion_end'] && (int) $row['suggestion_end'] < $now)) ||
205 (!$a_only_exceeded && ((int) $row['suggestion_start'] && (int) $row['suggestion_start'] < $now))
206 ) {
207 foreach ($a_user_ids as $user_id) {
208 // only if course member
209 if (in_array($user_id, $course_members_map[$obj_id])) {
210 $res[$sub_ref_id][$user_id] = $user_id;
211 }
212 }
213 }
214 }
215
216 // gather all objects which might have user-specific settings
217 if ($row['changeable'] ||
219 $user_relevant[] = $sub_ref_id;
220 }
221 }
222
223 if ($user_relevant !== []) {
224 // get user-specific data
225 $query = 'SELECT * FROM crs_timings_user' .
226 ' WHERE ' . $ilDB->in('usr_id', $a_user_ids, false, 'integer') .
227 ' AND ' . $ilDB->in('ref_id', $user_relevant, false, 'integer');
228 $set = $ilDB->query($query);
229 while ($row = $ilDB->fetchAssoc($set)) {
230 $ref_id = (int) $row['ref_id'];
231 $user_id = (int) $row['usr_id'];
232
233 // only if course member
234 $crs_obj_id = $course_parent_map[$ref_id];
235 if (!in_array($user_id, $course_members_map[$crs_obj_id])) {
236 continue;
237 }
238
239 // gather meta data
240 if (is_array($a_meta)) {
241 $a_meta[$user_id][$ref_id]['start'] = (int) $row['sstart'];
242 $a_meta[$user_id][$ref_id]['end'] = (int) $row['ssend'];
243 }
244
245 if (
246 ($a_only_exceeded && (int) $row['ssend'] && (int) $row['ssend'] < $now) ||
247 (!$a_only_exceeded && (int) $row['sstart'] && (int) $row['sstart'] < $now)
248 ) {
250 } else {
251 // if not exceeded remove preset data
252 unset($res[$ref_id][$user_id]);
253 }
254 }
255 }
256
257 // clean-up/minimize the result
258 foreach (array_keys($res) as $ref_id) {
259 if (count($res[$ref_id]) === 0) {
260 if (isset($res['ref_id']) && !count($res['ref_id'])) {
261 unset($res[$ref_id]);
262 } else {
263 $res[$ref_id] = array_values($res[$ref_id]);
264 }
265 }
266 }
267
268 if (isset($res) && count($res)) {
269 $obj_map = array();
270 $invalid_lp = self::getObjectsWithInactiveLP(array_keys($res), $obj_map);
271
272 foreach (array_keys($res) as $ref_id) {
273 // invalid LP?
274 if (in_array($ref_id, $invalid_lp)) {
275 $res[$ref_id] = array();
276 } // LP completed?
277 else {
278 $user_ids = $res[$ref_id];
279 if ($user_ids !== []) {
280 $res[$ref_id] = array_diff(
281 $user_ids,
283 );
284 }
285 }
286
287 // delete reference array, if no users are given anymore
288 if ($res[$ref_id] === []) {
289 unset($res[$ref_id]);
290 }
291 }
292 }
293
294 // #2176 - add course entries (1 exceeded sub-item is enough)
295 foreach ($res as $ref_id => $user_ids) {
296 // making sure one last time
297 if ($user_ids === [] && isset($res['ref_id'])) {
298 unset($res[$ref_id]);
299 } else {
300 $crs_obj_id = $course_parent_map[$ref_id];
301 $crs_ref_id = $course_map[$crs_obj_id];
302 if (!array_key_exists($crs_ref_id, $res)) {
303 $res[$crs_ref_id] = $user_ids;
304 } else {
305 $res[$crs_ref_id] = array_unique(array_merge($user_ids, $res[$crs_ref_id]));
306 }
307 }
308 }
309 return $res;
310 }
311
316 public static function getObjectsWithInactiveLP(array $a_ref_ids, ?array &$a_obj_map = null): array
317 {
318 global $DIC;
319
320 $ilDB = $DIC->database();
321
322 $res = array();
323 $query = 'SELECT oref.ref_id, oref.obj_id, od.type' .
324 ' FROM object_reference oref' .
325 ' JOIN object_data od ON (oref.obj_id = od.obj_id)' .
326 ' WHERE ' . $ilDB->in('oref.ref_id', $a_ref_ids, false, 'integer');
327 $set = $ilDB->query($query);
328 $item_map = $item_types = array();
329 while ($row = $ilDB->fetchAssoc($set)) {
330 $item_map[(int) $row['ref_id']] = (int) $row['obj_id'];
331 $item_types[(int) $row['obj_id']] = $row['type'];
332 }
333
334 $a_obj_map = $item_map;
335
336 // LP modes
337 $db_modes = ilLPObjSettings::_lookupDBModeForObjects(array_values($item_map));
338
339 $type_modes = array();
340 foreach ($a_ref_ids as $ref_id) {
341 $obj_id = $item_map[$ref_id];
342 $type = $item_types[$obj_id];
343
345 $res[] = $ref_id;
346 continue;
347 }
348
349 // use db mode
350 if (array_key_exists($obj_id, $db_modes)) {
351 $mode = $db_modes[$obj_id];
352 } // use default
353 else {
354 if (!array_key_exists($type, $type_modes)) {
355 $type_modes[$type] = ilObjectLP::getInstance($obj_id);
356 $type_modes[$type] = $type_modes[$type]->getDefaultMode();
357 }
358 $mode = $type_modes[$type];
359 }
360
363 $res[] = $ref_id;
364 }
365 }
366 return $res;
367 }
368}
const IL_CAL_UNIX
const IL_CAL_DAY
@classDescription Date and time handling
increment(string $a_type, int $a_count=1)
static _lookupDBModeForObjects(array $a_obj_ids)
static _lookupCompletedForObject(int $a_obj_id, ?array $a_user_ids=null)
Get completed users for object.
static getItem(int $ref_id)
static preloadData(array $ref_ids)
Preload data to internal cache.
static isSupportedObjectType(string $type)
static getInstance(int $obj_id)
static _getAllReferences(int $id)
get all reference ids for object ID
static getUserMembershipAssignmentsByType(array $a_user_ids, array $a_type, bool $a_only_member_roles)
Get user membership assignments by type.
TableGUI class for timings administration.
Handle user timings.
static getInstanceByContainerId(int $a_container_obj_id)
static lookupTimings(array $a_user_ids, ?array &$a_meta=null, bool $a_only_exceeded=true)
Lookup references, users with exceeded timings.
handleUnsubscribe(int $a_usr_id)
static getObjectsWithInactiveLP(array $a_ref_ids, ?array &$a_obj_map=null)
Check object LP modes.
static lookupTimingsExceededByUser(array $a_user_ids)
Check if users currently exceeded ANY object.
static array $instances
__construct(int $a_container_obj_id)
Singleton constructor.
handleNewMembership(int $a_usr_id, ilDateTime $sub_date)
ilDBInterface $db
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
Interface ilDBInterface.
$ref_id
Definition: ltiauth.php:66
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:26