ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilBookingReservation.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
13 {
17  protected $db;
18 
19  protected $id; // int
20  protected $object_id; // int
21  protected $user_id; // int
22  protected $from; // timestamp
23  protected $to; // timestamp
24  protected $status; // status
25  protected $group_id; // int
26  protected $assigner_id; // int
27 
31  protected $context_obj_id = 0;
32 
33  const STATUS_IN_USE = 2;
34  const STATUS_CANCELLED = 5;
35 
39  protected $repo;
40 
48  public function __construct($a_id = null)
49  {
50  global $DIC;
51 
52  $this->db = $DIC->database();
53  $this->id = (int) $a_id;
54 
56  $this->repo = $f->getRepo();
57 
58  $this->read();
59  }
60 
65  public function getId()
66  {
67  return $this->id;
68  }
69 
74  public function setObjectId($a_object_id)
75  {
76  $this->object_id = $a_object_id;
77  }
78 
83  public function getObjectId()
84  {
85  return $this->object_id;
86  }
87 
92  public function setUserId($a_user_id)
93  {
94  $this->user_id = (int) $a_user_id;
95  }
96 
101  public function getUserId()
102  {
103  return $this->user_id;
104  }
105 
110  public function setAssignerId($a_assigner_id)
111  {
112  $this->assigner_id = (int) $a_assigner_id;
113  }
114 
119  public function getAssignerId()
120  {
121  return $this->assigner_id;
122  }
123 
128  public function setFrom($a_from)
129  {
130  $this->from = (int) $a_from;
131  }
132 
137  public function getFrom()
138  {
139  return $this->from;
140  }
141 
146  public function setTo($a_to)
147  {
148  $this->to = (int) $a_to;
149  }
150 
155  public function getTo()
156  {
157  return $this->to;
158  }
159 
164  public function setStatus($a_status)
165  {
166  if ($a_status === null) {
167  $this->status = null;
168  }
169  if ($this->isValidStatus((int) $a_status)) {
170  $this->status = (int) $a_status;
171  }
172  }
173 
178  public function getStatus()
179  {
180  return $this->status;
181  }
182 
188  public static function isValidStatus($a_status)
189  {
190  if (in_array($a_status, array(self::STATUS_IN_USE, self::STATUS_CANCELLED))) {
191  return true;
192  }
193  return false;
194  }
195 
200  public function setGroupId($a_group_id)
201  {
202  $this->group_id = $a_group_id;
203  }
204 
209  public function getGroupId()
210  {
211  return $this->group_id;
212  }
213 
219  public function setContextObjId($a_val)
220  {
221  $this->context_obj_id = $a_val;
222  }
223 
229  public function getContextObjId()
230  {
231  return $this->context_obj_id;
232  }
233 
234 
238  protected function read()
239  {
240  if ($this->id) {
241  $row = $this->repo->getForId($this->id);
242  $this->setUserId($row['user_id']);
243  $this->setAssignerId($row['assigner_id']);
244  $this->setObjectId($row['object_id']);
245  $this->setFrom($row['date_from']);
246  $this->setTo($row['date_to']);
247  $this->setStatus($row['status']);
248  $this->setGroupId($row['group_id']);
249  $this->setContextObjId($row['context_obj_id']);
250  }
251  }
252 
257  public function save()
258  {
259  if ($this->id) {
260  return false;
261  }
262 
263  $this->id = $this->repo->create(
264  $this->getUserId(),
265  $this->getAssignerId(),
266  $this->getObjectId(),
267  $this->getContextObjId(),
268  $this->getFrom(),
269  $this->getTo(),
270  $this->getStatus(),
271  $this->getGroupId()
272  );
273  return ($this->id > 0);
274  }
275 
279  public function update()
280  {
281  if (!$this->id) {
282  return false;
283  }
284 
285  $this->repo->update(
286  $this->id,
287  $this->getUserId(),
288  $this->getAssignerId(),
289  $this->getObjectId(),
290  $this->getContextObjId(),
291  $this->getFrom(),
292  $this->getTo(),
293  $this->getStatus(),
294  $this->getGroupId()
295  );
296  return true;
297  }
298 
302  public function delete()
303  {
304  $this->repo->delete($this->id);
305  }
306 
307 
316  public static function getAvailableObject(array $a_ids, $a_from, $a_to, $a_return_single = true, $a_return_counter = false)
317  {
318  $nr_map = ilBookingObject::getNrOfItemsForObjects($a_ids);
319 
321  $repo = $f->getRepo();
322 
323  $blocked = $counter = array();
324  foreach ($repo->getNumberOfReservations($a_ids, $a_from, $a_to) as $row) {
325  if ($row['cnt'] >= $nr_map[$row['object_id']]) {
326  $blocked[] = $row['object_id'];
327  } elseif ($a_return_counter) {
328  $counter[$row['object_id']] = (int) $nr_map[$row['object_id']] - (int) $row['cnt'];
329  }
330  }
331 
332  // #17868 - validate against schedule availability
333  foreach ($a_ids as $obj_id) {
334  $bobj = new ilBookingObject($obj_id);
335  if ($bobj->getScheduleId()) {
336  $schedule = new ilBookingSchedule($bobj->getScheduleId());
337 
338  $av_from = ($schedule->getAvailabilityFrom() && !$schedule->getAvailabilityFrom()->isNull())
339  ? $schedule->getAvailabilityFrom()->get(IL_CAL_UNIX)
340  : null;
341  $av_to = ($schedule->getAvailabilityTo() && !$schedule->getAvailabilityTo()->isNull())
342  ? $schedule->getAvailabilityTo()->get(IL_CAL_UNIX)
343  : null;
344 
345  if (($av_from && $a_from < $av_from) ||
346  ($av_to && $a_to > $av_to)) {
347  $blocked[] = $obj_id;
348  unset($counter[$obj_id]);
349  }
350  }
351  }
352 
353  $available = array_diff($a_ids, $blocked);
354  if (sizeof($available)) {
355  if ($a_return_counter) {
356  foreach ($a_ids as $id) {
357  if (!isset($counter[$id])) {
358  $counter[$id] = (int) $nr_map[$id];
359  }
360  }
361  return $counter;
362  } elseif ($a_return_single) {
363  return array_shift($available);
364  } else {
365  return $available;
366  }
367  }
368  }
369 
370  public static function isObjectAvailableInPeriod($a_obj_id, ilBookingSchedule $a_schedule, $a_from, $a_to)
371  {
372  global $DIC;
373 
374  $ilDB = $DIC->database();
375 
376  if (!$a_from) {
377  $a_from = time();
378  }
379  if (!$a_to) {
380  $a_to = strtotime("+1year", $a_from);
381  }
382 
383  if ($a_from > $a_to) {
384  return;
385  }
386 
387  // all nr of reservations in period that are not over yet (to >= now)
389  $repo = $f->getRepo();
390  $res = $repo->getNumberOfReservations([$a_obj_id], $a_from, $a_to, true);
391  $booked_in_period = (int) $res[$a_obj_id]["cnt"];
392 
393  $per_slot = ilBookingObject::getNrOfItemsForObjects(array($a_obj_id));
394  $per_slot = $per_slot[$a_obj_id];
395 
396  // max available nr of items per (week)day
397  $schedule_slots = array();
398  $definition = $a_schedule->getDefinition();
399  $map = array_flip(array("su", "mo", "tu", "we", "th", "fr", "sa"));
400  foreach ($definition as $day => $day_slots) {
401  $schedule_slots[$map[$day]] = $day_slots;
402  }
403 
404  $av_from = ($a_schedule->getAvailabilityFrom() && !$a_schedule->getAvailabilityFrom()->isNull())
405  ? $a_schedule->getAvailabilityFrom()->get(IL_CAL_UNIX)
406  : null;
407  $av_to = ($a_schedule->getAvailabilityTo() && !$a_schedule->getAvailabilityTo()->isNull())
408  ? strtotime($a_schedule->getAvailabilityTo()->get(IL_CAL_DATE) . " 23:59:59")
409  : null;
410 
411  // sum up max available (to >= now) items in period per (week)day
412  $available_in_period = 0;
413  $loop = 0;
414  while ($a_from < $a_to &&
415  ++$loop < 1000) {
416  // any slots for current weekday?
417  $day_slots = $schedule_slots[date("w", $a_from)];
418  if ($day_slots) {
419  foreach ($day_slots as $slot) {
420  // convert slot to current datetime
421  $slot = explode("-", $slot);
422  $slot_from = strtotime(date("Y-m-d", $a_from) . " " . $slot[0]);
423  $slot_to = strtotime(date("Y-m-d", $a_from) . " " . $slot[1]);
424  // slot has to be in the future and part of schedule availability
425  if ($slot_to > time() &&
426  $slot_from >= $av_from &&
427  ($slot_to <= $av_to || is_null($av_to))) {
428  $available_in_period += $per_slot;
429  }
430  }
431  }
432 
433  $a_from += (60 * 60 * 24);
434  }
435  if ($available_in_period - $booked_in_period > 0) {
436  return true;
437  }
438 
439  return false;
440  }
441 
442  //check if the user reached the limit of bookings in this booking pool.
443  public static function isBookingPoolLimitReachedByUser(int $a_user_id, int $a_pool_id) : int
444  {
445  global $DIC;
446  $ilDB = $DIC->database();
447 
448  $booking_pool_objects = ilBookingObject::getObjectsForPool($a_pool_id);
449 
450  $query = "SELECT count(user_id) total" .
451  " FROM booking_reservation" .
452  " WHERE " . $ilDB->in('object_id', $booking_pool_objects, false, 'integer') .
453  " AND user_id = " . $a_user_id .
454  " AND (status IS NULL OR status <> " . ilBookingReservation::STATUS_CANCELLED . ')';
455  $res = $ilDB->query($query);
456  $row = $res->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
457 
458  return (int) $row['total'];
459  }
460 
461  public static function getMembersWithoutReservation(int $a_object_id) : array
462  {
463  global $DIC;
464  $ilDB = $DIC->database();
465 
466  $pool_id = ilBookingObject::lookupPoolId($a_object_id);
467 
468  $res = array();
469  $query = 'SELECT DISTINCT bm.user_id user_id' .
470  ' FROM booking_member bm' .
471  ' WHERE bm.booking_pool_id = ' . $ilDB->quote($pool_id, 'integer') .
472  ' AND bm.user_id NOT IN (' .
473  'SELECT user_id' .
474  ' FROM booking_reservation' .
475  ' WHERE object_id = ' . $ilDB->quote($a_object_id, 'integer') .
476  ' AND (status IS NULL OR status <> ' . ilBookingReservation::STATUS_CANCELLED . '))';
477 
478  $set = $ilDB->query($query);
479 
480  while ($row = $ilDB->fetchAssoc($set)) {
481  $res[] = $row['user_id'];
482  }
483 
484  return $res;
485  }
486 
487  public static function isObjectAvailableNoSchedule($a_obj_id)
488  {
489  $available = self::getNumAvailablesNoSchedule($a_obj_id);
490  return (bool) $available; // #11864
491  }
492  public static function numAvailableFromObjectNoSchedule($a_obj_id)
493  {
494  $available = self::getNumAvailablesNoSchedule($a_obj_id);
495  return (int) $available;
496  }
497 
498  public static function getNumAvailablesNoSchedule($a_obj_id)
499  {
500  global $DIC;
501 
502  $ilDB = $DIC->database();
503 
504  $all = ilBookingObject::getNrOfItemsForObjects(array($a_obj_id));
505  $all = (int) $all[$a_obj_id];
506 
507  $set = $ilDB->query('SELECT COUNT(*) cnt' .
508  ' FROM booking_reservation r' .
509  ' JOIN booking_object o ON (o.booking_object_id = r.object_id)' .
510  ' WHERE (status IS NULL OR status <> ' . $ilDB->quote(self::STATUS_CANCELLED, 'integer') . ')' .
511  ' AND r.object_id = ' . $ilDB->quote($a_obj_id, 'integer'));
512  $cnt = $ilDB->fetchAssoc($set);
513  $cnt = (int) $cnt['cnt'];
514 
515  return (int) $all - $cnt; // #11864
516  }
517 
523  public static function getCurrentOrUpcomingReservation($a_object_id)
524  {
525  global $DIC;
526 
527  $ilDB = $DIC->database();
528 
529  $now = $ilDB->quote(time(), 'integer');
530 
531  $ilDB->setLimit(1);
532  $set = $ilDB->query('SELECT user_id, status, date_from, date_to' .
533  ' FROM booking_reservation' .
534  ' WHERE ((date_from <= ' . $now . ' AND date_to >= ' . $now . ')' .
535  ' OR date_from > ' . $now . ')' .
536  ' AND (status <> ' . $ilDB->quote(self::STATUS_CANCELLED, 'integer') .
537  ' OR STATUS IS NULL) AND object_id = ' . $ilDB->quote($a_object_id, 'integer') .
538  ' ORDER BY date_from');
539  $row = $ilDB->fetchAssoc($set);
540  return $row;
541  }
542 
543  public static function getObjectReservationForUser($a_object_id, $a_user_id, $a_multi = false)
544  {
545  global $DIC;
546 
547  $ilDB = $DIC->database();
548 
549  $set = $ilDB->query('SELECT booking_reservation_id FROM booking_reservation' .
550  ' WHERE user_id = ' . $ilDB->quote($a_user_id, 'integer') .
551  ' AND object_id = ' . $ilDB->quote($a_object_id, 'integer') .
552  ' AND (status <> ' . $ilDB->quote(self::STATUS_CANCELLED, 'integer') .
553  ' OR STATUS IS NULL)');
554  if (!$a_multi) {
555  $row = $ilDB->fetchAssoc($set);
556  return $row['booking_reservation_id'];
557  } else {
558  $res = array();
559  while ($row = $ilDB->fetchAssoc($set)) {
560  $res[] = $row['booking_reservation_id'];
561  }
562  return $res;
563  }
564  }
565 
574  public static function getList($a_object_ids, $a_limit = 10, $a_offset = 0, array $filter = [])
575  {
576  global $DIC;
577 
578  $ilDB = $DIC->database();
579 
580  $sql = 'SELECT r.*,o.title' .
581  ' FROM booking_reservation r' .
582  ' JOIN booking_object o ON (o.booking_object_id = r.object_id)';
583 
584  $count_sql = 'SELECT COUNT(*) AS counter' .
585  ' FROM booking_reservation r' .
586  ' JOIN booking_object o ON (o.booking_object_id = r.object_id)';
587 
588  $where = array($ilDB->in('r.object_id', $a_object_ids, '', 'integer'));
589  if ($filter['status']) {
590  if ($filter['status'] > 0) {
591  $where[] = 'status = ' . $ilDB->quote($filter['status'], 'integer');
592  } else {
593  $where[] = '(status != ' . $ilDB->quote(-$filter['status'], 'integer') .
594  ' OR status IS NULL)';
595  }
596  }
597  if ($filter['from']) {
598  $where[] = 'date_from >= ' . $ilDB->quote($filter['from'], 'integer');
599  }
600  if ($filter['to']) {
601  $where[] = 'date_to <= ' . $ilDB->quote($filter['to'], 'integer');
602  }
603  if (sizeof($where)) {
604  $sql .= ' WHERE ' . implode(' AND ', $where);
605  $count_sql .= ' WHERE ' . implode(' AND ', $where);
606  }
607 
608  $set = $ilDB->query($count_sql);
609  $row = $ilDB->fetchAssoc($set);
610  $counter = $row['counter'];
611 
612  $sql .= ' ORDER BY date_from DESC, booking_reservation_id DESC';
613 
614  $ilDB->setLimit($a_limit, $a_offset);
615  $set = $ilDB->query($sql);
616  $res = array();
617  while ($row = $ilDB->fetchAssoc($set)) {
618  $res[] = $row;
619  }
620 
621  return array('data' => $res, 'counter' => $counter);
622  }
623 
624 
631  public static function getUserFilter(array $a_object_ids)
632  {
633  global $DIC;
634 
635  $ilDB = $DIC->database();
636 
637  $res = array();
638 
639  $sql = "SELECT ud.usr_id,ud.lastname,ud.firstname,ud.login" .
640  " FROM usr_data ud " .
641  " LEFT JOIN booking_reservation r ON (r.user_id = ud.usr_id)" .
642  " WHERE ud.usr_id <> " . $ilDB->quote(ANONYMOUS_USER_ID, "integer") .
643  " AND " . $ilDB->in("r.object_id", $a_object_ids, "", "integer") .
644  " ORDER BY ud.lastname,ud.firstname";
645  $set = $ilDB->query($sql);
646  while ($row = $ilDB->fetchAssoc($set)) {
647  $res[$row["usr_id"]] = $row["lastname"] . ", " . $row["firstname"] .
648  " (" . $row["login"] . ")";
649  }
650 
651  return $res;
652  }
653 
654 
661  public static function changeStatus(array $a_ids, $a_status)
662  {
663  global $DIC;
664 
665  $ilDB = $DIC->database();
666 
667  if (self::isValidStatus($a_status)) {
668  return $ilDB->manipulate('UPDATE booking_reservation' .
669  ' SET status = ' . $ilDB->quote($a_status, 'integer') .
670  ' WHERE ' . $ilDB->in('booking_reservation_id', $a_ids, '', 'integer'));
671  }
672  }
673 
674  public function getCalendarEntry()
675  {
676  $ilDB = $this->db;
677 
678 
679  $set = $ilDB->query("SELECT ce.cal_id FROM cal_entries ce" .
680  " JOIN cal_cat_assignments cca ON ce.cal_id = cca.cal_id" .
681  " JOIN cal_categories cc ON cca.cat_id = cc.cat_id" .
682  " JOIN booking_reservation br ON ce.context_id = br.booking_reservation_id" .
683  " WHERE cc.obj_id = " . $ilDB->quote($this->getUserId(), 'integer') .
684  " AND br.user_id = " . $ilDB->quote($this->getUserId(), 'integer') .
685  " AND cc.type = " . $ilDB->quote(ilCalendarCategory::TYPE_BOOK, 'integer') .
686  " AND ce.context_id = " . $ilDB->quote($this->getId(), 'integer'));
687  $row = $ilDB->fetchAssoc($set);
688  return $row["cal_id"];
689  }
690 
700  public static function getCancelDetails($a_obj_id, $a_user_id, $a_from, $a_to)
701  {
702  global $DIC;
703 
704  $ilDB = $DIC->database();
705 
706  $res = array();
707 
708  $sql = "SELECT booking_reservation_id" .
709  " FROM booking_reservation" .
710  " WHERE object_id = " . $ilDB->quote($a_obj_id, "integer") .
711  " AND user_id = " . $ilDB->quote($a_user_id, "integer") .
712  " AND date_from = " . $ilDB->quote($a_from, "integer") .
713  " AND date_to = " . $ilDB->quote($a_to, "integer") .
714  " AND (status IS NULL" .
715  " OR status <> " . $ilDB->quote(self::STATUS_CANCELLED, "integer") . ")";
716  $set = $ilDB->query($sql);
717  while ($row = $ilDB->fetchAssoc($set)) {
718  $res[] = $row["booking_reservation_id"];
719  }
720 
721  return $res;
722  }
723 }
getAssignerId()
Get assigner user id.
a bookable ressource
const ANONYMOUS_USER_ID
Definition: constants.php:25
setStatus($a_status)
Set booking status.
setGroupId($a_group_id)
Set group id.
static isObjectAvailableNoSchedule($a_obj_id)
static getUserFilter(array $a_object_ids)
Get all users who have reservations for object(s)
getAvailabilityFrom()
Get availability start.
setFrom($a_from)
Set booking from date.
schedule for booking ressource
getAvailabilityTo()
Get availability end.
getStatus()
Get booking status.
const IL_CAL_UNIX
setAssignerId($a_assigner_id)
Set assigner user id.
static getObjectsForPool(int $a_pool_id)
Get all booking pool object ids from an specific booking pool.
getFrom()
Get booking from date.
getContextObjId()
Get context object id.
static getNrOfItemsForObjects(array $a_obj_ids)
Get nr of available items.
static isValidStatus($a_status)
Check if given status is valid.
setContextObjId($a_val)
Set context object id.
static getObjectReservationForUser($a_object_id, $a_user_id, $a_multi=false)
foreach($_POST as $key=> $value) $res
static getMembersWithoutReservation(int $a_object_id)
global $DIC
Definition: goto.php:24
getDefinition()
Get definition.
static getList($a_object_ids, $a_limit=10, $a_offset=0, array $filter=[])
List all reservations.
$query
setObjectId($a_object_id)
Set object id.
static getCurrentOrUpcomingReservation($a_object_id)
Get details about object reservation.
static getAvailableObject(array $a_ids, $a_from, $a_to, $a_return_single=true, $a_return_counter=false)
Check if any of given objects are bookable.
static lookupPoolId($object_id)
Lookup pool id.
static isBookingPoolLimitReachedByUser(int $a_user_id, int $a_pool_id)
__construct($a_id=null)
Constructor.
const IL_CAL_DATE
static isObjectAvailableInPeriod($a_obj_id, ilBookingSchedule $a_schedule, $a_from, $a_to)
global $ilDB
setUserId($a_user_id)
Set booking user id.
static numAvailableFromObjectNoSchedule($a_obj_id)
save()
Create new entry in db.
static getCancelDetails($a_obj_id, $a_user_id, $a_from, $a_to)
Get reservation ids from aggregated id for cancellation.
static changeStatus(array $a_ids, $a_status)
Batch update reservation status.
getUserId()
Get booking user id.
getTo()
Get booking to date.
setTo($a_to)
Set booking to date.
static getNumAvailablesNoSchedule($a_obj_id)