PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.2
VikBooking Hotel Booking Engine & PMS v1.7.2
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
vikbooking / admin / helpers / src / performance / cleaner.php

cleaner.php in VikBooking Hotel Booking Engine & PMS 1.7.2, at admin/helpers/src/performance/cleaner.php

261 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2024 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * Performance Cleaner implementation.
16 *
17 * @since 1.17.2 (J) - 1.7.2 (WP)
18 */
19 final class VBOPerformanceCleaner
20 {
21 /**
22 * @var array
23 */
24 private static $options = [];
25
26 /**
27 * Sets a list of given options to filter certain cleaning operations.
28 *
29 * @param array $options List of options to set.
30 *
31 * @return void
32 */
33 public static function setOptions(array $options)
34 {
35 static::$options = $options;
36 }
37
38 /**
39 * Performs a global check on what needs to be done to clean up performances.
40 *
41 * @return int The number of database records that were cleaned up.
42 */
43 public static function runCheck()
44 {
45 // list of operations that should be skipped
46 $skip_checks = VBOFactory::getConfig()->getArray('performance_cleaner_skip_list', []);
47
48 // number of records affected
49 $affected_records = 0;
50
51 if (!in_array('seasons', $skip_checks)) {
52 // clean up expired seasonal records
53 $affected_records += self::pricingAlterations();
54 }
55
56 return $affected_records;
57 }
58
59 /**
60 * Cleans up expired season pricing records.
61 *
62 * @return int The number of rows affected.
63 */
64 public static function pricingAlterations()
65 {
66 $dbo = JFactory::getDbo();
67
68 $affected = 0;
69
70 $nowinfo = getdate();
71
72 $year_base = mktime(0, 0, 0, 1, 1, $nowinfo['year']);
73 $midnight_base = ($nowinfo['hours'] * 3600) + ($nowinfo['minutes'] * 60) + $nowinfo['seconds'];
74
75 $season_secs = $nowinfo[0] - $year_base - $midnight_base;
76
77 $isleap = $nowinfo['year'] % 4 == 0 && ($nowinfo['year'] % 100 != 0 || $nowinfo['year'] % 400 == 0);
78
79 if ($isleap) {
80 $leapts = mktime(0, 0, 0, 2, 29, $nowinfo['year']);
81 if ($nowinfo[0] >= $leapts) {
82 $season_secs -= 86400;
83 }
84 }
85
86 // delete the records of the past year
87 $dbo->setQuery(
88 $dbo->getQuery(true)
89 ->delete($dbo->qn('#__vikbooking_seasons'))
90 ->where($dbo->qn('year') . ' = ' . $dbo->q(($nowinfo['year'] - 1)))
91 );
92
93 $dbo->execute();
94
95 $affected += (int) $dbo->getAffectedRows();
96
97 // delete the expired records for the current year
98 $dbo->setQuery(
99 $dbo->getQuery(true)
100 ->delete($dbo->qn('#__vikbooking_seasons'))
101 ->where($dbo->qn('from') . ' < ' . $season_secs)
102 ->where($dbo->qn('to') . ' < ' . $season_secs)
103 ->where($dbo->qn('from') . ' < ' . $dbo->qn('to'))
104 ->where($dbo->qn('from') . ' > 0')
105 ->where($dbo->qn('to') . ' > 0')
106 ->where($dbo->qn('year') . ' = ' . $dbo->q($nowinfo['year']))
107 );
108
109 $dbo->execute();
110
111 $affected += (int) $dbo->getAffectedRows();
112
113 return $affected;
114 }
115
116 /**
117 * Performs a pricing snapshot of a listing for a range of dates, by cleaning up
118 * all previous seasonal rates and by re-creating only the needed records. Useful
119 * for those listings who had hundreds of pricing alteration updates for the same
120 * calendar day. Strongly recommended only for those who use a SINGLE rate plan.
121 *
122 * @return array Seasons snapshot operation results.
123 *
124 * @throws Exception
125 */
126 public static function listingSeasonSnapshot()
127 {
128 $dbo = JFactory::getDbo();
129
130 $listing_id = (int) (static::$options['listing_id'] ?? null);
131 $id_price = (int) (static::$options['id_price'] ?? null);
132 $from_date = static::$options['from_date'] ?? date('Y-m-d');
133 $to_date = static::$options['to_date'] ?? date('Y-m-d', strtotime('+3 months'));
134
135 if (!$listing_id) {
136 throw new Exception('Missing required listing ID.', 400);
137 }
138
139 if (!$from_date || !$to_date || strtotime($from_date) > strtotime($to_date)) {
140 throw new Exception('Invalid dates provided.', 400);
141 }
142
143 // obtain a pricing snapshot for the given listing and dates
144 $snapshot = VBOModelPricing::getInstance()->getRoomRates([
145 'from_date' => $from_date,
146 'to_date' => $to_date,
147 'id_room' => $listing_id,
148 'id_price' => $id_price,
149 'all_rplans' => false,
150 'restrictions' => false,
151 ]);
152
153 // confirm the rate plan ID
154 foreach ($snapshot as $dayrate) {
155 $id_price = $dayrate['idprice'];
156 break;
157 }
158
159 // gather the list of season records to remove
160 $involved_seasons = [];
161 foreach ($snapshot as $dayrate) {
162 foreach ($dayrate['spids'] ?? [] as $sp_id) {
163 if (!in_array($sp_id, $involved_seasons)) {
164 $involved_seasons[] = $sp_id;
165 }
166 }
167 }
168
169 if (!$involved_seasons) {
170 throw new Exception('No seasonal records to clean for the given listing and dates.', 500);
171 }
172
173 // clean up database records
174 $dbo->setQuery(
175 $dbo->getQuery(true)
176 ->delete($dbo->qn('#__vikbooking_seasons'))
177 ->where($dbo->qn('id') . ' IN (' . implode(',', array_map('intval', $involved_seasons)) . ')')
178 );
179 $dbo->execute();
180
181 $records_removed = (int) $dbo->getAffectedRows();
182
183 // build new season intervals from snapshot
184 $all_days = array_keys($snapshot);
185 $season_intervals = [];
186 $firstind = 0;
187 $firstdaycost = $snapshot[$all_days[0]]['cost'];
188 $nextdaycost = false;
189 for ($i = 1; $i < count($all_days); $i++) {
190 $ind = $all_days[$i];
191 $nextdaycost = $snapshot[$ind]['cost'];
192 if ($firstdaycost != $nextdaycost) {
193 $interval = [
194 'from' => $all_days[$firstind],
195 'to' => $all_days[($i - 1)],
196 'cost' => $firstdaycost
197 ];
198 $season_intervals[] = $interval;
199 $firstdaycost = $nextdaycost;
200 $firstind = $i;
201 }
202 }
203 if ($nextdaycost === false) {
204 $interval = [
205 'from' => $all_days[$firstind],
206 'to' => $all_days[$firstind],
207 'cost' => $firstdaycost
208 ];
209 $season_intervals[] = $interval;
210 } elseif ($firstdaycost == $nextdaycost) {
211 $interval = [
212 'from' => $all_days[$firstind],
213 'to' => $all_days[($i - 1)],
214 'cost' => $firstdaycost
215 ];
216 $season_intervals[] = $interval;
217 }
218
219 // list of errors occurred
220 $errors = [];
221
222 /**
223 * Attempt to preload and cache seasons for other dates, so that applying new rates
224 * will be faster. We cannot preload these dates, because seasons were just removed.
225 */
226 VikBooking::preloadSeasonRecords([$listing_id], strtotime($to_date), strtotime('+1 month', strtotime($to_date)));
227
228 // scan all season intervals
229 foreach ($season_intervals as $season_snap) {
230 try {
231 // set the new rate for this calculated interval
232 VBOModelPricing::getInstance([
233 'from_date' => $season_snap['from'],
234 'to_date' => $season_snap['to'],
235 'id_room' => $listing_id,
236 'id_price' => $id_price,
237 'rate' => $season_snap['cost'],
238 'min_los' => 0,
239 'max_los' => 0,
240 'update_otas' => false,
241 ])->modifyRateRestrictions();
242 } catch (Exception $e) {
243 // silently push the error
244 $errors[] = sprintf('%s - %s: %s', $season_snap['from'], $season_snap['to'], $e->getMessage());
245 }
246 }
247
248 // unset preloaded and cached seasons
249 VikBooking::preloadSeasonRecords([$listing_id], false);
250
251 // return values
252 return [
253 'listing_id' => $listing_id,
254 'new_intervals' => count($season_intervals),
255 'records_removed' => $records_removed,
256 'intervals' => $season_intervals,
257 'errors' => $errors,
258 ];
259 }
260 }
261