PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
← All changes | admin/helpers/availability.php +391 -31 1.7.1 → 1.8.16 View file →
@@ -154,8 +154,15 @@
154 154 // load dependencies
155 155 if (!class_exists('TACVBO')) {
156 156 require_once VBO_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'tac.vikbooking.php';
157 157 }
158 +
159 + /**
160 + * Set default nights transfer ratio.
161 + *
162 + * @since 1.18.5 (J) - 1.8.5 (WP)
163 + */
164 + $this->setNightsTransfersRatio();
158 165 }
159 166
160 167 /**
161 168 * Returns the global object, either a new instance or the existing instance
@@ -270,24 +277,98 @@
270 277 return 'No rooms available due to room or rate plan restrictions.';
271 278 default:
272 279 return 'Unknown error code.';
273 280 }
274 -
275 281 }
276 282
277 283 /**
284 + * Returns a list of room IDs from the given category IDs.
285 + *
286 + * @param array $category_ids List of category IDs to filter.
287 + *
288 + * @return array List of involved and unique room IDs.
289 + *
290 + * @since 1.17.6 (J) - 1.7.6 (WP)
291 + */
292 + public function filterRoomCategories(array $category_ids)
293 + {
294 + $category_ids = array_filter(array_map('abs', array_map('intval', $category_ids)));
295 +
296 + if (!$category_ids) {
297 + return [];
298 + }
299 +
300 + $dbo = JFactory::getDbo();
301 +
302 + $q = $dbo->getQuery(true)
303 + ->select($dbo->qn('id'))
304 + ->from($dbo->qn('#__vikbooking_rooms'));
305 +
306 + foreach ($category_ids as $cat_id) {
307 + $q->where([
308 + $dbo->qn('idcat') . ' = ' . $dbo->q($cat_id . ';'),
309 + $dbo->qn('idcat') . ' LIKE ' . $dbo->q($cat_id . ';%'),
310 + $dbo->qn('idcat') . ' LIKE ' . $dbo->q('%;' . $cat_id . ';%'),
311 + $dbo->qn('idcat') . ' LIKE ' . $dbo->q('%;' . $cat_id . ';'),
312 + ], 'OR');
313 + }
314 +
315 + $dbo->setQuery($q);
316 +
317 + return array_values(array_unique(array_map('intval', $dbo->loadColumn())));
318 + }
319 +
320 + /**
321 + * Loads a list of room categories.
322 + *
323 + * @param bool $public True for excluding the "private" categories.
324 + *
325 + * @return array The associative list of categories.
326 + *
327 + * @since 1.17.6 (J) - 1.7.6 (WP)
328 + * @since 1.18.3 (J) - 1.8.3 (WP) added argument $public.
329 + */
330 + public function loadRoomCategories($public = false)
331 + {
332 + $dbo = JFactory::getDbo();
333 +
334 + $dbo->setQuery(
335 + $dbo->getQuery(true)
336 + ->select([
337 + $dbo->qn('id'),
338 + $dbo->qn('name'),
339 + ])
340 + ->from($dbo->qn('#__vikbooking_categories'))
341 + ->order($dbo->qn('name') . ' ASC')
342 + );
343 +
344 + $categories = $dbo->loadAssocList();
345 +
346 + if ($public) {
347 + $categories = array_values(array_filter($categories, function($category) {
348 + return substr((string) $category['name'], 0, 1) !== '_';
349 + }));
350 + }
351 +
352 + return $categories;
353 + }
354 +
355 + /**
278 356 * Loads all rooms in VBO and maps them into an associative array.
279 357 *
280 358 * @param array $ids optional list of IDs to load.
281 359 * @param int $max optional rooms limit to fetch.
360 + * @param bool $anew true to avoid object caching.
282 361 *
283 362 * @return array the associative list of rooms.
284 363 *
285 364 * @since 1.16.10 (J) - 1.6.10 (WP) added arguments $ids, $max.
365 + * @since 1.17.5 (J) - 1.7.5 (WP) added argument $anew.
366 + * @since 1.18.6 (J) - 1.8.6 (WP) added support to negative IDs for category IDs.
286 367 */
287 - public function loadRooms(array $ids = [], $max = 0)
368 + public function loadRooms(array $ids = [], $max = 0, $anew = false)
288 369 {
289 - if ($this->all_rooms) {
370 + if ($this->all_rooms && !$anew) {
290 371 // return previously cached array if available
291 372 return $this->all_rooms;
292 373 }
293 374
@@ -310,9 +391,27 @@
310 391 ])
311 392 ->from($dbo->qn('#__vikbooking_rooms'));
312 393
313 394 if ($ids) {
395 + // cast all IDs to signed integers
314 396 $ids = array_map('intval', $ids);
397 +
398 + // normalize listing IDs to support (negative) category IDs
399 + $categoryIds = array_filter($ids, function($id) {
400 + return $id < 0;
401 + });
402 +
403 + if ($categoryIds) {
404 + // filter out negative IDs
405 + $ids = array_values(array_filter($ids, function($id) {
406 + return $id > 0;
407 + }));
408 +
409 + // include the listing IDs from category IDs, if any
410 + $ids = array_values(array_unique(array_merge($ids, $this->filterRoomCategories($categoryIds))));
411 + }
412 +
413 + // set query clause
315 414 $q->where($dbo->qn('id') . ' IN (' . implode(', ', $ids) . ')');
316 415 }
317 416
318 417 $q->order($dbo->qn('avail') . ' DESC');
@@ -321,9 +420,9 @@
321 420 $dbo->setQuery($q, 0, $max);
322 421 $room_rows = $dbo->loadAssocList();
323 422
324 423 if (!$room_rows) {
325 - return $this->all_rooms;
424 + return $anew ? [] : $this->all_rooms;
326 425 }
327 426
328 427 if ($this->isFrontBooking()) {
329 428 // apply translations on rooms
@@ -330,13 +429,19 @@
330 429 $vbo_tn = VikBooking::getTranslator();
331 430 $vbo_tn->translateContents($room_rows, '#__vikbooking_rooms');
332 431 }
333 432
433 + $assoc_rooms = [];
334 434 foreach ($room_rows as $room) {
335 - $this->all_rooms[$room['id']] = $room;
435 + $assoc_rooms[$room['id']] = $room;
336 436 }
337 437
338 - return $this->all_rooms;
438 + if (!$anew) {
439 + // cache room records
440 + $this->all_rooms = $assoc_rooms;
441 + }
442 +
443 + return $anew ? $assoc_rooms : $this->all_rooms;
339 444 }
340 445
341 446 /**
342 447 * Sets the current rooms as an associative array of information. The
@@ -371,17 +476,19 @@
371 476 return $rooms;
372 477 }
373 478
374 479 /**
375 - * Finds a room by name.
480 + * Finds a room (or multiple rooms) by name.
376 481 *
377 482 * @param string $name The room name to look for.
483 + * @param bool $all True to return a list of matches.
378 484 *
379 485 * @return array
380 486 *
381 487 * @since 1.16.10 (J) - 1.6.10 (WP)
488 + * @since 1.18.17 (J) - 1.8.17 (WP) added argument $all.
382 489 */
383 - public function getRoomByName(string $name)
490 + public function getRoomByName(string $name, bool $all = false)
384 491 {
385 492 $dbo = JFactory::getDbo();
386 493
387 494 $q = $dbo->getQuery(true)
@@ -389,12 +496,18 @@
389 496 ->from($dbo->qn('#__vikbooking_rooms'))
390 497 ->order($dbo->qn('avail') . ' DESC')
391 498 ->order($dbo->qn('name') . ' ASC');
392 499
393 - foreach (array_filter(explode(' ', $name)) as $nm_part) {
500 + foreach (array_filter(preg_split("/[\s\-_.,]+/", $name)) as $nm_part) {
394 501 $q->where($dbo->qn('name') . ' LIKE ' . $dbo->q("%{$nm_part}%"));
395 502 }
396 503
504 + if ($all) {
505 + // match all records
506 + $dbo->setQuery($q);
507 + return $dbo->loadAssocList();
508 + }
509 +
397 510 $dbo->setQuery($q, 0, 1);
398 511 $record = $dbo->loadAssoc();
399 512
400 513 return $record ?? [];
@@ -402,13 +515,17 @@
402 515
403 516 /**
404 517 * Loads all rate plans in VBO and maps them into an associative array.
405 518 *
519 + * @param bool $no_cache True to avoid internal caching.
520 + *
406 521 * @return array the associative list of rate plans.
522 + *
523 + * @since 1.17.6 (J) - 1.7.6 (WP) added $no_cache argument.
407 524 */
408 - public function loadRatePlans()
525 + public function loadRatePlans($no_cache = false)
409 526 {
410 - if ($this->all_rplans) {
527 + if (!$no_cache && $this->all_rplans) {
411 528 // return previously cached array if available
412 529 return $this->all_rplans;
413 530 }
414 531
@@ -442,9 +559,11 @@
442 559
443 560 // sort rate plans
444 561 $rate_plans = VikBooking::sortRatePlans($rate_plans, true);
445 562
446 - $this->all_rplans = $rate_plans;
563 + if (!$no_cache) {
564 + $this->all_rplans = $rate_plans;
565 + }
447 566
448 567 return $rate_plans;
449 568 }
450 569
@@ -451,18 +570,20 @@
451 570 /**
452 571 * Returns a list of rate plans derived from the given parent rate plan ID.
453 572 *
454 573 * @param int $parent_rate_id The parent rate plan ID.
574 + * @param ?array $all_rate_plans Optional cached rate plans list.
455 575 *
456 576 * @return array
457 577 *
458 578 * @since 1.16.10 (J) - 1.6.10 (WP)
579 + * @since 1.18.5 (J) - 1.8.5 (WP) added argument $all_rate_plans.
459 580 */
460 - public function getDerivedRatePlans(int $parent_rate_id)
581 + public function getDerivedRatePlans(int $parent_rate_id, ?array $all_rate_plans = null)
461 582 {
462 583 $derived_rplans = [];
463 584
464 - foreach ($this->loadRatePlans() as $rp_id => $rplan) {
585 + foreach (($all_rate_plans ?: $this->loadRatePlans()) as $rp_id => $rplan) {
465 586 if ($rplan['derived_id'] && $rplan['derived_id'] == $parent_rate_id && $rplan['derived_data']) {
466 587 // this rate plan is derived from the given parent rate plan
467 588 $derived_rplans[] = $rplan;
468 589 }
@@ -471,8 +592,226 @@
471 592 return $derived_rplans;
472 593 }
473 594
474 595 /**
596 + * Returns the orphan dates for the given or set rooms and dates.
597 + *
598 + * @param array $options List of fetching options.
599 + *
600 + * @return array Associative list of rooms orphan dates.
601 + *
602 + * @since 1.17.7 (J) - 1.7.7 (WP)
603 + */
604 + public function getOrphanDates(array $options = [])
605 + {
606 + // flag to indicate whether room-level restrictions were loaded
607 + $use_room_level_restr = false;
608 +
609 + // load and set rooms and restrictions
610 + if ($options['room_ids'] ?? []) {
611 + // force the requested rooms to be loaded
612 + $this->loadRooms((array) $options['room_ids']);
613 +
614 + // load restrictions with room filters
615 + $all_restrictions = VikBooking::loadRestrictions(true, (array) $options['room_ids']);
616 +
617 + // turn flag on for room-level restrictions being used
618 + $use_room_level_restr = true;
619 + } else {
620 + // load restrictions with no filters
621 + $all_restrictions = VikBooking::loadRestrictions(false);
622 + }
623 +
624 + // default minimum stay
625 + $def_min_stay = VikBooking::getDefaultNightsCalendar();
626 +
627 + // figure out dates range
628 + if (($current_stay_dates = $this->getStayDates()) && !($options['from_date'] ?? null)) {
629 + // populate current stay dates
630 + $options['from_date'] = $current_stay_dates[0];
631 + $options['to_date'] = $current_stay_dates[1];
632 + } else {
633 + // check given fetching options
634 + if (!($options['from_date'] ?? null)) {
635 + // default to today's date
636 + $options['from_date'] = date('Y-m-d');
637 + }
638 +
639 + if (!($options['to_date'] ?? null)) {
640 + // default to next week's date
641 + $options['to_date'] = date('Y-m-d', strtotime('+1 week'));
642 + }
643 + }
644 +
645 + // calculate the highest minimum stay for a better accuracy
646 + $all_min_los = [($def_min_stay > 1 ? $def_min_stay : 0)];
647 + foreach ($all_restrictions as $index => $restrs) {
648 + $all_min_los = array_merge($all_min_los, array_column($restrs, 'minlos'));
649 + }
650 + $max_min_los = max(array_map('intval', $all_min_los));
651 +
652 + if (!$max_min_los) {
653 + // no minimum stay restrictions to apply, hence no orphan dates
654 + return [];
655 + }
656 +
657 + // calculate past limit timestamp for today at midnight
658 + $lim_past_ts = strtotime(date('Y-m-d'));
659 +
660 + // always fetch a wider availability window for better accuracy
661 + $fetch_from_date = date('Y-m-d', strtotime("-{$max_min_los} days", strtotime($options['from_date'])));
662 + $fetch_to_date = date('Y-m-d', strtotime("+{$max_min_los} days", strtotime($options['to_date'])));
663 + if (strtotime($fetch_from_date) < $lim_past_ts) {
664 + // start fetching the inventory from today's date (past dates not accepted)
665 + $fetch_from_date = date('Y-m-d');
666 + }
667 +
668 + // always set stay dates
669 + $this->setStayDates($fetch_from_date, $fetch_to_date);
670 +
671 + // obtain the availability inventory by ignoring restrictions
672 + $ari = $this->getInventory(false);
673 +
674 + if (!$ari) {
675 + return [];
676 + }
677 +
678 + // build orphan dates pool
679 + $orphans_pool = [];
680 +
681 + // UTC timezone
682 + $utc_tz = new DateTimezone('UTC');
683 +
684 + // get date bounds
685 + $from_bound = new DateTime($options['from_date'], $utc_tz);
686 + $to_bound = new DateTime($options['to_date'], $utc_tz);
687 +
688 + // build iterable dates interval (period)
689 + $date_range = new DatePeriod(
690 + // start date included by default in the result set
691 + $from_bound,
692 + // interval between recurrences within the period
693 + new DateInterval('P1D'),
694 + // end date excluded by default from the result set
695 + $to_bound->modify('+1 day')
696 + );
697 +
698 + // scan rooms availability inventory
699 + foreach ($ari as $idroom => $room_ari) {
700 + // load proper room-level restrictions if not done already
701 + $all_restrictions = $use_room_level_restr ? $all_restrictions : VikBooking::loadRestrictions(true, [$idroom]);
702 +
703 + // iterate the dates interval
704 + foreach ($date_range as $dt) {
705 + // calculate date values
706 + $day_key = $dt->format('Y-m-d');
707 + $day_now_ts = strtotime($day_key);
708 + $day_after_ts = strtotime('+1 day', $day_now_ts);
709 +
710 + // parse room restrictions for the current inventory day and room to get the minimum stay
711 + $restr = VikBooking::parseSeasonRestrictions($day_now_ts, $day_after_ts, 1, $all_restrictions);
712 + $minimum_stay = (int) ($restr['minlos'] ?? $def_min_stay);
713 +
714 + if ($minimum_stay < 2) {
715 + // no real minimum stay restriction detected for this day
716 + continue;
717 + }
718 +
719 + // scan rooms availability
720 + foreach ($room_ari['inventory'] as $keypoint => $inventory) {
721 + if ($inventory['day'] != $day_key) {
722 + // not the date-key point we are looking for
723 + continue;
724 + }
725 +
726 + // tell whether the listing is available on the current date-key point
727 + $is_available = (bool) ($inventory['units_to_sell'] ?? $inventory['available'] ?? 0);
728 + if (!$is_available) {
729 + // this day is fully booked, hence no orphan dates
730 + continue 2;
731 + }
732 +
733 + // scan the availability for the next minimum stay days from the current day-key point
734 + for ($d = 0; $d < $minimum_stay; $d++) {
735 + // build next date-key point value (start from current day-key point as it counts as one available night of stay)
736 + $next_keypoint = $keypoint + $d;
737 +
738 + if (!isset($room_ari['inventory'][$next_keypoint])) {
739 + // no more data available
740 + break;
741 + }
742 +
743 + // tell whether the listing will be available on this future date-key point (0th day will always be available)
744 + $will_be_available = (bool) ($room_ari['inventory'][$next_keypoint]['units_to_sell'] ?? $room_ari['inventory'][$next_keypoint]['available'] ?? 0);
745 +
746 + if (!$will_be_available) {
747 + /**
748 + * Probable orphan date found for bookings on days ahead. Ensure this
749 + * is truly an orphan date by checking the days before. If staying
750 + * on this (available) night is allowed, then this should not be
751 + * considered as an orphan date, even though arriving is not allowed.
752 + */
753 + if (!($options['orphans_checkin'] ?? false)) {
754 + // check previous dates before saying it's an orphan date
755 + for ($backd = ($keypoint - 1), $distance = 1; $backd >= 0; $backd--, $distance++) {
756 + if (!isset($room_ari['inventory'][$backd])) {
757 + // nothing to do, let it be an orphan date
758 + break;
759 + }
760 +
761 + // tell whether the listing was available on this previous date-key point
762 + $was_available = (bool) ($room_ari['inventory'][$backd]['units_to_sell'] ?? $room_ari['inventory'][$backd]['available'] ?? 0);
763 +
764 + if (!$was_available) {
765 + // nothing to do, let it be an orphan date
766 + break;
767 + }
768 +
769 + // calculate past date values
770 + $past_day_now_ts = strtotime($room_ari['inventory'][$backd]['day']);
771 + $past_day_after_ts = strtotime('+1 day', $past_day_now_ts);
772 +
773 + // parse room restrictions for the current past day and room to get the minimum stay
774 + $restr = VikBooking::parseSeasonRestrictions($past_day_now_ts, $past_day_after_ts, 1, $all_restrictions);
775 + $minimum_stay = (int) ($restr['minlos'] ?? $def_min_stay);
776 +
777 + if ($minimum_stay <= $distance) {
778 + // free day with a minimum stay that allows to stay on the presumed orphan date
779 + // break the cycles for the presumed orphan date-key point, because it's not truly an orphan
780 + break 3;
781 + }
782 + }
783 + }
784 +
785 + // orphan date found
786 + if (!isset($orphans_pool[$idroom])) {
787 + // start container
788 + $orphans_pool[$idroom] = [
789 + 'room_name' => $room_ari['room_name'],
790 + 'orphans' => [],
791 + ];
792 + }
793 +
794 + // push orphan date information
795 + $orphans_pool[$idroom]['orphans'][] = [
796 + 'day' => $day_key,
797 + 'current_min_stay_nights' => $minimum_stay,
798 + 'max_min_stay_nights_allowed' => $d,
799 + ];
800 +
801 + // break the cycles for this date-key point
802 + break 2;
803 + }
804 + }
805 + }
806 + }
807 + }
808 +
809 + // return the associative list of room orphan dates found, if any
810 + return $orphans_pool;
811 + }
812 +
813 + /**
475 814 * Returns the inventory for the rooms and dates set.
476 815 *
477 816 * @param bool $restrictions Whether to include booking restrictions data.
478 817 *
@@ -659,9 +998,9 @@
659 998 return false;
660 999 }
661 1000
662 1001 // count injected rooms, if any
663 - $tot_rooms = count($this->room_ids);
1002 + $tot_rooms = (int) (($params['rooms_count'] ?? 0) ?: count($this->room_ids));
664 1003
665 1004 // build options array for TACVBO
666 1005 $options = [
667 1006 'hash' => md5('vbo.e4j.vbo'),
@@ -738,9 +1077,9 @@
738 1077 }
739 1078
740 1079 // optional filter by room IDs will be applied on this flow
741 1080 $found_rids = array_keys($website_rates);
742 - $unwanted_rids = $tot_rooms ? array_diff($found_rids, $this->room_ids) : [];
1081 + $unwanted_rids = $this->room_ids ? array_diff($found_rids, $this->room_ids) : [];
743 1082 foreach ($unwanted_rids as $rid) {
744 1083 unset($website_rates[$rid]);
745 1084 }
746 1085
@@ -747,8 +1086,20 @@
747 1086 return $website_rates;
748 1087 }
749 1088
750 1089 /**
1090 + * Returns the fully booked linear array of room IDs.
1091 + *
1092 + * @return array
1093 + *
1094 + * @since 1.18.8 (J) - 1.8.8 (WP)
1095 + */
1096 + public function getFullyBooked()
1097 + {
1098 + return (array) $this->fully_booked;
1099 + }
1100 +
1101 + /**
751 1102 * Finds the available suggestions in case of no availability previously occurred
752 1103 * while getting the rates. This method should be called after getRates() so that
753 1104 * a valid errorCode to be analized will be available, unless code is forced.
754 1105 * Suggestions can include closest booking dates and/or different room-guest parties.
@@ -807,15 +1158,15 @@
807 1158 * we build a list of available solutions for booking split stays on the same dates. The
808 1159 * visibility should be public so that other Views could use just this method.
809 1160 *
810 1161 * @param array $room_ids list of unavailable, yet compatible, room IDs.
811 - * @param array $busy_list optional list of busy records for the involved dates.
1162 + * @param ?array $busy_list optional list of busy records for the involved dates.
812 1163 *
813 1164 * @return array associative list of available split stays, or empty array.
814 1165 *
815 1166 * @since 1.16.0 (J) - 1.6.0 (WP)
816 1167 */
817 - public function findSplitStays(array $room_ids = [], array $busy_list = null)
1168 + public function findSplitStays(array $room_ids = [], ?array $busy_list = null)
818 1169 {
819 1170 if (!$room_ids) {
820 1171 return [];
821 1172 }
@@ -916,15 +1267,15 @@
916 1267 }
917 1268 }
918 1269 }
919 1270
920 - if (!count($avroom_nights)) {
1271 + if (!$avroom_nights) {
921 1272 // no rooms available at all, there's no way to do anything
922 1273 return [];
923 1274 }
924 1275
925 1276 // make sure all nights requested can be satisfied by at least one room
926 - foreach ($groupdays as $gday) {
1277 + foreach ($groupdays as $gday_index => $gday) {
927 1278 $day_key = date('Y-m-d', $gday);
928 1279 $day_av = false;
929 1280 foreach ($avroom_nights as $rid => $av_nights) {
930 1281 if (in_array($day_key, $av_nights)) {
@@ -932,10 +1283,11 @@
932 1283 $day_av = true;
933 1284 break;
934 1285 }
935 1286 }
936 - if (!$day_av) {
937 - // this night is not available in any room, unable to proceed
1287 + // ensure there's availability for this day, or permit if it's the check-out day
1288 + if (!$day_av && !($gday_index === (count($groupdays) - 1) && $this->inonout_allowed)) {
1289 + // this night of stay is not available in any room, unable to proceed
938 1290 return [];
939 1291 }
940 1292 }
941 1293
@@ -1133,9 +1485,9 @@
1133 1485 }
1134 1486
1135 1487 // apply nights/transfers ratio limit (unless disabled)
1136 1488 $nights_transfers_ratio = $this->getNightsTransfersRatio();
1137 - if ($nights_transfers_ratio > 0 && $nights_transfers_ratio < 100) {
1489 + if ($nights_transfers_ratio > 0 && $nights_transfers_ratio <= 100) {
1138 1490 // count and apply limits
1139 1491 foreach ($split_stay_sols as $k => $split_stay_sol) {
1140 1492 // count nights and transfers
1141 1493 $split_stay_transfers = count($split_stay_sol) - 1;
@@ -1150,11 +1502,14 @@
1150 1502 unset($split_stay_sols[$k]);
1151 1503 $altered_sols = true;
1152 1504 }
1153 1505 }
1506 + } else {
1507 + // split stays have been disabled
1508 + $split_stay_sols = [];
1154 1509 }
1155 1510
1156 - if ($altered_sols && count($split_stay_sols)) {
1511 + if ($altered_sols && $split_stay_sols) {
1157 1512 // restore the array keys
1158 1513 $split_stay_sols = array_values($split_stay_sols);
1159 1514 }
1160 1515
@@ -2025,13 +2380,13 @@
2025 2380 return $this;
2026 2381 }
2027 2382
2028 2383 /**
2029 - * Returns the current stay date or timestamps.
2384 + * Returns the current stay dates or timestamps.
2030 2385 *
2031 2386 * @param bool $ts whether to get the date timestamps.
2032 2387 *
2033 - * @return array the current stay date timestamps.
2388 + * @return array the current stay dates or timestamps.
2034 2389 */
2035 2390 public function getStayDates($ts = false)
2036 2391 {
2037 2392 return $ts ? $this->stay_ts : $this->stay_dates;
@@ -2146,23 +2501,28 @@
2146 2501 * @since 1.16.0 (J) - 1.6.0 (WP)
2147 2502 */
2148 2503 public function getDefaultNightsTransfersRatio()
2149 2504 {
2150 - $config = VBOFactory::getConfig();
2505 + static $transferRatio = null;
2151 2506
2152 - return (int)$config->get('split_stay_ratio', 50);
2507 + if ($transferRatio === null) {
2508 + $config = VBOFactory::getConfig();
2509 + $transferRatio = (int) $config->get('split_stay_ratio', 50);
2510 + }
2511 +
2512 + return $transferRatio;
2153 2513 }
2154 2514
2155 2515 /**
2156 2516 * Sets the nights/transfers ratio for split stays. Use it to start applying limits.
2157 2517 *
2158 - * @param mixed $ratio integer value, or the default config setting will be applied.
2518 + * @param ?int $ratio Optional ratio integer value, or default value will apply.
2159 2519 *
2160 2520 * @return self
2161 2521 *
2162 2522 * @since 1.16.0 (J) - 1.6.0 (WP)
2163 2523 */
2164 - public function setNightsTransfersRatio($ratio = null)
2524 + public function setNightsTransfersRatio(?int $ratio = null)
2165 2525 {
2166 2526 if (is_int($ratio)) {
2167 2527 $this->nights_transfers_ratio = $ratio;
2168 2528 } else {
@@ -2180,9 +2540,9 @@
2180 2540 * @since 1.16.0 (J) - 1.6.0 (WP)
2181 2541 */
2182 2542 public function isFrontBooking()
2183 2543 {
2184 - return (bool)$this->is_front_booking;
2544 + return (bool) $this->is_front_booking;
2185 2545 }
2186 2546
2187 2547 /**
2188 2548 * Toggles the flag to behave for the front-end booking process.