PluginProbe
Booking Calendar / 10.10.2
Booking Calendar v10.10.2
11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 10.11.3 All 202 releases
booking / includes / page-availability / availability__resource.php

availability__resource.php in Booking Calendar 10.10.2, at includes/page-availability/availability__resource.php

481 lines 21.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version 1.0
4 * @package Booking Calendar
5 * @category Resource Availability - define "unavailable" "date_status" in "wp_booking_dates_props" table.
6 * @author wpdevelop
7 *
8 * @web-site https://wpbookingcalendar.com/
9 * @email info@wpbookingcalendar.com
10 * @modified 2022-11-23
11 *
12 */
13
14 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
15
16
17 /**
18 * Get unavailable dates for the booking resource. Based on 'resource availability' - new Availability UI.
19 *
20 * @param int $resource_id
21 *
22 * @return array|object|stdClass[]|null
23 */
24 function wpbc_resource__get_unavailable_dates( $resource_id = 1 ){
25
26 $resource_id = intval( $resource_id );
27 if ( empty( $resource_id ) ) {
28 $resource_id = 1;
29 }
30
31 $resource_availability = wpbc_availability__get_dates_status__sql( array(
32 'calendar_date' => 'CURDATE', // 'CURDATE' | 'ALL'
33 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
34 'prop_value' => 'unavailable', // 'unavailable', 'available', 'pending', 'approved'
35 'resource_id' => intval( $resource_id ) // int or dcv
36 ) );
37
38 $unavailable__dates_y_m_d__arr = array();
39
40 foreach ( $resource_availability as $unavailable_db_obj ) {
41 list( $date_y_m_d, $time_his ) = explode( ' ', $unavailable_db_obj->calendar_date );
42 $unavailable__dates_y_m_d__arr[] = $date_y_m_d;
43 }
44
45 return $unavailable__dates_y_m_d__arr;
46 }
47
48
49 /**
50 * Get unavailable dates for array of booking resources
51 *
52 * @param array $resource_id_arr // [1, 13, 8, 6, 7]
53 * @param mixed $search_dates // 'CURDATE' | 'ALL' | [ "2023-08-03" , "2023-08-04" , "2023-08-05" ]
54 *
55 * @return array - array of unavailable dates: array( resource_A_ID => array( DATES_Y_M_D, .... ),
56 resource_B_ID => array( DATES_Y_M_D, .... ), ...
57 Example:
58 array( 1 => array( "2023-08-03" , "2023-08-04" ),
59 8 => array( "2023-08-03" ), ...
60 */
61 function wpbc_for_resources_arr__get_unavailable_dates( $resource_id_arr, $search_dates = 'CURDATE' ) { // FixIn: 9.7.3.11.
62
63 // Booking resources -----------------------------------------------------------------------------------------------
64 $resource_id_csd = implode( ',', $resource_id_arr ); // '9,13,5,6,7,1,2,10,11,12,3,4,8'
65
66 // Dates -----------------------------------------------------------------------------------------------------------
67 if ( is_array( $search_dates ) ) { // Array of dates: ["2023-08-03"]
68
69 foreach ( $search_dates as $date_ymd ) {
70 $search_dates_arr[] = $date_ymd . ' 00:00:00';
71 }
72 $search_dates_formated = implode( ',', $search_dates_arr );
73
74 } else { // Probably 'CURDATE' | 'ALL'
75
76 $search_dates_formated = ( in_array( $search_dates, array( 'ALL', 'CURDATE' ) ) )
77 ? $search_dates
78 : 'CURDATE' ;
79 }
80
81 // Unavailable objects ---------------------------------------------------------------------------------------------
82 $resource_availability = wpbc_availability__get_dates_status__sql( array(
83 'calendar_date' => $search_dates_formated, // 'CURDATE' | 'ALL'
84 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
85 'prop_value' => 'unavailable', // 'unavailable', 'available', 'pending', 'approved'
86 'resource_id' => $resource_id_csd // int or dcv
87 ) );
88
89 // Formatted array of unavailable booking resource dates ----------------------------------------------------------
90 $resource_unavailable_dates_arr = array();
91 foreach ( $resource_availability as $resource_unavailable_obj ) {
92
93 if ( ! isset( $resource_unavailable_dates_arr[ $resource_unavailable_obj->resource_id ] ) ) {
94 $resource_unavailable_dates_arr[ $resource_unavailable_obj->resource_id ] = array();
95 }
96 $calendar_date = explode( ' ', $resource_unavailable_obj->calendar_date );
97 $resource_unavailable_dates_arr[ $resource_unavailable_obj->resource_id ][] = $calendar_date[0];
98 }
99
100 return $resource_unavailable_dates_arr;
101 }
102
103
104 /**
105 * Get dates status of specific booking resource
106 *
107 * @param array $params = array(
108 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
109 'prop_value' => 'unavailable', // 'unavailable', 'available', 'pending', 'approved'
110 'resource_id' => 1 // int or dcv
111 )
112 *
113 * booking date property can be relative to: prop_name = 'date_status', 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
114 *
115 * prop_name = 'date_status' -> prop_value = 'unavailable', 'available', 'pending', 'approved'
116 *
117 * @return array of DB objects array(
118 0 = {stdClass} {
119 ->booking_dates_prop_id = "1"
120 ->resource_id = "4"
121 ->calendar_date = "2023-04-04 00:00:00"
122 ->prop_name = "date_status"
123 ->prop_value = "unavailable"
124 }
125 , ... )
126 *
127 * Example:
128 wpbc_availability__get_dates_status__sql( array(
129 'calendar_date' => 'CURDATE', // 'CURDATE' | 'ALL' | '2023-07-15 00:00:00,2023-07-21 00:00:00'
130 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
131 'prop_value' => 'unavailable', // 'unavailable', 'available', 'pending', 'approved'
132 'resource_id' => 1 // int or dcv
133 ) );
134 */
135 function wpbc_availability__get_dates_status__sql( $params ){
136
137 // CACHE - GET :: check if such request was cached and get it ----------------------------------------------- // FixIn: 9.7.3.14.
138 $params_for_cache_key = $params;
139 if ( isset( $params_for_cache_key['resource_id'] ) ) {
140 $params_for_cache_key['resource_id'] = (string) $params_for_cache_key['resource_id'];
141 }
142 $params_for_cache = maybe_serialize( $params_for_cache_key );
143 $cache_result = wpbc_cache__get( 'wpbc_availability__get_dates_status__sql', $params_for_cache );
144 if ( ! is_null( $cache_result ) ) {
145 return $cache_result;
146 }
147 // -----------------------------------------------------------------------------------------------------------------
148
149
150 $defaults = array(
151 'calendar_date' => 'CURDATE', // 'CURDATE' | 'ALL' | '2023-07-15 00:00:00,2023-07-21 00:00:00' // FixIn: 9.7.3.11.
152 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
153 'prop_value' => 'unavailable', // 'unavailable', 'available', 'pending', 'approved'
154 'resource_id' => 1 // int or dcv
155 );
156 $params = wp_parse_args( $params, $defaults );
157
158 // S a n i t i z e
159 $params_rules = array(
160 'calendar_date' => array( 'validate' => 's', 'default' => 'CURDATE' ) , // array( 'validate' => array( 'CURDATE', 'ALL' ), 'default' => 'CURDATE' ) ,
161 'prop_name' => array( 'validate' => 's', 'default' => 'date_status' ) ,
162 'prop_value' => array( 'validate' => 's', 'default' => 'unavailable' ) ,
163 'resource_id' => array( 'validate' => 'digit_or_csd', 'default' => 1 )
164 );
165 $params = wpbc_sanitize_params_in_arr( $params, $params_rules );
166 /**
167
168 $params['resource_id'] = ( '' != $params['resource_id'] ) ? wpbc_sanitize_digit_or_csd( $params['resource_id'] ) : 1;
169 $params['prop_name'] = wpbc_sanitize_text( $params['prop_name'] );
170 $params['prop_value'] = wpbc_sanitize_text( $params['prop_value'] );
171 */
172
173
174 // S Q L
175 global $wpdb;
176 $sql = array();
177 $sql_args = array();
178
179
180 $sql['start_select'] = "SELECT * "; // "SELECT DISTINCT calendar_date ";
181 $sql['from'] = "FROM {$wpdb->prefix}booking_dates_props ";
182
183 // W H E R E
184 $sql['where'] = 'WHERE ( 1 = 1 ) ';
185 $sql['where'] .= " AND resource_id IN ( {$params['resource_id']} ) ";
186
187 if ( '' != $params['calendar_date'] ) {
188
189 // FixIn: 9.7.3.11.
190 if ( 'ALL' == $params['calendar_date'] ) {
191 // All dates
192 } else if ( 'CURDATE' == $params['calendar_date'] ) {
193
194 $sql['where'] .= " AND calendar_date >= CURDATE() "; // Current dates
195
196 } else { // Specific Date(s)
197
198 if ( false === strpos( $params['calendar_date'], ',' ) ) { // One date: - '2023-07-15 00:00:00'
199
200 $sql['where'] .= " AND ( calendar_date = %s ) ";
201 $sql_args[] = $params['calendar_date'];
202 } else { // Comma seperated dates: - '2023-07-15 00:00:00, 2023-07-16 00:00:00'
203
204 $dates_arr = explode( ',', $params['calendar_date'] );
205 $in_search_arr = array();
206 foreach ( $dates_arr as $date_ymd ) {
207 $in_search_arr[] = '%s';
208 $sql_args[] = $date_ymd;
209 }
210 $in_search_dates_csv = implode( ',', $in_search_arr );
211 $sql['where'] .= " AND calendar_date IN ( {$in_search_dates_csv} ) ";
212 }
213 }
214 }
215
216 if ( '' != $params['prop_name'] ) {
217 $sql['where'] .= " AND ( prop_name = %s ) ";
218 $sql_args[] = $params['prop_name'];
219 }
220
221 if ( '' != $params['prop_value'] ) {
222 $sql['where'] .= " AND ( prop_value = %s ) ";
223 $sql_args[] = $params['prop_value'];
224 }
225
226 // O R D E R
227 $sql['order'] = " ORDER BY calendar_date";
228
229 // L I M I T
230 $sql['limit'] = '';
231 /**
232 * $sql['limit'] = " LIMIT %d, %d ";
233 $sql_args[] = ( $params['page_num'] - 1 ) * $params['page_items_count'];
234 $sql_args[] = $params['page_items_count'];
235 */
236
237
238
239 /**
240 * Good Practice: https://blog.ircmaxell.com/2017/10/disclosure-wordpress-wpdb-sql-injection-technical.html
241 *
242 $sql['where'] .= "( bk.form LIKE %s ) ";
243 $sql_args[] = '%' . $wpdb->esc_like( $params['keyword'] ) . '%';
244
245 if ( is_numeric( $params['keyword'] ) ) {
246 $sql['where'] .= " OR ( bk.booking_id = %d ) ";
247 $sql_args[] = intval( $params['keyword'] );
248 }
249 *
250 */
251 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
252 $sql_prepared = $wpdb->prepare( $sql['start_select'] . $sql['from'] . $sql['where'] . $sql['order'] . $sql['limit'], $sql_args );
253 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
254 $bookings_sql_obj = $wpdb->get_results( $sql_prepared );
255
256 // CACHE - SAVE :: ------------------------------------------------------------------------------------------------
257 $cache_result = wpbc_cache__save( 'wpbc_availability__get_dates_status__sql', $params_for_cache, $bookings_sql_obj );
258
259 return $bookings_sql_obj;
260 /*
261 "CREATE TABLE {$wpdb->prefix}booking_dates_props (
262 booking_dates_prop_id bigint(20) unsigned NOT NULL auto_increment,
263 resource_id bigint(10) NOT NULL default 1,
264 calendar_date datetime NOT NULL default '0000-00-00 00:00:00',
265 prop_name varchar(200) NOT NULL default '',
266 prop_value text,
267 PRIMARY KEY (booking_dates_prop_id)
268 )";
269 */
270 }
271
272
273 /**
274 * Update dates status
275 *
276 * @param $params array(
277 'resource_id' => 1, // int
278 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
279 'prop_value' => 'unavailable', // 'available', 'unavailable' , 'pending', 'approved'
280 'dates_selection' => '' // '2023-04-04 | 2023-04-07'
281
282 )
283 *
284 * @return bool|int - return how many DB rows affected -how many dates processed
285 */
286 function wpbc_availability__update_dates_status__sql( $params ){
287
288 $defaults = array(
289 'resource_id' => 1, // int
290 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
291 'prop_value' => 'unavailable', // 'available', 'unavailable' , 'pending', 'approved'
292 'dates_selection' => '' // '2023-04-04 | 2023-04-07'
293
294 );
295 $params = wp_parse_args( $params, $defaults );
296
297 // S a n i t i z e
298 $params_rules = array(
299 'dates_selection' => array( 'validate' => 's', 'default' => '' ) ,
300 'prop_name' => array( 'validate' => 's', 'default' => 'date_status' ) ,
301 'prop_value' => array( 'validate' => 's', 'default' => 'unavailable' ) ,
302 'resource_id' => array( 'validate' => 'digit_or_csd', 'default' => 1 )
303 );
304 $params = wpbc_sanitize_params_in_arr( $params, $params_rules );
305
306
307 if ( false !== strpos( $params['dates_selection'], '~' ) ) { // Range Days
308
309 $dates_arr = wpbc_get_dates_arr__from_dates_range( array(
310 'dates_separator' => ' ~ ', // ' ~ '
311 'dates' => $params['dates_selection'], // '2023-04-04 ~ 2023-04-07'
312 ) );
313
314 } else { // Multiple Days
315 $dates_arr = wpbc_get_dates_arr__from_dates_comma_separated( array(
316 'dates_separator' => ', ', // ', '
317 'dates' => $params['dates_selection'], // '2023-04-04 ~ 2023-04-07'
318 ) );
319 }
320
321 $row_number = false;
322
323 if ( ! empty( $dates_arr ) ) {
324
325 global $wpdb;
326
327 // Remove dates ------------------------------------------------------------------------------------------------
328
329 // "DELETE FROM {$wpdb->prefix}booking_dates_props WHERE resource_id = %d AND prop_name = %s AND ( calendar_date = %s OR calendar_date = %s )"
330 $sql = "DELETE FROM {$wpdb->prefix}booking_dates_props WHERE resource_id = %d AND prop_name = %s ";
331
332 $sql_args = array();
333 $sql_args[] = $params['resource_id'];
334 $sql_args[] = $params['prop_name'];
335
336 $sub_sql = array();
337 foreach ( $dates_arr as $calendar_date ) {
338
339 $sub_sql[] = 'calendar_date = %s';
340 $sql_args[] = $calendar_date . ' 00:00:00';
341 }
342 if ( count( $sub_sql ) > 0 ) {
343 $sql .= ' AND ( ';
344 $sub_sql = implode( ' OR ', $sub_sql );
345 $sql .= $sub_sql;
346 $sql .= " )";
347 }
348 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
349 $sql_prepared = $wpdb->prepare( $sql, $sql_args );
350 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
351 $row_number = $wpdb->query( $sql_prepared );
352
353
354 // If we set the dates as 'available', then we skip INSERT into DB, because previously we have already deleted all 'unavailable' dates status for such dates
355 if ( ( 'date_status' == $params['prop_name'] ) && ( 'available' == $params['prop_value'] ) ) {
356 return $row_number;
357 }
358
359 // Insert new dates ------------------------------------------------------------------------------------------------
360 $sql_args = array();
361
362 $sql = "INSERT INTO {$wpdb->prefix}booking_dates_props ( resource_id, calendar_date, prop_name, prop_value) VALUES ";
363
364 $sub_sql = array();
365 foreach ( $dates_arr as $calendar_date ) {
366
367 $sub_sql[] = "( %d, %s, %s, %s )";
368 $sql_args[] = $params['resource_id'];
369 $sql_args[] = $calendar_date . ' 00:00:00';
370 $sql_args[] = $params['prop_name'];
371 $sql_args[] = $params['prop_value'];
372 }
373
374 $sub_sql = implode( ',', $sub_sql );
375 $sql .= $sub_sql;
376 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
377 $sql_prepared = $wpdb->prepare( $sql, $sql_args );
378 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
379 $row_number = $wpdb->query( $sql_prepared );
380 }
381
382 return $row_number;
383 }
384
385
386 /**
387 * Delete the dates status from DB - erase availability
388 *
389 * @param array $params array(
390 'resource_id' => 1, // int
391 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
392 'prop_value' => 'unavailable', // 'available', 'unavailable' , 'pending', 'approved'
393 'dates_selection' => 'all' // '2023-04-04 ~ 2023-04-07'
394
395 )
396 *
397 * @return bool|int - count of deleted rows or false if operation was not applied
398 *
399 * Examples:
400 * wpbc_availability__delete_dates_status__sql(array( 'resource_id' => 1 ));
401 * wpbc_availability__delete_dates_status__sql(array( 'resource_id' => 1, 'prop_name' => 'date_status' ))
402 * wpbc_availability__delete_dates_status__sql(array( 'resource_id' => 1, 'prop_name' => 'date_status', 'dates_selection' => 'all' ))
403 * wpbc_availability__delete_dates_status__sql(array( 'resource_id' => 1, 'prop_name' => 'date_status', 'dates_selection' => '2023-04-04 ~ 2023-04-07' ))
404 * wpbc_availability__delete_dates_status__sql(array( 'resource_id' => 1, 'prop_name' => 'date_status', 'dates_selection' => '2023-04-04, 2023-04-07, 2023-04-05' ))
405 */
406 function wpbc_availability__delete_dates_status__sql( $params ){
407
408 $defaults = array(
409 'resource_id' => 1, // int
410 'prop_name' => 'date_status', // 'rate', 'allow_start_day_selection', 'allow_days_number_to_select', 'availability_count', ...
411 'prop_value' => 'unavailable', // 'available', 'unavailable' , 'pending', 'approved'
412 'dates_selection' => 'all' // '2023-04-04 ~ 2023-04-07'
413
414 );
415 $params = wp_parse_args( $params, $defaults );
416
417 // S a n i t i z e
418 $params_rules = array(
419 'dates_selection' => array( 'validate' => 's', 'default' => '' ) ,
420 'prop_name' => array( 'validate' => 's', 'default' => 'date_status' ) ,
421 'prop_value' => array( 'validate' => 's', 'default' => 'unavailable' ) ,
422 'resource_id' => array( 'validate' => 'digit_or_csd', 'default' => 1 )
423 );
424 $params = wpbc_sanitize_params_in_arr( $params, $params_rules );
425
426
427
428 if ( 'all' === $params['dates_selection'] ) { // All Dates
429
430 $dates_arr = array();
431
432 } elseif ( false !== strpos( $params['dates_selection'], '~' ) ) { // Range Days
433
434 $dates_arr = wpbc_get_dates_arr__from_dates_range( array(
435 'dates_separator' => ' ~ ', // ' ~ '
436 'dates' => $params['dates_selection'], // '2023-04-04 ~ 2023-04-07'
437 ) );
438
439 } else { // Multiple Days
440 $dates_arr = wpbc_get_dates_arr__from_dates_comma_separated( array(
441 'dates_separator' => ', ', // ', '
442 'dates' => $params['dates_selection'], // '2023-04-04, 2023-04-07, 2023-04-05'
443 ) );
444 }
445
446 $row_number = false;
447
448 global $wpdb;
449
450 // Remove dates ------------------------------------------------------------------------------------------------
451
452 // "DELETE FROM {$wpdb->prefix}booking_dates_props WHERE resource_id = %d AND prop_name = %s AND ( calendar_date = %s OR calendar_date = %s )"
453 $sql = "DELETE FROM {$wpdb->prefix}booking_dates_props WHERE resource_id = %d AND prop_name = %s ";
454
455 $sql_args = array();
456 $sql_args[] = $params['resource_id'];
457 $sql_args[] = $params['prop_name'];
458
459 // If we transfer here dates, instead of 'all', then we delete only such specific dates status from DB
460 if ( ! empty( $dates_arr ) ) {
461 $sub_sql = array();
462 foreach ( $dates_arr as $calendar_date ) {
463
464 $sub_sql[] = 'calendar_date = %s';
465 $sql_args[] = $calendar_date . ' 00:00:00';
466 }
467 if ( count( $sub_sql ) > 0 ) {
468 $sql .= ' AND ( ';
469 $sub_sql = implode( ' OR ', $sub_sql );
470 $sql .= $sub_sql;
471 $sql .= " )";
472 }
473 }
474 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
475 $sql_prepared = $wpdb->prepare( $sql, $sql_args );
476 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
477 $row_number = $wpdb->query( $sql_prepared );
478
479 return $row_number;
480 }
481