Completed
Branch FET-8476-powered-by-event-espr... (1a0127)
by
unknown
435:56 queued 415:37
created

EE_Checkout::refresh_entity_map()   D

Complexity

Conditions 9
Paths 21

Size

Total Lines 44
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 26
nc 21
nop 0
dl 0
loc 44
rs 4.909
c 0
b 0
f 0
1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) { exit('No direct script access allowed'); }
2
 /**
3
 *
4
 * Class EE_Checkout
5
 *
6
 * Description
7
 *
8
 * @package 			Event Espresso
9
 * @subpackage    core
10
 * @author				Brent Christensen
11
 * @since 				4.5.0
12
 *
13
 */
14
class EE_Checkout {
15
16
	/**
17
	 * 	whether current request originated from the EE admin
18
	 * @type bool
19
	 */
20
	public $admin_request = FALSE;
21
22
	/**
23
	 * whether returning to edit attendee information or to retry a payment
24
	 * @type bool
25
	 */
26
	public $revisit = FALSE;
27
28
	/**
29
	 * whether the primary registrant is returning to edit attendee information or to retry a payment
30
	 * @type bool
31
	 */
32
	public $primary_revisit = FALSE;
33
34
	/**
35
	 * is registration allowed to progress or halted for some reason such as failing to pass recaptcha?
36
	 * @type bool
37
	 */
38
	public $continue_reg = TRUE;
39
40
	/**
41
	 * redirect to thank you page ?
42
	 * @type bool
43
	 */
44
	public $redirect = FALSE;
45
46
	/**
47
	 * generate the reg form or not ?
48
	 * @type bool
49
	 */
50
	public $generate_reg_form = TRUE;
51
52
	/**
53
	 * process a reg form submission or not ?
54
	 * @type bool
55
	 */
56
	public $process_form_submission = FALSE;
57
58
	/**
59
	 * tracks whether the TXN status modified during this checkout
60
	 *
61
	 * @type bool
62
	 */
63
	public $txn_status_updated = FALSE;
64
65
	/**
66
	 * only triggered to true after absolutely everything has finished.
67
	 *
68
	 * @type bool
69
	 */
70
	protected $exit_spco = FALSE;
71
72
	/**
73
	 * tracks whether any of the TXN's Registrations statuses modified during this checkout
74
	 * indexed by registration ID
75
	 *
76
	 * @type array
77
	 */
78
	protected $reg_status_updated = array();
79
80
	/**
81
	 * total number of tickets that were in the cart
82
	 * @type int
83
	 */
84
	public $total_ticket_count = 0;
85
86
	/**
87
	 * corresponds loosely to EE_Transaction::remaining()
88
	 * but can be modified by SPCO
89
	 *
90
	 * @type float
91
	 */
92
	public $amount_owing = 0;
93
94
	/**
95
	 * the reg step slug from the incoming request
96
	 * @type string
97
	 */
98
	public $step = '';
99
100
	/**
101
	 * the reg step slug for a step being edited
102
	 * @type string
103
	 */
104
	public $edit_step = '';
105
106
	/**
107
	 * the action being performed on the current step
108
	 * @type string
109
	 */
110
	public $action = '';
111
112
	/**
113
	 * reg_url_link for a previously saved registration
114
	 * @type string
115
	 */
116
	public $reg_url_link = '';
117
118
	/**
119
	 * string slug for the payment method that was selected during the payment options step
120
	 * @type string
121
	 */
122
	public $selected_method_of_payment = '';
123
124
	/**
125
	 * base url for the site's registration checkout page - additional url params will be added to this
126
	 * @type string
127
	 */
128
	public $reg_page_base_url = '';
129
130
	/**
131
	 * base url for the site's registration cancelled page - additional url params will be added to this
132
	 * @type string
133
	 */
134
	public $cancel_page_url = '';
135
136
	/**
137
	 * base url for the site's thank you page - additional url params will be added to this
138
	 * @type string
139
	 */
140
	public $thank_you_page_url = '';
141
142
	/**
143
	 * base url for any redirects - additional url params will be added to this
144
	 * @type string
145
	 */
146
	public $redirect_url = '';
147
148
	/**
149
	 * form of POST data for use with off-site gateways
150
	 * @type string
151
	 */
152
	public $redirect_form = '';
153
154
	/**
155
	 * array of query where params to use when retrieving cached registrations from $this->checkout->transaction
156
	 * @type array
157
	 */
158
	public $reg_cache_where_params = array();
159
160
	/**
161
	 * a class for managing and creating the JSON encoded array of data that gets passed back to the client during AJAX requests
162
	 * @type EE_SPCO_JSON_Response
163
	 */
164
	public $json_response;
165
166
	/**
167
	 * where we are going next in the reg process
168
	 * @type EE_SPCO_Reg_Step
169
	 */
170
	public $next_step;
171
172
	/**
173
	 * where we are in the reg process
174
	 * @type EE_SPCO_Reg_Step
175
	 */
176
	public $current_step;
177
178
	/**
179
	 * 	$_cart - the current cart object
180
	 *	@var EE_CART
181
	 */
182
	public $cart;
183
184
	/**
185
	 * 	$_transaction - the current transaction object
186
	 *	@var EE_Transaction
187
	 */
188
	public $transaction;
189
190
	/**
191
	 * 	the related attendee object for the primary registrant
192
	 * @type EE_Attendee
193
	 */
194
	public $primary_attendee_obj;
195
196
	/**
197
	 *	$payment_method - the payment method object for the selected method of payment
198
	 *	@type EE_Payment_Method
199
	 */
200
	public $payment_method;
201
202
	/**
203
	 * 	$payment - if a payment was successfully made during the reg process,
204
	 * 	then here it is !!!
205
	 *	@type EE_Payment
206
	 */
207
	public $payment;
208
209
	/**
210
	 * 	if a payment method was selected that uses an on-site gateway, then this is the billing form
211
	 * @type EE_Billing_Info_Form | EE_Billing_Attendee_Info_Form
212
	 */
213
	public $billing_form;
214
215
	/**
216
	 * 	the entire registration form composed of ALL of the subsections generated by the various reg steps
217
	 * @type EE_Form_Section_Proper
218
	 */
219
	public $registration_form;
220
221
	/**
222
	 * array of EE_SPCO_Reg_Step objects
223
	 * @type EE_SPCO_Reg_Step[]
224
	 */
225
	public $reg_steps = array();
226
227
	/**
228
	 * array of EE_Payment_Method objects
229
	 * @type EE_Payment_Method[]
230
	 */
231
	public $available_payment_methods = array();
232
233
234
235
	/**
236
	 *    class constructor
237
	 *
238
	 * @access    public
239
	 */
240
	public function __construct(  ) {
241
		$this->reg_page_base_url = EE_Registry::instance()->CFG->core->reg_page_url();
0 ignored issues
show
Documentation Bug introduced by
It seems like \EE_Registry::instance()...G->core->reg_page_url() can also be of type integer. However, the property $reg_page_base_url is declared as type string. Maybe add an additional type check?

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 the id property of an instance of the Account 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.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
242
		$this->thank_you_page_url = EE_Registry::instance()->CFG->core->thank_you_page_url();
243
		$this->cancel_page_url = EE_Registry::instance()->CFG->core->cancel_page_url();
244
		$this->continue_reg = apply_filters( 'FHEE__EE_Checkout___construct___continue_reg', TRUE );
245
		$this->admin_request = is_admin() && ! EE_Registry::instance()->REQ->ajax;
246
		$this->reg_cache_where_params = array( 'order_by' => array( 'REG_count' => 'ASC' ));
247
	}
248
249
250
251
	/**
252
	 * returns true if ANY reg status was updated during checkout
253
	 *
254
	 * @return boolean
255
	 */
256
	public function any_reg_status_updated() {
257
		foreach ( $this->reg_status_updated as $reg_status ) {
258
			if ( $reg_status ) {
259
				return true;
260
			}
261
		}
262
		return false;
263
	}
264
265
266
267
	/**
268
	 * @param $REG_ID
269
	 * @return boolean
270
	 */
271
	public function reg_status_updated( $REG_ID ) {
272
		return isset( $this->reg_status_updated[ $REG_ID ] ) ? $this->reg_status_updated[ $REG_ID ] : false;
273
	}
274
275
276
277
	/**
278
	 * @param $REG_ID
279
	 * @param $reg_status
280
	 */
281
	public function set_reg_status_updated( $REG_ID, $reg_status ) {
282
		$this->reg_status_updated[ $REG_ID ] = filter_var( $reg_status, FILTER_VALIDATE_BOOLEAN );
283
	}
284
285
286
287
	/**
288
	 * exit_spco
289
	 *
290
	 * @return bool
291
	 */
292
	public function exit_spco() {
293
		return $this->exit_spco;
294
	}
295
296
297
298
	/**
299
	 * set_exit_spco
300
	 * can ONLY be set by the  Finalize_Registration reg step
301
	 */
302
	public function set_exit_spco() {
303
		if ( $this->current_step instanceof EE_SPCO_Reg_Step_Finalize_Registration ) {
304
			$this->exit_spco = true;
305
		}
306
	}
307
308
309
310
311
312
	/**
313
	 *    reset_for_current_request
314
	 *
315
	 * @access    public
316
	 * @return    void
317
	 */
318
	public function reset_for_current_request() {
319
		$this->process_form_submission = FALSE;
320
		$this->continue_reg = apply_filters( 'FHEE__EE_Checkout___construct___continue_reg', true );
321
		$this->admin_request = is_admin() && ! EE_Registry::instance()->REQ->front_ajax;
322
		$this->continue_reg = true;
323
		$this->redirect = false;
324
		// don't reset the cached redirect form if we're about to be asked to display it !!!
325
		if ( EE_Registry::instance()->REQ->get( 'action', 'display_spco_reg_step' ) !== 'redirect_form' ) {
326
			$this->redirect_form = '';
327
		}
328
		$this->redirect_url = '';
329
		$this->json_response = new EE_SPCO_JSON_Response();
330
		EE_Form_Section_Proper::reset_js_localization();
331
	}
332
333
334
335
	/**
336
	 *    add_reg_step
337
	 *
338
	 * @access    public
339
	 * @param EE_SPCO_Reg_Step $reg_step_obj
340
	 * @return    void
341
	 */
342
	public function add_reg_step( EE_SPCO_Reg_Step $reg_step_obj ) {
343
		$this->reg_steps[ $reg_step_obj->slug()  ] = $reg_step_obj;
344
	}
345
346
347
348
	/**
349
	 * skip_reg_step
350
	 * if the current reg step does not need to run for some reason,
351
	 * then this will advance SPCO to the next reg step,
352
	 * and mark the skipped step as completed
353
	 *
354
	 * @access    public
355
	 * @param string $reg_step_slug
356
	 * @return    void
357
	 * @throws \EE_Error
358
	 */
359
	public function skip_reg_step( $reg_step_slug = '' ) {
360
		$step_to_skip = $this->find_reg_step( $reg_step_slug );
361
		if ( $step_to_skip instanceof EE_SPCO_Reg_Step && $step_to_skip->is_current_step() ) {
362
			$step_to_skip->set_is_current_step( false );
363
			$step_to_skip->set_completed();
364
			// advance to the next step
365
			$this->set_current_step( $this->next_step->slug() );
366
			// also reset the step param in the request in case any other code references that directly
367
			EE_Registry::instance()->REQ->set( 'step', $this->current_step->slug() );
368
			// since we are skipping a step and setting the current step to be what was previously the next step,
369
			// we need to check that the next step is now correct, and not still set to the current step.
370
			if ( $this->current_step->slug() === $this->next_step->slug() ) {
371
				// correctly setup the next step
372
				$this->set_next_step();
373
			}
374
			$this->set_reg_step_initiated( $this->current_step );
375
		}
376
	}
377
378
379
380
	/**
381
	 *    remove_reg_step
382
	 *
383
	 * @access    public
384
	 * @param string $reg_step_slug
385
	 * @param bool   $reset whether to reset reg steps after removal
386
	 * @throws EE_Error
387
	 */
388
	public function remove_reg_step( $reg_step_slug = '', $reset = true ) {
389
		unset( $this->reg_steps[ $reg_step_slug  ] );
390
		if ( $this->transaction instanceof EE_Transaction ) {
391
			// now remove reg step from TXN and save
392
			$this->transaction->remove_reg_step( $reg_step_slug );
393
			$this->transaction->save();
394
		}
395
		if ( $reset ) {
396
			$this->reset_reg_steps();
397
		}
398
	}
399
400
401
402
	/**
403
	 *    set_reg_step_order
404
	 *
405
	 * @access    public
406
	 * @param string $reg_step_slug
407
	 * @param int    $order
408
	 * @return    void
409
	 */
410
	public function set_reg_step_order( $reg_step_slug = '', $order = 100 ) {
411
		if ( isset( $this->reg_steps[ $reg_step_slug  ] )) {
412
			$this->reg_steps[ $reg_step_slug ]->set_order( $order );
413
		}
414
	}
415
416
417
418
	/**
419
	 *    set_current_step
420
	 *
421
	 * @access    public
422
	 * @param string $current_step
423
	 * @return    void
424
	 */
425
	public function set_current_step( $current_step ) {
426
		// grab what step we're on
427
		$this->current_step = isset( $this->reg_steps[ $current_step ] ) ? $this->reg_steps[ $current_step ] : reset( $this->reg_steps );
0 ignored issues
show
Documentation Bug introduced by
It seems like isset($this->reg_steps[$...reset($this->reg_steps) can also be of type false. However, the property $current_step is declared as type object<EE_SPCO_Reg_Step>. Maybe add an additional type check?

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 the id property of an instance of the Account 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.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
428
		// verify instance
429
		if ( $this->current_step instanceof EE_SPCO_Reg_Step ) {
430
			// we don't want to repeat completed steps if this is the first time through SPCO
431
			if ( $this->continue_reg && ! $this->revisit && $this->current_step->completed() ) {
432
				// so advance to the next step
433
				$this->set_next_step();
434
				if ( $this->next_step instanceof EE_SPCO_Reg_Step ) {
435
					// and attempt to set it as the current step
436
					$this->set_current_step( $this->next_step->slug() );
437
				}
438
				return;
439
			}
440
			$this->current_step->set_is_current_step( TRUE );
441
		} else {
442
			EE_Error::add_error(
443
				__( 'The current step could not be set.', 'event_espresso' ),
444
				__FILE__, __FUNCTION__, __LINE__
445
			);
446
		}
447
	}
448
449
450
451
	/**
452
	 * 	set_next_step
453
	 * advances the reg_steps array pointer and sets the next step, then reverses pointer back to the current step
454
	 *
455
	 *  @access 	public
456
	 *  @return 	void
457
	 */
458
	public function set_next_step() {
459
		// set pointer to start of array
460
		reset( $this->reg_steps );
461
		// if there is more than one step
462
		if ( count( $this->reg_steps ) > 1 ) {
463
			// advance to the current step and set pointer
464
			while ( key( $this->reg_steps ) !== $this->current_step->slug() && key( $this->reg_steps ) !== '' ) {
465
				next( $this->reg_steps );
466
			}
467
		}
468
		// advance one more spot ( if it exists )
469
		$this->next_step = next( $this->reg_steps );
470
		// verify instance
471
		$this->next_step = $this->next_step instanceof EE_SPCO_Reg_Step ? $this->next_step  : NULL;
472
		// then back to current step to reset
473
		prev( $this->reg_steps );
474
	}
475
476
477
478
479
	/**
480
	 * 	get_next_reg_step
481
	 * 	this simply returns the next step from reg_steps array
482
	 *
483
	 *  @access 	public
484
	 *  @return 	EE_SPCO_Reg_Step | null
485
	 */
486
	public function get_next_reg_step() {
487
		$next = next( $this->reg_steps );
488
		prev( $this->reg_steps );
489
		return $next instanceof EE_SPCO_Reg_Step ? $next : null;
490
	}
491
492
493
494
495
	/**
496
	 * get_prev_reg_step
497
	 * 	this simply returns the previous step from reg_steps array
498
	 *
499
	 *  @access 	public
500
	 *  @return 	EE_SPCO_Reg_Step | null
501
	 */
502
	public function get_prev_reg_step() {
503
		$prev = prev( $this->reg_steps );
504
		next( $this->reg_steps );
505
		return $prev instanceof EE_SPCO_Reg_Step ? $prev : null;
506
	}
507
508
509
510
	/**
511
	 * sort_reg_steps
512
	 *
513
	 * @access public
514
	 * @return void
515
	 */
516
	public function sort_reg_steps() {
517
		$reg_step_sorting_callback = apply_filters( 'FHEE__EE_Checkout__sort_reg_steps__reg_step_sorting_callback', 'reg_step_sorting_callback' );
518
		uasort( $this->reg_steps, array( $this, $reg_step_sorting_callback ));
519
	}
520
521
522
523
	/**
524
	 * find_reg_step
525
	 * finds a reg step by the given slug
526
	 *
527
	 * @access    public
528
	 * @param string $reg_step_slug
529
	 * @return EE_SPCO_Reg_Step|null
530
	 */
531
	public function find_reg_step( $reg_step_slug = '' ) {
532
		if ( ! empty( $reg_step_slug ) ) {
533
			// copy reg step array
534
			$reg_steps = $this->reg_steps;
535
			// set pointer to start of array
536
			reset( $reg_steps );
537
			// if there is more than one step
538
			if ( count( $reg_steps ) > 1 ) {
539
				// advance to the current step and set pointer
540
				while ( key( $reg_steps ) !== $reg_step_slug && key( $reg_steps ) !== '' ) {
541
					next( $reg_steps );
542
				}
543
				return current( $reg_steps );
544
			}
545
		}
546
		return null;
547
	}
548
549
550
551
	/**
552
	 * reg_step_sorting_callback
553
	 *
554
	 * @access public
555
	 * @param EE_SPCO_Reg_Step $reg_step_A
556
	 * @param EE_SPCO_Reg_Step $reg_step_B
557
	 * @return int
558
	 */
559
	public function reg_step_sorting_callback( EE_SPCO_Reg_Step $reg_step_A, EE_SPCO_Reg_Step $reg_step_B ) {
560
		// send finalize_registration step to the end of the array
561
		if ( $reg_step_A->slug() === 'finalize_registration' ) {
562
			return 1;
563
		} else if ( $reg_step_B->slug() === 'finalize_registration' ) {
564
			return -1;
565
		}
566
		if ( $reg_step_A->order() === $reg_step_B->order() ) {
567
			return 0;
568
		}
569
		return ( $reg_step_A->order() > $reg_step_B->order() ) ? 1 : -1;
570
	}
571
572
573
574
	/**
575
	 * set_reg_step_initiated
576
	 *
577
	 * @access    public
578
	 * @param    EE_SPCO_Reg_Step $reg_step
579
	 * @throws \EE_Error
580
	 */
581
	public function set_reg_step_initiated( EE_SPCO_Reg_Step $reg_step ) {
582
		// call set_reg_step_initiated ???
583
		if (
584
			// first time visiting SPCO ?
585
			! $this->revisit
586
			&& (
587
				// and displaying the reg step form for the first time ?
588
				$this->action === 'display_spco_reg_step'
589
				// or initializing the final step
590
				|| $reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration
591
			)
592
		) {
593
			// set the start time for this reg step
594
			if ( ! $this->transaction->set_reg_step_initiated( $reg_step->slug() ) ) {
595 View Code Duplication
				if ( WP_DEBUG ) {
596
					EE_Error::add_error(
597
						sprintf(
598
							__( 'The "%1$s" registration step was not initialized properly.', 'event_espresso' ),
599
							$reg_step->name()
600
						),
601
						__FILE__, __FUNCTION__, __LINE__
602
					);
603
				}
604
			}
605
		}
606
	}
607
608
609
610
	/**
611
	 * 	set_reg_step_JSON_info
612
	 *
613
	 * 	@access public
614
	 * 	@return 	void
615
	 */
616
	public function set_reg_step_JSON_info() {
617
		EE_Registry::$i18n_js_strings[ 'reg_steps' ] = array();
618
		// pass basic reg step data to JS
619
		foreach ( $this->reg_steps as $reg_step ) {
620
			EE_Registry::$i18n_js_strings[ 'reg_steps' ][] = $reg_step->slug();
621
		}
622
		// reset reg step html
623
//		$this->json_response->set_reg_step_html( '' );
624
	}
625
626
627
628
	/**
629
	 * 	reset_reg_steps
630
	 *
631
	 * 	@access public
632
	 * 	@return void
633
	 */
634
	public function reset_reg_steps() {
635
		$this->sort_reg_steps();
636
		$this->set_current_step( EE_Registry::instance()->REQ->get( 'step' ));
637
		$this->set_next_step();
638
		// the text that appears on the reg step form submit button
639
		$this->current_step->set_submit_button_text();
640
		$this->set_reg_step_JSON_info();
641
	}
642
643
644
645
	/**
646
	 *    get_registration_time_limit
647
	 *
648
	 * @access    public
649
	 * @return        string
650
	 */
651
	public function get_registration_time_limit() {
652
653
		$registration_time_limit = (float)( EE_Registry::instance()	->SSN->expiration() - time() );
654
		$time_limit_format = $registration_time_limit > 60 * MINUTE_IN_SECONDS ? 'H:i:s' : 'i:s';
655
		$registration_time_limit = gmdate( $time_limit_format, $registration_time_limit );
656
		return apply_filters(
657
			'FHEE__EE_Checkout__get_registration_time_limit__registration_time_limit',
658
			$registration_time_limit
659
		);
660
	}
661
662
663
664
	/**
665
	 * payment_required
666
	 * @return boolean
667
	 */
668
	public function payment_required() {
669
		// if NOT:
670
		//		registration via admin
671
		//		completed TXN
672
		//		overpaid TXN
673
		//		free TXN ( total = 0.00 )
674
		// then payment required is TRUE
675
		return ! ( $this->admin_request || $this->transaction->is_completed() || $this->transaction->is_overpaid() || $this->transaction->is_free() ) ? TRUE : FALSE;
676
	}
677
678
679
680
	/**
681
	 * get_cart_for_transaction
682
	 *
683
	 * @access public
684
	 * @param EE_Transaction $transaction
685
	 * @return EE_Cart
686
	 */
687
	public function get_cart_for_transaction( $transaction ) {
688
		$session = EE_Registry::instance()->load_core( 'Session' );
689
		$cart = $transaction instanceof EE_Transaction ? EE_Cart::get_cart_from_txn( $transaction, $session ) : null;
0 ignored issues
show
Bug introduced by
It seems like $session defined by \EE_Registry::instance()->load_core('Session') on line 688 can also be of type boolean or object; however, EE_Cart::get_cart_from_txn() does only seem to accept null|object<EE_Session>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
690
		// verify cart
691
		if ( ! $cart instanceof EE_Cart ) {
692
			$cart = EE_Registry::instance()->load_core( 'Cart' );
0 ignored issues
show
Bug Compatibility introduced by
The expression \EE_Registry::instance()->load_core('Cart'); of type null|object|boolean adds the type boolean to the return on line 695 which is incompatible with the return type documented by EE_Checkout::get_cart_for_transaction of type EE_Cart|null.
Loading history...
693
		}
694
695
		return $cart;
696
	}
697
698
699
700
	/**
701
	 * 	initialize_txn_reg_steps_array
702
	 *
703
	 * 	@access public
704
	 * 	@return 	array
705
	 */
706
	public function initialize_txn_reg_steps_array() {
707
		$txn_reg_steps_array = array();
708
		foreach ( $this->reg_steps as $reg_step ) {
709
			$txn_reg_steps_array[ $reg_step->slug() ] = FALSE;
710
		}
711
		return $txn_reg_steps_array;
712
	}
713
714
715
716
	/**
717
	 *    update_txn_reg_steps_array
718
	 *
719
	 * @access public
720
	 * @return    bool
721
	 * @throws \EE_Error
722
	 */
723
	public function update_txn_reg_steps_array() {
724
		$updated = false;
725
		foreach ( $this->reg_steps as $reg_step ) {
726
			if ( $reg_step->completed() ) {
727
				$updated = $this->transaction->set_reg_step_completed( $reg_step->slug() )
728
					? true
729
					: $updated;
730
			}
731
		}
732
		if ( $updated ) {
733
			$this->transaction->save();
734
		}
735
		return $updated;
736
	}
737
738
739
740
	/**
741
	 *    stash_transaction_and_checkout
742
	 *
743
	 * @access public
744
	 * @return    void
745
	 * @throws \EE_Error
746
	 */
747
	public function stash_transaction_and_checkout() {
748
		if ( ! $this->revisit ) {
749
			$this->update_txn_reg_steps_array();
750
		}
751
		$this->track_transaction_and_registration_status_updates();
752
		// save all data to the db, but suppress errors
753
		//$this->save_all_data( FALSE );
754
		// cache the checkout in the session
755
		EE_Registry::instance()->SSN->set_checkout( $this );
756
	}
757
758
759
760
	/**
761
	 *    track_transaction_and_registration_status_updates
762
	 *    stores whether any updates were made to the TXN or it's related registrations
763
	 *
764
	 * @access public
765
	 * @return void
766
	 * @throws \EE_Error
767
	 */
768
	public function track_transaction_and_registration_status_updates() {
769
		// verify the transaction
770
		if ( $this->transaction instanceof EE_Transaction ) {
771
			// has there been a TXN status change during this checkout?
772
			$this->txn_status_updated = $this->transaction->txn_status_updated();
773
			/** @type EE_Registration_Processor $registration_processor */
774
			$registration_processor = EE_Registry::instance()->load_class( 'Registration_Processor' );
775
			// grab the saved registrations from the transaction
776
			foreach ( $this->transaction->registrations( $this->reg_cache_where_params ) as $registration ) {
777
				if ( $registration_processor->reg_status_updated( $registration->ID() ) ) {
778
					$this->set_reg_status_updated( $registration->ID(), true );
779
				}
780
			}
781
		}
782
	}
783
784
785
786
	/**
787
	 *    visit_allows_processing_of_this_registration
788
	 *    determines if the current SPCO visit should allow the passed EE_Registration to be used in processing.
789
	 *    one of the following conditions must be met:
790
	 *        EITHER:    A) first time thru SPCO -> process ALL registrations ( NOT a revisit )
791
	 *        OR :        B) primary registrant is editing info -> process ALL registrations ( primary_revisit )
792
	 *        OR :        C) another registrant is editing info -> ONLY process their registration ( revisit AND their reg_url_link matches )
793
	 *
794
	 * @access public
795
	 * @param    EE_Registration $registration
796
	 * @return    bool
797
	 * @throws \EE_Error
798
	 */
799
	public function visit_allows_processing_of_this_registration( EE_Registration $registration ) {
800
		return ! $this->revisit
801
		       || $this->primary_revisit
802
		       || (
803
			       $this->revisit && $this->reg_url_link === $registration->reg_url_link()
804
		       )
805
			? true
806
			: false;
807
	}
808
809
810
811
	/**
812
	 * 	_transaction_has_primary_registration
813
	 *
814
	 * 	@access 		private
815
	 * 	@return 		bool
816
	 */
817
	public function transaction_has_primary_registrant() {
818
		return $this->primary_attendee_obj instanceof EE_Attendee ? TRUE : FALSE;
819
	}
820
821
822
823
	/**
824
	 *    save_all_data
825
	 *    simply loops through the current transaction and saves all data for each registration
826
	 *
827
	 * @access public
828
	 * @param bool $show_errors
829
	 * @return bool
830
	 * @throws \EE_Error
831
	 */
832
	public function save_all_data( $show_errors = TRUE ) {
833
		// verify the transaction
834
		if ( $this->transaction instanceof EE_Transaction ) {
835
			// save to ensure that TXN has ID
836
			$this->transaction->save();
837
			// grab the saved registrations from the transaction
838
			foreach ( $this->transaction->registrations( $this->reg_cache_where_params ) as  $registration ) {
839
				$this->_save_registration( $registration, $show_errors );
0 ignored issues
show
Compatibility introduced by
$registration of type object<EE_Base_Class> is not a sub-type of object<EE_Registration>. It seems like you assume a child class of the class EE_Base_Class to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
840
			}
841
		} else {
842
			if ( $show_errors ) {
843
				EE_Error::add_error( __( 'A valid Transaction was not found when attempting to save your registration information.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__);
844
			}
845
			return FALSE;
846
		}
847
		return TRUE;
848
	}
849
850
851
852
	/**
853
	 * _save_registration_attendee
854
	 *
855
	 * @param    EE_Registration $registration
856
	 * @param bool               $show_errors
857
	 * @return void
858
	 * @throws \EE_Error
859
	 */
860
	private function _save_registration( $registration, $show_errors = TRUE  ) {
861
		// verify object
862
		if ( $registration instanceof EE_Registration ) {
863
			// should this registration be processed during this visit ?
864
			if ( $this->visit_allows_processing_of_this_registration( $registration ) ) {
865
				//set TXN ID
866
				if ( ! $registration->transaction_ID() ) {
867
					$registration->set_transaction_id( $this->transaction->ID() );
868
				}
869
				// verify and save the attendee
870
				$this->_save_registration_attendee( $registration, $show_errors );
871
				// save answers to reg form questions
872
				$this->_save_registration_answers( $registration, $show_errors );
873
				// save changes
874
				$registration->save();
875
				// update txn cache
876 View Code Duplication
				if ( ! $this->transaction->update_cache_after_object_save( 'Registration', $registration )) {
877
					if ( $show_errors ) {
878
						EE_Error::add_error( __( 'The newly saved Registration object could not be cached on the Transaction.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__);
879
					}
880
				}
881
			}
882
		} else {
883
			if ( $show_errors ) {
884
				EE_Error::add_error(
885
					__( 'An invalid Registration object was discovered when attempting to save your registration information.', 'event_espresso' ),
886
					__FILE__, __FUNCTION__, __LINE__
887
				);
888
			}
889
		}
890
	}
891
892
893
894
	/**
895
	 * _save_registration_attendee
896
	 *
897
	 * @param    EE_Registration $registration
898
	 * @param bool               $show_errors
899
	 * @return void
900
	 * @throws \EE_Error
901
	 */
902
	private function _save_registration_attendee( $registration, $show_errors = TRUE ) {
903
		if ( $registration->attendee() instanceof EE_Attendee ) {
904
			// save so that ATT has ID
905
			$registration->attendee()->save();
906 View Code Duplication
			if ( ! $registration->update_cache_after_object_save( 'Attendee', $registration->attendee() ) ) {
907
				if ( $show_errors ) {
908
					EE_Error::add_error(
909
						__( 'The newly saved Attendee object could not be cached on the registration.', 'event_espresso' ),
910
						__FILE__, __FUNCTION__, __LINE__
911
					);
912
				}
913
			}
914 View Code Duplication
		} else {
915
			if ( $show_errors ) {
916
				EE_Error::add_error(
917
					sprintf(
918
						'%1$s||%1$s $attendee = %2$s',
919
						__( 'Either no Attendee information was found, or an invalid Attendee object was discovered when attempting to save your registration information.', 'event_espresso' ),
920
						var_export( $registration->attendee(), true )
921
					),
922
					__FILE__, __FUNCTION__, __LINE__
923
				);
924
			}
925
		}
926
	}
927
928
929
930
	/**
931
	 * _save_question_answers
932
	 *
933
	 * @param    EE_Registration $registration
934
	 * @param bool               $show_errors
935
	 * @return void
936
	 * @throws \EE_Error
937
	 */
938
	private function _save_registration_answers( $registration, $show_errors = TRUE ) {
939
		// now save the answers
940
		foreach ( $registration->answers() as $cache_key => $answer ) {
941
			// verify object
942
			if ( $answer instanceof EE_Answer ) {
943
				$answer->set_registration( $registration->ID() );
944
				$answer->save();
945
				if ( ! $registration->update_cache_after_object_save( 'Answer', $answer, $cache_key )) {
946
					if ( $show_errors ) {
947
						EE_Error::add_error(
948
							__( 'The newly saved Answer object could not be cached on the registration.', 'event_espresso' ),
949
							__FILE__, __FUNCTION__, __LINE__
950
						);
951
					}
952
				}
953
			} else {
954
				if ( $show_errors ) {
955
					EE_Error::add_error(
956
						__( 'An invalid Answer object was discovered when attempting to save your registration information.', 'event_espresso' ),
957
						__FILE__, __FUNCTION__, __LINE__
958
					);
959
				}
960
			}
961
		}
962
	}
963
964
965
966
	/**
967
	 *    refresh_all_entities
968
	 *   will either refresh the entity map with objects form the db or from the checkout cache
969
	 *
970
	 * @access public
971
	 * @param bool $from_db
972
	 * @return bool
973
	 * @throws \EE_Error
974
	 */
975
	public function refresh_all_entities( $from_db = false ) {
976
		$from_db = $this->current_step->is_final_step() || $this->action === 'process_gateway_response'
977
			? true
978
			: $from_db;
979
		//$this->log(
980
		//	__CLASS__, __FUNCTION__, __LINE__,
981
		//	array( 'from_db' =>$from_db )
982
		//);
983
		return $from_db ? $this->refresh_from_db() : $this->refresh_entity_map();
984
	}
985
986
987
988
	/**
989
	 *  refresh_entity_map
990
	 *  simply loops through the current transaction and updates each
991
	 *  model's entity map using EEM_Base::refresh_entity_map_from_db()
992
	 *
993
	 * @access public
994
	 * @return bool
995
	 * @throws \EE_Error
996
	 */
997
	protected function refresh_from_db() {
998
		// verify the transaction
999
		if ( $this->transaction instanceof EE_Transaction && $this->transaction->ID() ) {
1000
			// pull fresh TXN data from the db
1001
			$this->transaction = $this->transaction->get_model()->refresh_entity_map_from_db( $this->transaction->ID() );
1002
			// update EE_Checkout's cached primary_attendee object
1003
			$this->primary_attendee_obj = $this->_refresh_primary_attendee_obj_from_db( $this->transaction );
1004
			// update EE_Checkout's cached payment object
1005
			$payment = $this->transaction->last_payment();
1006
			$this->payment = $payment instanceof EE_Payment ? $payment : $this->payment;
1007
			// update EE_Checkout's cached payment_method object
1008
			$payment_method = $this->payment instanceof EE_Payment ? $this->payment->payment_method() : null;
1009
			$this->payment_method = $payment_method instanceof EE_Payment_Method ? $payment_method : $this->payment_method;
1010
			//now refresh the cart, based on the TXN
1011
			$this->cart = $this->get_cart_for_transaction( $this->transaction );
1012
		} else {
1013
			EE_Error::add_error( __( 'A valid Transaction was not found when attempting to update the model entity mapper.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__);
1014
			return FALSE;
1015
		}
1016
		return TRUE;
1017
	}
1018
1019
1020
1021
	/**
1022
	 * _refresh_primary_attendee_obj_from_db
1023
	 *
1024
	 * @param   EE_Transaction $transaction
1025
	 * @return  EE_Attendee | null
1026
	 * @throws \EE_Error
1027
	 */
1028
	protected function _refresh_primary_attendee_obj_from_db( EE_Transaction $transaction ) {
1029
1030
		$primary_attendee_obj = null;
1031
		// grab the saved registrations from the transaction
1032
		foreach ( $transaction->registrations( $this->reg_cache_where_params, true ) as $registration ) {
1033
			// verify object
1034
			if ( $registration instanceof EE_Registration ) {
1035
				$attendee = $registration->attendee();
1036
				// verify object && maybe cache primary_attendee_obj ?
1037
				if ( $attendee instanceof EE_Attendee&& $registration->is_primary_registrant() ) {
1038
					$primary_attendee_obj = $attendee;
1039
				}
1040
			} else {
1041
				EE_Error::add_error(
1042
						__( 'An invalid Registration object was discovered when attempting to update the model entity mapper.', 'event_espresso' ),
1043
						__FILE__, __FUNCTION__, __LINE__
1044
				);
1045
			}
1046
		}
1047
		return $primary_attendee_obj;
1048
	}
1049
1050
1051
1052
	/**
1053
	 *  refresh_entity_map
1054
	 *  simply loops through the current transaction and updates
1055
	 *  each model's entity map using EEM_Base::refresh_entity_map_with()
1056
	 *
1057
	 * @access public
1058
	 * @return bool
1059
	 * @throws \EE_Error
1060
	 */
1061
	protected function refresh_entity_map() {
1062
		// verify the transaction
1063
		if ( $this->transaction instanceof EE_Transaction && $this->transaction->ID() ) {
1064
			// never cache payment info
1065
			$this->transaction->clear_cache( 'Payment' );
1066
			// is the Payment Options Reg Step completed ?
1067
			if ( $this->transaction->reg_step_completed( 'payment_options' ) ) {
1068
				// then check for payments and update TXN accordingly
1069
				/** @type EE_Transaction_Payments $transaction_payments */
1070
				$transaction_payments = EE_Registry::instance()->load_class( 'Transaction_Payments' );
1071
				$transaction_payments->calculate_total_payments_and_update_status( $this->transaction );
1072
			}
1073
			// grab the saved registrations from the transaction
1074
			foreach (
1075
				$this->transaction->registrations( $this->reg_cache_where_params ) as $reg_cache_ID => $registration
1076
			) {
1077
				$this->_refresh_registration( $reg_cache_ID, $registration );
0 ignored issues
show
Compatibility introduced by
$registration of type object<EE_Base_Class> is not a sub-type of object<EE_Registration>. It seems like you assume a child class of the class EE_Base_Class to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1078
			}
1079
			// make sure our cached TXN is added to the model entity mapper
1080
			$this->transaction = $this->transaction->get_model()->refresh_entity_map_with( $this->transaction->ID(), $this->transaction );
1081
1082
		} else {
1083
			EE_Error::add_error( __( 'A valid Transaction was not found when attempting to update the model entity mapper.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__);
1084
			return FALSE;
1085
		}
1086
		// verify and update the cart because inaccurate totals are not so much fun
1087
		if ( $this->cart instanceof EE_Cart ) {
1088
			$grand_total = $this->cart->get_grand_total();
1089
			if ( $grand_total instanceof EE_Line_Item && $grand_total->ID() ) {
1090
				$grand_total->recalculate_total_including_taxes();
1091
				$grand_total = $grand_total->get_model()->refresh_entity_map_with(
1092
					$this->cart->get_grand_total()->ID(),
1093
					$this->cart->get_grand_total()
1094
				);
1095
			}
1096
			if ( $grand_total instanceof EE_Line_Item ) {
1097
				$this->cart = EE_Cart::instance( $grand_total );
1098
			} else {
1099
				EE_Error::add_error( __( 'A valid Cart was not found when attempting to update the model entity mapper.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
1100
				return false;
1101
			}
1102
		}
1103
		return TRUE;
1104
	}
1105
1106
1107
1108
	/**
1109
	 * _refresh_registration
1110
	 *
1111
	 * @param    string | int    $reg_cache_ID
1112
	 * @param    EE_Registration $registration
1113
	 * @return void
1114
	 * @throws \EE_Error
1115
	 */
1116
	protected function _refresh_registration( $reg_cache_ID, $registration ) {
1117
1118
		// verify object
1119 View Code Duplication
		if ( $registration instanceof EE_Registration ) {
1120
			// update the entity mapper attendee
1121
			$this->_refresh_registration_attendee( $registration );
1122
			// update the entity mapper answers for reg form questions
1123
			$this->_refresh_registration_answers( $registration );
1124
			// make sure the cached registration is added to the model entity mapper
1125
			$registration->get_model()->refresh_entity_map_with( $reg_cache_ID, $registration );
1126
		} else {
1127
			EE_Error::add_error(
1128
				__( 'An invalid Registration object was discovered when attempting to update the model entity mapper.', 'event_espresso' ),
1129
				__FILE__, __FUNCTION__, __LINE__
1130
			);
1131
		}
1132
	}
1133
1134
1135
1136
	/**
1137
	 * _save_registration_attendee
1138
	 *
1139
	 * @param    EE_Registration $registration
1140
	 * @return void
1141
	 * @throws \EE_Error
1142
	 */
1143
	protected function _refresh_registration_attendee( $registration ) {
1144
1145
		$attendee = $registration->attendee();
1146
		// verify object
1147
		if ( $attendee instanceof EE_Attendee && $attendee->ID() ) {
1148
			// make sure the cached attendee is added to the model entity mapper
1149
			$registration->attendee()->get_model()->refresh_entity_map_with( $attendee->ID(), $attendee );
1150
			// maybe cache primary_attendee_obj ?
1151
			if ( $registration->is_primary_registrant() ) {
1152
				$this->primary_attendee_obj = $attendee;
1153
			}
1154
		}
1155
	}
1156
1157
1158
1159
	/**
1160
	 * _refresh_registration_answers
1161
	 *
1162
	 * @param    EE_Registration $registration
1163
	 * @return void
1164
	 * @throws \EE_Error
1165
	 */
1166
	protected function _refresh_registration_answers( $registration ) {
1167
1168
		// now update the answers
1169
		foreach ( $registration->answers() as $cache_key => $answer ) {
1170
			// verify object
1171 View Code Duplication
			if ( $answer instanceof EE_Answer ) {
1172
				if ( $answer->ID() ) {
1173
					// make sure the cached answer is added to the model entity mapper
1174
					$answer->get_model()->refresh_entity_map_with( $answer->ID(), $answer );
1175
				}
1176
			} else {
1177
				EE_Error::add_error(
1178
					__( 'An invalid Answer object was discovered when attempting to update the model entity mapper.', 'event_espresso' ),
1179
					__FILE__, __FUNCTION__, __LINE__
1180
				);
1181
			}
1182
		}
1183
	}
1184
1185
1186
1187
	/**
1188
	 * 	__wakeup
1189
	 * to conserve db space, we are removing the EE_Checkout object from EE_SPCO_Reg_Step objects upon serialization
1190
	 * this will reinstate the EE_Checkout object on each EE_SPCO_Reg_Step object
1191
	 */
1192
	public function __wakeup() {
1193
		foreach ( $this->reg_steps as $reg_step ) {
1194
			$reg_step->checkout = $this;
1195
		}
1196
	}
1197
1198
1199
1200
	/**
1201
	 * debug
1202
	 *
1203
	 * @param string $class
1204
	 * @param string $func
1205
	 * @param string $line
1206
	 * @param array  $info
1207
	 * @param bool   $display_request
1208
	 * @throws \EE_Error
1209
	 */
1210
	public function log( $class = '', $func = '', $line = '', $info = array(), $display_request = false ) {
1211
		$disabled = true;
1212
		if ( WP_DEBUG && ! $disabled ) {
1213
			$debug_data = get_option( 'EE_DEBUG_SPCO_' . EE_Session::instance()->id(), array() );
1214
			$default_data = array(
1215
				$class 		=> $func . '() : ' . $line,
1216
				'request->step' 		=> $this->step,
1217
				'request->action' 	=> $this->action,
1218
				'current_step->slug' => $this->current_step instanceof EE_SPCO_Reg_Step ?
1219
					$this->current_step->slug() : '',
1220
				'current_step->completed' => $this->current_step instanceof EE_SPCO_Reg_Step ?
1221
					$this->current_step->completed() : '',
1222
				'txn_status_updated' => $this->transaction->txn_status_updated(),
1223
				'reg_status_updated' => $this->reg_status_updated,
1224
				'reg_url_link' => $this->reg_url_link,
1225
				'REQ' => $display_request ? $_REQUEST : '',
1226
			);
1227
			if ( $this->transaction instanceof EE_Transaction ) {
1228
				$default_data[ 'TXN_status' ] 		= $this->transaction->status_ID();
1229
				$default_data[ 'TXN_reg_steps' ] 	= $this->transaction->reg_steps();
1230
				foreach ( $this->transaction->registrations( $this->reg_cache_where_params ) as $REG_ID => $registration ) {
1231
					$default_data[ 'registrations' ][ $REG_ID ] = $registration->status_ID();
0 ignored issues
show
Documentation Bug introduced by
The method status_ID does not exist on object<EE_Base_Class>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1232
				}
1233
				if ( $this->transaction->ID() ) {
1234
					$TXN_ID = 'EE_Transaction: ' . $this->transaction->ID();
1235
					// don't serialize objects
1236
					$info = $this->_strip_objects( $info );
1237
					if ( ! isset( $debug_data[ $TXN_ID ] ) ) {
1238
						$debug_data[ $TXN_ID ] = array();
1239
					}
1240
					$debug_data[ $TXN_ID ][ microtime() ] = array_merge(
1241
						$default_data,
1242
						$info
1243
					);
1244
					update_option( 'EE_DEBUG_SPCO_' . EE_Session::instance()->id(), $debug_data );
1245
				}
1246
			}
1247
		}
1248
	}
1249
1250
1251
	/**
1252
	 * _strip_objects
1253
	 *
1254
	 * @param array $info
1255
	 * @return array
1256
	 */
1257
	public function _strip_objects( $info = array() ) {
1258
		foreach ( (array)$info as $key => $value ) {
1259 View Code Duplication
			if ( is_array( $value )) {
1260
				$info[ $key ] = $this->_strip_objects( $value );
1261
			} else if ( is_object( $value ) ) {
1262
				$object_class = get_class( $value );
1263
				$info[ $object_class ] = array();
1264
				$info[ $object_class ][ 'ID' ] = method_exists( $value, 'ID' ) ? $value->ID() : 0;
1265
				if ( method_exists( $value, 'status' ) ) {
1266
					$info[ $object_class ][ 'status' ] = $value->status();
1267
				} else if ( method_exists( $value, 'status_ID' ) ) {
1268
					$info[ $object_class ][ 'status' ] = $value->status_ID();
1269
				}
1270
				unset( $info[ $key ] );
1271
			}
1272
		}
1273
		return (array)$info;
1274
	}
1275
1276
1277
1278
1279
}
1280
// End of file EE_Checkout.class.php
1281
// Location: /EE_Checkout.class.php