em-tickets-bookings.php
15.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
<?php
/**
* Deals with the each ticket booked in a single booking.
* Each ticket is grouped by EM_Ticket_Bookings, which is stored as an array in the tickets_bookings object.
*
* You can access/add/unset the array of EM_Ticket_Bookings and its sub array of EM_Ticket_Booking objects in a few ways, with example ticket ID # 34884:
*
* Access the EM_Ticket_Bookings of a ticket:
* $EM_Tickets_Bookings[34884]
* $EM_Tickets_Bookings->tickets_bookings[34884]
*
* Add a new EM_Ticket_Bookings for a ticket:
* $EM_Tickets_Bookings[1234] = new EM_Tickets_Bookings(...)
* $EM_Tickets_Bookings->tickets_bookings[1234] = new EM_Tickets_Bookings(...)
*
* Add a new EM_Ticket_Booking object to existing EM_Ticket_Bookings objects
* $EM_Tickets_Bookings[34884]['uuid'] = new EM_Ticket_Booking(...); // text key - should be a uuid
* $EM_Tickets_Bookings->tickets_bookings[34884]['uuid'] = new EM_Ticket_Booking(...);
* $EM_Tickets_Bookings->tickets_bookings[34884]->tickets_bookings['uuid'] = new EM_Ticket_Booking(...);
*
* Unset works the same way:
* unset($EM_Tickets_Bookings[35280]);
* unset($EM_Tickets_Bookings->tickets_bookings[34884]);
* etc.
*
* @author marcus
*
*/
class EM_Tickets_Bookings extends EM_Object implements Iterator, Countable, ArrayAccess {
/**
* Array of EM_Ticket_Booking objects for a specific event
* @var EM_Ticket_Bookings[]
*/
public $tickets_bookings = array();
protected $tickets_bookings_loaded;
/**
* When adding existing booked tickets via add() with 0 spaces, they get slotted here for deletion during save() so they circumvent validation.
* @var array[EM_Ticket_Booking]
*/
var $tickets_bookings_deleted = array();
/**
* This object belongs to this booking object
* @var EM_Booking
*/
protected $booking;
/**
* This object belongs to this booking object
* @var EM_Ticket
*/
var $spaces;
var $price;
/**
* Used to prefix any actions/filters on this class, so that extended classes can force their own prefix.
* @var string
*/
public static $n = 'em_tickets_bookings';
/**
* Creates an EM_Tickets instance.
* @note This function will eventually require an EM_Booking object. At time of writing, this means versions of Events Manager Pro < 3.0 will break.
* @param EM_Booking $EM_Booking
*/
function __construct( $EM_Booking = null ){
if( is_object($EM_Booking) && !empty($EM_Booking->booking_uuid) ){ // all booking objects have a uuid
$this->booking = $EM_Booking;
}elseif( is_numeric($EM_Booking) ){
$this->booking = em_get_booking($EM_Booking);
}
$this->get_ticket_bookings();
do_action( static::$n, $this, $EM_Booking);
}
public function __get( $shortname ){
if( $shortname === 'booking_id' ){
return $this->booking->booking_id;
}
return parent::__get($shortname);
}
public function __set( $prop, $val ){
if( $prop === 'booking' && !empty($val->booking_uuid) ){
$this->booking = $val;
$this->tickets_bookings_loaded = false;
$this->get_ticket_bookings(); // refresh ticket bookings
return;
}
parent::__set( $prop, $val );
}
/**
* Return relevant fields that will be used for storage, excluding things such as event and ticket objects that should get reloaded
* @return string[]
*/
public function __sleep(){
$array = array('tickets_bookings','tickets_bookings_loaded');
return apply_filters('em_tickets_bookings_sleep', $array, $this);
}
public function get_post( $override_availability = false ){
if( !empty($_REQUEST['em_tickets']) ){
foreach( $_REQUEST['em_tickets'] as $ticket_id => $values){
//make sure ticket exists
$ticket_id = absint($ticket_id);
if( !empty($values['spaces']) || $this->booking->booking_id ){ // if spaces booked for first time, editing and spaces are 0 (in case we need to delete anything)
// get an EM_Ticket_Bookings object, which will be added if non-existent, $EM_Ticket_Bookings is therefore passed by reference.
$EM_Ticket_Bookings = $this->get_ticket_bookings($ticket_id);
if( !$EM_Ticket_Bookings->get_post() ){
$this->add_error($EM_Ticket_Bookings->get_errors());
}
// make sure things are recalculated
$this->price = 0; //so price calculations are reset
$this->get_spaces(true);
$this->get_price();
}
}
}
return apply_filters( static::$n . '_get_post', empty($this->errors), $this, $override_availability );
}
public function validate( $override_availability = false ){
if( count($this->tickets_bookings) > 0 ){
foreach($this->tickets_bookings as $EM_Ticket_Bookings){ /* @var $EM_Ticket_Bookings EM_Ticket_Bookings */
if ( !$EM_Ticket_Bookings->validate( $override_availability ) ){
$this->errors = array_merge($this->errors, $EM_Ticket_Bookings->get_errors());
}
}
}
return apply_filters( static::$n . '_validate', empty($this->errors), $this, $override_availability );
}
/**
* Saves the ticket bookings for this booking into the database, whether a new or existing booking
* @return boolean
*/
function save(){
do_action(static::$n . '_save_pre',$this);
//save/update tickets
foreach( $this->tickets_bookings as $EM_Ticket_Booking ){
$result = $EM_Ticket_Booking->save();
if(!$result){
$this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
}
}
//delete old tickets if set to 0 in an update
foreach($this->tickets_bookings_deleted as $EM_Ticket_Booking ){
$result = $EM_Ticket_Booking->delete();
if(!$result){
$this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
}
}
//return result
if( count($this->errors) > 0 ){
$this->feedback_message = __('There was a problem saving the booking.', 'events-manager');
$this->errors[] = __('There was a problem saving the booking.', 'events-manager');
return apply_filters(static::$n . '_save', false, $this);
}
return apply_filters(static::$n . '_save', true, $this);
}
/**
* Adds a ticket booking to the object, equivalent of adding directly to the array of tickets_bookings
*
* @param EM_Ticket_Booking $EM_Ticket_Booking
* @return bool
*/
function add( $EM_Ticket_Booking ){
if( $EM_Ticket_Booking instanceof EM_Ticket_Booking ) {
$this->get_ticket_bookings($EM_Ticket_Booking->ticket_id)->tickets_bookings[$EM_Ticket_Booking->ticket_uuid] = $EM_Ticket_Booking;
return true;
}
return false;
}
/**
* Checks if this set has a specific ticket booked, returning the key of the ticket in the EM_Tickets_Bookings->ticket_bookings array
* @param int $ticket_id
* @return mixed
*/
function has_ticket( $ticket_id ){
foreach ($this->tickets_bookings as $key => $EM_Ticket_Booking){
if( $EM_Ticket_Booking->ticket_id == $ticket_id ){
return apply_filters(static::$n . '_has_ticket',$key,$this);
}
}
return apply_filters(static::$n . '_has_ticket',false,$this);
}
/**
* Smart event locator, saves a database read if possible.
*/
function get_booking(){
return apply_filters(static::$n . '_get_booking', $this->booking, $this);
}
/**
* Delete all ticket bookings
* @return boolean
*/
function delete(){
global $wpdb;
$result = false;
if( $this->get_booking()->can_manage() ){
$result_meta = $wpdb->query("DELETE FROM ".EM_TICKETS_BOOKINGS_META_TABLE." WHERE ticket_booking_id IN (SELECT ticket_booking_id FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE booking_id='{$this->booking_id}')");
$result = $wpdb->query("DELETE FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE booking_id='{$this->booking_id}'");
}
return apply_filters(static::$n . '_delete', ($result !== false && $result_meta !== false), $this);
}
/**
* Get the total number of spaces booked in this booking. Seting $force_reset to true will recheck spaces, even if previously done so.
* @param unknown_type $force_refresh
* @return mixed
*/
function get_spaces( $force_refresh = false ){
if( $force_refresh || $this->spaces == 0 ){
$spaces = 0;
foreach( $this->tickets_bookings as $EM_Ticket_Bookings ){
$spaces += $EM_Ticket_Bookings->get_spaces( $force_refresh );
}
$this->spaces = $spaces;
}
return apply_filters(static::$n . '_get_spaces',$this->spaces,$this);
}
/**
* Gets the total price for this whole booking by adding up subtotals of booked tickets. Seting $force_reset to true will recheck spaces, even if previously done so.
* @param boolean $format
* @return float
*/
function get_price( $format = false ){
if( $this->price == 0 ){
$price = $this->calculate_price( true );
// deprecated, use the _calculate_price filter instead
$this->price = apply_filters(static::$n . '_get_price', $price, $this);
}
if($format){
return $this->format_price($this->price);
}
return $this->price;
}
function calculate_price( $force_refresh = false ){
if( $this->price == null || $force_refresh ){
$price = 0;
foreach($this->tickets_bookings as $EM_Ticket_Bookings ){
$price += $EM_Ticket_Bookings->calculate_price( $force_refresh );
}
$this->price = apply_filters(static::$n . '_calculate_price', $price, $this, $force_refresh);
}
return $this->price;
}
/**
* Return a specific EM_Ticket_Bookings object if a valid $ticket_id is supplied, or alternatively returns all EM_Ticket_Bookings objects registered to this object.
* If when requesting a $ticket_id and no EM_Ticket_Bookings object exists for it within the object, a new blank object is created and appended to the tickets_bookings property, with 0 spaces and 0 price.
* @param EM_Ticket|int $ticket
* @return EM_Ticket_Bookings|EM_Ticket_Bookings[]
*/
function get_ticket_bookings( $ticket = false ){
$ticket_id = is_object($ticket) ? $ticket->ticket_id : absint($ticket);
if( !$this->tickets_bookings_loaded && !empty($this->booking->booking_id) ){
// we could get tickets individually via EM_Ticket_Bookings, but this is one db call vs multiple
global $wpdb;
$sql = "SELECT * FROM ". EM_TICKETS_BOOKINGS_TABLE ." WHERE booking_id ='{$this->booking->booking_id}'";
$results = $wpdb->get_results($sql, ARRAY_A);
//Get tickets belonging to this tickets booking.
$tickets_bookings = array();
foreach ($results as $ticket_booking){
$ticket_booking['booking'] = $this->booking;
$EM_Ticket_Booking = new EM_Ticket_Booking($ticket_booking);
if( empty($tickets_bookings[$EM_Ticket_Booking->ticket_id]) ) $tickets_bookings[$EM_Ticket_Booking->ticket_id] = array();
$tickets_bookings[$EM_Ticket_Booking->ticket_id][]= $EM_Ticket_Booking;
}
foreach( $tickets_bookings as $id => $ticket_bookings ){
$this->tickets_bookings[$id] = new EM_Ticket_Bookings($ticket_bookings);
}
}
$this->tickets_bookings_loaded = true;
if( $ticket_id ){
if( empty($this->tickets_bookings[$ticket_id]) ){
$this->tickets_bookings[$ticket_id] = new EM_Ticket_Bookings( array('ticket_id' => $ticket_id, 'booking' => $this->get_booking() ) );
}
return $this->tickets_bookings[$ticket_id];
}
return $this->tickets_bookings;
}
/* Overrides EM_Object method to apply a filter to result
* @see wp-content/plugins/events-manager/classes/EM_Object#build_sql_conditions()
*/
public static function build_sql_conditions( $args = array() ){
$conditions = parent::build_sql_conditions($args);
if( is_numeric($args['status']) ){
$conditions['status'] = 'ticket_status='.$args['status'];
}
return apply_filters(static::$n . '_build_sql_conditions', $conditions, $args);
}
/* Overrides EM_Object method to apply a filter to result
* @see wp-content/plugins/events-manager/classes/EM_Object#build_sql_orderby()
*/
public static function build_sql_orderby( $args, $accepted_fields, $default_order = 'ASC' ){
return apply_filters( static::$n . '_build_sql_orderby', parent::build_sql_orderby($args, $accepted_fields, get_option('dbem_events_default_order')), $args, $accepted_fields, $default_order );
}
/*
* Adds custom Events search defaults
* @param array $array_or_defaults may be the array to override defaults
* @param array $array
* @return array
* @uses EM_Object#get_default_search()
*/
public static function get_default_search( $array_or_defaults = array(), $array = array() ){
$defaults = array(
'status' => false,
'person' => true //to add later, search by person's tickets...
);
//sort out whether defaults were supplied or just the array of search values
if( empty($array) ){
$array = $array_or_defaults;
}else{
$defaults = array_merge($defaults, $array_or_defaults);
}
//specific functionality
$defaults['owner'] = !current_user_can('manage_others_bookings') ? get_current_user_id():false;
return apply_filters(static::$n . '_get_default_search', parent::get_default_search($defaults,$array), $array, $defaults);
}
//Iterator Implementation
#[\ReturnTypeWillChange]
/**
* @return void
*/
public function rewind(){
$this->get_ticket_bookings();
reset($this->tickets_bookings);
}
#[\ReturnTypeWillChange]
/**
* @return EM_Ticket_Bookings
*/
public function current(){
return current($this->tickets_bookings);
}
#[\ReturnTypeWillChange]
/**
* @return int Ticket ID
*/
public function key(){
return key($this->tickets_bookings);
}
#[\ReturnTypeWillChange]
/**
* @return EM_Ticket_Bookings
*/
public function next(){
return next($this->tickets_bookings);
}
#[\ReturnTypeWillChange]
public function valid(){
$key = key($this->tickets_bookings);
return ($key !== NULL && $key !== FALSE);
}
//Countable Implementation
#[\ReturnTypeWillChange]
/**
* @return int
*/
public function count(){
return count($this->tickets_bookings);
}
// ArrayAccess Implementation
#[\ReturnTypeWillChange]
/**
* @param $offset
* @param $value
* @return void
*/
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->tickets_bookings[] = $value;
} else {
$this->tickets_bookings[$offset] = $value;
}
}
#[\ReturnTypeWillChange]
/**
* @param $offset
* @return bool
*/
public function offsetExists($offset) {
return isset($this->tickets_bookings[$offset]);
}
#[\ReturnTypeWillChange]
/**
* @param $offset
* @return void
*/
public function offsetUnset($offset) {
unset($this->tickets_bookings[$offset]);
}
#[\ReturnTypeWillChange]
/**
* @param $offset
* @return EM_Ticket_Bookings|null
*/
public function offsetGet($offset) {
return isset($this->tickets_bookings[$offset]) ? $this->tickets_bookings[$offset] : null;
}
public function __debugInfo(){
$object = clone($this);
$object->booking = !empty($this->booking->booking_id) ? 'Booking ID #'.$this->booking->booking_id : 'New Booking - No ID';
$object->shortnames = 'Removed for export, uncomment from __debugInfo()';
$object->mime_types = 'Removed for export, uncomment from __debugInfo()';
if( empty($object->errors) ) $object->errors = false;
return (Array) $object;
}
}
?>