ILIAS  trunk Revision v13.0_alpha-52-g21c366bbdd4
class.ilBookingReservation.php
Go to the documentation of this file.
1<?php
2
24{
25 public const int STATUS_IN_USE = 2;
26 public const int STATUS_CANCELLED = 5;
27
28 protected ilDBInterface $db;
29 protected int $id = 0;
30 protected int $object_id = 0;
31 protected int $user_id = 0;
32 protected int $from = 0;
33 protected int $to = 0;
34 protected int $status = 0;
35 protected int $group_id = 0;
36 protected int $assigner_id = 0;
37 protected int $context_obj_id = 0;
38 protected string $message = "";
39 protected \ILIAS\BookingManager\Reservations\ReservationDBRepository $repo;
40
41 public function __construct(
42 ?int $a_id = null
43 ) {
44 global $DIC;
45
46 $this->db = $DIC->database();
47 $this->id = (int) $a_id;
48
49 $this->repo = $DIC->bookingManager()
50 ->internal()
51 ->repo()
52 ->reservation();
53 $this->read();
54 }
55
56 public function getId(): int
57 {
58 return $this->id;
59 }
60
61 public function setObjectId(int $a_object_id): void
62 {
63 $this->object_id = $a_object_id;
64 }
65
66 public function getObjectId(): int
67 {
68 return $this->object_id;
69 }
70
71 public function setUserId(int $a_user_id): void
72 {
73 $this->user_id = $a_user_id;
74 }
75
76 public function getUserId(): int
77 {
78 return $this->user_id;
79 }
80
81 public function setMessage(string $message): void
82 {
83 $this->message = $message;
84 }
85
86 public function getMessage(): string
87 {
88 return $this->message;
89 }
90
94 public function setAssignerId(int $a_assigner_id): void
95 {
96 $this->assigner_id = $a_assigner_id;
97 }
98
99 public function getAssignerId(): int
100 {
101 return $this->assigner_id;
102 }
103
107 public function setFrom(int $a_from): void
108 {
109 $this->from = $a_from;
110 }
111
112 public function getFrom(): int
113 {
114 return $this->from;
115 }
116
120 public function setTo(int $a_to): void
121 {
122 $this->to = $a_to;
123 }
124
125 public function getTo(): int
126 {
127 return $this->to;
128 }
129
133 public function setStatus(?int $a_status): void
134 {
135 if ($a_status === null) {
136 $this->status = 0;
137 }
138 if (self::isValidStatus((int) $a_status)) {
139 $this->status = (int) $a_status;
140 }
141 }
142
146 public function getStatus(): ?int
147 {
148 return $this->status;
149 }
150
151 public static function isValidStatus(int $a_status): bool
152 {
153 return in_array($a_status, array(self::STATUS_IN_USE, self::STATUS_CANCELLED));
154 }
155
156 public function setGroupId(int $a_group_id): void
157 {
158 $this->group_id = $a_group_id;
159 }
160
161 public function getGroupId(): int
162 {
163 return $this->group_id;
164 }
165
169 public function setContextObjId(int $a_val): void
170 {
171 $this->context_obj_id = $a_val;
172 }
173
177 public function getContextObjId(): int
178 {
180 }
181
182 protected function read(): void
183 {
184 if ($this->id && $row = $this->repo->getForId($this->id)) {
185 $this->setUserId($row['user_id']);
186 $this->setAssignerId((int) $row['assigner_id']);
187 $this->setObjectId($row['object_id']);
188 $this->setFrom($row['date_from']);
189 $this->setTo($row['date_to']);
190 $this->setStatus($row['status']);
191 $this->setGroupId((int) $row['group_id']);
192 $this->setContextObjId((int) $row['context_obj_id']);
193 $this->setMessage($row['message']);
194 }
195 }
196
197 public function save(): bool
198 {
199 if ($this->id) {
200 return false;
201 }
202
203 $this->id = $this->repo->create(
204 $this->getUserId(),
205 $this->getAssignerId(),
206 $this->getObjectId(),
207 $this->getContextObjId(),
208 $this->getFrom(),
209 $this->getTo(),
210 $this->getStatus(),
211 $this->getGroupId(),
212 $this->getMessage()
213 );
214 return ($this->id > 0);
215 }
216
217 public function update(): bool
218 {
219 if (!$this->id) {
220 return false;
221 }
222
223 $this->repo->update(
224 $this->id,
225 $this->getUserId(),
226 $this->getAssignerId(),
227 $this->getObjectId(),
228 $this->getContextObjId(),
229 $this->getFrom(),
230 $this->getTo(),
231 $this->getStatus(),
232 $this->getGroupId(),
233 $this->getMessage()
234 );
235 return true;
236 }
237
238 public function delete(): void
239 {
240 $this->repo->delete($this->id);
241 }
242
243
247 public static function getAvailableObject(
248 array $a_ids,
249 int $a_from,
250 int $a_to,
251 bool $a_return_single = true,
252 bool $a_return_counter = false
253 ): array {
254 global $DIC;
255
257
258 $repo = $DIC->bookingManager()->internal()->repo()->reservation();
259
260 $blocked = $counter = [];
261 foreach ($repo->getNumberOfReservations($a_ids, $a_from, $a_to) as $row) {
262 if ($row['cnt'] >= $nr_map[$row['object_id']]) {
263 $blocked[] = $row['object_id'];
264 continue;
265 }
266
267 if (!$a_return_counter) {
268 continue;
269 }
270
271 $counter[$row['object_id']] = $nr_map[$row['object_id']] - (int) $row['cnt'];
272 }
273
274 // #17868 - validate against schedule availability
275 foreach ($a_ids as $obj_id) {
276 $bobj = new ilBookingObject($obj_id);
277 if (!$bobj->getScheduleId()) {
278 continue;
279 }
280
281 $schedule = new ilBookingSchedule($bobj->getScheduleId());
282
283 $av_from = ($schedule->getAvailabilityFrom() && !$schedule->getAvailabilityFrom()->isNull())
284 ? $schedule->getAvailabilityFrom()->get(IL_CAL_UNIX)
285 : PHP_INT_MIN;
286 $av_to = ($schedule->getAvailabilityTo() && !$schedule->getAvailabilityTo()->isNull())
287 ? $schedule->getAvailabilityTo()->get(IL_CAL_UNIX)
288 : PHP_INT_MAX;
289
290 if ($a_from >= $av_from && $a_to <= $av_to) {
291 continue;
292 }
293
294 $blocked[] = $obj_id;
295 unset($counter[$obj_id]);
296 }
297
298 $available = array_diff($a_ids, $blocked);
299 if ($available !== []) {
300 if ($a_return_counter) {
301 foreach ($a_ids as $id) {
302 if (isset($counter[$id])) {
303 break;
304 }
305
306 $counter[$id] = $nr_map[$id];
307 }
308
309 return $counter;
310 }
311
312 return $a_return_single ? array_shift($available) : $available;
313 }
314
315 return [];
316 }
317
318 public static function isObjectAvailableInPeriod(
319 int $a_obj_id,
320 ilBookingSchedule $a_schedule,
321 ?int $a_from,
322 ?int $a_to
323 ): bool {
324 global $DIC;
325
326 if (!$a_from) {
327 $a_from = time();
328 }
329 if (!$a_to) {
330 $a_to = strtotime("+1year", $a_from);
331 }
332
333 if ($a_from > $a_to) {
334 return false;
335 }
336
337 // all nr of reservations in period that are not over yet (to >= now)
338 $repo = $DIC->bookingManager()->internal()->repo()->reservation();
339 $res = $repo->getNumberOfReservations([$a_obj_id], $a_from, $a_to, true);
340 $booked_in_period = (int) ($res[$a_obj_id]["cnt"] ?? 0);
341
342 $per_slot = ilBookingObject::getNrOfItemsForObjects(array($a_obj_id));
343 $per_slot = $per_slot[$a_obj_id];
344
345 // max available nr of items per (week)day
346 $schedule_slots = array();
347 $definition = $a_schedule->getDefinition();
348 $map = array_flip(array("su", "mo", "tu", "we", "th", "fr", "sa"));
349 foreach ($definition as $day => $day_slots) {
350 $schedule_slots[$map[$day]] = $day_slots;
351 }
352
353 $av_from = ($a_schedule->getAvailabilityFrom() && !$a_schedule->getAvailabilityFrom()->isNull())
354 ? $a_schedule->getAvailabilityFrom()->get(IL_CAL_UNIX)
355 : null;
356 $av_to = ($a_schedule->getAvailabilityTo() && !$a_schedule->getAvailabilityTo()->isNull())
357 ? strtotime($a_schedule->getAvailabilityTo()->get(IL_CAL_DATE) . " 23:59:59")
358 : null;
359
360 // sum up max available (to >= now) items in period per (week)day
361 $available_in_period = 0;
362 $loop = 0;
363 while ($a_from < $a_to &&
364 ++$loop < 1000) {
365 // any slots for current weekday?
366 $day_slots = $schedule_slots[date("w", $a_from)] ?? false;
367 if ($day_slots) {
368 foreach ($day_slots as $slot) {
369 // convert slot to current datetime
370 $slot = explode("-", $slot);
371 $slot_from = strtotime(date("Y-m-d", $a_from) . " " . $slot[0]);
372 $slot_to = strtotime(date("Y-m-d", $a_from) . " " . $slot[1]);
373 // slot has to be in the future and part of schedule availability
374 if ($slot_from >= $av_from &&
375 ($slot_to <= $av_to || is_null($av_to)) &&
376 $slot_to > time()) {
377 $available_in_period += $per_slot;
378 }
379 }
380 }
381
382 $a_from += (60 * 60 * 24);
383 }
384 return $available_in_period - $booked_in_period > 0;
385 }
386
387 //check if the user reached the limit of bookings in this booking pool.
388 public static function isBookingPoolLimitReachedByUser(
389 int $a_user_id,
390 int $a_pool_id
391 ): int {
392 global $DIC;
393 $ilDB = $DIC->database();
394 $object_manager = $DIC->bookingManager()->internal()->domain()
395 ->objects($a_pool_id);
396
397 $booking_pool_objects = $object_manager->getObjectIds();
398
399 $query = "SELECT count(user_id) total" .
400 " FROM booking_reservation" .
401 " WHERE " . $ilDB->in('object_id', $booking_pool_objects, false, 'integer') .
402 " AND user_id = " . $a_user_id .
403 " AND (status IS NULL OR status <> " . self::STATUS_CANCELLED . ')';
404 $res = $ilDB->query($query);
405 $row = $res->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
406
407 return (int) $row['total'];
408 }
409
413 public static function getMembersWithoutReservation(
414 int $a_object_id
415 ): array {
416 global $DIC;
417 $ilDB = $DIC->database();
418
419 $pool_id = ilBookingObject::lookupPoolId($a_object_id);
420
421 $res = array();
422 $query = 'SELECT DISTINCT bm.user_id user_id' .
423 ' FROM booking_member bm' .
424 ' WHERE bm.booking_pool_id = ' . $ilDB->quote($pool_id, 'integer') .
425 ' AND bm.user_id NOT IN (' .
426 'SELECT user_id' .
427 ' FROM booking_reservation' .
428 ' WHERE object_id = ' . $ilDB->quote($a_object_id, 'integer') .
429 ' AND (status IS NULL OR status <> ' . self::STATUS_CANCELLED . '))';
430
431 $set = $ilDB->query($query);
432
433 while ($row = $ilDB->fetchAssoc($set)) {
434 $res[] = (int) $row['user_id'];
435 }
436
437 return $res;
438 }
439
440 public static function isObjectAvailableNoSchedule(int $a_obj_id): bool
441 {
442 $available = self::getNumAvailablesNoSchedule($a_obj_id);
443 return (bool) $available; // #11864
444 }
445
446 public static function numAvailableFromObjectNoSchedule(int $a_obj_id): int
447 {
448 return self::getNumAvailablesNoSchedule($a_obj_id);
449 }
450
451 public static function getNumAvailablesNoSchedule(int $a_obj_id): int
452 {
453 global $DIC;
454
455 $ilDB = $DIC->database();
456
457 $all = ilBookingObject::getNrOfItemsForObjects(array($a_obj_id));
458 $all = $all[$a_obj_id];
459
460 $set = $ilDB->query('SELECT COUNT(*) cnt' .
461 ' FROM booking_reservation r' .
462 ' JOIN booking_object o ON (o.booking_object_id = r.object_id)' .
463 ' WHERE (status IS NULL OR status <> ' . $ilDB->quote(self::STATUS_CANCELLED, 'integer') . ')' .
464 ' AND r.object_id = ' . $ilDB->quote($a_obj_id, 'integer'));
465 $cnt = $ilDB->fetchAssoc($set);
466 $cnt = (int) $cnt['cnt'];
467
468 return $all - $cnt; // #11864
469 }
470
474 public static function getCurrentOrUpcomingReservation(
475 int $a_object_id
476 ): array {
477 global $DIC;
478
479 $ilDB = $DIC->database();
480
481 $now = $ilDB->quote(time(), 'integer');
482
483 $ilDB->setLimit(1);
484 $set = $ilDB->query('SELECT user_id, status, date_from, date_to' .
485 ' FROM booking_reservation' .
486 ' WHERE ((date_from <= ' . $now . ' AND date_to >= ' . $now . ')' .
487 ' OR date_from > ' . $now . ')' .
488 ' AND (status <> ' . $ilDB->quote(self::STATUS_CANCELLED, 'integer') .
489 ' OR STATUS IS NULL) AND object_id = ' . $ilDB->quote($a_object_id, 'integer') .
490 ' ORDER BY date_from');
491 return $ilDB->fetchAssoc($set);
492 }
493
497 public static function getObjectReservationForUser(
498 int $a_object_id,
499 int $a_user_id
500 ): ?array {
501 global $DIC;
502
503 $ilDB = $DIC->database();
504
505 $set = $ilDB->query('SELECT booking_reservation_id FROM booking_reservation' .
506 ' WHERE user_id = ' . $ilDB->quote($a_user_id, 'integer') .
507 ' AND object_id = ' . $ilDB->quote($a_object_id, 'integer') .
508 ' AND (status <> ' . $ilDB->quote(self::STATUS_CANCELLED, 'integer') .
509 ' OR STATUS IS NULL)');
510 $res = array();
511 while ($row = $ilDB->fetchAssoc($set)) {
512 $res[] = (int) $row['booking_reservation_id'];
513 }
514 return $res;
515 }
516
521 public static function getList(
522 array $a_object_ids,
523 int $a_limit = 10,
524 int $a_offset = 0,
525 array $filter = []
526 ): array {
527 global $DIC;
528
529 $ilDB = $DIC->database();
530
531 $sql = 'SELECT r.*,o.title' .
532 ' FROM booking_reservation r' .
533 ' JOIN booking_object o ON (o.booking_object_id = r.object_id)';
534
535 $count_sql = 'SELECT COUNT(*) AS counter' .
536 ' FROM booking_reservation r' .
537 ' JOIN booking_object o ON (o.booking_object_id = r.object_id)';
538
539 $where = array($ilDB->in('r.object_id', $a_object_ids, '', 'integer'));
540 if (isset($filter['status'])) {
541 if ($filter['status'] > 0) {
542 $where[] = 'status = ' . $ilDB->quote($filter['status'], 'integer');
543 } else {
544 $where[] = '(status != ' . $ilDB->quote(-$filter['status'], 'integer') .
545 ' OR status IS NULL)';
546 }
547 }
548 if (isset($filter['from'])) {
549 $where[] = 'date_from >= ' . $ilDB->quote($filter['from'], 'integer');
550 }
551 if (isset($filter['to'])) {
552 $where[] = 'date_to <= ' . $ilDB->quote($filter['to'], 'integer');
553 }
554 if (isset($filter['user_id'])) {
555 $where[] = 'user_id = ' . $ilDB->quote($filter['user_id'], 'integer');
556 }
557 if (count($where)) {
558 $sql .= ' WHERE ' . implode(' AND ', $where);
559 $count_sql .= ' WHERE ' . implode(' AND ', $where);
560 }
561
562 $set = $ilDB->query($count_sql);
563 $row = $ilDB->fetchAssoc($set);
564 $counter = $row['counter'];
565
566 $sql .= ' ORDER BY date_from DESC, booking_reservation_id DESC';
567
568 $ilDB->setLimit($a_limit, $a_offset);
569 $set = $ilDB->query($sql);
570 $res = array();
571 while ($row = $ilDB->fetchAssoc($set)) {
572 $res[] = $row;
573 }
574
575 return array('data' => $res, 'counter' => $counter);
576 }
577
578
585 public static function getUserFilter(
586 array $a_object_ids
587 ): array {
588 global $DIC;
589
590 $ilDB = $DIC->database();
591
592 $res = array();
593
594 $sql = "SELECT ud.usr_id,ud.lastname,ud.firstname,ud.login" .
595 " FROM usr_data ud " .
596 " LEFT JOIN booking_reservation r ON (r.user_id = ud.usr_id)" .
597 " WHERE ud.usr_id <> " . $ilDB->quote(ANONYMOUS_USER_ID, "integer") .
598 " AND " . $ilDB->in("r.object_id", $a_object_ids, "", "integer") .
599 " ORDER BY ud.lastname,ud.firstname";
600 $set = $ilDB->query($sql);
601 while ($row = $ilDB->fetchAssoc($set)) {
602 $res[$row["usr_id"]] = $row["lastname"] . ", " . $row["firstname"] .
603 " (" . $row["login"] . ")";
604 }
605
606 return $res;
607 }
608
609
616 public static function changeStatus(
617 array $a_ids,
618 int $a_status
619 ): int {
620 global $DIC;
621
622 $ilDB = $DIC->database();
623
624 if (self::isValidStatus($a_status)) {
625 return $ilDB->manipulate('UPDATE booking_reservation' .
626 ' SET status = ' . $ilDB->quote($a_status, 'integer') .
627 ' WHERE ' . $ilDB->in('booking_reservation_id', $a_ids, '', 'integer'));
628 }
629 return 0;
630 }
631
632 // get calendar id of reservation
633 public function getCalendarEntry(): int
634 {
635 $ilDB = $this->db;
636
637 $set = $ilDB->query("SELECT ce.cal_id FROM cal_entries ce" .
638 " JOIN cal_cat_assignments cca ON ce.cal_id = cca.cal_id" .
639 " JOIN cal_categories cc ON cca.cat_id = cc.cat_id" .
640 " JOIN booking_reservation br ON ce.context_id = br.booking_reservation_id" .
641 " WHERE cc.obj_id = " . $ilDB->quote($this->getUserId(), 'integer') .
642 " AND br.user_id = " . $ilDB->quote($this->getUserId(), 'integer') .
643 " AND cc.type = " . $ilDB->quote(ilCalendarCategory::TYPE_BOOK, 'integer') .
644 " AND ce.context_id = " . $ilDB->quote($this->getId(), 'integer'));
645 $row = $ilDB->fetchAssoc($set);
646 return (int) ($row["cal_id"] ?? 0);
647 }
648
653 public static function getCancelDetails(
654 int $a_obj_id,
655 int $a_user_id,
656 int $a_from,
657 int $a_to
658 ): array {
659 global $DIC;
660
661 $ilDB = $DIC->database();
662
663 $res = array();
664
665 $sql = "SELECT booking_reservation_id" .
666 " FROM booking_reservation" .
667 " WHERE object_id = " . $ilDB->quote($a_obj_id, "integer") .
668 " AND user_id = " . $ilDB->quote($a_user_id, "integer") .
669 " AND date_from = " . $ilDB->quote($a_from, "integer") .
670 " AND date_to = " . $ilDB->quote($a_to, "integer") .
671 " AND (status IS NULL" .
672 " OR status <> " . $ilDB->quote(self::STATUS_CANCELLED, "integer") . ")";
673 $set = $ilDB->query($sql);
674 while ($row = $ilDB->fetchAssoc($set)) {
675 $res[] = (int) $row["booking_reservation_id"];
676 }
677
678 return $res;
679 }
680}
const IL_CAL_DATE
const IL_CAL_UNIX
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getNrOfItemsForObjects(array $a_obj_ids)
Get nr of available items for a set of object ids.
static lookupPoolId(int $object_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getObjectReservationForUser(int $a_object_id, int $a_user_id)
static getCurrentOrUpcomingReservation(int $a_object_id)
Get details about object reservation.
static getCancelDetails(int $a_obj_id, int $a_user_id, int $a_from, int $a_to)
Get reservation ids from aggregated id for cancellation.
static getNumAvailablesNoSchedule(int $a_obj_id)
static isValidStatus(int $a_status)
ILIAS BookingManager Reservations ReservationDBRepository $repo
setAssignerId(int $a_assigner_id)
Set assigner user id.
static isObjectAvailableNoSchedule(int $a_obj_id)
static changeStatus(array $a_ids, int $a_status)
Batch update reservation status.
static isObjectAvailableInPeriod(int $a_obj_id, ilBookingSchedule $a_schedule, ?int $a_from, ?int $a_to)
static isBookingPoolLimitReachedByUser(int $a_user_id, int $a_pool_id)
static getMembersWithoutReservation(int $a_object_id)
static getList(array $a_object_ids, int $a_limit=10, int $a_offset=0, array $filter=[])
List all reservations.
static numAvailableFromObjectNoSchedule(int $a_obj_id)
static getAvailableObject(array $a_ids, int $a_from, int $a_to, bool $a_return_single=true, bool $a_return_counter=false)
Check if any of given objects are bookable.
static getUserFilter(array $a_object_ids)
Get all users who have reservations for object(s)
setTo(int $a_to)
Set booking to date.
setStatus(?int $a_status)
Set booking status.
setFrom(int $a_from)
Set booking from date.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const FETCHMODE_ASSOC
const ANONYMOUS_USER_ID
Definition: constants.php:27
Interface ilDBInterface.
to(\GdImage $image, ?int $quality=null)
Currently this is the only way to make a FileStream from a GD image resource.
foreach($_POST as $key=> $value) $res
global $DIC
Definition: shib_login.php:26