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

EED_Messages::run()   F

Complexity

Conditions 15
Paths 448

Size

Total Lines 40
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 23
nc 448
nop 1
dl 0
loc 40
rs 3.4683
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file contains the module for the messages system
4
 *
5
 * @since 4.5.0
6
 * @package  Event Espresso
7
 * @subpackage modules, messages
8
 */
9
if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
10
/**
11
 *
12
 * Messages module.  Takes care of registering all the triggers for messages.
13
 *
14
 * @since 4.5.0
15
 *
16
 * @package		Event Espresso
17
 * @subpackage	modules, messages
18
 * @author 		Darren Ethier
19
 *
20
 * ------------------------------------------------------------------------
21
 */
22
class EED_Messages  extends EED_Module {
23
24
	/**
25
	 * This holds the EE_messages controller
26
	 *
27
	 * @var EE_messages
28
	 */
29
	protected  static $_EEMSG;
30
31
32
	/**
33
	 * holds all the paths for various messages components.
34
	 * Utilized by autoloader registry
35
	 *
36
	 * @var array
37
	 */
38
	protected static $_MSG_PATHS;
39
40
41
42
	/**
43
	 * This will hold an array of messages template packs that are registered in the messages system.
44
	 * Format is:
45
	 * array(
46
	 * 	'template_pack_dbref' => EE_Messages_Template_Pack (instance)
47
	 * )
48
	 *
49
	 * @var EE_Messages_Template_Pack[]
50
	 */
51
	protected static $_TMP_PACKS = array();
52
53
54
55
56
57
	/**
58
	 * @return EED_Module
59
	 */
60
	public static function instance() {
61
		return parent::get_instance( __CLASS__ );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_instance() instead of instance()). Are you sure this is correct? If so, you might want to change this to $this->get_instance().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
62
	}
63
64
65
66
67
	/**
68
	 *  set_hooks - for hooking into EE Core, other modules, etc
69
	 *
70
	 *  @since 4.5.0
71
	 *
72
	 *  @return 	void
73
	 */
74
	public static function set_hooks() {
75
		//actions
76
		add_action( 'AHEE__EE_Payment_Processor__update_txn_based_on_payment', array( 'EED_Messages', 'payment' ), 10, 2 );
77
		add_action( 'AHEE__EE_Registration_Processor__trigger_registration_update_notifications', array( 'EED_Messages', 'maybe_registration' ), 10, 2 );
78
		//filters
79
		add_filter( 'FHEE__EE_Registration__receipt_url__receipt_url', array( 'EED_Messages', 'registration_message_trigger_url' ), 10, 4 );
80
		add_filter( 'FHEE__EE_Registration__invoice_url__invoice_url', array( 'EED_Messages', 'registration_message_trigger_url' ), 10, 4 );
81
		//register routes
82
		self::_register_routes();
83
	}
84
85
	/**
86
	 * 	set_hooks_admin - for hooking into EE Admin Core, other modules, etc
87
	 *
88
	 *  @access 	public
89
	 *  @return 	void
90
	 */
91
	public static function set_hooks_admin() {
92
		//actions
93
		add_action( 'AHEE__EE_Payment_Processor__update_txn_based_on_payment', array( 'EED_Messages', 'payment' ), 10, 2 );
94
		add_action( 'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder', array( 'EED_Messages', 'payment_reminder'), 10 );
95
		add_action( 'AHEE__EE_Registration_Processor__trigger_registration_update_notifications', array( 'EED_Messages', 'maybe_registration' ), 10, 3 );
96
		add_action( 'AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send__with_registrations', array( 'EED_Messages', 'send_newsletter_message'), 10, 2 );
97
		add_action( 'AHEE__EES_Espresso_Cancelled__process_shortcode__transaction', array( 'EED_Messages', 'cancelled_registration' ), 10 );
98
		//filters
99
		add_filter( 'FHEE__EE_Admin_Page___process_admin_payment_notification__success', array( 'EED_Messages', 'process_admin_payment'), 10, 2 );
100
		add_filter( 'FHEE__EE_Registration__receipt_url__receipt_url', array( 'EED_Messages', 'registration_message_trigger_url' ), 10, 4 );
101
		add_filter( 'FHEE__EE_Registration__invoice_url__invoice_url', array( 'EED_Messages', 'registration_message_trigger_url' ), 10, 4 );
102
	}
103
104
105
106
107
	/**
108
	 * All the message triggers done by route go in here.
109
	 *
110
	 * @since 4.5.0
111
	 *
112
	 * @return void
113
	 */
114
	protected static function _register_routes() {
115
		EE_Config::register_route( 'msg_url_trigger', 'Messages', 'run' );
116
		do_action( 'AHEE__EED_Messages___register_routes' );
117
	}
118
119
120
121
	/**
122
	 *  This runs when the msg_url_trigger route has initiated.
123
	 *
124
	 * @since 4.5.0
125
	 * @param WP $WP
126
	 * @throws EE_Error
127
	 * @return    void
128
	 */
129
	public function run( $WP ) {
130
131
		$sending_messenger = EE_Registry::instance()->REQ->is_set('snd_msgr') ? EE_Registry::instance()->REQ->get('snd_msgr') : '';
132
		$generating_messenger = EE_Registry::instance()->REQ->is_set('gen_msgr') ? EE_Registry::instance()->REQ->get('gen_msgr') : '';
133
		$message_type = EE_Registry::instance()->REQ->is_set('message_type') ? EE_Registry::instance()->REQ->get('message_type') : '';
134
		$context = EE_Registry::instance()->REQ->is_set('context') ? EE_Registry::instance()->REQ->get('context') : '';
135
		$token = EE_Registry::instance()->REQ->is_set('token') ? EE_Registry::instance()->REQ->get('token') : '';
136
		$data_id = EE_Registry::instance()->REQ->is_set('id') ? (int) EE_Registry::instance()->REQ->get('id') : 0;
137
138
		//verify the needed params are present.
139
		if ( empty( $sending_messenger ) || empty( $generating_messenger ) || empty( $message_type ) || empty( $context ) || empty( $token ) ) {
140
			EE_Error::add_error( __( 'The request for the "msg_url_trigger" route has a malformed url.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
141
			return;
142
		}
143
		//get the registration: the token will always be the unique REG_url_link saved with a registration.  We use that to make sure we retrieve the correct data for the given registration.
144
		$registration = EEM_Registration::instance()->get_one( array( array( 'REG_url_link' => $token ) ) );
145
		//if no registration then bail early.
146
		if ( ! $registration instanceof EE_Registration ) {
147
			EE_Error::add_error( __( 'Unable to complete the request because the token is invalid.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
148
			return;
149
		}
150
		//ensure controller is loaded
151
		self::_load_controller();
152
		// attempt to process message
153
		try {
154
			// retrieve the data via the handler
155
			//  Depending on the context and the message type data handler, the data_id will correspond to the specific data handler item we need to retrieve for specific messages
156
			// (i.e. a specific payment or specific refund).
157
			$data = $this->_get_messages_data_from_url( $generating_messenger, $message_type, $registration, $data_id, $context );
158
			//make sure we drop generating messenger if both sending and generating are the same.
159
			$generating_messenger = $sending_messenger != $generating_messenger ? $generating_messenger : NULL;
160
			//now we can trigger the actual sending of the message via the message type.
161
			self::$_EEMSG->send_message( $message_type, $data, $sending_messenger, $generating_messenger, $context );
162
		} catch ( EE_Error $e ) {
163
			$error_msg = __( 'Please note that a system message failed to send due to a technical issue.', 'event_espresso' );
164
			// add specific message for developers if WP_DEBUG in on
165
			$error_msg .= '||' . $e->getMessage();
166
			EE_Error::add_error( $error_msg, __FILE__, __FUNCTION__, __LINE__ );
167
		}
168
	}
169
170
171
172
173
	/**
174
	 * This is used to retrieve the template pack for the given name.
175
	 * Retrieved packs are cached on the static $_TMP_PACKS array.  If there is no class matching the given name then the default template pack is returned.
176
	 *
177
	 * @param string $template_pack_name This should correspond to the dbref of the template pack (which is also used in generating the Pack class name).
178
	 *
179
	 * @return EE_Messages_Template_Pack
180
	 */
181
	public static function get_template_pack( $template_pack_name ) {
182
		if ( isset( self::$_TMP_PACKS[$template_pack_name] ) ) {
183
			return self::$_TMP_PACKS[$template_pack_name];
184
		}
185
186
		//not set yet so let's attempt to get it.
187
		$pack_class = 'EE_Messages_Template_Pack_' . str_replace( ' ', '_', ucwords( str_replace( '_' , ' ', $template_pack_name ) ) );
188
189
		if ( ! class_exists( $pack_class ) ) {
190
			$pack_class = 'EE_Messages_Template_Pack_Default';
191
			self::$_TMP_PACKS['default'] = empty( self::$_TMP_PACKS['default'] ) ? new $pack_class : self::$_TMP_PACKS['default'];
192
			return self::$_TMP_PACKS['default'];
193
		} else {
194
			$pack = new $pack_class;
195
			self::$_TMP_PACKS[$template_pack_name] = $pack;
196
			return self::$_TMP_PACKS[$template_pack_name];
197
		}
198
	}
199
200
201
202
203
	/**
204
	 * Retrieves an array of all template packs.
205
	 * Array is in the format array( 'dbref' => EE_Messages_Template_Pack )
206
	 *
207
	 * @return EE_Messages_Template_Pack[]
208
	 */
209
	public static function get_template_packs() {
210
		//glob the defaults directory for messages
211
		$templates = glob( EE_LIBRARIES . 'messages/defaults/*', GLOB_ONLYDIR );
212
		$template_packs = array();
213
		foreach( $templates as $template_path ) {
214
			//grab folder name
215
			$template = basename( $template_path );
216
217
			//is this already set?
218
			if ( isset( self::$_TMP_PACKS[$template] ) )
219
				continue;
220
221
			//setup classname.
222
			$pack_class = 'EE_Messages_Template_Pack_' . str_replace( ' ', '_', ucwords( str_replace( '_' , ' ', $template ) ) );
223
224
			if ( ! class_exists( $pack_class ) )
225
				continue;
226
227
			$template_packs[$template] = new $pack_class;
228
		}
229
230
		$template_packs = apply_filters( 'FHEE__EED_Messages__get_template_packs__template_packs', $template_packs );
231
		self::$_TMP_PACKS = array_merge( self::$_TMP_PACKS, $template_packs );
232
		return self::$_TMP_PACKS;
233
	}
234
235
236
237
238
239
	/**
240
	 * Given the token (reg_url_link) and (optionally) the $data_id, this returns the appropriate data object(s) for the given message_type.
241
	 *
242
	 * @since 4.5.0
243
	 * @throws EE_Error
244
	 *
245
	 * @param string $generating_messenger The messenger that is used for generating templates for this message type.
246
	 * @param string $message_type Used to figure out what data handler is used (which in turn enables us to know what data type is required)
247
	 * @param EE_Registration $registration
248
	 * @param int      $data_id Some data handlers require a specific object.  The id is used to provide that specific object.
249
	 * @param string $context what context is being requested.
250
	 *
251
	 * @return mixed  (EE_Base_Class||EE_Base_Class[])
252
	 */
253
	protected function _get_messages_data_from_url( $generating_messenger, $message_type, EE_Registration $registration, $data_id, $context ) {
254
		//get message type object then get the correct data setup for that message type.
255
		$message_type = self::$_EEMSG->get_active_message_type( $generating_messenger, $message_type );
256
		//if no message type then it likely isn't active for this messenger.
257
		if ( ! $message_type instanceof EE_message_type ) {
258
			throw new EE_Error( sprintf( __('Unable to get data for the %s message type, likely because it is not active for the %s messenger.', 'event_espresso'), $message_type->name, $generating_messenger ) );
259
		}
260
		//get data according to data handler requirements
261
		return $message_type->get_data_for_context( $context, $registration, $data_id );
262
	}
263
264
265
266
	/**
267
	 * This simply makes sure the autoloaders are registered for the EE_Messages system.
268
	 *
269
	 * @since 4.5.0
270
	 *
271
	 * @return void
272
	 */
273
	public static function set_autoloaders() {
274
		if ( empty( self::$_MSG_PATHS ) ) {
275
			self::_set_messages_paths();
276
			EE_Registry::instance()->load_helper('Autoloader');
277
			foreach ( self::$_MSG_PATHS as $path ) {
278
				EEH_Autoloader::register_autoloaders_for_each_file_in_folder( $path );
279
			}
280
		}
281
	}
282
283
284
285
286
	/**
287
	 * Take care of adding all the paths for the messages components to the $_MSG_PATHS property
288
	 * for use by the Messages Autoloaders
289
	 *
290
	 * @since 4.5.0
291
	 *
292
	 * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
293
	 */
294
	protected static function _set_messages_paths() {
295
		$dir_ref = array(
296
			'messages',
297
			'messages/message_type',
298
			'messages/messenger',
299
			'messages/defaults',
300
			'messages/defaults/email',
301
			'messages/data_class',
302
			'messages/validators',
303
			'messages/validators/email',
304
			'messages/validators/html',
305
			'shortcodes'
306
			);
307
		$paths = array();
308
		foreach ( $dir_ref as $index => $dir ) {
309
			$paths[$index] = EE_LIBRARIES . $dir;
310
		}
311
		self::$_MSG_PATHS = apply_filters( 'FHEE__EED_Messages___set_messages_paths___MSG_PATHS', $paths );
312
	}
313
314
315
	/**
316
	 * Takes care of loading the Messages system controller into the $_EEMSG property
317
	 *
318
	 * @since 4.5.0
319
	 *
320
	 * @return void
321
	 */
322
	protected static function _load_controller() {
323
		if ( ! self::$_EEMSG instanceof EE_messages ) {
324
			self::set_autoloaders();
325
			self::$_EEMSG = new EE_messages();
326
		}
327
	}
328
329
330
331
	/**
332
	 * @param EE_Transaction $transaction
333
	 */
334
	public static function payment_reminder( EE_Transaction $transaction ) {
335
		self::_load_controller();
336
		$data = array( $transaction, null );
337
		if ( self::$_EEMSG->send_message( 'payment_reminder', $data ) ) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
338
			//self::log(
339
			//	__CLASS__, __FUNCTION__, __LINE__,
340
			//	$transaction,
341
			//	array(
342
			//		'delivered'  			=> current_time( 'mysql' ),
343
			//		'message_type' 	=> 'payment_reminder',
344
			//		'txn_status' 			=> $transaction->status_obj()->code( false, 'sentence' ),
345
			//	)
346
			//);
347
		}
348
	}
349
350
351
352
	/**
353
	 * Any messages triggers for after successful gateway payments should go in here.
354
	 * @param  EE_Transaction object
355
	 * @param  EE_Payment object
356
	 * @return void
357
	 */
358
	public static function payment( EE_Transaction $transaction, EE_Payment $payment ) {
359
		self::_load_controller();
360
		$data = array( $transaction, $payment );
361
362
		$message_type = self::_get_payment_message_type( $payment->STS_ID() );
0 ignored issues
show
Documentation introduced by
$payment->STS_ID() is of type boolean, but the function expects a string.

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...
363
364
		//if payment amount is less than 0 then switch to payment_refund message type.
365
		$message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
366
367
		//verify this message type is present and active.  If it isn't then no message is sent.
368
		$active_mts = self::$_EEMSG->get_active_message_types();
369
370
		$message_type = in_array( $message_type, $active_mts ) ? $message_type : false;
371
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, current_time( 'mysql' ), 'delivered' );
372
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, $message_type, '$message_type' );
373
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, $transaction->status_ID(), '$transaction->status_ID()' );
374
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, $payment->status(), '$payment->status()' );
375
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, print_r( $active_mts, true ), '$active_mts' );
376
377
		if ( $message_type ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $message_type of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
378
			if ( self::$_EEMSG->send_message( $message_type, $data ) ) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
379
				//self::log(
380
				//	__CLASS__, __FUNCTION__, __LINE__,
381
				//	$transaction,
382
				//	array(
383
				//		'delivered' 			=>  current_time( 'mysql' ),
384
				//		'message_type' 	=> $message_type,
385
				//		'txn_status' 			=> $transaction->status_obj()->code( false, 'sentence' ),
386
				//		'pay_status' 		=> $payment->status_obj()->code( false, 'sentence' ),
387
				//	)
388
				//);
389
			}
390
		}
391
	}
392
393
394
395
	/**
396
	 * @param EE_Transaction $transaction
397
	 */
398
	public static function cancelled_registration( EE_Transaction $transaction ) {
399
		self::_load_controller();
400
401
		$data = array( $transaction, NULL );
402
403
		$active_mts = self::$_EEMSG->get_active_message_types();
404
405
		if ( in_array( 'cancelled_registration', $active_mts ) ) {
406
			self::$_EEMSG->send_message( 'cancelled_registration', $data );
407
		}
408
		return;
409
	}
410
411
412
413
	/**
414
	 * Trigger for Registration messages
415
	 * Note that what registration message type is sent depends on what the reg status is for the registrations on the incoming transaction.
416
	 *
417
	 * @param EE_Registration $registration
418
	 * @param array $extra_details
419
	 * @return void
420
	 */
421
	public static function maybe_registration( EE_Registration $registration, $extra_details = array() ) {
422
423
		if ( ! self::_verify_registration_notification_send( $registration, $extra_details ) ) {
424
			//no messages please
425
			return;
426
		}
427
428
429
		EE_Registry::instance()->load_helper( 'MSG_Template' );
430
431
		//get all registrations so we make sure we send messages for the right status.
432
		$all_registrations = $registration->transaction()->registrations();
433
434
		//cached array of statuses so we only trigger messages once per status.
435
		$statuses_sent = array();
436
437
		//loop through registrations and trigger messages once per status.
438
		foreach ( $all_registrations as $reg ) {
439
440
			//already triggered?
441
			if ( in_array( $reg->status_ID(), $statuses_sent ) ) {
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...
442
				continue;
443
			}
444
445
			$message_type = self::_get_reg_status_array( $reg->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...
446
			if ( EEH_MSG_Template::is_mt_active( $message_type ) ) {
0 ignored issues
show
Bug introduced by
It seems like $message_type defined by self::_get_reg_status_array($reg->status_ID()) on line 445 can also be of type array<string|integer,string>; however, EEH_MSG_Template::is_mt_active() does only seem to accept string, 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...
447
				self::_load_controller();
448
449
				//send away, send away, uhhuh
450
				if ( self::$_EEMSG->send_message( $message_type, array( $registration->transaction(), null, $reg->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...
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
Bug introduced by
It seems like $message_type defined by self::_get_reg_status_array($reg->status_ID()) on line 445 can also be of type array<string|integer,string>; however, EE_messages::send_message() does only seem to accept string, 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...
451
					// DEBUG LOG
452
					// self::log(
453
					// 	__CLASS__, __FUNCTION__, __LINE__,
454
					// 	$registration->transaction(),
455
					// 	array(
456
					// 		'delivered'    => current_time( 'mysql' ),
457
					// 		'message_type' => $message_type,
458
					// 		'reg_status'   => $reg->status_obj()->code( false, 'sentence' ),
459
					// 		'context' => 'in all registrations loop'
460
					// 	)
461
					// );
462
				}
463
			}
464
465
			$statuses_sent[] = $reg->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...
466
		}
467
468
		//now send summary (registration_summary) if active
469
		if ( EEH_MSG_Template::is_mt_active( 'registration_summary' ) ) {
470
			self::_load_controller();
471
			if ( self::$_EEMSG->send_message( 'registration_summary', array( $registration->transaction(), null ) ) ) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
472
					// DEBUG LOG
473
					// self::log(
474
					// 	__CLASS__, __FUNCTION__, __LINE__,
475
					// 	$registration->transaction(),
476
					// 	array(
477
					// 		'delivered'    => current_time( 'mysql' ),
478
					// 		'message_type' => 'registration_summary',
479
					// 		'reg_status'   => $registration->status_obj()->code( false, 'sentence' ),
480
					// 	)
481
					// );
482
				}
483
		}
484
	}
485
486
487
488
	/**
489
	 * This is a helper method used to very whether a registration notification should be sent or
490
	 * not.  Prevents duplicate notifications going out for registration context notifications.
491
	 *
492
	 * @param EE_Registration $registration  [description]
493
	 * @param array           $extra_details [description]
494
	 *
495
	 * @return bool          true = send away, false = nope halt the presses.
496
	 */
497
	protected static function _verify_registration_notification_send( EE_Registration $registration, $extra_details = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $extra_details 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...
498
		 //self::log(
499
		 //	__CLASS__, __FUNCTION__, __LINE__,
500
		 //	$registration->transaction(),
501
		 //	array( '$extra_details' => $extra_details )
502
		 //);
503
		// currently only using this to send messages for the primary registrant
504
		if ( ! $registration->is_primary_registrant() ) {
505
			return false;
506
		}
507
		if (
508
			! apply_filters( 'FHEE__EED_Messages___maybe_registration__deliver_notifications', false ) &&
509
			$registration->status_ID() !== EEM_Registration::status_id_not_approved
510
		) {
511
			return false;
512
		}
513
		// release the kraken
514
		return true;
515
	}
516
517
518
519
	/**
520
	 * Simply returns an array indexed by Registration Status ID and the related message_type name associated with that status id.
521
	 *
522
	 * @param string $reg_status
523
	 * @return array
524
	 */
525
	protected static function _get_reg_status_array( $reg_status = '' ) {
526
		$reg_status_array = array(
527
			EEM_Registration::status_id_approved => 'registration',
528
			EEM_Registration::status_id_pending_payment => 'pending_approval',
529
			EEM_Registration::status_id_not_approved => 'not_approved_registration',
530
			EEM_Registration::status_id_cancelled => 'cancelled_registration',
531
			EEM_Registration::status_id_declined => 'declined_registration'
532
		);
533
		return isset( $reg_status_array[ $reg_status ] ) ? $reg_status_array[ $reg_status ] : $reg_status_array;
534
	}
535
536
537
538
	/**
539
	 * Simply returns the payment message type for the given payment status.
540
	 *
541
	 * @param string  $payment_status The payment status being matched.
542
	 *
543
	 * @return string|bool The payment message type slug matching the status or false if no match.
544
	 */
545
	protected static function _get_payment_message_type( $payment_status ) {
546
		$matches = array(
547
			EEM_Payment::status_id_approved => 'payment',
548
			EEM_Payment::status_id_pending => 'payment_pending',
549
			EEM_Payment::status_id_cancelled => 'payment_cancelled',
550
			EEM_Payment::status_id_declined => 'payment_declined',
551
			EEM_Payment::status_id_failed => 'payment_failed'
552
			);
553
554
		return isset( $matches[$payment_status] ) ? $matches[$payment_status] : false;
555
	}
556
557
558
559
560
	/**
561
	 * Message triggers for a resend registration confirmation (in admin)
562
	 *
563
	 * @access public
564
	 * @param array $req_data This is the $_POST & $_GET data sent from EE_Admin Pages
565
	 * @return bool          success/fail
566
	 */
567
	public static function process_resend( $req_data ) {
568
		$regs_to_send = array();
569
570
		//first let's make sure we have the reg id (needed for resending!);
571 View Code Duplication
		if ( ! isset( $req_data['_REG_ID'] ) ) {
572
			EE_Error::add_error( __('Something went wrong because we\'re missing the registration ID', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
573
			return false;
574
		}
575
576
		//if $req_data['_REG_ID'] is an array then let's group the registrations by transaction and reg status
577
		// so we can only trigger messages per group.
578
		if ( is_array( $req_data['_REG_ID'] ) ) {
579
			foreach ( $req_data['_REG_ID'] as $reg_id ) {
580
				$reg = EE_Registry::instance()->load_model( 'Registration' )->get_one_by_ID( $reg_id );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()...d_model('Registration') (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
581 View Code Duplication
				if ( ! $reg instanceof EE_Registration ) {
582
					EE_Error::add_error( sprintf( __('Unable to retrieve a registration object for the given reg id (%s)', 'event_espresso'), $req_data['_REG_ID'] ) );
583
					return false;
584
				}
585
				$regs_to_send[$reg->transaction_ID()][$reg->status_ID()][] = $reg;
586
			}
587
		} else {
588
			//we have a single registration id, so let's see if we can get a EE_Registration from it, and if so set it up for sending.
589
			//get reg object from reg_id
590
			$reg = EE_Registry::instance()->load_model('Registration')->get_one_by_ID( $req_data['_REG_ID'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()...d_model('Registration') (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
591
592
			//if no reg object then send error
593 View Code Duplication
			if ( ! $reg instanceof EE_Registration ) {
594
				EE_Error::add_error( sprintf( __('Unable to retrieve a registration object for the given reg id (%s)', 'event_espresso'), $req_data['_REG_ID'] ) );
595
				return false;
596
			}
597
598
			$regs_to_send[$reg->transaction_ID()][$reg->status_ID()][] = $reg;
599
		}
600
601
		self::_load_controller();
602
		$status_match_array = self::_get_reg_status_array();
603
		$active_mts = self::$_EEMSG->get_active_message_types();
604
		$success = false;
605
		//loop through and send!
606
		foreach( $regs_to_send as $status_group ) {
607
			foreach ( $status_group as $status_id => $registrations ) {
608
				if ( ! in_array( $status_match_array[ $status_id ], $active_mts ) ) {
609
					EE_Error::add_error(
610
						sprintf(
611
							__('Cannot resend the message for this registration because the corresponding message type (%1$s) is not active.  If you wish to send messages for this message type then please activate it by visiting the %2$sMessages Admin Page%3$s.', 'event_espresso'),
612
							$status_match_array[ $reg->status_ID() ],
0 ignored issues
show
Bug introduced by
The variable $reg does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
613
							'<a href="' . admin_url('admin.php?page=espresso_messages&action=settings') . '">',
614
							'</a>'
615
						)
616
					);
617
					return false;
618
				}
619
620
				if ( self::$_EEMSG->send_message( $status_match_array[$status_id], array( $registrations, $status_id ) ) ) {
621
					EE_Error::overwrite_success();
622
					EE_Error::add_success( __('The message for this registration has been re-sent', 'event_espresso') );
623
					$success = true;
624
				} else {
625
					EE_Error::add_error( __('Something went wrong and the message for this registration was NOT resent', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
626
				}
627
			}
628
		}
629
630
		/**
631
		 * Note this returns true if ANY messages were sent successfully. So if client code wants to catch messages
632
		 * that might not have sent successfully, it needs to check EE_Error for any errors.
633
		 */
634
		return $success;
635
	}
636
637
638
639
640
641
	/**
642
	 * Message triggers for manual payment applied by admin
643
	 * @param  bool     $success incoming success value
644
	 * @param  EE_Payment $payment EE_payment object
645
	 * @return bool              success/fail
646
	 */
647
	public static function process_admin_payment( $success = TRUE, EE_Payment $payment ) {
648
		//we need to get the transaction object
649
		$transaction = $payment->transaction();
650
		if ( $transaction instanceof EE_Transaction ) {
651
			$data = array( $transaction, $payment );
652
			$message_type = self::_get_payment_message_type( $payment->STS_ID() );
0 ignored issues
show
Documentation introduced by
$payment->STS_ID() is of type boolean, but the function expects a string.

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...
653
654
			//if payment amount is less than 0 then switch to payment_refund message type.
655
			$message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
656
657
			//if payment_refund is selected, but the status is NOT accepted.  Then change message type to false so NO message notification goes out.
658
			$message_type = $message_type == 'payment_refund' && $payment->STS_ID() != EEM_Payment::status_id_approved ? false : $message_type;
659
660
			self::_load_controller();
661
			//verify this message type is present and active.  If it isn't then no message is sent.
662
			$active_mts = self::$_EEMSG->get_active_message_types();
663
			$message_type = in_array( $message_type, $active_mts ) ? $message_type : false;
664
665
666
			if ( $message_type ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $message_type of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
667
668
				$success = self::$_EEMSG->send_message( $message_type, $data );
669
				if ( ! $success ) {
670
					EE_Error::add_error( __('Something went wrong and the payment confirmation was NOT resent', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
671
				}
672
673
			} else {
674
				EE_Error::add_error( __('The message type for the status of this payment is not active or does not exist, so no notification was sent.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
675
			}
676
677
		}
678
		return $success;
679
	}
680
681
682
683
	/**
684
	 * Callback for AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send_with_registrations trigger
685
	 *
686
	 * @since   4.3.0
687
	 *
688
	 * @param  EE_Registration[]  $registrations   an array of EE_Registration objects
689
	 * @param  int      	      $grp_id     a specific message template group id.
690
	 * @return void
691
	 */
692
	public static function send_newsletter_message( $registrations, $grp_id ) {
693
		//make sure mtp is id and set it in the EE_Request Handler later messages setup.
694
		EE_Registry::instance()->REQ->set( 'GRP_ID', (int) $grp_id );
695
696
		self::_load_controller();
697
		self::$_EEMSG->send_message( 'newsletter', $registrations );
698
	}
699
700
701
	/**
702
	 * Callback for FHEE__EE_Registration__invoice_url__invoice_url or FHEE__EE_Registration__receipt_url__receipt_url
703
	 *
704
	 * @since   4.3.0
705
	 *
706
	 * @param 	string 	$registration_message_trigger_url
707
	 * @param 	EE_Registration $registration
708
	 * @param string 	$messenger
709
	 * @param string 	$message_type
710
	 * @return 	string
711
	 */
712
	public static function registration_message_trigger_url( $registration_message_trigger_url, EE_Registration $registration, $messenger = 'html', $message_type = 'invoice' ) {
713
		EE_Registry::instance()->load_helper('MSG_Template');
714
		// whitelist $messenger
715
		switch ( $messenger ) {
716
			case 'pdf' :
717
				$sending_messenger = 'pdf';
718
				$generating_messenger = 'html';
719
				break;
720
			case 'html' :
721
			default :
722
				$sending_messenger = 'html';
723
				$generating_messenger = 'html';
724
				break;
725
		}
726
		// whitelist $message_type
727
		switch ( $message_type ) {
728
			case 'receipt' :
729
				$message_type = 'receipt';
730
				break;
731
			case 'invoice' :
732
			default :
733
				$message_type = 'invoice';
734
				break;
735
		}
736
		// verify that both the messenger AND the message type are active
737
		if ( EEH_MSG_Template::is_messenger_active( $sending_messenger ) && EEH_MSG_Template::is_mt_active( $message_type )) {
738
			//need to get the correct message template group for this (i.e. is there a custom invoice for the event this registration is registered for?)
739
			$template_query_params = array(
740
				'MTP_is_active' => TRUE,
741
				'MTP_messenger' => $generating_messenger,
742
				'MTP_message_type' => $message_type,
743
				'Event.EVT_ID' => $registration->event_ID()
744
			);
745
			//get the message template group.
746
			$msg_template_group = EEM_Message_Template_Group::instance()->get_one( array( $template_query_params ));
747
			//if we don't have an EE_Message_Template_Group then return
748
			if ( ! $msg_template_group instanceof EE_Message_Template_Group ) {
749
				// remove EVT_ID from query params so that global templates get picked up
750
				unset( $template_query_params[ 'Event.EVT_ID' ] );
751
				//get global template as the fallback
752
				$msg_template_group = EEM_Message_Template_Group::instance()->get_one( array( $template_query_params ));
753
			}
754
			//if we don't have an EE_Message_Template_Group then return
755
			if ( ! $msg_template_group instanceof EE_Message_Template_Group ) {
756
				return '';
757
			}
758
			// generate the URL
759
			$registration_message_trigger_url = EEH_MSG_Template::generate_url_trigger(
760
				$sending_messenger,
761
				$generating_messenger,
762
				'purchaser',
763
				$message_type,
764
				$registration,
765
				$msg_template_group->ID(),
766
				$registration->transaction_ID()
0 ignored issues
show
Documentation introduced by
$registration->transaction_ID() is of type boolean, but the function expects a integer.

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...
767
			);
768
769
		}
770
		return $registration_message_trigger_url;
771
	}
772
773
774
775
	/**
776
	 * debug
777
	 *
778
	 * @param string $class
779
	 * @param string $func
780
	 * @param string $line
781
	 * @param \EE_Transaction $transaction
782
	 * @param array $info
783
	 * @param bool $display_request
784
	 */
785 View Code Duplication
	protected static function log( $class = '', $func = '', $line = '', EE_Transaction $transaction, $info = array(), $display_request = false ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
786
		EE_Registry::instance()->load_helper('Debug_Tools');
787
		if ( WP_DEBUG && false ) {
788
			if ( $transaction instanceof EE_Transaction ) {
789
				// don't serialize objects
790
				$info = EEH_Debug_Tools::strip_objects( $info );
791
				$info[ 'TXN_status' ] = $transaction->status_ID();
792
				$info[ 'TXN_reg_steps' ] = $transaction->reg_steps();
793
				if ( $transaction->ID() ) {
794
					$index = 'EE_Transaction: ' . $transaction->ID();
795
					EEH_Debug_Tools::log( $class, $func, $line, $info, $display_request, $index );
796
				}
797
			}
798
		}
799
800
	}
801
802
}
803
// End of file EED_Messages.module.php
804
// Location: /modules/messages/EED_Messages.module.php
805