Completed
Branch BUG/11475/decode-site-title-fo... (bbd86e)
by
unknown
13:39 queued 25s
created

ProcessTicketSelector::setInitialTicketDatetimeAvailability()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 20
nc 5
nop 1
dl 0
loc 39
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\modules\ticket_selector;
4
5
use EE_Cart;
6
use EE_Core_Config;
7
use EE_Error;
8
use EE_Session;
9
use EE_Ticket;
10
use EEH_Event_View;
11
use EEM_Ticket;
12
use EventEspresso\core\domain\services\factories\CartFactory;
13
use EEH_URL;
14
use EventEspresso\core\exceptions\InvalidDataTypeException;
15
use EventEspresso\core\exceptions\InvalidInterfaceException;
16
use EventEspresso\core\services\loaders\LoaderFactory;
17
use EventEspresso\core\services\loaders\LoaderInterface;
18
use EventEspresso\core\services\request\Request;
19
use InvalidArgumentException;
20
21
defined('EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
22
23
24
25
/**
26
 * Class ProcessTicketSelector
27
 * Description
28
 *
29
 * @package       Event Espresso
30
 * @subpackage    core
31
 * @author        Brent Christensen
32
 * @since         4.9.0
33
 */
34
class ProcessTicketSelector
35
{
36
37
    /**
38
     * @var EE_Cart $cart
39
     */
40
    private $cart;
41
42
    /**
43
     * @var EE_Core_Config $core_config
44
     */
45
    private $core_config;
46
47
    /**
48
     * @var Request $request
49
     */
50
    private $request;
51
52
    /**
53
     * @var EE_Session $session
54
     */
55
    private $session;
56
57
    /**
58
     * @var EEM_Ticket $ticket_model
59
     */
60
    private $ticket_model;
61
62
    /**
63
     * @var TicketDatetimeAvailabilityTracker $tracker
64
     */
65
    private $tracker;
66
67
68
    /**
69
     * ProcessTicketSelector constructor.
70
     * NOTE: PLZ use the Loader to instantiate this class if need be
71
     * so that all dependencies get injected correctly (which will happen automatically)
72
     * Null values for parameters are only for backwards compatibility but will be removed later on.
73
     *
74
     * @param EE_Core_Config                    $core_config
75
     * @param Request                           $request
76
     * @param EE_Session                        $session
77
     * @param EEM_Ticket                        $ticket_model
78
     * @param TicketDatetimeAvailabilityTracker $tracker
79
     * @throws InvalidArgumentException
80
     * @throws InvalidDataTypeException
81
     * @throws InvalidInterfaceException
82
     */
83
    public function __construct(
84
        EE_Core_Config $core_config = null,
85
        Request $request = null,
86
        EE_Session $session = null,
87
        EEM_Ticket $ticket_model = null,
88
        TicketDatetimeAvailabilityTracker $tracker = null
89
    ) {
90
        /** @var LoaderInterface $loader */
91
        $loader             = LoaderFactory::getLoader();
92
        $this->core_config  = $core_config instanceof EE_Core_Config
93
            ? $core_config
94
            : $loader->getShared('EE_Core_Config');
95
        $this->request      = $request instanceof Request
96
            ? $request
97
            : $loader->getShared('EventEspresso\core\services\request\Request');
98
        $this->session      = $session instanceof EE_Session
99
            ? $session
100
            : $loader->getShared('EE_Session');
101
        $this->ticket_model = $ticket_model instanceof EEM_Ticket
102
            ? $ticket_model
103
            : $loader->getShared('EEM_Ticket');
104
        $this->tracker      = $tracker instanceof TicketDatetimeAvailabilityTracker
105
            ? $tracker
106
            : $loader->getShared('EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker');
107
    }
108
109
110
    /**
111
     * cancelTicketSelections
112
     *
113
     * @return bool
114
     * @throws EE_Error
115
     * @throws InvalidArgumentException
116
     * @throws InvalidInterfaceException
117
     * @throws InvalidDataTypeException
118
     */
119
    public function cancelTicketSelections()
120
    {
121
        // check nonce
122
        if (! $this->processTicketSelectorNonce('cancel_ticket_selections')) {
123
            return false;
124
        }
125
        $this->session->clear_session(__CLASS__, __FUNCTION__);
126
        if ($this->request->requestParamIsSet('event_id')) {
127
            EEH_URL::safeRedirectAndExit(
128
                EEH_Event_View::event_link_url(
129
                    $this->request->getRequestParam('event_id')
130
                )
131
            );
132
        }
133
        EEH_URL::safeRedirectAndExit(
134
            site_url('/' . $this->core_config->event_cpt_slug . '/')
135
        );
136
        return true;
137
    }
138
139
140
    /**
141
     * processTicketSelectorNonce
142
     *
143
     * @param  string $nonce_name
144
     * @param string  $id
145
     * @return bool
146
     */
147
    private function processTicketSelectorNonce($nonce_name, $id = '')
148
    {
149
        $nonce_name_with_id = ! empty($id) ? "{$nonce_name}_nonce_{$id}" : "{$nonce_name}_nonce";
150
        if (
151
            ! $this->request->isAdmin()
152
            && (
153
                ! $this->request->is_set($nonce_name_with_id)
154
                || ! wp_verify_nonce(
155
                    $this->request->get($nonce_name_with_id),
156
                    $nonce_name
157
                )
158
            )
159
        ) {
160
            EE_Error::add_error(
161
                sprintf(
162
                    esc_html__(
163
                        'We\'re sorry but your request failed to pass a security check.%sPlease click the back button on your browser and try again.',
164
                        'event_espresso'
165
                    ),
166
                    '<br/>'
167
                ),
168
                __FILE__,
169
                __FUNCTION__,
170
                __LINE__
171
            );
172
            return false;
173
        }
174
        return true;
175
    }
176
177
178
    /**
179
     * process_ticket_selections
180
     *
181
     * @return array|bool
182
     * @throws EE_Error
183
     * @throws InvalidArgumentException
184
     * @throws InvalidDataTypeException
185
     * @throws InvalidInterfaceException
186
     */
187
    public function processTicketSelections()
188
    {
189
        do_action('EED_Ticket_Selector__process_ticket_selections__before');
190
        if($this->request->isBot()) {
191
            EEH_URL::safeRedirectAndExit(
192
                apply_filters(
193
                    'FHEE__EE_Ticket_Selector__process_ticket_selections__bot_redirect_url',
194
                    site_url()
195
                )
196
            );
197
        }
198
        // do we have an event id?
199
        $id = $this->getEventId();
200
        // we should really only have 1 registration in the works now
201
        // (ie, no MER) so unless otherwise requested, clear the session
202
        if (apply_filters('FHEE__EE_Ticket_Selector__process_ticket_selections__clear_session', true)) {
203
            $this->session->clear_session(__CLASS__, __FUNCTION__);
204
        }
205
        // validate/sanitize/filter data
206
        $valid = apply_filters(
207
            'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data',
208
            $this->validatePostData($id)
209
        );
210
        //check total tickets ordered vs max number of attendees that can register
211
        if ($valid['total_tickets'] > $valid['max_atndz']) {
212
            $this->maxAttendeesViolation($valid);
213
        } else {
214
            // all data appears to be valid
215
            if ($this->processSuccessfulCart($this->addTicketsToCart($valid))) {
216
                return true;
217
            }
218
        }
219
        // die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< KILL BEFORE REDIRECT
220
        // at this point, just return if registration is being made from admin
221
        if ($this->request->isAdmin() || $this->request->isFrontAjax()) {
222
            return false;
223
        }
224
        if ($valid['return_url']) {
225
            EEH_URL::safeRedirectAndExit($valid['return_url']);
226
        }
227
        if ($id) {
228
            EEH_URL::safeRedirectAndExit(get_permalink($id));
229
        }
230
        echo EE_Error::get_notices();
231
        return false;
232
    }
233
234
235
    /**
236
     * @return int
237
     */
238
    private function getEventId()
239
    {
240
        // do we have an event id?
241
        if (! $this->request->requestParamIsSet('tkt-slctr-event-id')) {
242
            // $_POST['tkt-slctr-event-id'] was not set ?!?!?!?
243
            EE_Error::add_error(
244
                sprintf(
245
                    esc_html__(
246
                        'An event id was not provided or was not received.%sPlease click the back button on your browser and try again.',
247
                        'event_espresso'
248
                    ),
249
                    '<br/>'
250
                ),
251
                __FILE__,
252
                __FUNCTION__,
253
                __LINE__
254
            );
255
        }
256
        //if event id is valid
257
        return absint($this->request->getRequestParam('tkt-slctr-event-id'));
258
    }
259
260
261
    /**
262
     * validate_post_data
263
     *
264
     * @param int $id
265
     * @return array|FALSE
266
     */
267
    private function validatePostData($id = 0)
268
    {
269
        if (! $id) {
270
            EE_Error::add_error(
271
                esc_html__('The event id provided was not valid.', 'event_espresso'),
272
                __FILE__,
273
                __FUNCTION__,
274
                __LINE__
275
            );
276
            return false;
277
        }
278
        // start with an empty array()
279
        $valid_data = array();
280
        // grab valid id
281
        $valid_data['id'] = $id;
282
        // array of other form names
283
        $inputs_to_clean = array(
284
            'event_id'   => 'tkt-slctr-event-id',
285
            'max_atndz'  => 'tkt-slctr-max-atndz-',
286
            'rows'       => 'tkt-slctr-rows-',
287
            'qty'        => 'tkt-slctr-qty-',
288
            'ticket_id'  => 'tkt-slctr-ticket-id-',
289
            'return_url' => 'tkt-slctr-return-url-',
290
        );
291
        // let's track the total number of tickets ordered.'
292
        $valid_data['total_tickets'] = 0;
293
        // cycle through $inputs_to_clean array
294
        foreach ($inputs_to_clean as $what => $input_to_clean) {
295
            // check for POST data
296
            if ($this->request->requestParamIsSet($input_to_clean . $id)) {
297
                // grab value
298
                $input_value = $this->request->getRequestParam($input_to_clean . $id);
299
                switch ($what) {
300
                    // integers
301
                    case 'event_id':
302
                        $valid_data[ $what ] = absint($input_value);
303
                        // get event via the event id we put in the form
304
                        break;
305
                    case 'rows':
306
                    case 'max_atndz':
307
                        $valid_data[ $what ] = absint($input_value);
308
                        break;
309
                    // arrays of integers
310
                    case 'qty':
311
                        /** @var array $row_qty */
312
                        $row_qty = $input_value;
313
                        // if qty is coming from a radio button input, then we need to assemble an array of rows
314
                        if (! is_array($row_qty)) {
315
                            /** @var string $row_qty */
316
                            // get number of rows
317
                            $rows = $this->request->requestParamIsSet('tkt-slctr-rows-' . $id)
318
                                ? absint($this->request->getRequestParam('tkt-slctr-rows-' . $id))
319
                                : 1;
320
                            // explode integers by the dash
321
                            $row_qty = explode('-', $row_qty);
322
                            $row     = isset($row_qty[0]) ? absint($row_qty[0]) : 1;
323
                            $qty     = isset($row_qty[1]) ? absint($row_qty[1]) : 0;
324
                            $row_qty = array($row => $qty);
325
                            for ($x = 1; $x <= $rows; $x++) {
326
                                if (! isset($row_qty[ $x ])) {
327
                                    $row_qty[ $x ] = 0;
328
                                }
329
                            }
330
                        }
331
                        ksort($row_qty);
332
                        // cycle thru values
333
                        foreach ($row_qty as $qty) {
334
                            $qty = absint($qty);
335
                            // sanitize as integers
336
                            $valid_data[ $what ][]       = $qty;
337
                            $valid_data['total_tickets'] += $qty;
338
                        }
339
                        break;
340
                    // array of integers
341
                    case 'ticket_id':
342
                        // cycle thru values
343
                        foreach ((array) $input_value as $key => $value) {
344
                            // allow only integers
345
                            $valid_data[ $what ][ $key ] = absint($value);
346
                        }
347
                        break;
348
                    case 'return_url' :
349
                        // grab and sanitize return-url
350
                        $input_value = esc_url_raw($input_value);
351
                        // was the request coming from an iframe ? if so, then:
352
                        if (strpos($input_value, 'event_list=iframe')) {
353
                            // get anchor fragment
354
                            $input_value = explode('#', $input_value);
355
                            $input_value = end($input_value);
356
                            // use event list url instead, but append anchor
357
                            $input_value = EEH_Event_View::event_archive_url() . '#' . $input_value;
358
                        }
359
                        $valid_data[ $what ] = $input_value;
360
                        break;
361
                }    // end switch $what
362
            }
363
        }    // end foreach $inputs_to_clean
364
        return $valid_data;
365
    }
366
367
368
    /**
369
     * @param array $valid
370
     */
371
    private function maxAttendeesViolation(array $valid)
372
    {
373
        // ordering too many tickets !!!
374
        $total_tickets_string = esc_html(
375
            _n(
376
                'You have attempted to purchase %s ticket.',
377
                'You have attempted to purchase %s tickets.',
378
                $valid['total_tickets'],
379
                'event_espresso'
380
            )
381
        );
382
        $limit_error_1        = sprintf($total_tickets_string, $valid['total_tickets']);
383
        // dev only message
384
        $max_attendees_string = esc_html(
385
            _n(
386
                'The registration limit for this event is %s ticket per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.',
387
                'The registration limit for this event is %s tickets per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.',
388
                $valid['max_atndz'],
389
                'event_espresso'
390
            )
391
        );
392
        $limit_error_2    = sprintf($max_attendees_string, $valid['max_atndz'], $valid['max_atndz']);
393
        EE_Error::add_error($limit_error_1 . '<br/>' . $limit_error_2, __FILE__, __FUNCTION__, __LINE__);
394
    }
395
396
397
    /**
398
     * @param array $valid
399
     * @return int|TRUE
400
     * @throws EE_Error
401
     * @throws InvalidArgumentException
402
     * @throws InvalidDataTypeException
403
     * @throws InvalidInterfaceException
404
     */
405
    private function addTicketsToCart(array $valid)
406
    {
407
        $tickets_added = 0;
408
        $tickets_selected = false;
409
        if($valid['total_tickets'] > 0){
410
            // load cart using factory because we don't want to do so until actually needed
411
            $this->cart = CartFactory::getCart();
412
            // cycle thru the number of data rows sent from the event listing
413
            for ($x = 0; $x < $valid['rows']; $x++) {
414
                // does this row actually contain a ticket quantity?
415
                if (isset($valid['qty'][ $x ]) && $valid['qty'][ $x ] > 0) {
416
                    // YES we have a ticket quantity
417
                    $tickets_selected = true;
418
                    $valid_ticket     = false;
419
                    // \EEH_Debug_Tools::printr(
420
                    //     $valid['ticket_id'][ $x ],
421
                    //     '$valid[\'ticket_id\'][ $x ]',
422
                    //     __FILE__, __LINE__
423
                    // );
424
                    if (isset($valid['ticket_id'][ $x ])) {
425
                        // get ticket via the ticket id we put in the form
426
                        $ticket = $this->ticket_model->get_one_by_ID($valid['ticket_id'][ $x ]);
427
                        if ($ticket instanceof EE_Ticket) {
428
                            $valid_ticket  = true;
429
                            $tickets_added += $this->addTicketToCart(
430
                                $ticket,
431
                                $valid['qty'][ $x ]
432
                            );
433
                        }
434
                    }
435 View Code Duplication
                    if ($valid_ticket !== true) {
436
                        // nothing added to cart retrieved
437
                        EE_Error::add_error(
438
                            sprintf(
439
                                esc_html__(
440
                                    'A valid ticket could not be retrieved for the event.%sPlease click the back button on your browser and try again.',
441
                                    'event_espresso'
442
                                ),
443
                                '<br/>'
444
                            ),
445
                            __FILE__, __FUNCTION__, __LINE__
446
                        );
447
                    }
448
                    if (EE_Error::has_error()) {
449
                        break;
450
                    }
451
                }
452
            }
453
        }
454
        do_action(
455
            'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
456
            $this->cart,
457
            $this
458
        );
459
        if (! apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', $tickets_selected)) {
460
            // no ticket quantities were selected
461
            EE_Error::add_error(
462
                esc_html__('You need to select a ticket quantity before you can proceed.', 'event_espresso'),
463
                __FILE__, __FUNCTION__, __LINE__
464
            );
465
        }
466
        return $tickets_added;
467
    }
468
469
470
471
    /**
472
     * adds a ticket to the cart
473
     *
474
     * @param EE_Ticket $ticket
475
     * @param int        $qty
476
     * @return TRUE on success, FALSE on fail
477
     * @throws InvalidArgumentException
478
     * @throws InvalidInterfaceException
479
     * @throws InvalidDataTypeException
480
     * @throws EE_Error
481
     */
482
    private function addTicketToCart(EE_Ticket $ticket, $qty = 1)
483
    {
484
        // get the number of spaces left for this datetime ticket
485
        $available_spaces = $this->tracker->ticketDatetimeAvailability($ticket);
486
        // compare available spaces against the number of tickets being purchased
487
        if ($available_spaces >= $qty) {
488
            // allow addons to prevent a ticket from being added to cart
489
            if (
490
                ! apply_filters(
491
                    'FHEE__EE_Ticket_Selector___add_ticket_to_cart__allow_add_to_cart',
492
                    true,
493
                    $ticket,
494
                    $qty,
495
                    $available_spaces
496
                )
497
            ) {
498
                return false;
499
            }
500
            $qty = absint(apply_filters('FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty', $qty, $ticket));
501
            // add event to cart
502
            if ($this->cart->add_ticket_to_cart($ticket, $qty)) {
503
                $this->tracker->recalculateTicketDatetimeAvailability($ticket, $qty);
504
                return true;
505
            }
506
            return false;
507
        }
508
        $this->tracker->processAvailabilityError($ticket, $qty, $this->cart->all_ticket_quantity_count());
509
        return false;
510
    }
511
512
513
    /**
514
     * @param $tickets_added
515
     * @return bool
516
     * @throws InvalidInterfaceException
517
     * @throws InvalidDataTypeException
518
     * @throws EE_Error
519
     * @throws InvalidArgumentException
520
     */
521
    private function processSuccessfulCart($tickets_added)
522
    {
523
        // exit('KILL REDIRECT BEFORE CART UPDATE'); // <<<<<<<<<<<<<<<<< KILL REDIRECT HERE BEFORE CART UPDATE
524
        if (apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__success', $tickets_added)) {
525
            // make sure cart is loaded
526
            if(! $this->cart  instanceof EE_Cart){
527
                $this->cart = CartFactory::getCart();
528
            }
529
            do_action(
530
                'FHEE__EE_Ticket_Selector__process_ticket_selections__before_redirecting_to_checkout',
531
                $this->cart,
532
                $this
533
            );
534
            $this->cart->recalculate_all_cart_totals();
535
            $this->cart->save_cart(false);
536
            // exit('KILL REDIRECT AFTER CART UPDATE'); // <<<<<<<<  OR HERE TO KILL REDIRECT AFTER CART UPDATE
537
            // just return TRUE for registrations being made from admin
538
            if ($this->request->isAdmin() || $this->request->isFrontAjax()) {
539
                return true;
540
            }
541
            EEH_URL::safeRedirectAndExit(
542
                apply_filters(
543
                    'FHEE__EE_Ticket_Selector__process_ticket_selections__success_redirect_url',
544
                    $this->core_config->reg_page_url()
545
                )
546
            );
547
        }
548
        if (! EE_Error::has_error() && ! EE_Error::has_error(true, 'attention')) {
549
            // nothing added to cart
550
            EE_Error::add_attention(
551
                esc_html__('No tickets were added for the event', 'event_espresso'),
552
                __FILE__, __FUNCTION__, __LINE__
553
            );
554
        }
555
        return false;
556
    }
557
}
558
// End of file ProcessTicketSelector.php
559
// Location: /ProcessTicketSelector.php
560