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

EED_Ticket_Selector   F

Complexity

Total Complexity 119

Size/Duplication

Total Lines 900
Duplicated Lines 0.67 %

Coupling/Cohesion

Components 3
Dependencies 19

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 119
c 1
b 1
f 0
lcom 3
cbo 19
dl 6
loc 900
rs 1.263

23 Methods

Rating   Name   Duplication   Size   Complexity  
D process_ticket_selections() 0 136 20
A instance() 0 3 1
A set_config() 0 5 1
A set_hooks_admin() 0 6 1
A set_definitions() 0 11 2
A run() 0 1 1
B ticket_selector_iframe() 0 44 1
A iframe_code_button() 0 22 3
A ticket_selector_form_close() 0 3 1
A display_view_details_btn() 0 12 2
A set_hooks() 0 11 1
B set_event() 6 20 8
F display_ticket_selector() 0 105 25
B ticket_selector_form_open() 0 23 5
B display_ticket_selector_submit() 0 22 5
D _validate_post_data() 0 107 18
B _add_ticket_to_cart() 0 42 5
B _ticket_datetime_availability() 0 21 5
B _set_initial_ticket_datetime_availability() 0 21 5
A _recalculate_ticket_datetime_availability() 0 9 3
A load_tckt_slctr_assets() 0 10 2
A load_tckt_slctr_assets_admin() 0 7 3
A no_tkt_slctr_end_dv() 0 3 1

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 EED_Ticket_Selector 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 EED_Ticket_Selector, and based on these observations, apply Extract Interface, too.

1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
2
/**
3
 * Event Espresso
4
 *
5
 * Event Registration and Management Plugin for WordPress
6
 *
7
 * @ package		Event Espresso
8
 * @ author			Seth Shoultes
9
 * @ copyright	(c) 2008-2011 Event Espresso  All Rights Reserved.
10
 * @ license			http://eventespresso.com/support/terms-conditions/   * see Plugin Licensing *
11
 * @ link				http://www.eventespresso.com
12
 * @ version		4.0
13
 *
14
 * ------------------------------------------------------------------------
15
 */
16
/**
17
 * ------------------------------------------------------------------------
18
 *
19
 * Ticket Selector  class
20
 *
21
 * @package		Event Espresso
22
 * @subpackage	includes/classes/EE_Ticket_Selector.class.php
23
 * @author			Brent Christensen
24
 *
25
 * ------------------------------------------------------------------------
26
 */
27
class EED_Ticket_Selector extends  EED_Module {
28
29
	/**
30
	 * event that ticket selector is being generated for
31
	 *
32
	 * @access protected
33
	 * @var \EE_Event
34
	 */
35
	protected static $_event = NULL;
36
37
	/**
38
	* array of datetimes and the spaces available for them
39
	*
40
	* @access private
41
	* @var array
42
	*/
43
	private static $_available_spaces = array();
44
45
46
47
48
	/**
49
	 * Used to flag when the ticket selector is being called from an external iframe.
50
	 *
51
	 * @var bool
52
	 */
53
	protected static $_in_iframe = false;
54
55
56
	/**
57
	 * @return EED_Ticket_Selector
58
	 */
59
	public static function instance() {
60
		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...
61
	}
62
63
64
65
	protected function set_config(){
66
		$this->set_config_section( 'template_settings' );
67
		$this->set_config_class( 'EE_Ticket_Selector_Config' );
68
		$this->set_config_name( 'EED_Ticket_Selector' );
69
	}
70
71
72
73
74
75
	/**
76
	 * 	set_hooks - for hooking into EE Core, other modules, etc
77
	 *
78
	 *  @access 	public
79
	 *  @return 	void
80
	 */
81
	public static function set_hooks() {
82
		// routing
83
		EE_Config::register_route( 'iframe', 'EED_Ticket_Selector', 'ticket_selector_iframe', 'ticket_selector' );
84
		EE_Config::register_route( 'process_ticket_selections', 'EED_Ticket_Selector', 'process_ticket_selections' );
85
		add_action( 'wp_loaded', array( 'EED_Ticket_Selector', 'set_definitions' ), 2 );
86
		//add_action( 'AHEE_event_details_before_post', array( 'EED_Ticket_Selector', 'ticket_selector_form_open' ), 10, 1 );
87
		add_action( 'AHEE_event_details_header_bottom', array( 'EED_Ticket_Selector', 'display_ticket_selector' ), 10, 1 );
88
		//add_action( 'AHEE__ticket_selector_chart__template__after_ticket_selector', array( 'EED_Ticket_Selector', 'display_ticket_selector_submit' ), 10, 1 );
89
		//add_action( 'AHEE_event_details_after_post', array( 'EED_Ticket_Selector', 'ticket_selector_form_close' ), 10 );
90
		add_action( 'wp_enqueue_scripts', array( 'EED_Ticket_Selector', 'load_tckt_slctr_assets' ), 10 );
91
	}
92
93
94
95
	/**
96
	 * 	set_hooks_admin - for hooking into EE Admin Core, other modules, etc
97
	 *
98
	 *  @access 	public
99
	 *  @return 	void
100
	 */
101
	public static function set_hooks_admin() {
102
		add_action( 'wp_loaded', array( 'EED_Ticket_Selector', 'set_definitions' ), 2 );
103
		//add button for iframe code to event editor.
104
		add_filter( 'get_sample_permalink_html', array( 'EED_Ticket_Selector', 'iframe_code_button' ), 10, 4 );
105
		add_action( 'admin_enqueue_scripts', array( 'EED_Ticket_Selector', 'load_tckt_slctr_assets_admin' ), 10 );
106
	}
107
108
109
110
	/**
111
	 * 	set_definitions
112
	 *
113
	 *  @access 	public
114
	 *  @return 	void
115
	 */
116
	public static function set_definitions() {
117
		define( 'TICKET_SELECTOR_ASSETS_URL', plugin_dir_url( __FILE__ ) . 'assets' . DS );
118
		define( 'TICKET_SELECTOR_TEMPLATES_PATH', str_replace( '\\', DS, plugin_dir_path( __FILE__ )) . 'templates' . DS );
119
120
		//if config is not set, initialize
121
		//If config is not set, set it.
122
		if ( ! isset( EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector ) ) {
123
			EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector = new EE_Ticket_Selector_Config();
0 ignored issues
show
Bug introduced by
The property EED_Ticket_Selector does not seem to exist in EE_Template_Config.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
124
		}
125
		EE_Registry::$i18n_js_strings[ 'ts_embed_iframe_title' ] = __( 'Copy and Paste the following:', 'event_espresso' );
126
	}
127
128
129
	/**
130
	 * 	gets the ball rolling
131
	 *
132
	 *	@access 	public
133
	 * 	@param	object 			$WP
134
	 * 	@return 	void
135
	 */
136
	public function run( $WP ) {}
137
138
139
	/**
140
	 * ticket_selector_iframe
141
	 *
142
	 *	@access 	public
143
	 * 	@return 	void
144
	 */
145
	public function ticket_selector_iframe() {
146
		self::$_in_iframe = true;
147
		/** @type EEM_Event $EEM_Event */
148
		$EEM_Event = EE_Registry::instance()->load_model( 'Event' );
149
		$event = $EEM_Event->get_one_by_ID(
150
			EE_Registry::instance()->REQ->get( 'event', 0 )
151
		);
152
		EE_Registry::instance()->REQ->set_espresso_page( true );
153
		$template_args['ticket_selector'] = EED_Ticket_Selector::display_ticket_selector( $event );
0 ignored issues
show
Coding Style Comprehensibility introduced by
$template_args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $template_args = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
154
		$template_args['css'] = apply_filters(
155
			'FHEE__EED_Ticket_Selector__ticket_selector_iframe__css',
156
			array(
157
				TICKET_SELECTOR_ASSETS_URL . 'ticket_selector_embed.css?ver=' . EVENT_ESPRESSO_VERSION,
158
				TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css?ver=' . EVENT_ESPRESSO_VERSION,
159
				includes_url( 'css/dashicons.min.css?ver=' . $GLOBALS['wp_version'] ),
160
				EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css?ver=' . EVENT_ESPRESSO_VERSION
161
			)
162
		);
163
		EE_Registry::$i18n_js_strings[ 'ticket_selector_iframe' ] = true;
164
		EE_Registry::$i18n_js_strings[ 'EEDTicketSelectorMsg' ] = __( 'Please choose at least one ticket before continuing.', 'event_espresso' );
165
		$template_args['eei18n'] = apply_filters(
166
			'FHEE__EED_Ticket_Selector__ticket_selector_iframe__eei18n_js_strings',
167
			EE_Registry::localize_i18n_js_strings()
168
		);
169
		$template_args['js'] = apply_filters(
170
			'FHEE__EED_Ticket_Selector__ticket_selector_iframe__js',
171
			array(
172
				includes_url( 'js/jquery/jquery.js?ver=' . $GLOBALS['wp_version'] ),
173
				EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js?ver=' . EVENT_ESPRESSO_VERSION,
174
				TICKET_SELECTOR_ASSETS_URL . 'ticket_selector_iframe_embed.js?ver=' . EVENT_ESPRESSO_VERSION
175
			)
176
		);
177
		EE_Registry::instance()->load_helper('Template');
178
		$template_args[ 'notices' ] = EEH_Template::display_template(
179
			EE_TEMPLATES . 'espresso-ajax-notices.template.php',
180
			array(),
181
			true
182
		);
183
		EEH_Template::display_template(
184
			TICKET_SELECTOR_TEMPLATES_PATH . 'ticket_selector_chart_iframe.template.php',
185
			$template_args
186
		);
187
		exit;
188
	}
189
190
191
192
193
	/**
194
	 * Adds an iframe embed code button to the Event editor.
195
	 *
196
	 * @param string $permalink_string    The current html string for the permalink section.
197
	 * @param int 	    $id           The post id for the event.
198
	 * @param string $new_title The for the event
199
	 * @param string $new_slug  The slug for the event.
200
	 *
201
	 * @return string The new html string for the permalink area.
202
	 */
203
	public static function iframe_code_button( $permalink_string, $id, $new_title, $new_slug ) {
0 ignored issues
show
Unused Code introduced by
The parameter $new_title 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...
Unused Code introduced by
The parameter $new_slug 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...
204
		//make sure this is ONLY when editing and the event id has been set.
205
		if ( ! empty( $id ) )  {
206
			$post = get_post( $id );
207
208
			//if NOT event then let's get out.
209
			if ( $post->post_type !== 'espresso_events' ) {
210
				return $permalink_string;
211
			}
212
213
			$ticket_selector_url = add_query_arg( array( 'ticket_selector' => 'iframe', 'event' => $id ), site_url() );
214
215
			$permalink_string .= '<a id="js-ticket-selector-embed-trigger" class="button button-small" href="#"  tabindex="-1">' . __('Embed', 'event_espresso') . '</a> ';
216
			$permalink_string .= '
217
<div id="js-ts-iframe" style="display:none">
218
	<div style="width:100%; height: 500px;">
219
		<iframe src="' . $ticket_selector_url . '" width="100%" height="100%"></iframe>
220
	</div>
221
</div>';
222
		}
223
		return $permalink_string;
224
	}
225
226
227
228
229
230
231
	/**
232
	 *    finds and sets the EE_Event object for use throughout class
233
	 *
234
	 * @access 	public
235
	 * @param 	mixed $event
236
	 * @return 	bool
237
	 */
238
	protected static function set_event( $event = null ) {
239
		if( $event === null ) {
240
			global $post;
241
			$event = $post;
242
		}
243
		if ( $event instanceof EE_Event ) {
244
			self::$_event = $event;
245
		} else if ( $event instanceof WP_Post && isset( $event->EE_Event ) && $event->EE_Event instanceof EE_Event ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
246
			self::$_event = $event->EE_Event;
247
		} else if ( $event instanceof WP_Post && $event->post_type == 'espresso_events' ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
248
			$event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object( $event );
249
			self::$_event = $event->EE_Event;
0 ignored issues
show
Documentation Bug introduced by
It seems like $event->EE_Event can also be of type object<EE_Base_Class>. However, the property $_event is declared as type object<EE_Event>. 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...
250 View Code Duplication
		} else {
251
			$user_msg = __( 'No Event object or an invalid Event object was supplied.', 'event_espresso' );
252
			$dev_msg = $user_msg . __( 'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.', 'event_espresso' );
253
			EE_Error::add_error( $user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__ );
254
			return false;
255
		}
256
		return true;
257
	}
258
259
260
261
262
263
264
	/**
265
	 *    creates buttons for selecting number of attendees for an event
266
	 *
267
	 * @access 	public
268
	 * @param 	object $event
269
	 * @param 	bool 	$view_details
270
	 * @return 	string
271
	 */
272
	public static function display_ticket_selector( $event = NULL, $view_details = FALSE ) {
273
		// reset filter for displaying submit button
274
		remove_filter( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true' );
275
		// poke and prod incoming event till it tells us what it is
276
		if ( ! EED_Ticket_Selector::set_event( $event )) {
277
			return false;
278
		}
279
		$event_post = self::$_event instanceof EE_Event ? self::$_event->ID() : $event;
280
		// grab event status
281
		$_event_active_status = self::$_event->get_active_status();
282
		if (
283
			! is_admin()
284
			&& (
285
				! self::$_event->display_ticket_selector()
286
				|| $view_details
287
				|| post_password_required( $event_post )
288
				|| (
289
					$_event_active_status != EE_Datetime::active
290
					&& $_event_active_status != EE_Datetime::upcoming
291
					&& $_event_active_status != EE_Datetime::sold_out
292
					&& ! (
293
						$_event_active_status == EE_Datetime::inactive
294
						&& is_user_logged_in()
295
					)
296
				)
297
			)
298
		) {
299
			return ! is_single() ? EED_Ticket_Selector::display_view_details_btn() : '';
300
		}
301
302
		$template_args = array();
303
		$template_args['event_status'] = $_event_active_status;
304
305
		$template_args['date_format'] = apply_filters( 'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format', get_option( 'date_format' ) );
306
		$template_args['time_format'] = apply_filters( 'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format', get_option( 'time_format' ) );
307
308
		$template_args['EVT_ID'] = self::$_event->ID();
309
		$template_args['event'] = self::$_event;
310
311
		// is the event expired ?
312
		$template_args['event_is_expired'] = self::$_event->is_expired();
313
		if ( $template_args['event_is_expired'] ) {
314
			return '<div class="ee-event-expired-notice"><span class="important-notice">' . __( 'We\'re sorry, but all tickets sales have ended because the event is expired.', 'event_espresso' ) . '</span></div>';
315
		}
316
317
		$ticket_query_args = array(
318
			array( 'Datetime.EVT_ID' => self::$_event->ID() ),
319
			'order_by' => array( 'TKT_order' => 'ASC', 'TKT_required' => 'DESC', 'TKT_start_date' => 'ASC', 'TKT_end_date' => 'ASC' , 'Datetime.DTT_EVT_start' => 'DESC' )
320
		);
321
322
		if ( ! EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector->show_expired_tickets ) {
0 ignored issues
show
Bug introduced by
The property EED_Ticket_Selector does not seem to exist in EE_Template_Config.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
323
			//use the correct applicable time query depending on what version of core is being run.
324
			$current_time = method_exists( 'EEM_Datetime', 'current_time_for_query' ) ? time() : current_time('timestamp');
325
			$ticket_query_args[0]['TKT_end_date'] = array( '>', $current_time );
326
		}
327
328
		// get all tickets for this event ordered by the datetime
329
		$template_args['tickets'] = EEM_Ticket::instance()->get_all( $ticket_query_args );
330
331
		if ( count( $template_args['tickets'] ) < 1 ) {
332
			return '<div class="ee-event-expired-notice"><span class="important-notice">' . __( 'We\'re sorry, but all ticket sales have ended.', 'event_espresso' ) . '</span></div>';
333
		}
334
335
		// filter the maximum qty that can appear in the Ticket Selector qty dropdowns
336
		$template_args['max_atndz'] = apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets', self::$_event->additional_limit() );
337
		if ( $template_args['max_atndz'] < 1 ) {
338
			$sales_closed_msg = __( 'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.', 'event_espresso' );
339
			if ( current_user_can( 'edit_post', self::$_event->ID() )) {
340
				$sales_closed_msg .=  sprintf(
341
					__( '%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s', 'event_espresso' ),
342
					'<div class="ee-attention" style="text-align: left;"><b>',
343
					'</b><br />',
344
					$link = '<span class="edit-link"><a class="post-edit-link" href="' . get_edit_post_link( self::$_event->ID() ) . '">',
345
					'</a></span></div>'
346
				);
347
			}
348
			return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
349
		}
350
351
		$templates['ticket_selector'] = TICKET_SELECTOR_TEMPLATES_PATH . 'ticket_selector_chart.template.php';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$templates was never initialized. Although not strictly required by PHP, it is generally a good practice to add $templates = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
352
		$templates['ticket_selector'] = apply_filters( 'FHEE__EE_Ticket_Selector__display_ticket_selector__template_path', $templates['ticket_selector'], self::$_event );
353
354
		// redirecting to another site for registration ??
355
		$external_url = self::$_event->external_url() !== NULL || self::$_event->external_url() !== '' ? self::$_event->external_url() : FALSE;
356
		// set up the form (but not for the admin)
357
		$ticket_selector = ! is_admin() ? EED_Ticket_Selector::ticket_selector_form_open( self::$_event->ID(), $external_url ) : '';
0 ignored issues
show
Documentation introduced by
$external_url 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...
358
		// if not redirecting to another site for registration
359
		if ( ! $external_url ) {
360
			EE_Registry::instance()->load_helper( 'Template' );
361
			EE_Registry::instance()->load_helper( 'URL' );
362
			// then display the ticket selector
363
			$ticket_selector .= EEH_Template::locate_template( $templates['ticket_selector'], $template_args );
364
		} else {
365
			// if not we still need to trigger the display of the submit button
366
			add_filter( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true' );
367
			//display notice to admin that registration is external
368
			$ticket_selector .= ! is_admin() ? '' : __( 'Registration is at an external URL for this event.', 'event_espresso' );
369
		}
370
		// submit button and form close tag
371
		$ticket_selector .= ! is_admin() ? EED_Ticket_Selector::display_ticket_selector_submit() : '';
372
		// set no cache headers and constants
373
		EE_System::do_not_cache();
374
375
		return $ticket_selector;
376
	}
377
378
379
380
	/**
381
	 *    ticket_selector_form_open
382
	 *
383
	 * @access 		public
384
	 * @param 		int 	$ID
385
	 * @param 		string $external_url
386
	 * @return 		string
387
	 */
388
	public static function ticket_selector_form_open( $ID = 0, $external_url = '' ) {
389
		// if redirecting, we don't need any anything else
390
		if ( $external_url ) {
391
			EE_Registry::instance()->load_helper( 'URL' );
392
			$html = '<form method="GET" action="' . EEH_URL::refactor_url( $external_url ) . '">';
393
			$query_args = EEH_URL::get_query_string( $external_url );
394
			foreach ( $query_args as $query_arg => $value ) {
0 ignored issues
show
Bug introduced by
The expression $query_args of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
395
				$html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
396
			}
397
			return $html;
398
		}
399
		EE_Registry::instance()->load_helper( 'Event_View' );
400
		$checkout_url = EEH_Event_View::event_link_url( $ID );
401
		if ( ! $checkout_url ) {
402
			EE_Error::add_error( __('The URL for the Event Details page could not be retrieved.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
403
		}
404
		$extra_params = self::$_in_iframe ? ' target="_blank"' : '';
405
		$html = '<form method="POST" action="' . $checkout_url . '"' . $extra_params . '>';
406
		$html .= wp_nonce_field( 	'process_ticket_selections', 'process_ticket_selections_nonce', TRUE, FALSE );
407
		$html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
408
		$html = apply_filters( 'FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, self::$_event );
409
		return $html;
410
	}
411
412
413
414
415
	/**
416
	 * 	display_ticket_selector_submit
417
	 *
418
	 *	@access public
419
	 * 	@access 		public
420
	 * 	@return		string
421
	 */
422
	public static function display_ticket_selector_submit() {
423
		if ( ! is_admin() ) {
424
			if ( apply_filters( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', FALSE ) ) {
425
				$btn_text = apply_filters(
426
					'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
427
					__('Register Now', 'event_espresso' ),
428
					self::$_event
429
				);
430
				$external_url = self::$_event->external_url();
431
				$html = '<input id="ticket-selector-submit-'. self::$_event->ID() .'-btn"';
432
				$html .= ' class="ticket-selector-submit-btn ';
433
				$html .= empty( $external_url ) ? 'ticket-selector-submit-ajax"' : '"';
434
				$html .= ' type="submit" value="' . $btn_text . '" />';
435
				$html .= apply_filters( 'FHEE__EE_Ticket_Selector__after_ticket_selector_submit', '', self::$_event );
436
				$html .= '<div class="clear"><br/></div></form>';
437
				return $html;
438
			} else if ( is_archive() ) {
439
				return EED_Ticket_Selector::ticket_selector_form_close() . EED_Ticket_Selector::display_view_details_btn();
440
			}
441
		}
442
		return '';
443
	}
444
445
446
447
448
	/**
449
	 * 	ticket_selector_form_close
450
	 *
451
	 *	@access public
452
	 * 	@access 		public
453
	 * 	@return		string
454
	 */
455
	public static function ticket_selector_form_close() {
456
		return '</form>';
457
	}
458
459
460
461
462
463
	/**
464
	 *    display_view_details_btn
465
	 *
466
	 *	@access public
467
	 * 	@access 		public
468
	 * 	@return		string
469
	 */
470
	public static function display_view_details_btn() {
471
		if ( ! self::$_event->get_permalink() ) {
472
			EE_Error::add_error( __('The URL for the Event Details page could not be retrieved.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
473
		}
474
		$view_details_btn = '<form method="POST" action="' . self::$_event->get_permalink() . '">';
475
		$btn_text = apply_filters( 'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text', __( 'View Details', 'event_espresso' ), self::$_event );
476
		$view_details_btn .= '<input id="ticket-selector-submit-'. self::$_event->ID() .'-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="' . $btn_text . '" />';
477
		$view_details_btn .= apply_filters( 'FHEE__EE_Ticket_Selector__after_view_details_btn', '', self::$_event );
478
		$view_details_btn .= '<div class="clear"><br/></div>';
479
		$view_details_btn .= '</form>';
480
		return $view_details_btn;
481
	}
482
483
484
485
486
487
488
	/**
489
	 * 	process_ticket_selections
490
	 *
491
	 *	@access public
492
	 * 	@access 		public
493
	 * 	@return		array  or FALSE
494
	 */
495
	public function process_ticket_selections() {
496
		do_action( 'EED_Ticket_Selector__process_ticket_selections__before' );
497
		// check nonce
498
		if ( ! is_admin() && ( ! EE_Registry::instance()->REQ->is_set( 'process_ticket_selections_nonce' ) || ! wp_verify_nonce( EE_Registry::instance()->REQ->get( 'process_ticket_selections_nonce' ), 'process_ticket_selections' ))) {
499
			EE_Error::add_error(
500
				sprintf( __( 'We\'re sorry but your request failed to pass a security check.%sPlease click the back button on your browser and try again.', 'event_espresso' ), '<br/>' ),
501
				__FILE__, __FUNCTION__, __LINE__
502
			);
503
			return FALSE;
504
		}
505
//		d( EE_Registry::instance()->REQ );
506
		self::$_available_spaces = array(
507
			'tickets' => array(),
508
			'datetimes' => array()
509
		);
510
511
512
		//we should really only have 1 registration in the works now (ie, no MER) so clear any previous items in the cart.
513
		// When MER happens this will probably need to be tweaked, possibly wrapped in a conditional checking for some constant defined in MER etc.
514
		EE_Registry::instance()->load_core( 'Session' );
515
		// unless otherwise requested, clear the session
516
		if ( apply_filters( 'FHEE__EE_Ticket_Selector__process_ticket_selections__clear_session', TRUE )) {
517
			EE_Registry::instance()->SSN->clear_session( __CLASS__, __FUNCTION__ );
518
		}
519
		//d( EE_Registry::instance()->SSN );
520
521
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
522
		// do we have an event id?
523
		if ( EE_Registry::instance()->REQ->is_set( 'tkt-slctr-event-id' ) ) {
524
			// validate/sanitize data
525
			$valid = self::_validate_post_data();
526
527
			//EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
528
			//EEH_Debug_Tools::printr( $valid, '$valid', __FILE__, __LINE__ );
529
			//EEH_Debug_Tools::printr( $valid[ 'total_tickets' ], 'total_tickets', __FILE__, __LINE__ );
530
			//EEH_Debug_Tools::printr( $valid[ 'max_atndz' ], 'max_atndz', __FILE__, __LINE__ );
531
532
			//check total tickets ordered vs max number of attendees that can register
533
			if ( $valid['total_tickets'] > $valid['max_atndz'] ) {
534
535
				// ordering too many tickets !!!
536
				$total_tickets_string = _n('You have attempted to purchase %s ticket.', 'You have attempted to purchase %s tickets.', $valid['total_tickets'], 'event_espresso');
537
				$limit_error_1 = sprintf( $total_tickets_string, $valid['total_tickets'] );
538
				// dev only message
539
				$max_atndz_string = _n('The registration limit for this event is %s ticket per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.', 'The registration limit for this event is %s tickets per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.', $valid['max_atndz'], 'event_espresso');
540
				$limit_error_2 = sprintf( $max_atndz_string, $valid['max_atndz'], $valid['max_atndz'] );
541
				EE_Error::add_error( $limit_error_1 . '<br/>' . $limit_error_2, __FILE__, __FUNCTION__, __LINE__ );
542
			} else {
543
544
				// all data appears to be valid
545
				$tckts_slctd = FALSE;
546
				$success = TRUE;
547
				// load cart
548
				EE_Registry::instance()->load_core( 'Cart' );
549
550
				// cycle thru the number of data rows sent from the event listing
551
				for ( $x = 0; $x < $valid['rows']; $x++ ) {
552
					// does this row actually contain a ticket quantity?
553
					if ( isset( $valid['qty'][$x] ) && $valid['qty'][$x] > 0 ) {
554
						// YES we have a ticket quantity
555
						$tckts_slctd = TRUE;
556
						//						d( $valid['ticket_obj'][$x] );
557
						if ( $valid['ticket_obj'][$x] instanceof EE_Ticket ) {
558
							// then add ticket to cart
559
							$ticket_added = self::_add_ticket_to_cart( $valid['ticket_obj'][$x], $valid['qty'][$x] );
560
							$success = ! $ticket_added ? FALSE : $success;
561
							if ( EE_Error::has_error() ) {
562
								break;
563
							}
564
						} else {
565
							// nothing added to cart retrieved
566
							EE_Error::add_error(
567
								sprintf( __( 'A valid ticket could not be retrieved for the event.%sPlease click the back button on your browser and try again.', 'event_espresso' ), '<br/>' ),
568
								__FILE__, __FUNCTION__, __LINE__
569
							);
570
						}
571
					}
572
				}
573
				//d( EE_Registry::instance()->CART );
574
				//die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< KILL REDIRECT HERE BEFORE CART UPDATE
575
576
				if ( $tckts_slctd ) {
577
					if ( $success ) {
578
						do_action( 'FHEE__EE_Ticket_Selector__process_ticket_selections__before_redirecting_to_checkout', EE_Registry::instance()->CART, $this );
579
						EE_Registry::instance()->CART->recalculate_all_cart_totals();
580
						EE_Registry::instance()->CART->save_cart( FALSE );
581
						EE_Registry::instance()->SSN->update();
582
						//d( EE_Registry::instance()->CART );
583
						//die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< OR HERE TO KILL REDIRECT AFTER CART UPDATE
584
						// just return TRUE for registrations being made from admin
585
						if ( is_admin() ) {
586
							return TRUE;
587
						}
588
						wp_safe_redirect( apply_filters( 'FHEE__EE_Ticket_Selector__process_ticket_selections__success_redirect_url', EE_Registry::instance()->CFG->core->reg_page_url() ));
589
						exit();
590
591
					} else {
592
						if ( ! EE_Error::has_error() ) {
593
							// nothing added to cart
594
							EE_Error::add_attention( __( 'No tickets were added for the event', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
595
						}
596
					}
597
598
				} else {
599
					// no ticket quantities were selected
600
					EE_Error::add_error( __( 'You need to select a ticket quantity before you can proceed.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
601
				}
602
			}
603
			//die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< KILL BEFORE REDIRECT
604
			// at this point, just return if registration is being made from admin
605
			if ( is_admin() ) {
606
				return FALSE;
607
			}
608
			if ( $valid['return_url'] ) {
609
				EE_Error::get_notices( FALSE, TRUE );
610
				wp_safe_redirect( $valid['return_url'] );
611
				exit();
612
			} elseif ( isset( $event_to_add['id'] )) {
0 ignored issues
show
Bug introduced by
The variable $event_to_add seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
613
				EE_Error::get_notices( FALSE, TRUE );
614
				wp_safe_redirect( get_permalink( $event_to_add['id'] ));
615
				exit();
616
			} else {
617
				echo EE_Error::get_notices();
618
			}
619
620
		} else {
621
			// $_POST['tkt-slctr-event-id'] was not set ?!?!?!?
622
			EE_Error::add_error(
623
				sprintf( __( 'An event id was not provided or was not received.%sPlease click the back button on your browser and try again.', 'event_espresso' ), '<br/>' ),
624
				__FILE__, __FUNCTION__, __LINE__
625
			);
626
		}
627
628
		return FALSE;
629
630
	}
631
632
633
634
	/**
635
	 *    validate_post_data
636
	 *
637
	 * @access        private
638
	 * @return        array  or FALSE
639
	 */
640
	private static function _validate_post_data() {
641
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
642
643
		// start with an empty array()
644
		$valid_data = array();
645
		//		d( $_POST );
646
		//if event id is valid
647
		$id = absint( EE_Registry::instance()->REQ->get( 'tkt-slctr-event-id' ));
648
		if ( $id ) {
649
			// grab valid id
650
			$valid_data['id'] = $id;
651
			// grab and sanitize return-url
652
			$valid_data['return_url'] = esc_url_raw( EE_Registry::instance()->REQ->get( 'tkt-slctr-return-url-' . $id ));
653
			// array of other form names
654
			$inputs_to_clean = array(
655
				'event_id' => 'tkt-slctr-event-id',
656
				'max_atndz' => 'tkt-slctr-max-atndz-',
657
				'rows' => 'tkt-slctr-rows-',
658
				'qty' => 'tkt-slctr-qty-',
659
				'ticket_id' => 'tkt-slctr-ticket-id-',
660
				'return_url' => 'tkt-slctr-return-url-',
661
			);
662
			// let's track the total number of tickets ordered.'
663
			$valid_data['total_tickets'] = 0;
664
			// cycle through $inputs_to_clean array
665
			foreach ( $inputs_to_clean as $what => $input_to_clean ) {
666
				// check for POST data
667
				if ( EE_Registry::instance()->REQ->is_set( $input_to_clean . $id )) {
668
					// grab value
669
					$input_value = EE_Registry::instance()->REQ->get( $input_to_clean . $id );
670
					switch ($what) {
671
672
						// integers
673
						case 'event_id':
674
							$valid_data[$what] = absint( $input_value );
675
							// get event via the event id we put in the form
676
							$valid_data['event'] = EE_Registry::instance()->load_model( 'Event' )->get_one_by_ID( $valid_data['event_id'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()->load_model('Event') (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...
677
							break;
678
						case 'rows':
679
						case 'max_atndz':
680
							$valid_data[$what] = absint( $input_value );
681
							break;
682
683
						// arrays of integers
684
						case 'qty':
685
							//							d( $input_value );
686
							$row_qty = $input_value;
687
							// if qty is coming from a radio button input, then we need to assemble an array of rows
688
							if( ! is_array( $row_qty )) {
689
								// get number of rows
690
								$rows = EE_Registry::instance()->REQ->is_set( 'tkt-slctr-rows-' . $id ) ? absint( EE_Registry::instance()->REQ->get( 'tkt-slctr-rows-' . $id )) : 1;
691
								//								d( $rows );
692
								// explode ints by the dash
693
								$row_qty = explode( '-', $row_qty );
694
								$row = isset( $row_qty[0] ) ? ( absint( $row_qty[0] )) : 1;
695
								$qty = isset( $row_qty[1] ) ? absint( $row_qty[1] ) : 0;
696
								$row_qty = array( $row => $qty );
697
								//								 d( $row_qty );
698
								for( $x = 1; $x <= $rows; $x++ ) {
699
									if ( ! isset( $row_qty[$x] )) {
700
										$row_qty[$x] = 0;
701
									}
702
								}
703
							}
704
							ksort( $row_qty );
705
							//							 d( $row_qty );
706
							// cycle thru values
707
							foreach ( $row_qty as $qty ) {
708
								$qty = absint( $qty );
709
								// sanitize as integers
710
								$valid_data[$what][] = $qty;
711
								$valid_data['total_tickets'] += $qty;
712
							}
713
							break;
714
715
						// array of integers
716
						case 'ticket_id':
717
							$value_array = array();
718
							// cycle thru values
719
							foreach ( $input_value as $key=>$value ) {
720
								// allow only numbers, letters,  spaces, commas and dashes
721
								$value_array[ $key ] = wp_strip_all_tags( $value );
722
								// get ticket via the ticket id we put in the form
723
								$ticket_obj = EE_Registry::instance()->load_model( 'Ticket' )->get_one_by_ID( $value );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()->load_model('Ticket') (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...
724
								$valid_data['ticket_obj'][ $key ] = $ticket_obj;
725
							}
726
							$valid_data[ $what ] = $value_array;
727
							break;
728
729
						case 'return_url' :
730
							// grab and sanitize return-url
731
							$valid_data[$what] = esc_url_raw( $input_value );
732
							break;
733
734
					} 	// end switch $what
735
				}
736
			} 	// end foreach $inputs_to_clean
737
738
		} else {
739
			EE_Error::add_error( __('The event id provided was not valid.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
740
			return FALSE;
741
		}
742
743
		//		d( $valid_data );
744
		//		die();
745
		return $valid_data;
746
	}
747
748
749
750
	/**
751
	 *    adds a ticket to the cart
752
	 * @access   private
753
	 * @param EE_Ticket $ticket
754
	 * @param int       $qty
755
	 * @return TRUE on success, FALSE on fail
756
	 */
757
	private static function _add_ticket_to_cart( EE_Ticket $ticket = NULL, $qty = 1 ) {
758
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
759
		// get the number of spaces left for this datetime ticket
760
		$available_spaces = self::_ticket_datetime_availability( $ticket );
0 ignored issues
show
Bug introduced by
It seems like $ticket defined by parameter $ticket on line 757 can be null; however, EED_Ticket_Selector::_ti...datetime_availability() 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...
761
		// compare available spaces against the number of tickets being purchased
762
		if ( $available_spaces >= $qty ) {
763
			// allow addons to prevent a ticket from being added to cart
764
			if ( ! apply_filters( 'FHEE__EE_Ticket_Selector___add_ticket_to_cart__allow_add_to_cart', true, $ticket, $qty, $available_spaces ) ) {
765
				return false;
766
			}
767
			// add event to cart
768
			if( EE_Registry::instance()->CART->add_ticket_to_cart( $ticket, $qty )) {
0 ignored issues
show
Bug introduced by
It seems like $ticket defined by parameter $ticket on line 757 can be null; however, EE_Cart::add_ticket_to_cart() 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...
769
				self::_recalculate_ticket_datetime_availability( $ticket, $qty );
0 ignored issues
show
Bug introduced by
It seems like $ticket defined by parameter $ticket on line 757 can be null; however, EED_Ticket_Selector::_re...datetime_availability() 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...
770
				return true;
771
			} else {
772
				return false;
773
			}
774
		} else {
775
			// tickets can not be purchased but let's find the exact number left for the last ticket selected PRIOR to subtracting tickets
776
			$available_spaces = self::_ticket_datetime_availability( $ticket, true );
0 ignored issues
show
Bug introduced by
It seems like $ticket defined by parameter $ticket on line 757 can be null; however, EED_Ticket_Selector::_ti...datetime_availability() 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...
777
			// greedy greedy greedy eh?
778
			if ( $available_spaces > 0 ) {
779
				// add error messaging - we're using the _n function that will generate the appropriate singular or plural message based on the number of $available_spaces
780
				EE_Error::add_error(
781
					sprintf(
782
						_n(
783
							'We\'re sorry, but there is only %s available space left for this event at this particular date and time.%sPlease select a different number (or different combination) of tickets.',
784
							'We\'re sorry, but there are only %s available spaces left for this event at this particular date and time.%sPlease select a different number (or different combination) of tickets.',
785
							$available_spaces,
786
							'event_espresso'
787
						),
788
						$available_spaces,
789
						'<br />'
790
					),
791
					__FILE__, __FUNCTION__, __LINE__
792
				);
793
			} else {
794
				EE_Error::add_error( __('We\'re sorry, but there are no available spaces left for this event at this particular date and time.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
795
			}
796
			return false;
797
		}
798
	}
799
800
801
802
	/**
803
	 *        _ticket_datetime_availability
804
	 *        creates an array of tickets plus all of the datetimes available to each ticket
805
	 *        and tracks the spaces remaining for each of those datetimes
806
	 *
807
	 * @access 	private
808
	 * @param 	EE_Ticket $ticket - selected ticket
809
	 * @param 	bool         $get_original_ticket_spaces
810
	 * @return 	int
811
	 */
812
	private static function _ticket_datetime_availability( EE_Ticket $ticket, $get_original_ticket_spaces = FALSE ) {
813
		// if the $_available_spaces array has not been set up yet...
814
		if ( ! isset( self::$_available_spaces['tickets'][ $ticket->ID() ] )) {
815
				self::_set_initial_ticket_datetime_availability( $ticket );
816
		}
817
		$available_spaces = $ticket->qty() - $ticket->sold();
818
		if ( isset( self::$_available_spaces['tickets'][ $ticket->ID() ] )) {
819
			// loop thru tickets, which will ALSO include individual ticket records AND a total
820
			foreach ( self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces  ) {
821
				// if we want the original datetime availability BEFORE we started subtracting tickets ?
822
				if ( $get_original_ticket_spaces ) {
823
					// then grab the available spaces from the "tickets" array and compare with the above to get the lowest number
824
					$available_spaces = min( $available_spaces, self::$_available_spaces['tickets'][ $ticket->ID() ][ $DTD_ID ] );
825
				} else {
826
					// we want the updated ticket availability as stored in the "datetimes" array
827
					$available_spaces = min( $available_spaces, self::$_available_spaces['datetimes'][ $DTD_ID ] );
828
				}
829
			}
830
		}
831
		return $available_spaces;
832
	}
833
834
835
836
	/**
837
	 *    _set_initial_ticket_datetime_availability
838
	 *
839
	 * @access 	private
840
	 * @param 	EE_Ticket $ticket
841
	 * @return 	int
842
	 */
843
	private static function _set_initial_ticket_datetime_availability( EE_Ticket $ticket ) {
844
		// first, get all of the datetimes that are available to this ticket
845
		$datetimes = $ticket->get_many_related(
846
			'Datetime',
847
			array( array( 'DTT_EVT_end' => array( '>=', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) ) ), 'order_by' => array( 'DTT_EVT_start' => 'ASC' ))
848
		);
849
		if ( ! empty( $datetimes )) {
850
			// now loop thru all of the datetimes
851
			foreach ( $datetimes as $datetime  ) {
852
				if ( $datetime instanceof EE_Datetime ) {
853
					// the number of spaces available for the datetime without considering individual ticket quantities
854
					$spaces_remaining = $datetime->spaces_remaining();
855
					// save the total available spaces ( the lesser of the ticket qty minus the number of tickets sold or the datetime spaces remaining) to this ticket using the datetime ID as the key
856
					self::$_available_spaces['tickets'][ $ticket->ID() ][ $datetime->ID() ] = min(( $ticket->qty() - $ticket->sold() ), $spaces_remaining );
857
					// if the remaining spaces for this datetime is already set, then compare that against the datetime spaces remaining, and take the lowest number,
858
					// else just take the datetime spaces remaining, and assign to the datetimes array
859
					self::$_available_spaces['datetimes'][ $datetime->ID() ] = isset( self::$_available_spaces['datetimes'][ $datetime->ID() ] ) ? min( self::$_available_spaces['datetimes'][ $datetime->ID() ], $spaces_remaining ) : $spaces_remaining;
860
				}
861
			}
862
		}
863
	}
864
865
866
867
	/**
868
	 *    _recalculate_ticket_datetime_availability
869
	 *
870
	 * @access 	private
871
	 * @param 	EE_Ticket $ticket
872
	 * @param 	int   $qty
873
	 * @return 	int
874
	 */
875
	private static function _recalculate_ticket_datetime_availability( EE_Ticket $ticket, $qty = 0 ) {
876
		if ( isset( self::$_available_spaces['tickets'][ $ticket->ID() ] )) {
877
			// loop thru tickets, which will ALSO include individual ticket records AND a total
878
			foreach ( self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces  ) {
879
				// subtract the qty of selected tickets from each datetime's available spaces this ticket has access to,
880
				self::$_available_spaces['datetimes'][ $DTD_ID ] = self::$_available_spaces['datetimes'][ $DTD_ID ] - $qty;
881
			}
882
		}
883
	}
884
885
886
887
888
889
	/**
890
	* 	load js
891
	*
892
	* 	@access 		public
893
	* 	@return 		void
894
	*/
895
	public static function load_tckt_slctr_assets() {
896
		// add some style
897
		if ( apply_filters( 'FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', FALSE ) ) {
898
			wp_register_style('ticket_selector', TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css');
899
			wp_enqueue_style('ticket_selector');
900
			// make it dance
901
			//			wp_register_script('ticket_selector', TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.js', array('espresso_core'), '', TRUE);
902
			//			wp_enqueue_script('ticket_selector');
903
		}
904
	}
905
906
907
908
909
910
	public static function load_tckt_slctr_assets_admin() {
911
		//iframe button js on admin event editor page
912
		if ( EE_Registry::instance()->REQ->get('page') == 'espresso_events' && EE_Registry::instance()->REQ->get('action') == 'edit' ) {
913
			wp_register_script( 'ticket_selector_embed', TICKET_SELECTOR_ASSETS_URL . 'ticket-selector-embed.js', array( 'ee-dialog' ), EVENT_ESPRESSO_VERSION, true );
914
			wp_enqueue_script( 'ticket_selector_embed' );
915
		}
916
	}
917
918
919
920
	public static function no_tkt_slctr_end_dv() {
921
		return '<div class="clear"></div></div>';
922
	}
923
924
925
926
}
927
928
929
930
931
// End of file EE_Ticket_Selector.class.php
932
// Location: /includes/classes/EE_Ticket_Selector.class.php
933