1
|
|
|
<?php |
2
|
|
|
namespace EventEspresso\modules\ticket_selector; |
3
|
|
|
|
4
|
|
|
use EE_Error; |
5
|
|
|
use EventEspresso\core\exceptions\UnexpectedEntityException; |
6
|
|
|
|
7
|
|
|
defined('EVENT_ESPRESSO_VERSION') || exit; |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Class TicketSelectorRowStandard |
13
|
|
|
* class for loading template and resolving template args for a single ticket row within a standard ticket selector |
14
|
|
|
* |
15
|
|
|
* @package Event Espresso |
16
|
|
|
* @author Brent Christensen |
17
|
|
|
* @since $VID:$ |
18
|
|
|
*/ |
19
|
|
|
class TicketSelectorRowStandard extends TicketSelectorRow |
20
|
|
|
{ |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var TicketDetails $ticket_details |
24
|
|
|
*/ |
25
|
|
|
protected $ticket_details; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var \EE_Ticket_Selector_Config $template_settings |
29
|
|
|
*/ |
30
|
|
|
protected $template_settings; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var \EE_Tax_Config $tax_settings |
34
|
|
|
*/ |
35
|
|
|
protected $tax_settings; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var boolean $prices_displayed_including_taxes |
39
|
|
|
*/ |
40
|
|
|
protected $prices_displayed_including_taxes; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var int $row |
44
|
|
|
*/ |
45
|
|
|
protected $row; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var int $cols |
49
|
|
|
*/ |
50
|
|
|
protected $cols; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var boolean $hidden_input_qty |
54
|
|
|
*/ |
55
|
|
|
protected $hidden_input_qty; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var string $ticket_datetime_classes |
59
|
|
|
*/ |
60
|
|
|
protected $ticket_datetime_classes; |
61
|
|
|
|
62
|
|
|
|
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* TicketDetails constructor. |
66
|
|
|
* |
67
|
|
|
* @param TicketDetails $ticket_details |
68
|
|
|
* @param \EE_Tax_Config $tax_settings |
69
|
|
|
* @param int $total_tickets |
70
|
|
|
* @param int $max_atndz |
71
|
|
|
* @param int $row |
72
|
|
|
* @param int $cols |
73
|
|
|
* @param boolean $required_ticket_sold_out |
74
|
|
|
* @param string $event_status |
75
|
|
|
* @param string $ticket_datetime_classes |
76
|
|
|
* @throws EE_Error |
77
|
|
|
* @throws UnexpectedEntityException |
78
|
|
|
*/ |
79
|
|
|
public function __construct( |
80
|
|
|
TicketDetails $ticket_details, |
81
|
|
|
\EE_Tax_Config $tax_settings, |
82
|
|
|
$total_tickets, |
83
|
|
|
$max_atndz, |
84
|
|
|
$row, |
85
|
|
|
$cols, |
86
|
|
|
$required_ticket_sold_out, |
87
|
|
|
$event_status, |
88
|
|
|
$ticket_datetime_classes |
89
|
|
|
) { |
90
|
|
|
$this->ticket = $ticket_details->getTicket(); |
91
|
|
|
$this->ticket_details = $ticket_details; |
92
|
|
|
$this->template_settings = $ticket_details->getTemplateSettings(); |
93
|
|
|
$this->tax_settings = $tax_settings; |
94
|
|
|
$this->total_tickets = $total_tickets; |
95
|
|
|
$this->max_atndz = $max_atndz; |
96
|
|
|
$this->row = $row; |
97
|
|
|
$this->cols = $cols; |
98
|
|
|
$this->date_format = $ticket_details->getDateFormat(); |
99
|
|
|
$this->ticket_datetime_classes = $ticket_datetime_classes; |
100
|
|
|
parent::__construct($this->ticket, $max_atndz, $this->date_format, $event_status, $required_ticket_sold_out); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
|
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* other ticket rows will need to know if a required ticket is sold out, |
107
|
|
|
* so that they are not offered for sale |
108
|
|
|
* |
109
|
|
|
* @return boolean |
110
|
|
|
*/ |
111
|
|
|
public function getRequiredTicketSoldOut() |
112
|
|
|
{ |
113
|
|
|
return $this->required_ticket_sold_out; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
|
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @return int |
120
|
|
|
*/ |
121
|
|
|
public function getCols() |
122
|
|
|
{ |
123
|
|
|
return $this->cols; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
|
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* getHtml |
130
|
|
|
* |
131
|
|
|
* @return string |
132
|
|
|
* @throws EE_Error |
133
|
|
|
*/ |
134
|
|
|
public function getHtml() |
135
|
|
|
{ |
136
|
|
|
$min = 0; |
137
|
|
|
$max = $this->ticket->max(); |
138
|
|
|
$remaining = $this->ticket->remaining(); |
139
|
|
|
if ($this->ticket->is_on_sale() && $this->ticket->is_remaining()) { |
140
|
|
|
list($min, $max) = $this->setTicketMinAndMax($remaining); |
141
|
|
|
} else { |
142
|
|
|
// set flag if ticket is required (flag is set to start date so that future tickets are not blocked) |
143
|
|
|
$this->required_ticket_sold_out = $this->ticket->required() && ! $remaining |
|
|
|
|
144
|
|
|
? $this->ticket->start_date() |
145
|
|
|
: $this->required_ticket_sold_out; |
146
|
|
|
} |
147
|
|
|
list($ticket_price, $ticket_bundle) = $this->getTicketPriceDetails(); |
148
|
|
|
list($tkt_status, $ticket_status, $status_class) = $this->getTicketStatusClasses($remaining); |
149
|
|
|
/** |
150
|
|
|
* Allow plugins to hook in and abort the generation and display of this row to do |
151
|
|
|
* something else if they want. |
152
|
|
|
* For an addon to abort things, all they have to do is register a filter with this hook, and |
153
|
|
|
* return a value that is NOT false. Whatever is returned gets echoed instead of the |
154
|
|
|
* current row. |
155
|
|
|
* |
156
|
|
|
* @var string|bool |
157
|
|
|
*/ |
158
|
|
|
$ticket_selector_row_html = apply_filters( |
159
|
|
|
'FHEE__ticket_selector_chart_template__do_ticket_entire_row', |
160
|
|
|
false, |
161
|
|
|
$this->ticket, |
162
|
|
|
$max, |
163
|
|
|
$min, |
164
|
|
|
$this->required_ticket_sold_out, |
165
|
|
|
$ticket_price, |
166
|
|
|
$ticket_bundle, |
167
|
|
|
$ticket_status, |
168
|
|
|
$status_class |
169
|
|
|
); |
170
|
|
|
if ($ticket_selector_row_html !== false) { |
171
|
|
|
return $ticket_selector_row_html; |
172
|
|
|
} |
173
|
|
|
$ticket_selector_row_html = \EEH_HTML::tr( |
174
|
|
|
'', '', |
175
|
|
|
"tckt-slctr-tbl-tr {$status_class}{$this->ticket_datetime_classes} " . espresso_get_object_css_class($this->ticket) |
176
|
|
|
); |
177
|
|
|
/** |
178
|
|
|
* Allow plugins to hook in and abort the generation and display of the contents of this |
179
|
|
|
* row to do something else if they want. |
180
|
|
|
* For an addon to abort things, all they have to do is register a filter with this hook, and |
181
|
|
|
* return a value that is NOT false. Whatever is returned gets echoed instead of the |
182
|
|
|
* current row. |
183
|
|
|
* |
184
|
|
|
* @var string|bool |
185
|
|
|
*/ |
186
|
|
|
$new_row_cells_content = apply_filters( |
187
|
|
|
'FHEE__ticket_selector_chart_template__do_ticket_inside_row', |
188
|
|
|
false, |
189
|
|
|
$this->ticket, |
190
|
|
|
$max, |
191
|
|
|
$min, |
192
|
|
|
$this->required_ticket_sold_out, |
193
|
|
|
$ticket_price, |
194
|
|
|
$ticket_bundle, |
195
|
|
|
$ticket_status, |
196
|
|
|
$status_class |
197
|
|
|
); |
198
|
|
|
if ($new_row_cells_content !== false && $this->max_atndz === 1) { |
199
|
|
|
return $ticket_selector_row_html |
200
|
|
|
. $new_row_cells_content |
201
|
|
|
. $this->ticketQtyAndIdHiddenInputs() |
202
|
|
|
. \EEH_HTML::trx(); |
203
|
|
|
} |
204
|
|
|
if ($new_row_cells_content !== false) { |
205
|
|
|
return $ticket_selector_row_html |
206
|
|
|
. $new_row_cells_content |
207
|
|
|
. \EEH_HTML::trx(); |
208
|
|
|
} |
209
|
|
|
$this->hidden_input_qty = $this->max_atndz > 1 ? true : false; |
210
|
|
|
|
211
|
|
|
$ticket_selector_row_html .= $this->ticketNameTableCell(); |
212
|
|
|
$ticket_selector_row_html .= $this->ticketPriceTableCell($ticket_price, $ticket_bundle); |
213
|
|
|
$ticket_selector_row_html .= \EEH_HTML::td('', '', 'tckt-slctr-tbl-td-qty cntr'); |
214
|
|
|
$this->setTicketStatusDisplay($tkt_status, $ticket_status, $remaining); |
215
|
|
|
if (empty($this->ticket_status_display)) { |
216
|
|
|
if ($this->max_atndz === 1) { |
217
|
|
|
// only ONE attendee is allowed to register at a time |
218
|
|
|
$ticket_selector_row_html .= $this->onlyOneAttendeeCanRegister(); |
219
|
|
|
} else if ($max > 0) { |
220
|
|
|
$ticket_selector_row_html .= $this->ticketQuantitySelector($min, $max); |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
$ticket_selector_row_html .= $this->ticket_status_display; |
224
|
|
|
$ticket_selector_row_html .= $this->ticketQtyAndIdHiddenInputs(); |
225
|
|
|
$ticket_selector_row_html .= $this->ticket_details->display($ticket_price, $remaining, $this->cols); |
226
|
|
|
$ticket_selector_row_html .= \EEH_HTML::tdx(); |
227
|
|
|
$ticket_selector_row_html .= \EEH_HTML::trx(); |
228
|
|
|
|
229
|
|
|
|
230
|
|
|
$this->row++; |
231
|
|
|
return $ticket_selector_row_html; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
|
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* setTicketMinAndMax |
238
|
|
|
* |
239
|
|
|
* @param int $remaining |
240
|
|
|
* @return array |
241
|
|
|
* @throws EE_Error |
242
|
|
|
*/ |
243
|
|
|
protected function setTicketMinAndMax($remaining) |
244
|
|
|
{ |
245
|
|
|
// offer the number of $tickets_remaining or $this->max_atndz, whichever is smaller |
246
|
|
|
$max = min($remaining, $this->max_atndz); |
247
|
|
|
// but... we also want to restrict the number of tickets by the ticket max setting, |
248
|
|
|
// however, the max still can't be higher than what was just set above |
249
|
|
|
$max = $this->ticket->max() > 0 ? min($this->ticket->max(), $max) : $max; |
250
|
|
|
// and we also want to restrict the minimum number of tickets by the ticket min setting |
251
|
|
|
$min = $this->ticket->min() > 0 ? $this->ticket->min() : 0; |
252
|
|
|
// and if the ticket is required, then make sure that min qty is at least 1 |
253
|
|
|
$min = $this->ticket->required() ? max($min, 1) : $min; |
254
|
|
|
return array($min, $max); |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
|
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* getTicketPriceDetails |
261
|
|
|
* |
262
|
|
|
* @return array |
263
|
|
|
* @throws EE_Error |
264
|
|
|
*/ |
265
|
|
|
protected function getTicketPriceDetails() |
266
|
|
|
{ |
267
|
|
|
$ticket_price = $this->tax_settings->prices_displayed_including_taxes |
268
|
|
|
? $this->ticket->get_ticket_total_with_taxes() |
269
|
|
|
: $this->ticket->get_ticket_subtotal(); |
270
|
|
|
$ticket_bundle = false; |
271
|
|
|
$ticket_min = $this->ticket->min(); |
272
|
|
|
// for ticket bundles, set min and max qty the same |
273
|
|
|
if ($ticket_min !== 0 && $ticket_min === $this->ticket->max()) { |
274
|
|
|
$ticket_price *= $ticket_min; |
275
|
|
|
$ticket_bundle = true; |
276
|
|
|
} |
277
|
|
|
$ticket_price = apply_filters( |
278
|
|
|
'FHEE__ticket_selector_chart_template__ticket_price', |
279
|
|
|
$ticket_price, |
280
|
|
|
$this->ticket |
281
|
|
|
); |
282
|
|
|
return array($ticket_price, $ticket_bundle); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
|
286
|
|
|
|
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* ticketNameTableCell |
290
|
|
|
* |
291
|
|
|
* @return string |
292
|
|
|
* @throws EE_Error |
293
|
|
|
*/ |
294
|
|
|
protected function ticketNameTableCell() |
295
|
|
|
{ |
296
|
|
|
$html = \EEH_HTML::td('', '', 'tckt-slctr-tbl-td-name'); |
297
|
|
|
$html .= \EEH_HTML::strong($this->ticket->get_pretty('TKT_name')); |
298
|
|
|
$html .= $this->ticket_details->getShowHideLinks(); |
299
|
|
|
if ($this->ticket->required()) { |
300
|
|
|
$html .= \EEH_HTML::p( |
301
|
|
|
apply_filters( |
302
|
|
|
'FHEE__ticket_selector_chart_template__ticket_required_message', |
303
|
|
|
esc_html__('This ticket is required and must be purchased.', 'event_espresso') |
304
|
|
|
), |
305
|
|
|
'', 'ticket-required-pg' |
306
|
|
|
); |
307
|
|
|
} |
308
|
|
|
$html .= \EEH_HTML::tdx(); |
309
|
|
|
return $html; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
|
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* ticketPriceTableCell |
316
|
|
|
* |
317
|
|
|
* @param float $ticket_price |
318
|
|
|
* @param bool $ticket_bundle |
319
|
|
|
* @return string |
320
|
|
|
* @throws EE_Error |
321
|
|
|
*/ |
322
|
|
|
protected function ticketPriceTableCell($ticket_price, $ticket_bundle) |
323
|
|
|
{ |
324
|
|
|
$html = ''; |
325
|
|
|
if (apply_filters('FHEE__ticket_selector_chart_template__display_ticket_price_details', true)) { |
326
|
|
|
$html .= \EEH_HTML::td('', '', 'tckt-slctr-tbl-td-price jst-rght'); |
327
|
|
|
$html .= \EEH_Template::format_currency($ticket_price); |
328
|
|
|
$html .= $this->ticket->taxable() |
329
|
|
|
? \EEH_HTML::span( '*', '', 'taxable-tickets-asterisk grey-text' ) |
330
|
|
|
: ''; |
331
|
|
|
$html .= ' '; |
332
|
|
|
$html .= \EEH_HTML::span( |
333
|
|
|
$ticket_bundle |
334
|
|
|
? apply_filters( |
335
|
|
|
'FHEE__ticket_selector_chart_template__per_ticket_bundle_text', |
336
|
|
|
__(' / bundle', 'event_espresso') |
337
|
|
|
) |
338
|
|
|
: apply_filters( |
339
|
|
|
'FHEE__ticket_selector_chart_template__per_ticket_text', |
340
|
|
|
__('', 'event_espresso') |
341
|
|
|
), |
342
|
|
|
'', 'smaller-text no-bold' |
343
|
|
|
); |
344
|
|
|
$html .= ' '; |
345
|
|
|
$html .= \EEH_HTML::tdx(); |
346
|
|
|
$this->cols++; |
347
|
|
|
} |
348
|
|
|
return $html; |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
|
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* onlyOneAttendeeCanRegister |
355
|
|
|
* |
356
|
|
|
* @return string |
357
|
|
|
*/ |
358
|
|
|
protected function onlyOneAttendeeCanRegister() |
359
|
|
|
{ |
360
|
|
|
// display submit button since we have tickets available |
361
|
|
|
add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
362
|
|
|
$this->hidden_input_qty = false; |
363
|
|
|
$html = '<input type="radio" name="tkt-slctr-qty-' . $this->EVT_ID . '"'; |
364
|
|
|
$html .= ' id="ticket-selector-tbl-qty-slct-' . $this->EVT_ID . '-' . $this->row . '"'; |
365
|
|
|
$html .= ' class="ticket-selector-tbl-qty-slct" value="' . $this->row . '-1"'; |
366
|
|
|
$html .= $this->total_tickets === 1 ? ' checked="checked"' : ''; |
367
|
|
|
$html .= ' title=""/>'; |
368
|
|
|
return $html; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
|
372
|
|
|
|
373
|
|
|
/** |
374
|
|
|
* ticketQuantitySelector |
375
|
|
|
* |
376
|
|
|
* @param int $min |
377
|
|
|
* @param int $max |
378
|
|
|
* @return string |
379
|
|
|
* @throws EE_Error |
380
|
|
|
*/ |
381
|
|
|
protected function ticketQuantitySelector($min = 0, $max = 0) |
382
|
|
|
{ |
383
|
|
|
// display submit button since we have tickets available |
384
|
|
|
add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
385
|
|
|
$this->hidden_input_qty = false; |
386
|
|
|
$html = '<select name="tkt-slctr-qty-' . $this->EVT_ID . '[]"'; |
387
|
|
|
$html .= ' id="ticket-selector-tbl-qty-slct-' . $this->EVT_ID . '-' . $this->row . '"'; |
388
|
|
|
$html .= ' class="ticket-selector-tbl-qty-slct">'; |
389
|
|
|
// this ensures that non-required tickets with non-zero MIN QTYs don't HAVE to be purchased |
390
|
|
|
if ($min !== 0 && ! $this->ticket->required()) { |
391
|
|
|
$html .= '<option value="0"> 0 </option>'; |
392
|
|
|
} |
393
|
|
|
// offer ticket quantities from the min to the max |
394
|
|
|
for ($i = $min; $i <= $max; $i++) { |
395
|
|
|
$html .= '<option value="' . $i . '"> ' . $i . ' </option>'; |
396
|
|
|
} |
397
|
|
|
$html .= '</select>'; |
398
|
|
|
return $html; |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
|
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* getHiddenInputs |
405
|
|
|
* |
406
|
|
|
* @return string |
407
|
|
|
* @throws EE_Error |
408
|
|
|
*/ |
409
|
|
|
protected function ticketQtyAndIdHiddenInputs() |
410
|
|
|
{ |
411
|
|
|
$html = ''; |
412
|
|
|
// depending on group reg we need to change the format for qty |
413
|
|
|
if ($this->hidden_input_qty) { |
414
|
|
|
$html .= '<input type="hidden" name="tkt-slctr-qty-' . $this->EVT_ID . '[]" value="0"/>'; |
415
|
|
|
} |
416
|
|
|
$html .= '<input type="hidden" name="tkt-slctr-ticket-id-' . $this->EVT_ID . '[]"'; |
417
|
|
|
$html .= ' value="' . $this->ticket->ID() . '"/>'; |
418
|
|
|
return $html; |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
} |
422
|
|
|
// End of file TicketSelectorRowStandard.php |
423
|
|
|
// Location: EventEspresso\modules\ticket_selector/TicketSelectorRowStandard.php |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.