Completed
Branch BUG-9625-better-us-phone-valid... (e0ce21)
by
unknown
631:18 queued 616:37
created

EE_PMT_Base   F

Complexity

Total Complexity 74

Size/Duplication

Total Lines 703
Duplicated Lines 0.57 %

Coupling/Cohesion

Components 4
Dependencies 21

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 74
lcom 4
cbo 21
dl 4
loc 703
rs 1.526
c 1
b 0
f 0

37 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 31 7
A file_folder() 0 6 2
A file_url() 0 6 2
A set_has_billing_form() 0 3 1
A _set_file_folder() 0 5 1
A _set_file_url() 0 6 1
A default_description() 0 3 1
A set_instance() 0 11 4
A settings_form() 0 13 3
generate_new_settings_form() 0 1 ?
A set_settings_form() 0 3 1
A has_billing_form() 0 3 1
B billing_form() 0 17 7
generate_new_billing_form() 0 1 ?
A apply_billing_form_debug_settings() 0 3 1
A set_billing_form() 0 3 1
A requires_https() 0 3 1
C process_payment() 0 89 7
A _get_billing_values_from_form() 0 7 2
A handle_ipn() 4 9 2
B _save_billing_info_to_attendee() 0 18 5
A find_payment_for_ipn() 0 3 1
A handle_unclaimed_ipn() 0 3 1
A finalize_payment_for() 0 3 1
A supports_sending_refunds() 0 7 3
A process_refund() 0 12 3
A payment_occurs() 0 11 4
A payment_overview_content() 0 4 1
A help_tabs_config() 0 3 1
A system_name() 0 4 1
A pretty_name() 0 3 1
A default_button_url() 0 3 1
A get_gateway() 0 3 1
A get_help_tab_link() 0 4 1
A get_help_tab_name() 0 3 1
A cap_name() 0 3 1
A update_txn_based_on_payment() 0 5 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EE_PMT_Base often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EE_PMT_Base, and based on these observations, apply Extract Interface, too.

1
<?php
2
EE_Registry::instance()->load_lib('Gateway');
3
EE_Registry::instance()->load_lib('Onsite_Gateway');
4
EE_Registry::instance()->load_lib('Offsite_Gateway');
5
/**
6
 *
7
 * Class EE_PMT_Base
8
 *
9
 * Description
10
 *
11
 * @package 			Event Espresso
12
 * @subpackage 	core
13
 * @author 				Mike Nelson
14
 * @since 				$VID:$
15
 *
16
 */
17
abstract class EE_PMT_Base{
18
19
	const onsite = 'on-site';
20
	const offsite = 'off-site';
21
	const offline = 'off-line';
22
23
	/**
24
	 * @var EE_Payment_Method
25
	 */
26
	protected $_pm_instance = NULL;
27
28
	/**
29
	 * @var boolean
30
	 */
31
	protected $_requires_https = FALSE;
32
33
	/**
34
	 * @var boolean
35
	 */
36
	protected $_has_billing_form;
37
38
	/**
39
	 * @var EE_Gateway
40
	 */
41
	protected $_gateway = NULL;
42
43
	/**
44
	 * @var EE_Payment_Method_Form
45
	 */
46
	protected $_settings_form = NULL;
47
48
	/**
49
	 * @var EE_Form_Section_Proper
50
	 */
51
	protected $_billing_form = NULL;
52
53
	/**
54
	 * @var boolean
55
	 */
56
	protected $_cache_billing_form = TRUE;
57
58
	/**
59
	 * String of the absolute path to the folder containing this file, with a trailing slash.
60
	 * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/'
61
	 * @var string
62
	 */
63
	protected $_file_folder = NULL;
64
65
	/**
66
	 * String to the absolute URL to this file (useful for getting its web-accessible resources
67
	 * like images, js, or css)
68
	 * @var string
69
	 */
70
	protected $_file_url = NULL;
71
72
	/**
73
	 * Pretty name for the payment method
74
	 * @var string
75
	 */
76
	protected $_pretty_name = NULL;
77
78
	/**
79
	 *
80
	 * @var string
81
	 */
82
	protected $_default_button_url = NULL;
83
84
	/**
85
	 *
86
	 * @var string
87
	 */
88
	protected $_default_description = NULL;
89
90
91
	/**
92
	 *
93
	 * @param EE_Payment_Method $pm_instance
94
	 * @throws EE_Error
95
	 * @return EE_PMT_Base
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
96
	 */
97
	function __construct($pm_instance = NULL) {
98
		if ( $pm_instance instanceof EE_Payment_Method ){
99
			$this->set_instance($pm_instance);
100
		}
101
		if($this->_gateway){
102
			$this->_gateway->set_payment_model( EEM_Payment::instance() );
103
			$this->_gateway->set_payment_log( EEM_Change_Log::instance() );
0 ignored issues
show
Documentation introduced by
\EEM_Change_Log::instance() is of type object<EEM_Change_Log>, but the function expects a object<EEMI_Payment_Log>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
104
			EE_Registry::instance()->load_helper( 'Template' );
105
			$this->_gateway->set_template_helper( new EEH_Template() );
0 ignored issues
show
Documentation introduced by
new \EEH_Template() is of type object<EEH_Template>, but the function expects a object<EEHI_Template>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
106
			EE_Registry::instance()->load_helper( 'Line_Item' );
107
			$this->_gateway->set_line_item_helper( new EEH_Line_Item() );
0 ignored issues
show
Documentation introduced by
new \EEH_Line_Item() is of type object<EEH_Line_Item>, but the function expects a object<EEHI_Line_Item>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
108
			EE_Registry::instance()->load_helper( 'Money' );
109
			$this->_gateway->set_money_helper( new EEH_Money() );
0 ignored issues
show
Documentation introduced by
new \EEH_Money() is of type object<EEH_Money>, but the function expects a object<EEHI_Money>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
110
		}
111
		if ( ! isset( $this->_has_billing_form ) ) {
112
			// by default, On Site gateways have a billing form
113
			if ( $this->payment_occurs() == EE_PMT_Base::onsite ) {
114
				$this->set_has_billing_form( true );
115
			} else {
116
				$this->set_has_billing_form( false );
117
			}
118
		}
119
120
		if( ! $this->_pretty_name){
121
			throw new EE_Error(sprintf(__("You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", "event_espresso")));
122
		}
123
		//if the child didn't specify a default button, use the credit card one
124
		if( $this->_default_button_url === NULL){
125
			$this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods' . DS . 'pay-by-credit-card.png';
126
		}
127
	}
128
129
130
131
	/**
132
	 * @param boolean $has_billing_form
133
	 */
134
	public function set_has_billing_form( $has_billing_form ) {
135
		$this->_has_billing_form = filter_var( $has_billing_form, FILTER_VALIDATE_BOOLEAN );
136
	}
137
138
139
140
	/**
141
	 * sets the file_folder property
142
	 */
143
	protected function _set_file_folder(){
144
		$reflector = new ReflectionClass(get_class($this));
145
		$fn = $reflector->getFileName();
146
		$this->_file_folder =  dirname($fn).DS;
147
	}
148
149
150
151
	/**
152
	 * sets the file URL with a trailing slash for this PMT
153
	 */
154
	protected function _set_file_url(){
155
		$plugins_dir_fixed = str_replace('\\',DS,WP_PLUGIN_DIR);
156
		$file_folder_fixed = str_replace('\\',DS,$this->file_folder());
157
		$file_path = str_replace($plugins_dir_fixed,WP_PLUGIN_URL,$file_folder_fixed);
158
		$this->_file_url = $file_path;
159
	}
160
161
	/**
162
	 * Gets the default description on all payment methods of this type
163
	 * @return string
164
	 */
165
	public function default_description(){
166
		return $this->_default_description;
167
	}
168
169
170
171
	/**
172
	 * Returns the folder containing the PMT child class, with a trailing slash
173
	 * @return string
174
	 */
175
	public function file_folder(){
176
		if( ! $this->_file_folder ) {
177
			$this->_set_file_folder();
178
		}
179
		return $this->_file_folder;
180
	}
181
182
183
184
	/**
185
	 * @return string
186
	 */
187
	public function file_url(){
188
		if( ! $this->_file_url ) {
189
			$this->_set_file_url();
190
		}
191
		return $this->_file_url;
192
	}
193
194
195
196
	/**
197
	 * Sets the payment method instance this payment method type is for.
198
	 * Its important teh payment method instance is set before
199
	 * @param EE_Payment_Method $payment_method_instance
200
	 */
201
	function set_instance($payment_method_instance){
202
		$this->_pm_instance = $payment_method_instance;
203
		//if they have already requested the settings form, make sure its
204
		//data matches this model object
205
		if($this->_settings_form){
206
			$this->settings_form()->populate_model_obj($payment_method_instance);
207
		}
208
		if($this->_gateway && $this->_gateway instanceof EE_Gateway){
209
			$this->_gateway->set_settings($payment_method_instance->settings_array());
210
		}
211
	}
212
213
214
215
	/**
216
	 * Gets teh form for displaying to admins where they setup the payment method
217
	 * @return EE_Payment_Method_Form
218
	 */
219
	function settings_form(){
220
		if( ! $this->_settings_form){
221
			$this->_settings_form = $this->generate_new_settings_form();
222
			$this->_settings_form->set_payment_method_type( $this );
223
			$this->_settings_form->_construct_finalize(NULL, NULL );
0 ignored issues
show
Documentation introduced by
NULL is of type null, but the function expects a object<EE_Form_Section_Proper>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
224
			//if we have already assigned a model object to this pmt, make
225
			//sure its reflected in teh form we just generated
226
			if($this->_pm_instance){
227
				$this->_settings_form->populate_model_obj($this->_pm_instance);
228
			}
229
		}
230
		return $this->_settings_form;
231
	}
232
233
234
235
	/**
236
	 * Gets the form for all the settings related to this payment method type
237
	 * @return EE_Payment_Method_Form
238
	 */
239
	abstract function generate_new_settings_form();
240
241
242
243
244
245
246
	/**
247
	 * Sets the form for settings. This may be useful if we have already received
248
	 * a form submission and have form data it in, and want to use it anytime we're showing
249
	 * this payment method type's settings form later in the request
250
	 * @param EE_Payment_Method_Form $form
251
	 */
252
	public function set_settings_form($form){
253
		$this->_settings_form = $form;
254
	}
255
256
257
258
	/**
259
	 * @return boolean
260
	 */
261
	public function has_billing_form() {
262
		return $this->_has_billing_form;
263
	}
264
265
266
267
	/**
268
	 * Gets the form for displaying to attendees where they can enter their billing info
269
	 * which will be sent to teh gateway (can be null)
270
	 *
271
	 * @param \EE_Transaction $transaction
272
	 * @param array $extra_args
273
	 * @return \EE_Billing_Attendee_Info_Form|\EE_Billing_Info_Form|null
274
	 */
275
	public function billing_form( EE_Transaction $transaction = NULL, $extra_args = array() ){
276
		// has billing form already been regenerated ? or overwrite cache?
277
		if ( ! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form ){
278
			$this->_billing_form = $this->generate_new_billing_form( $transaction, $extra_args );
0 ignored issues
show
Unused Code introduced by
The call to EE_PMT_Base::generate_new_billing_form() has too many arguments starting with $extra_args.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
279
		}
280
		//if we know who the attendee is, and this is a billing form
281
		//that uses attendee info, populate it
282
		if (
283
			$this->_billing_form instanceof EE_Billing_Attendee_Info_Form &&
284
			$transaction instanceof EE_Transaction &&
285
			$transaction->primary_registration() instanceof EE_Registration &&
286
			$transaction->primary_registration()->attendee() instanceof EE_Attendee
287
		){
288
			$this->_billing_form->populate_from_attendee( $transaction->primary_registration()->attendee() );
289
		}
290
		return $this->_billing_form;
291
	}
292
293
294
	/**
295
	 * Creates the billing form for this payment method type
296
	 * @param \EE_Transaction $transaction
297
	 * @return \EE_Billing_Info_Form
298
	 */
299
	abstract function generate_new_billing_form( EE_Transaction $transaction = NULL );
300
301
302
303
	/**
304
	 * apply_billing_form_debug_settings
305
	 * applies debug data to the form
306
	 *
307
	 * @param \EE_Billing_Info_Form $billing_form
308
	 * @return \EE_Billing_Info_Form
309
	 */
310
	public function apply_billing_form_debug_settings( EE_Billing_Info_Form $billing_form ) {
311
		return $billing_form;
312
	}
313
314
315
316
	/**
317
	 * Sets the billing form for this payment method type. You may want to use this
318
	 * if you have form
319
	 * @param EE_Payment_Method $form
320
	 */
321
	public function set_billing_form($form){
322
		$this->_billing_form = $form;
0 ignored issues
show
Documentation Bug introduced by
It seems like $form of type object<EE_Payment_Method> is incompatible with the declared type object<EE_Form_Section_Proper> of property $_billing_form.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
323
	}
324
325
326
327
	/**
328
	 * Returns whether or not this payment method requires HTTPS to be used
329
	 * @return boolean
330
	 */
331
	function requires_https(){
332
		return $this->_requires_https;
333
	}
334
335
336
337
	/**
338
	 *
339
	 * @param EE_Transaction       $transaction
340
	 * @param float                $amount
341
	 * @param EE_Billing_Info_Form $billing_info
342
	 * @param string               $return_url
343
	 * @param string                 $fail_url
344
	 * @param string               $method
345
	 * @param bool           $by_admin
346
	 * @return EE_Payment
347
	 * @throws EE_Error
348
	 */
349
	function process_payment( EE_Transaction $transaction, $amount = null, $billing_info = null, $return_url = null,$fail_url = '', $method = 'CART', $by_admin = false ){
0 ignored issues
show
Unused Code introduced by
The parameter $by_admin is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
350
		// @todo: add surcharge for the payment method, if any
351
		if ( $this->_gateway ) {
352
			//there is a gateway, so we're going to make a payment object
353
			//but wait! do they already have a payment in progress that we thought was failed?
354
			$duplicate_properties = array(
355
				'STS_ID' 								=> EEM_Payment::status_id_failed,
356
				'TXN_ID' 								=> $transaction->ID(),
357
				'PMD_ID' 							=> $this->_pm_instance->ID(),
358
				'PAY_source' 						=> $method,
359
				'PAY_amount' 					=> $amount !== null ? $amount : $transaction->remaining(),
360
				'PAY_gateway_response' 	=> null,
361
			);
362
			$payment = EEM_Payment::instance()->get_one( array( $duplicate_properties ));
363
			//if we didn't already have a payment in progress for the same thing,
364
			//then we actually want to make a new payment
365
			if ( ! $payment instanceof EE_Payment ){
366
				$payment = EE_Payment::new_instance(
367
					array_merge(
368
						$duplicate_properties,
369
						array(
370
							'PAY_timestamp' 			=> time(),
371
							'PAY_txn_id_chq_nmbr' 	=> null,
372
							'PAY_po_number' 			=> null,
373
							'PAY_extra_accntng' 		=> null,
374
							'PAY_details' 					=> null,
375
						)
376
					)
377
				);
378
			}
379
			//make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
380
			$payment->save();
381
			$billing_values = $this->_get_billing_values_from_form( $billing_info );
0 ignored issues
show
Bug introduced by
It seems like $billing_info defined by parameter $billing_info on line 349 can be null; however, EE_PMT_Base::_get_billing_values_from_form() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
382
383
			//  Offsite Gateway
384
			if( $this->_gateway instanceof EE_Offsite_Gateway ){
385
386
				$payment = $this->_gateway->set_redirection_info(
387
					$payment,
388
					$billing_values,
0 ignored issues
show
Bug introduced by
It seems like $billing_values defined by $this->_get_billing_valu...rom_form($billing_info) on line 381 can also be of type null; however, EE_Offsite_Gateway::set_redirection_info() does only seem to accept array, 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...
389
					$return_url,
390
					EE_Config::instance()->core->txn_page_url(
391
						array(
392
							'e_reg_url_link' 				=> $transaction->primary_registration()->reg_url_link(),
393
							'ee_payment_method' 	=> $this->_pm_instance->slug()
394
						)
395
					),
396
					$fail_url
397
				);
398
				$payment->save();
399
			//  Onsite Gateway
400
			} elseif ( $this->_gateway instanceof EE_Onsite_Gateway ) {
401
402
				$payment = $this->_gateway->do_direct_payment($payment,$billing_values);
403
				$payment->save();
404
405
			} else {
406
				throw new EE_Error(
407
					sprintf(
408
						__('Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', 'event_espresso' ),
409
						get_class($this),
410
						gettype( $this->_gateway )
411
					)
412
				);
413
			}
414
415
		} else {
416
			// no gateway provided
417
			// there is no payment. Must be an offline gateway
418
			// create a payment object anyways, but dont save it
419
			$payment = EE_Payment::new_instance(
420
				array(
421
					'STS_ID' 					=> EEM_Payment::status_id_pending,
422
					'TXN_ID'        			=> $transaction->ID(),
423
					'PMD_ID' 				=> $transaction->payment_method_ID(),
424
					'PAY_amount'    		=> 0.00,
425
					'PAY_timestamp' 	=> time(),
426
				)
427
			);
428
429
		}
430
431
		// if there is billing info, clean it and save it now
432
		if( $billing_info instanceof EE_Billing_Attendee_Info_Form ){
433
			$this->_save_billing_info_to_attendee( $billing_info, $transaction );
434
		}
435
436
		return $payment;
437
	}
438
439
	/**
440
	 * Gets the values we want to pass onto the gateway. Normally these
441
	 * are just the 'pretty' values, but there may be times the data may need
442
	 * a  little massaging. Proper subsections will become arrays of inputs
443
	 * @param EE_Billing_Info_Form $billing_form
444
	 * @return array
445
	 */
446
	protected function _get_billing_values_from_form( $billing_form ){
447
		if($billing_form instanceof EE_Form_Section_Proper ){
448
			return $billing_form->input_pretty_values( true );
449
		}else{
450
			return NULL;
451
		}
452
	}
453
454
455
456
	/**
457
	 * Handles an instant payment notification when the transaction is known (by default).
458
	 * @param array $req_data
459
	 * @param EE_Transaction $transaction
460
	 * @return EE_Payment
461
	 * @throws EE_Error
462
	 */
463
	public function handle_ipn($req_data,$transaction){
464
		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
465 View Code Duplication
		if( ! $this->_gateway instanceof EE_Offsite_Gateway){
466
			throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r( $this->_gateway, TRUE )));
467
468
		}
469
		$payment = $this->_gateway->handle_payment_update( $req_data, $transaction );
0 ignored issues
show
Documentation introduced by
$transaction is of type object<EE_Base_Class>, but the function expects a object<EEI_Transaction>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
470
		return $payment;
471
	}
472
473
474
475
	/**
476
	 * Saves the billing info onto the attendee of the primary registrant on this transaction, and
477
	 * cleans it first.
478
	 * @param EE_Billing_Attendee_Info_Form $billing_form
479
	 * @param EE_Transaction $transaction
480
	 * @return boolean success
481
	 */
482
	protected function _save_billing_info_to_attendee($billing_form, $transaction){
483
		if( ! $transaction || ! $transaction instanceof EE_Transaction){
484
			EE_Error::add_error(__("Cannot save billing info because no transaction was specified", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
485
			return false;
486
		}
487
		$primary_reg = $transaction->primary_registration();
488
		if( ! $primary_reg ){
489
			EE_Error::add_error(__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
490
			return false;
491
		}
492
		$attendee = $primary_reg->attendee();
493
		if( ! $attendee ){
494
			EE_Error::add_error(__("Cannot save billing info because the transaction's primary registration has no attendee!", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
495
			return false;
496
		}
497
		return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method() );
0 ignored issues
show
Bug introduced by
It seems like $transaction->payment_method() can be null; however, save_and_clean_billing_info_for_payment_method() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
498
499
	}
500
501
502
503
	/**
504
	 * Gets the payment this IPN is for. Children may often want to
505
	 * override this to inspect the request
506
	 * @param EE_Transaction $transaction
507
	 * @param array $req_data
508
	 * @return EE_Payment
509
	 */
510
	protected function find_payment_for_ipn( EE_Transaction $transaction, $req_data = array() ){
0 ignored issues
show
Unused Code introduced by
The parameter $req_data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
511
		return $transaction->last_payment();
512
	}
513
514
515
516
	/**
517
	 * In case generic code cannot provide the payment processor with a specific payment method
518
	 * and transaction, it will try calling this method on each activate payment method.
519
	 * If the payment method is able to identify the request as being for it, it should fetch
520
	 * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot
521
	 * handle the IPN
522
	 * @param array $req_data
523
	 * @return EE_Payment only if this payment method can find the info its needs from $req_data
524
	 * and identifies the IPN as being for this payment method (not just fo ra payment method of this type)
525
	 * @throws EE_Error
526
	 */
527
	public function handle_unclaimed_ipn( $req_data = array() ){
0 ignored issues
show
Unused Code introduced by
The parameter $req_data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
528
		throw new EE_Error(sprintf(__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this) ));
529
	}
530
531
532
533
	/**
534
	 * Logic to be accomplished when the payment attempt is complete.
535
	 * Most payment methods don't need to do anything at this point; but some, like Mijireh, do.
536
	 * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from
537
	 * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status
538
	 * of the payment). Fed a transaction because it's always assumed to be the last payment that
539
	 * we're dealing with. Returns that last payment (if there is one)
540
	 *
541
	 * @param EE_Transaction $transaction
542
	 * @return EE_Payment
543
	 */
544
	public function finalize_payment_for($transaction){
545
		return $transaction->last_payment();
546
	}
547
548
549
550
	/**
551
	 * Whether or not this payment method's gateway supports sending refund requests
552
	 * @return boolean
553
	 */
554
	public function supports_sending_refunds(){
555
		if($this->_gateway && $this->_gateway instanceof EE_Gateway){
556
			return $this->_gateway->supports_sending_refunds();
557
		}else{
558
			return false;
559
		}
560
	}
561
562
563
564
	/**
565
	 *
566
	 * @param EE_Payment $payment
567
	 * @param array      $refund_info
568
	 * @throws EE_Error
569
	 * @return EE_Payment
570
	 */
571
	public function process_refund( EE_Payment $payment, $refund_info = array()){
572
		if ( $this->_gateway && $this->_gateway instanceof EE_Gateway ) {
573
			return $this->_gateway->do_direct_refund( $payment, $refund_info );
574
		} else {
575
			throw new EE_Error(
576
				sprintf(
577
					__( 'Payment Method Type "%s" does not support sending refund requests', 'event_espresso' ),
578
					get_class( $this )
579
				)
580
			);
581
		}
582
	}
583
584
585
586
	/**
587
	 * Returns one the class's constants onsite,offsite, or offline, depending on this
588
	 * payment method's gateway.
589
	 * @return string
590
	 * @throws EE_Error
591
	 */
592
	public function payment_occurs(){
593
		if( ! $this->_gateway){
594
			return EE_PMT_Base::offline;
595
		}elseif($this->_gateway instanceof EE_Onsite_Gateway){
596
			return EE_PMT_Base::onsite;
597
		}elseif($this->_gateway instanceof EE_Offsite_Gateway){
598
			return EE_PMT_Base::offsite;
599
		}else{
600
			throw new EE_Error(sprintf(__("Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those", "event_espresso"),get_class($this)));
601
		}
602
	}
603
604
605
606
	/**
607
	 * For adding any html output ab ove the payment overview.
608
	 * Many gateways won't want ot display anything, so this function just returns an empty string.
609
	 * Other gateways may want to override this, such as offline gateways.
610
	 * @param EE_Payment $payment
611
	 * @return string
612
	 */
613
	public function payment_overview_content(EE_Payment $payment){
614
		EE_Registry::instance()->load_helper('Template');
615
		return EEH_Template::display_template(EE_LIBRARIES.'payment_methods'.DS.'templates'.DS.'payment_details_content.template.php', array('payment_method'=>$this->_pm_instance,'payment'=>$payment) , true);
616
	}
617
618
619
620
	/**
621
	 * @return array where keys are the help tab name,
622
	 * values are: array {
623
	 *	@type string $title i18n name for the help tab
624
	 *	@type string $filename name of the file located in ./help_tabs/ (ie, in a folder next to this file)
625
	 *	@type array $template_args any arguments you want passed to the template file while rendering. 
626
	 *				Keys will be variable names and values with be their values.
627
	 */
628
	public function help_tabs_config(){
629
		return array();
630
	}
631
632
633
634
	/**
635
	 * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into
636
	 * the payment method's table's PMT_type column)
637
	 * @return string
638
	 */
639
	public function system_name(){
640
		$classname = get_class($this);
641
		return str_replace("EE_PMT_",'',$classname);
642
	}
643
644
645
646
	/**
647
	 * A pretty i18n version of the PMT name
648
	 * @return string
649
	 */
650
	public function pretty_name(){
651
		return $this->_pretty_name;
652
	}
653
654
655
656
	/**
657
	 * Gets the default absolute URL to the payment method type's button
658
	 * @return string
659
	 */
660
	public function default_button_url(){
661
		return $this->_default_button_url;
662
	}
663
664
665
666
	/**
667
	 * Gets the gateway used by this payment method (if any)
668
	 * @return EE_Gateway
669
	 */
670
	public function get_gateway(){
671
		return $this->_gateway;
672
	}
673
674
675
676
	/**
677
	 * @return string html for the link to a help tab
678
	 */
679
	public function get_help_tab_link(){
680
		EE_Registry::instance()->load_helper( 'Template' );
681
		return EEH_Template::get_help_tab_link( $this->get_help_tab_name() );
682
	}
683
684
685
686
	/**
687
	 * Returns the name of the help tab for this PMT
688
	 * @return string
689
	 */
690
	public function get_help_tab_name(){
691
		return 'ee_' . strtolower( $this->system_name() ) . '_help_tab';
692
	}
693
694
	/**
695
	 * The name of the wp capability that should be associated with the usage of
696
	 * this PMT by an admin
697
	 * @return string
698
	 */
699
	public function cap_name(){
700
		return 'ee_payment_method_' . strtolower( $this->system_name() );
701
	}
702
703
	/**
704
	 * Called by client code to tell the gateway that if it wants to change
705
	 * the transaction or line items or registrations related to teh payment it already
706
	 * processed (we think, but possibly not) that now's the time to do it.
707
	 * It is expected that gateways will store any info they need for this on the PAY_details,
708
	 * or maybe an extra meta value
709
	 * @param EE_Payment $payment
710
	 * @return void
711
	 */
712
	public function update_txn_based_on_payment( $payment ){
713
		if( $this->_gateway instanceof EE_Gateway ){
714
			$this->_gateway->update_txn_based_on_payment( $payment );
715
		}
716
	}
717
718
719
}
720