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

Events_Admin_Page   F

Complexity

Total Complexity 305

Size/Duplication

Total Lines 2330
Duplicated Lines 17.94 %

Coupling/Cohesion

Components 2
Dependencies 21

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 305
c 2
b 0
f 0
lcom 2
cbo 21
dl 418
loc 2330
rs 0.6314

65 Methods

Rating   Name   Duplication   Size   Complexity  
C _permanently_delete_event() 0 71 12
A _init_page_props() 0 16 1
A _ajax_hooks() 0 3 1
A _define_page_props() 23 23 1
B _set_page_routes() 0 127 4
A _add_screen_options() 0 3 1
A _add_screen_options_default() 0 3 1
A _add_screen_options_category_list() 6 6 1
A _add_feature_pointers() 0 3 1
A load_scripts_styles() 0 11 1
A load_scripts_styles_create_new() 0 3 1
A load_scripts_styles_edit() 11 11 1
A load_scripts_styles_add_category() 0 3 1
A load_scripts_styles_edit_category() 0 1 1
A _set_list_table_views_category_list() 12 12 1
A admin_init() 0 3 1
A admin_notices() 0 1 1
A admin_footer_scripts() 0 1 1
B _set_page_config() 0 256 3
C verify_event_edit() 17 42 12
A _edit_event_warning() 0 3 1
B _set_list_table_views_default() 0 32 2
A _event_legend_items() 0 49 1
A _event_model() 0 6 2
A extra_permalink_field_buttons() 0 9 2
A _events_overview_list_table() 0 7 1
A extra_misc_actions_publish_box() 0 3 1
F _insert_update_cpt_item() 4 47 17
A _restore_cpt_item() 0 10 2
F _default_venue_update() 0 49 22
F _default_tickets_update() 46 218 46
D _add_prices_to_ticket() 11 27 10
A _ee_autosave_create_new() 0 3 1
B _ee_autosave_edit() 0 61 7
A _generate_publish_box_extra_content() 0 62 1
A get_event_object() 0 3 1
A _register_event_editor_meta_boxes() 0 23 1
B ticket_metabox() 14 73 6
F _get_ticket_row() 0 49 21
B registration_options_meta_box() 0 27 1
F get_events() 15 126 35
A trash_cpt_item() 0 4 1
A restore_cpt_item() 0 4 1
A delete_cpt_item() 0 4 1
B _trash_or_restore_event() 25 25 6
C _trash_or_restore_events() 30 30 8
C _change_event_status() 47 47 7
B _delete_event() 0 25 6
B _delete_events() 0 25 6
A total_events() 0 5 1
A total_events_draft() 0 8 1
A total_trashed_events() 0 8 1
A _default_event_settings() 0 21 2
A _update_default_event_settings() 0 8 2
A _template_settings() 0 6 1
B _set_category_object() 24 24 5
A _set_empty_category_object() 0 5 1
A _category_list_table() 6 6 1
B _category_details() 24 24 3
B _category_details_content() 36 36 2
A _delete_categories() 14 14 3
A _delete_category() 0 5 1
A _insert_or_update_category() 16 16 3
D _insert_category() 8 34 9
B get_categories() 29 29 5

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

1
<?php
2
if (!defined('EVENT_ESPRESSO_VERSION'))
3
	exit('NO direct script access allowed');
4
5
/**
6
 * Event Espresso
7
 *
8
 * Event Registration and Management Plugin for Wordpress
9
 *
10
 * @package		Event Espresso
11
 * @author		Seth Shoultes
12
 * @copyright	(c)2009-2012 Event Espresso All Rights Reserved.
13
 * @license		http://eventespresso.com/support/terms-conditions/  ** see Plugin Licensing **
14
 * @link		http://www.eventespresso.com
15
 * @version		4.0
16
 *
17
 * ------------------------------------------------------------------------
18
 *
19
 * Events_Admin_Page
20
 *
21
 * This contains the logic for setting up the Events related pages.  Any methods without phpdoc comments have inline docs with parent class.
22
 *
23
 *
24
 * @package		Events_Admin_Page
25
 * @subpackage	includes/core/admin/Events_Admin_Page.core.php
26
 * @author		Darren Ethier
27
 *
28
 * ------------------------------------------------------------------------
29
 */
30
class Events_Admin_Page extends EE_Admin_Page_CPT {
31
32
	/**
33
	 * _event
34
	 * This will hold the event object for event_details screen.
35
	 *
36
	 * @access protected
37
	 * @var object
38
	 */
39
	protected $_event;
40
41
42
	/**
43
	 * This will hold the category object for category_details screen.
44
	 * @var object
45
	 */
46
	protected $_category;
47
48
49
	/**
50
	 * This will hold the event model instance
51
	 * @var object
52
	 */
53
	protected $_event_model;
54
55
56
	protected function _init_page_props() {
57
58
		$this->page_slug = EVENTS_PG_SLUG;
59
		$this->page_label = EVENTS_LABEL;
60
		$this->_admin_base_url = EVENTS_ADMIN_URL;
61
		$this->_admin_base_path = EVENTS_ADMIN;
62
		$this->_cpt_model_names = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('create_new' => 'E... 'edit' => 'EEM_Event') of type array<string,string,{"cr...ring","edit":"string"}> is incompatible with the declared type boolean of property $_cpt_model_names.

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

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

Loading history...
63
			'create_new' => 'EEM_Event',
64
			'edit' => 'EEM_Event'
65
			);
66
		$this->_cpt_edit_routes = array(
67
			'espresso_events' => 'edit'
68
			);
69
70
		add_action('AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object', array( $this, 'verify_event_edit' ) );
71
	}
72
73
	protected function _ajax_hooks() {
74
		//todo: all hooks for events ajax goes in here.
75
	}
76
77 View Code Duplication
	protected function _define_page_props() {
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...
78
		$this->_admin_page_title = EVENTS_LABEL;
79
		$this->_labels = array(
80
			'buttons' => array(
81
				'add' => __('Add New Event', 'event_espresso'),
82
				'edit' => __('Edit Event', 'event_espresso'),
83
				'delete' => __('Delete Event', 'event_espresso'),
84
				'add_category' => __('Add New Category', 'event_espresso'),
85
				'edit_category' => __('Edit Category', 'event_espresso'),
86
				'delete_category' => __('Delete Category', 'event_espresso')
87
			),
88
			'editor_title' => array(
89
				'espresso_events' => __('Enter event title here', 'event_espresso')
90
				),
91
			'publishbox' => array(
92
				'create_new' => __('Save New Event', 'event_espresso'),
93
				'edit' => __('Update Event', 'event_espresso'),
94
				'add_category' => __('Save New Category', 'event_espresso'),
95
				'edit_category' => __('Update Category', 'event_espresso'),
96
				'template_settings' => __( 'Update Settings', 'event_espresso' )
97
				)
98
		);
99
	}
100
101
	protected function _set_page_routes() {
102
		//load formatter helper
103
		EE_Registry::instance()->load_helper( 'Formatter' );
104
		//load field generator helper
105
		EE_Registry::instance()->load_helper( 'Form_Fields' );
106
107
		//is there a evt_id in the request?
108
		$evt_id = ! empty( $this->_req_data['EVT_ID'] ) && ! is_array( $this->_req_data['EVT_ID'] ) ? $this->_req_data['EVT_ID'] : 0;
109
		$evt_id = ! empty( $this->_req_data['post'] ) ? $this->_req_data['post'] : $evt_id;
110
111
112
		$this->_page_routes = array(
113
			'default' => array(
114
				'func' => '_events_overview_list_table',
115
				'capability' => 'ee_read_events'
116
				),
117
			'create_new' => array(
118
				'func' => '_create_new_cpt_item',
119
				'capability' => 'ee_edit_events'
120
				),
121
			'edit' => array(
122
				'func' => '_edit_cpt_item',
123
				'capability' => 'ee_edit_event',
124
				'obj_id' => $evt_id
125
				),
126
			'copy_event' => array(
127
				'func' => '_copy_events',
128
				'capability' => 'ee_edit_event',
129
				'obj_id' => $evt_id,
130
				'noheader' => true
131
			),
132
			'trash_event' => array(
133
				'func' => '_trash_or_restore_event',
134
				'args' => array('event_status' => 'trash'),
135
				'capability' => 'ee_delete_event',
136
				'obj_id' => $evt_id,
137
				'noheader' => true
138
			),
139
			'trash_events' => array(
140
				'func' => '_trash_or_restore_events',
141
				'args' => array('event_status' => 'trash'),
142
				'capability' => 'ee_delete_events',
143
				'noheader' => true
144
			),
145
			'restore_event' => array(
146
				'func' => '_trash_or_restore_event',
147
				'args' => array('event_status' => 'draft'),
148
				'capability' => 'ee_delete_event',
149
				'obj_id' => $evt_id,
150
				'noheader' => true
151
			),
152
			'restore_events' => array(
153
				'func' => '_trash_or_restore_events',
154
				'args' => array('event_status' => 'draft'),
155
				'capability' => 'ee_delete_events',
156
				'noheader' => true
157
			),
158
			'delete_event' => array(
159
				'func' => '_delete_event',
160
				'capability' => 'ee_delete_event',
161
				'obj_id' => $evt_id,
162
				'noheader' => true
163
			),
164
			'delete_events' => array(
165
				'func' => '_delete_events',
166
				'capability' => 'ee_delete_events',
167
				'noheader' => true
168
			),
169
			'view_report' => array(
170
				'func' => '_view_report',
171
				'capablity' => 'ee_edit_events'
172
				),
173
			'default_event_settings' => array(
174
				'func' => '_default_event_settings',
175
				'capability' => 'manage_options'
176
				),
177
			'update_default_event_settings' => array(
178
				'func' => '_update_default_event_settings',
179
				'capability' => 'manage_options',
180
				'noheader' => TRUE,
181
				),
182
			'template_settings' => array(
183
				'func' => '_template_settings',
184
				'capability' => 'manage_options'
185
				),
186
			//event category tab related
187
			'add_category' => array(
188
				'func' => '_category_details',
189
				'capability' => 'ee_edit_event_category',
190
				'args' => array('add'),
191
				),
192
			'edit_category' => array(
193
				'func' => '_category_details',
194
				'capability' => 'ee_edit_event_category',
195
				'args' => array('edit')
196
				),
197
			'delete_categories' => array(
198
				'func' => '_delete_categories',
199
				'capability' => 'ee_delete_event_category',
200
				'noheader' => TRUE
201
				),
202
203
			'delete_category' => array(
204
				'func' => '_delete_categories',
205
				'capability' => 'ee_delete_event_category',
206
				'noheader' => TRUE
207
				),
208
209
			'insert_category' => array(
210
				'func' => '_insert_or_update_category',
211
				'args' => array('new_category' => TRUE),
212
				'capability' => 'ee_edit_event_category',
213
				'noheader' => TRUE
214
				),
215
216
			'update_category' => array(
217
				'func' => '_insert_or_update_category',
218
				'args' => array('new_category' => FALSE),
219
				'capability' => 'ee_edit_event_category',
220
				'noheader' => TRUE
221
				),
222
			'category_list' => array(
223
				'func' => '_category_list_table',
224
				'capability' => 'ee_manage_event_categories'
225
				)
226
		);
227
	}
228
229
	protected function _set_page_config() {
230
231
232
233
		$this->_page_config = array(
234
			'default' => array(
235
				'nav' => array(
236
					'label' => __('Overview', 'event_espresso'),
237
					'order' => 10
238
				),
239
				'list_table' => 'Events_Admin_List_Table',
240
				'help_tabs' => array(
241
					'events_overview_help_tab' => array(
242
						'title' => __('Events Overview', 'event_espresso'),
243
						'filename' => 'events_overview'
244
					),
245
					'events_overview_table_column_headings_help_tab' => array(
246
						'title' => __('Events Overview Table Column Headings', 'event_espresso'),
247
						'filename' => 'events_overview_table_column_headings'
248
					),
249
					'events_overview_filters_help_tab' => array(
250
						'title' => __('Events Overview Filters', 'event_espresso'),
251
						'filename' => 'events_overview_filters'
252
					),
253
					'events_overview_view_help_tab' => array(
254
						'title' => __('Events Overview Views', 'event_espresso'),
255
						'filename' => 'events_overview_views'
256
					),
257
					'events_overview_other_help_tab' => array(
258
						'title' => __('Events Overview Other', 'event_espresso'),
259
						'filename' => 'events_overview_other'
260
					)
261
				),
262
				'help_tour' => array(
263
					'Event_Overview_Help_Tour',
264
					//'New_Features_Test_Help_Tour' for testing multiple help tour
265
					),
266
				'qtips' => array(
267
					'EE_Event_List_Table_Tips'
268
					),
269
				'require_nonce' => FALSE
270
			),
271
			'create_new' => array(
272
				'nav' => array(
273
					'label' => __('Add Event', 'event_espresso'),
274
					'order' => 5,
275
					'persistent' => false
276
				),
277
				'metaboxes' => array('_register_event_editor_meta_boxes'),
278
				'help_tabs' => array(
279
					'event_editor_help_tab' => array(
280
						'title' => __('Event Editor', 'event_espresso'),
281
						'filename' => 'event_editor'
282
					),
283
					'event_editor_title_richtexteditor_help_tab' => array(
284
						'title' => __('Event Title & Rich Text Editor', 'event_espresso'),
285
						'filename' => 'event_editor_title_richtexteditor'
286
					),
287
					'event_editor_venue_details_help_tab' => array(
288
						'title' => __('Event Venue Details', 'event_espresso'),
289
						'filename' => 'event_editor_venue_details'
290
					),
291
					'event_editor_event_datetimes_help_tab' => array(
292
						'title' => __('Event Datetimes', 'event_espresso'),
293
						'filename' => 'event_editor_event_datetimes'
294
					),
295
					'event_editor_event_tickets_help_tab' => array(
296
						'title' => __('Event Tickets', 'event_espresso'),
297
						'filename' => 'event_editor_event_tickets'
298
					),
299
					'event_editor_event_registration_options_help_tab' => array(
300
						'title' => __('Event Registration Options', 'event_espresso'),
301
						'filename' => 'event_editor_event_registration_options'
302
					),
303
					'event_editor_tags_categories_help_tab' => array(
304
						'title' => __('Event Tags & Categories', 'event_espresso'),
305
						'filename' => 'event_editor_tags_categories'
306
					),
307
					'event_editor_questions_registrants_help_tab' => array(
308
						'title' => __('Questions for Registrants', 'event_espresso'),
309
						'filename' => 'event_editor_questions_registrants'
310
					),
311
					'event_editor_save_new_event_help_tab' => array(
312
						'title' => __('Save New Event', 'event_espresso'),
313
						'filename' => 'event_editor_save_new_event'
314
					),
315
					'event_editor_other_help_tab' => array(
316
						'title' => __('Event Other', 'event_espresso'),
317
						'filename' => 'event_editor_other'
318
					)
319
				),
320
				'help_tour' => array(
321
					'Event_Editor_Help_Tour'
322
					),
323
				'qtips' => array( 'EE_Event_Editor_Decaf_Tips' ),
324
				'require_nonce' => FALSE
325
			),
326
			'edit' => array(
327
				'nav' => array(
328
					'label' => __('Edit Event', 'event_espresso'),
329
					'order' => 5,
330
					'persistent' => false,
331
					'url' => isset($this->_req_data['post']) ? EE_Admin_Page::add_query_args_and_nonce(array('post' => $this->_req_data['post'], 'action' => 'edit'), $this->_current_page_view_url) : $this->_admin_base_url
332
				),
333
				'metaboxes' => array('_register_event_editor_meta_boxes'),
334
				'help_tabs' => array(
335
					'event_editor_help_tab' => array(
336
						'title' => __('Event Editor', 'event_espresso'),
337
						'filename' => 'event_editor'
338
					),
339
					'event_editor_title_richtexteditor_help_tab' => array(
340
						'title' => __('Event Title & Rich Text Editor', 'event_espresso'),
341
						'filename' => 'event_editor_title_richtexteditor'
342
					),
343
					'event_editor_venue_details_help_tab' => array(
344
						'title' => __('Event Venue Details', 'event_espresso'),
345
						'filename' => 'event_editor_venue_details'
346
					),
347
					'event_editor_event_datetimes_help_tab' => array(
348
						'title' => __('Event Datetimes', 'event_espresso'),
349
						'filename' => 'event_editor_event_datetimes'
350
					),
351
					'event_editor_event_tickets_help_tab' => array(
352
						'title' => __('Event Tickets', 'event_espresso'),
353
						'filename' => 'event_editor_event_tickets'
354
					),
355
					'event_editor_event_registration_options_help_tab' => array(
356
						'title' => __('Event Registration Options', 'event_espresso'),
357
						'filename' => 'event_editor_event_registration_options'
358
					),
359
					'event_editor_tags_categories_help_tab' => array(
360
						'title' => __('Event Tags & Categories', 'event_espresso'),
361
						'filename' => 'event_editor_tags_categories'
362
					),
363
					'event_editor_questions_registrants_help_tab' => array(
364
						'title' => __('Questions for Registrants', 'event_espresso'),
365
						'filename' => 'event_editor_questions_registrants'
366
					),
367
					'event_editor_save_new_event_help_tab' => array(
368
						'title' => __('Save New Event', 'event_espresso'),
369
						'filename' => 'event_editor_save_new_event'
370
					),
371
					'event_editor_other_help_tab' => array(
372
						'title' => __('Event Other', 'event_espresso'),
373
						'filename' => 'event_editor_other'
374
					)
375
				),
376
				/*'help_tour' => array(
377
					'Event_Edit_Help_Tour'
378
				),*/
379
				'qtips' => array( 'EE_Event_Editor_Decaf_Tips' ),
380
				'require_nonce' => FALSE
381
			),
382
			'default_event_settings' => array(
383
				'nav' => array(
384
					'label' => __('Default Settings', 'event_espresso'),
385
					'order' => 40
386
				),
387
				'metaboxes' => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
388
				'labels' => array(
389
					'publishbox' => __('Update Settings', 'event_espresso')
390
				),
391
				'help_tabs' => array(
392
					'default_settings_help_tab' => array(
393
						'title' => __('Default Event Settings', 'event_espresso'),
394
						'filename' => 'events_default_settings'
395
					),
396
					'default_settings_status_help_tab' => array(
397
						'title' => __('Default Registration Status', 'event_espresso'),
398
						'filename' => 'events_default_settings_status'
399
					)
400
				),
401
				'help_tour' => array( 'Event_Default_Settings_Help_Tour'),
402
				'require_nonce' => FALSE
403
			),
404
			//template settings
405
			'template_settings' => array(
406
				'nav' => array(
407
					'label' => __('Templates', 'event_espresso'),
408
					'order' => 30
409
				),
410
				'metaboxes' => $this->_default_espresso_metaboxes,
411
				'help_tabs' => array(
412
					'general_settings_templates_help_tab' => array(
413
						'title' => __('Templates', 'event_espresso'),
414
						'filename' => 'general_settings_templates'
415
					)
416
				),
417
				'help_tour' => array( 'Templates_Help_Tour' ),
418
				'require_nonce' => FALSE
419
			),
420
			//event category stuff
421
			'add_category' => array(
422
				'nav' => array(
423
					'label' => __('Add Category', 'event_espresso'),
424
					'order' => 15,
425
					'persistent' => false),
426
				'help_tabs' => array(
427
					'add_category_help_tab' => array(
428
						'title' => __('Add New Event Category', 'event_espresso'),
429
						'filename' => 'events_add_category'
430
						)
431
					),
432
			'help_tour' => array('Event_Add_Category_Help_Tour'),
433
				'metaboxes' => array('_publish_post_box'),
434
				'require_nonce' => FALSE
435
				),
436
			'edit_category' => array(
437
				'nav' => array(
438
					'label' => __('Edit Category', 'event_espresso'),
439
					'order' => 15,
440
					'persistent' => FALSE,
441
					'url' => isset($this->_req_data['EVT_CAT_ID']) ? add_query_arg(array('EVT_CAT_ID' => $this->_req_data['EVT_CAT_ID'] ), $this->_current_page_view_url )  : $this->_admin_base_url
442
					),
443
				'help_tabs' => array(
444
					'edit_category_help_tab' => array(
445
						'title' => __('Edit Event Category', 'event_espresso'),
446
						'filename' => 'events_edit_category'
447
						)
448
					),
449
				/*'help_tour' => array('Event_Edit_Category_Help_Tour'),*/
450
					'metaboxes' => array('_publish_post_box'),
451
					'require_nonce' => FALSE
452
					),
453
			'category_list' => array(
454
				'nav' => array(
455
					'label' => __('Categories', 'event_espresso'),
456
					'order' => 20
457
					),
458
				'list_table' => 'Event_Categories_Admin_List_Table',
459
				'help_tabs' => array(
460
					'events_categories_help_tab' => array(
461
						'title' => __('Event Categories', 'event_espresso'),
462
						'filename' => 'events_categories'
463
					),
464
					'events_categories_table_column_headings_help_tab' => array(
465
						'title' => __('Event Categories Table Column Headings', 'event_espresso'),
466
						'filename' => 'events_categories_table_column_headings'
467
					),
468
					'events_categories_view_help_tab' => array(
469
						'title' => __('Event Categories Views', 'event_espresso'),
470
						'filename' => 'events_categories_views'
471
					),
472
					'events_categories_other_help_tab' => array(
473
						'title' => __('Event Categories Other', 'event_espresso'),
474
						'filename' => 'events_categories_other'
475
					)
476
				),
477
				'help_tour' => array(
478
					'Event_Categories_Help_Tour'
479
					),
480
				'metaboxes' => $this->_default_espresso_metaboxes,
481
				'require_nonce' => FALSE
482
				),
483
		);
484
	}
485
486
487
	protected function _add_screen_options() {
488
		//todo
489
	}
490
491
	protected function _add_screen_options_default() {
492
		$this->_per_page_screen_option();
493
	}
494
495 View Code Duplication
	protected function _add_screen_options_category_list() {
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...
496
		$page_title = $this->_admin_page_title;
497
		$this->_admin_page_title = __('Categories', 'event_espresso');
498
		$this->_per_page_screen_option();
499
		$this->_admin_page_title = $page_title;
500
	}
501
502
	protected function _add_feature_pointers() {
503
		//todo
504
	}
505
506
507
508
509
	public function load_scripts_styles() {
510
511
		wp_register_style('events-admin-css', EVENTS_ASSETS_URL . 'events-admin-page.css', array(), EVENT_ESPRESSO_VERSION);
512
		wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION );
513
		wp_enqueue_style('events-admin-css');
514
		wp_enqueue_style('ee-cat-admin');
515
		//todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
516
		//registers for all views
517
		//scripts
518
		wp_register_script('event_editor_js', EVENTS_ASSETS_URL . 'event_editor.js', array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'), EVENT_ESPRESSO_VERSION, TRUE);
519
	}
520
521
	/**
522
	 * enqueuing scripts and styles specific to this view
523
	 * @return void
524
	 */
525
	public function load_scripts_styles_create_new() {
526
		$this->load_scripts_styles_edit();
527
	}
528
529
	/**
530
	 * enqueuing scripts and styles specific to this view
531
	 * @return void
532
	 */
533 View Code Duplication
	public function load_scripts_styles_edit() {
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...
534
		//styles
535
		wp_enqueue_style('espresso-ui-theme');
536
		wp_register_style('event-editor-css', EVENTS_ASSETS_URL . 'event-editor.css', array('ee-admin-css'), EVENT_ESPRESSO_VERSION );
537
		wp_enqueue_style('event-editor-css');
538
539
		//scripts
540
		wp_register_script('event-datetime-metabox', EVENTS_ASSETS_URL . 'event-datetime-metabox.js', array('event_editor_js', 'ee-datepicker'), EVENT_ESPRESSO_VERSION );
541
		wp_enqueue_script('event-datetime-metabox');
542
543
	}
544
545
546
547
	public function load_scripts_styles_add_category() {
548
		$this->load_scripts_styles_edit_category();
549
	}
550
551
552
553
554
555
	public function load_scripts_styles_edit_category() {}
556
557
558
559 View Code Duplication
	protected function _set_list_table_views_category_list() {
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...
560
		$this->_views = array(
561
			'all' => array(
562
				'slug' => 'all',
563
				'label' => __('All', 'event_espresso'),
564
				'count' => 0,
565
				'bulk_action' => array(
566
					'delete_categories' => __('Delete Permanently', 'event_espresso')
567
					)
568
				)
569
		);
570
	}
571
572
573
574
	public function admin_init() {
575
		EE_Registry::$i18n_js_strings[ 'image_confirm' ] = __( 'Do you really want to delete this image? Please remember to update your event to complete the removal.', 'event_espresso' );
576
	}
577
578
579
580
	//nothing needed for events with these methods.
581
	public function admin_notices() {}
582
	public function admin_footer_scripts() {}
583
584
585
586
587
	/**
588
	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a warning (via EE_Error::add_error());
589
	 *
590
	 * @param  EE_Event    $event 	Event object
591
	 * @access public
592
	 * @return void
593
	 */
594
	public function verify_event_edit($event = NULL) {
595
		// no event?
596
		if ( empty( $event )) {
597
			// set event
598
			$event = $this->_cpt_model_obj;
599
		}
600
		// STILL no event?
601
		if ( empty ( $event )) {
602
			return;
603
		}
604
		// first check if event is active.
605
		if ( $event->is_expired() || $event->is_inactive() || $event->status() == EEM_Event::cancelled || $event->status() == EEM_Event::postponed ) {
0 ignored issues
show
Documentation Bug introduced by
The method is_expired does not exist on object<EE_CPT_Base>? 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...
Documentation Bug introduced by
The method is_inactive does not exist on object<EE_CPT_Base>? 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...
606
			return;
607
		}
608
		$orig_status = $event->status();
609
		//made it here so it IS active... next check that any of the tickets are sold.
610
		if ( $event->is_sold_out( true ) ) {
0 ignored issues
show
Documentation Bug introduced by
The method is_sold_out does not exist on object<EE_CPT_Base>? 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...
611 View Code Duplication
			if ( $event->status() !== $orig_status && $orig_status !== EEM_Event::sold_out  ) {
612
				EE_Error::add_attention(
613
					sprintf(
614
						__( 'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.', 'event_espresso' ),
615
						EEH_Template::pretty_status( EEM_Event::sold_out, FALSE, 'sentence' )
616
					)
617
				);
618
			}
619
			return;
620 View Code Duplication
		} else if ( $orig_status === EEM_Event::sold_out ) {
621
			EE_Error::add_attention(
622
				sprintf(
623
					__( 'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
624
						'event_espresso' ),
625
					EEH_Template::pretty_status( $event->status(), false, 'sentence' )
0 ignored issues
show
Documentation introduced by
$event->status() 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...
626
				)
627
			);
628
		}
629
		//now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
630
		if ( ! $event->tickets_on_sale() ) {
0 ignored issues
show
Documentation Bug introduced by
The method tickets_on_sale does not exist on object<EE_CPT_Base>? 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...
631
			return;
632
		}
633
		//made it here so show warning
634
		EE_Error::add_attention( $this->_edit_event_warning() );
635
	}
636
637
638
639
640
	/**
641
	 * This is the text used for when an event is being edited that is public and has tickets for sale.
642
	 * When needed, hook this into a EE_Error::add_error() notice.
643
	 *
644
	 * @access protected
645
	 * @return string
646
	 */
647
	protected function _edit_event_warning() {
648
		return __('Please be advised that this event has been published and is open for registrations on your website. If you update any registration-related details (i.e. custom questions, messages, tickets, datetimes, etc.) while a registration is in process, the registration process could be interrupted and result in errors for the person registering and potentially incorrect registration or transaction data inside Event Espresso. We recommend editing events during a period of slow traffic, or even temporarily changing the status of an event to "Draft" until your edits are complete.', 'event_espresso');
649
	}
650
651
652
653
654
	protected function _set_list_table_views_default() {
655
		$this->_views = array(
656
			'all' => array(
657
				'slug' => 'all',
658
				'label' => __('View All Events', 'event_espresso'),
659
				'count' => 0,
660
				'bulk_action' => array(
661
					'trash_events' => __('Move to Trash', 'event_espresso')
662
				)
663
			),
664
			'draft' => array(
665
				'slug' => 'draft',
666
				'label' => __('Draft', 'event_espresso'),
667
				'count' => 0,
668
				'bulk_action' => array(
669
					'trash_events' => __('Move to Trash', 'event_espresso'),
670
					)
671
			),
672
		);
673
674
		if ( EE_Registry::instance()->CAP->current_user_can( 'ee_delete_events', 'espresso_events_trash_events' ) ) {
675
			$this->_views['trash'] = array(
676
				'slug' => 'trash',
677
				'label' => __('Trash', 'event_espresso'),
678
				'count' => 0,
679
				'bulk_action' => array(
680
					'restore_events' => __('Restore From Trash', 'event_espresso'),
681
					'delete_events' => __('Delete Permanently', 'event_espresso')
682
					)
683
				);
684
		}
685
	}
686
687
688
689
	protected function _event_legend_items() {
690
		$items = array(
691
			'view_details' => array(
692
				'class' => 'dashicons dashicons-search',
693
				'desc' => __('View Event', 'event_espresso')
694
			),
695
			'edit_event' => array(
696
				'class' => 'ee-icon ee-icon-calendar-edit',
697
				'desc' => __('Edit Event Details', 'event_espresso')
698
			),
699
			'view_attendees' => array(
700
				'class' => 'dashicons dashicons-groups',
701
				'desc' => __('View Registrations for Event', 'event_espresso')
702
			)
703
		);
704
		$items  = apply_filters( 'FHEE__Events_Admin_Page___event_legend_items__items', $items );
705
		$statuses = array(
706
			'sold_out_status' => array(
707
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
708
				'desc' => EEH_Template::pretty_status( EE_Datetime::sold_out, FALSE, 'sentence' )
709
			),
710
			'active_status' => array(
711
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
712
				'desc' => EEH_Template::pretty_status( EE_Datetime::active, FALSE, 'sentence' )
713
			),
714
			'upcoming_status' => array(
715
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
716
				'desc' => EEH_Template::pretty_status( EE_Datetime::upcoming, FALSE, 'sentence' )
717
			),
718
			'postponed_status' => array(
719
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
720
				'desc' => EEH_Template::pretty_status( EE_Datetime::postponed, FALSE, 'sentence' )
721
			),
722
			'cancelled_status' => array(
723
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
724
				'desc' => EEH_Template::pretty_status( EE_Datetime::cancelled, FALSE, 'sentence' )
725
			),
726
			'expired_status' => array(
727
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
728
				'desc' => EEH_Template::pretty_status( EE_Datetime::expired, FALSE, 'sentence' )
729
			),
730
			'inactive_status' => array(
731
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
732
				'desc' => EEH_Template::pretty_status( EE_Datetime::inactive, FALSE, 'sentence' )
733
			)
734
		);
735
		$statuses = apply_filters( 'FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses );
736
		return array_merge( $items, $statuses );
737
	}
738
739
740
741
742
743
	/**
744
	 * _event_model
745
	 * @return EEM_Event
746
	 */
747
	private function _event_model() {
748
		if ( ! $this->_event_model instanceof EEM_Event ) {
749
			$this->_event_model = EE_Registry::instance()->load_model( 'Event' );
0 ignored issues
show
Documentation Bug introduced by
It seems like \EE_Registry::instance()->load_model('Event') of type boolean is incompatible with the declared type object of property $_event_model.

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

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

Loading history...
750
		}
751
		return $this->_event_model;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_event_model; of type boolean|EEM_Event adds the type boolean to the return on line 751 which is incompatible with the return type documented by Events_Admin_Page::_event_model of type EEM_Event.
Loading history...
752
	}
753
754
755
756
757
758
	/**
759
	 * Adds extra buttons to the WP CPT permalink field row.
760
	 *
761
	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
762
	 * @param  string $return    the current html
763
	 * @param  int    $id        the post id for the page
764
	 * @param  string $new_title What the title is
765
	 * @param  string $new_slug  what the slug is
766
	 * @return string            The new html string for the permalink area
767
	 */
768
	public function extra_permalink_field_buttons( $return, $id, $new_title, $new_slug ) {
769
		//make sure this is only when editing
770
		if ( !empty( $id ) ) {
771
			$post = get_post( $id );
772
			$return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">' . __('Shortcode', 'event_espresso') . '</a> ';
773
			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id=' . $post->ID . ']">';
774
		}
775
		return $return;
776
	}
777
778
779
780
781
	/**
782
	 * _events_overview_list_table
783
	 * This contains the logic for showing the events_overview list
784
	 *
785
	 * @access protected
786
	 * @return string html for generated table
787
	 */
788
	protected function _events_overview_list_table() {
789
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
790
		$this->_template_args['after_list_table'] = EEH_Template::get_button_or_link( get_post_type_archive_link('espresso_events'), __("View Event Archive Page", "event_espresso"), 'button' ) .
791
		$this->_display_legend($this->_event_legend_items());
792
		$this->_admin_page_title .= $this->get_action_link_or_button('create_new', 'add', array(), 'add-new-h2');
793
		$this->display_admin_list_table_page_with_no_sidebar();
794
	}
795
796
797
	/**
798
	 * this allows for extra misc actions in the default WP publish box
799
	 * @return string html to add
800
	 */
801
	public function extra_misc_actions_publish_box() {
802
		$this->_generate_publish_box_extra_content();
803
	}
804
805
806
807
808
	protected function _insert_update_cpt_item( $post_id, $post ) {
809
810
		if ( $post instanceof WP_Post && $post->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...
811
			//getout we're not processing an event save.
812
			return;
813
		}
814
815
		$event_values = array(
816
			'EVT_display_desc' => !empty( $this->_req_data['display_desc'] ) ? 1 : 0,
817
			'EVT_display_ticket_selector' => !empty( $this->_req_data['display_ticket_selector'] ) ? 1 : 0,
818
			'EVT_additional_limit' => min(
819
					apply_filters( 'FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255 ),
820
					!empty( $this->_req_data['additional_limit'] ) ? $this->_req_data['additional_limit'] : NULL ),
821
			'EVT_default_registration_status' => !empty( $this->_req_data['EVT_default_registration_status'] ) ? $this->_req_data['EVT_default_registration_status'] : EE_Registry::instance()->CFG->registration->default_STS_ID,
822
			'EVT_member_only' => !empty( $this->_req_data['member_only'] ) ? 1 : 0,
823
			'EVT_allow_overflow' => !empty( $this->_req_data['EVT_allow_overflow'] ) ? 1 : 0,
824
			'EVT_timezone_string' => !empty( $this->_req_data['timezone_string'] ) ? $this->_req_data['timezone_string'] : NULL,
825
			'EVT_external_URL' => !empty( $this->_req_data['externalURL'] ) ? $this->_req_data['externalURL'] : NULL,
826
			'EVT_phone' => !empty( $this->_req_data['event_phone'] ) ? $this->_req_data['event_phone'] : NULL
827
			);
828
829
		//update event
830
		$success = $this->_event_model()->update_by_ID( $event_values, $post_id );
831
832
833
		//get event_object for other metaboxes... though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id ).. i have to setup where conditions to override the filters in the model that filter out autodraft and inherit statuses so we GET the inherit id!
834
		$get_one_where = array( $this->_event_model()->primary_key_name() => $post_id, 'status' => $post->post_status );
835
		$event = $this->_event_model()->get_one( array($get_one_where) );
836
837
838
		//the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
839
		$event_update_callbacks = apply_filters( 'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks', array( array($this, '_default_venue_update' ), array( $this, '_default_tickets_update') ) );
840
841
		$att_success = TRUE;
842
843 View Code Duplication
		foreach ( $event_update_callbacks as $e_callback ) {
844
			$_succ = call_user_func_array( $e_callback, array( $event,  $this->_req_data ) );
845
			$att_success = !$att_success ? $att_success : $_succ; //if ANY of these updates fail then we want the appropriate global error message
846
		}
847
848
		//any errors?
849
		if ( $success && FALSE === $att_success ) {
850
			EE_Error::add_error( __('Event Details saved successfully but something went wrong with saving attachments.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
851
		} else if ( $success === FALSE ) {
852
			EE_Error::add_error( __('Event Details did not save successfully.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
853
		}
854
	}
855
856
857
858
859
	/**
860
	 * @see parent::restore_item()
861
	 */
862
	protected function _restore_cpt_item( $post_id, $revision_id ) {
863
		//copy existing event meta to new post
864
		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
865
		if ( $post_evt instanceof EE_Event ) {
866
			//meta revision restore
867
			$post_evt->restore_revision( $revision_id );
868
			//related objs restore
869
			$post_evt->restore_revision( $revision_id, array( 'Venue', 'Datetime', 'Price' ) );
870
		}
871
	}
872
873
874
875
876
	/**
877
	 * Attach the venue to the Event
878
	 * @param  object $evtobj Event Object to add the venue to
879
	 * @param  array  $data   The request data from the form
880
	 * @return bool           Success or fail.
881
	 */
882
	protected function _default_venue_update( $evtobj, $data ) {
883
		require_once( EE_MODELS . 'EEM_Venue.model.php' );
884
		$venue_model = EE_Registry::instance()->load_model('Venue');
885
		$rows_affected = NULL;
0 ignored issues
show
Unused Code introduced by
$rows_affected is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
886
		$venue_id = !empty( $data['venue_id'] ) ? $data['venue_id'] : NULL;
887
888
		// very important.  If we don't have a venue name...
889
		// then we'll get out because not necessary to create empty venue
890
		if ( empty( $data['venue_title'] ) ) {
891
			return false;
892
		}
893
894
		$venue_array = array(
895
				'VNU_wp_user' => $evtobj->get('EVT_wp_user'),
896
				'VNU_name' => !empty( $data['venue_title'] ) ? $data['venue_title'] : NULL,
897
				'VNU_desc' => !empty( $data['venue_description'] ) ? $data['venue_description'] : NULL,
898
				'VNU_identifier' => !empty( $data['venue_identifier'] ) ? $data['venue_identifier'] : NULL,
899
				'VNU_short_desc' => !empty( $data['venue_short_description'] ) ? $data['venue_short_description'] : NULL,
900
				'VNU_address' => !empty( $data['address'] ) ? $data['address'] : NULL,
901
				'VNU_address2' => !empty( $data['address2'] ) ? $data['address2'] : NULL,
902
				'VNU_city' => !empty( $data['city'] ) ? $data['city'] : NULL,
903
				'STA_ID' => !empty( $data['state'] ) ? $data['state'] : NULL,
904
				'CNT_ISO' => !empty( $data['countries'] ) ? $data['countries'] : NULL,
905
				'VNU_zip' => !empty( $data['zip'] ) ? $data['zip'] : NULL,
906
				'VNU_phone' => !empty( $data['venue_phone'] ) ? $data['venue_phone'] : NULL,
907
				'VNU_capacity' => !empty( $data['venue_capacity'] ) ? $data['venue_capacity'] : NULL,
908
				'VNU_url' => !empty($data['venue_url'] ) ? $data['venue_url'] : NULL,
909
				'VNU_virtual_phone' => !empty($data['virtual_phone']) ? $data['virtual_phone'] : NULL,
910
				'VNU_virtual_url' => !empty( $data['virtual_url'] ) ? $data['virtual_url'] : NULL,
911
				'VNU_enable_for_gmap' => isset( $data['enable_for_gmap'] ) ? 1 : 0,
912
				'status' => 'publish'
913
			);
914
915
916
		//if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
917
		if ( !empty( $venue_id ) ) {
918
			$update_where = array( $venue_model->primary_key_name() => $venue_id );
0 ignored issues
show
Bug introduced by
The method primary_key_name cannot be called on $venue_model (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...
919
			$rows_affected = $venue_model->update( $venue_array, array( $update_where ) );
0 ignored issues
show
Bug introduced by
The method update cannot be called on $venue_model (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...
920
			//we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
921
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
922
			return $rows_affected > 0 ? TRUE : FALSE;
923
		} else {
924
			//we insert the venue
925
			$venue_id = $venue_model->insert( $venue_array );
0 ignored issues
show
Bug introduced by
The method insert cannot be called on $venue_model (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...
926
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
927
			return !empty( $venue_id ) ? TRUE : FALSE;
928
		}
929
		//when we have the ancestor come in it's already been handled by the revision save.
930
	}
931
932
933
934
935
	/**
936
	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
937
	 * @param  EE_Event $evtobj The Event object we're attaching data to
938
	 * @param  array    $data   The request data from the form
939
	 * @return bool             success or fail
940
	 */
941
	protected function _default_tickets_update( EE_Event $evtobj, $data ) {
942
		$success = true;
943
		$saved_dtt = null;
944
		$saved_tickets = array();
945
		$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
946
947
		foreach ( $data['edit_event_datetimes'] as $row => $dtt ) {
948
			//trim all values to ensure any excess whitespace is removed.
949
			$dtt =  array_map( 'trim', $dtt );
950
			$dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty( $dtt['DTT_EVT_end'] ) ? $dtt['DTT_EVT_end'] : $dtt['DTT_EVT_start'];
951
			$datetime_values = array(
952
				'DTT_ID' 		=> ! empty( $dtt['DTT_ID'] ) ? $dtt['DTT_ID'] : NULL,
953
				'DTT_EVT_start' => $dtt['DTT_EVT_start'],
954
				'DTT_EVT_end' 	=> $dtt['DTT_EVT_end'],
955
				'DTT_reg_limit' => empty( $dtt['DTT_reg_limit'] ) ? EE_INF : $dtt['DTT_reg_limit'],
956
				'DTT_order' 	=> $row,
957
			);
958
959
			//if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
960
961
			if ( !empty( $dtt['DTT_ID'] ) ) {
962
				$DTM = EE_Registry::instance()->load_model('Datetime', array( $evtobj->get_timezone() ) )->get_one_by_ID($dtt['DTT_ID'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()...vtobj->get_timezone())) (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...
963
				$DTM->set_date_format( $incoming_date_formats[0] );
964
				$DTM->set_time_format( $incoming_date_formats[1] );
965
				foreach ( $datetime_values as $field => $value ) {
966
					$DTM->set( $field, $value );
967
				}
968
969
				//make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
970
				$saved_dtts[$DTM->ID()] = $DTM;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$saved_dtts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $saved_dtts = 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...
971
			} else {
972
				$DTM = EE_Registry::instance()->load_class('Datetime', array( $datetime_values ), FALSE, FALSE );
973
				$DTM->set_date_format( $incoming_date_formats[0] );
0 ignored issues
show
Bug introduced by
The method set_date_format cannot be called on $DTM (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...
974
				$DTM->set_time_format( $incoming_date_formats[1] );
0 ignored issues
show
Bug introduced by
The method set_time_format cannot be called on $DTM (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...
975
				$DTM->set_timezone( $evtobj->get_timezone() );
0 ignored issues
show
Bug introduced by
The method set_timezone cannot be called on $DTM (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...
976
				foreach ( $datetime_values as $field => $value ) {
977
					$DTM->set( $field, $value );
0 ignored issues
show
Bug introduced by
The method set cannot be called on $DTM (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...
978
				}
979
			}
980
			$DTM->save();
981
982
			$DTT = $evtobj->_add_relation_to( $DTM, 'Datetime' );
983
984
			//load DTT helper
985
			EE_Registry::instance()->load_helper('DTT_Helper');
986
987
			//before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
988
			if( $DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end') ) {
989
				$DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start') );
990
				$DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
991
				$DTT->save();
992
			}
993
994
			//now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
995
			$saved_dtt = $DTT;
996
997
			$success = !$success ? $success : $DTT; //if ANY of these updates fail then we want the appropriate global error message. //todod this is actually sucky we need a better error message but this is what it is for now.
998
		}
999
1000
		//no dtts get deleted so we don't do any of that logic here.
1001
		//update tickets next
1002
		$old_tickets = isset( $data['ticket_IDs'] ) ? explode(',', $data['ticket_IDs'] ) : array();
1003
		foreach ( $data['edit_tickets'] as $row => $tkt ) {
1004
			$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
1005
			$update_prices = false;
1006
			$ticket_price = isset( $data['edit_prices'][$row][1]['PRC_amount'] ) ? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
1007
1008
			// trim inputs to ensure any excess whitespace is removed.
1009
			$tkt = array_map( 'trim', $tkt );
1010
1011
			if ( empty( $tkt['TKT_start_date'] ) ) {
1012
				//let's use now in the set timezone.
1013
				$now = new DateTime( 'now', new DateTimeZone( $evtobj->get_timezone() ) );
1014
				$tkt['TKT_start_date'] = $now->format( $incoming_date_formats[0] . ' ' . $incoming_date_formats[1] );
1015
			}
1016
1017
			if ( empty( $tkt['TKT_end_date'] ) ) {
1018
				//use the start date of the first datetime
1019
				$dtt = $evtobj->first_datetime();
1020
				$tkt['TKT_end_date'] = $dtt->start_date_and_time( $incoming_date_formats[0], $incoming_date_formats[1] );
1021
			}
1022
1023
			$TKT_values = array(
1024
				'TKT_ID' 			=> !empty( $tkt['TKT_ID'] ) ? $tkt['TKT_ID'] : NULL,
1025
				'TTM_ID' 			=> !empty( $tkt['TTM_ID'] ) ? $tkt['TTM_ID'] : 0,
1026
				'TKT_name' 			=> !empty( $tkt['TKT_name'] ) ? $tkt['TKT_name'] : '',
1027
				'TKT_description' 	=> !empty( $tkt['TKT_description'] ) ? $tkt['TKT_description'] : '',
1028
				'TKT_start_date' 	=> $tkt['TKT_start_date'],
1029
				'TKT_end_date' 		=> $tkt['TKT_end_date'],
1030
				'TKT_qty' 			=> ! isset( $tkt[ 'TKT_qty' ] ) || $tkt[ 'TKT_qty' ] === '' ? EE_INF : $tkt['TKT_qty'],
1031
				'TKT_uses' 			=> ! isset( $tkt[ 'TKT_uses' ] ) || $tkt[ 'TKT_uses' ] === '' ? EE_INF : $tkt[ 'TKT_uses' ],
1032
				'TKT_min' 			=> empty( $tkt['TKT_min'] ) ? 0 : $tkt['TKT_min'],
1033
				'TKT_max' 			=> empty( $tkt['TKT_max'] ) ? EE_INF : $tkt['TKT_max'],
1034
				'TKT_row' 			=> $row,
1035
				'TKT_order' 		=> isset( $tkt['TKT_order'] ) ? $tkt['TKT_order'] : $row,
1036
				'TKT_price' 		=> $ticket_price
1037
			);
1038
1039
1040
1041
1042
			//if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
1043 View Code Duplication
			if ( isset( $tkt['TKT_is_default'] ) && $tkt['TKT_is_default'] ) {
1044
				$TKT_values['TKT_ID'] = 0;
1045
				$TKT_values['TKT_is_default'] = 0;
1046
				$TKT_values['TKT_price'] = $ticket_price;
1047
				$update_prices = TRUE;
1048
			}
1049
1050
			//if we have a TKT_ID then we need to get that existing TKT_obj and update it
1051
			//we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1052
			//keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1053
1054
			if ( !empty( $tkt['TKT_ID'] ) ) {
1055
				$TKT = EE_Registry::instance()->load_model( 'Ticket', array( $evtobj->get_timezone() ) )->get_one_by_ID( $tkt['TKT_ID'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()...vtobj->get_timezone())) (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...
1056
				if ( $TKT instanceof EE_Ticket ) {
1057
					$ticket_sold = $TKT->count_related( 'Registration', array( array( 'STS_ID' => array( 'NOT IN', array( EEM_Registration::status_id_incomplete ) ) ) ) ) > 0 ? true : false;
1058
					//let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
1059
					$create_new_TKT = $ticket_sold && $ticket_price != $TKT->get( 'TKT_price' ) && ! $TKT->get( 'TKT_deleted' ) ? true : false;
1060
					$TKT->set_date_format( $incoming_date_formats[ 0 ] );
1061
					$TKT->set_time_format( $incoming_date_formats[ 1 ] );
1062
					//set new values
1063 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1064
						if ( $field == 'TKT_qty' ) {
1065
							$TKT->set_qty( $value );
1066
						} else {
1067
							$TKT->set( $field, $value );
1068
						}
1069
					}
1070
					//if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1071
					if ( $create_new_TKT ) {
1072
						//archive the old ticket first
1073
						$TKT->set( 'TKT_deleted', 1 );
1074
						$TKT->save();
1075
						//make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1076
						$saved_tickets[ $TKT->ID() ] = $TKT;
1077
						//create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1078
						$TKT = clone $TKT;
1079
						$TKT->set( 'TKT_ID', 0 );
1080
						$TKT->set( 'TKT_deleted', 0 );
1081
						$TKT->set( 'TKT_price', $ticket_price );
1082
						$TKT->set( 'TKT_sold', 0 );
1083
						//now we need to make sure that $new prices are created as well and attached to new ticket.
1084
						$update_prices = true;
1085
					}
1086
					//make sure price is set if it hasn't been already
1087
					$TKT->set( 'TKT_price', $ticket_price );
1088
				}
1089
1090
			} else {
1091
				//no TKT_id so a new TKT
1092
				$TKT_values['TKT_price'] = $ticket_price;
1093
				$TKT = EE_Registry::instance()->load_class('Ticket', array( $TKT_values ), FALSE, FALSE );
1094
				if ( $TKT instanceof EE_Ticket ) {
1095
					//need to reset values to properly account for the date formats
1096
					$TKT->set_date_format( $incoming_date_formats[0] );
1097
					$TKT->set_time_format( $incoming_date_formats[1] );
1098
					$TKT->set_timezone( $evtobj->get_timezone() );
1099
1100
					//set new values
1101 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1102
						if ( $field == 'TKT_qty' ) {
1103
							$TKT->set_qty( $value );
1104
						} else {
1105
							$TKT->set( $field, $value );
1106
						}
1107
					}
1108
1109
					$update_prices = TRUE;
1110
				}
1111
			}
1112
			// cap ticket qty by datetime reg limits
1113
			$TKT->set_qty( min( $TKT->qty(), $TKT->qty( 'reg_limit' ) ) );
1114
			//update ticket.
1115
			$TKT->save();
1116
1117
			//before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1118 View Code Duplication
			if( $TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date') ) {
1119
				$TKT->set('TKT_end_date', $TKT->get('TKT_start_date') );
1120
				EE_Registry::instance()->load_helper('DTT_Helper');
1121
				$TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1122
				$TKT->save();
1123
			}
1124
1125
			//initially let's add the ticket to the dtt
1126
			$saved_dtt->_add_relation_to( $TKT, 'Ticket' );
1127
1128
			$saved_tickets[$TKT->ID()] = $TKT;
1129
1130
			//add prices to ticket
1131
			$this->_add_prices_to_ticket( $data['edit_prices'][$row], $TKT, $update_prices );
1132
		}
1133
		//however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1134
		$old_tickets = isset( $old_tickets[0] ) && $old_tickets[0] == '' ? array() : $old_tickets;
1135
		$tickets_removed = array_diff( $old_tickets, array_keys( $saved_tickets ) );
1136
1137 View Code Duplication
		foreach ( $tickets_removed as $id ) {
1138
			$id = absint( $id );
1139
1140
			//get the ticket for this id
1141
			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
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...
1142
1143
			//need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
1144
			$dtts = $tkt_to_remove->get_many_related('Datetime');
1145
1146
			foreach( $dtts as $dtt ) {
1147
				$tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1148
			}
1149
1150
			//need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1151
			$tkt_to_remove->delete_related_permanently('Price');
1152
1153
1154
			//finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1155
			$tkt_to_remove->delete_permanently();
1156
		}
1157
		return array( $saved_dtt, $saved_tickets );
1158
	}
1159
1160
1161
1162
	/**
1163
	 * This attaches a list of given prices to a ticket.
1164
	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1165
	 *
1166
	 * @access  private
1167
	 * @param array  	$prices  	Array of prices from the form.
1168
	 * @param EE_Ticket $ticket  	EE_Ticket object that prices are being attached to.
1169
	 * @param bool 		$new_prices Whether attach existing incoming prices or create new ones.
1170
	 * @return  void
1171
	 */
1172
	private function  _add_prices_to_ticket( $prices, EE_Ticket $ticket, $new_prices = FALSE ) {
1173
		foreach ( $prices as $row => $prc ) {
1174
			$PRC_values = array(
1175
				'PRC_ID' => !empty( $prc['PRC_ID'] ) ? $prc['PRC_ID'] : NULL,
1176
				'PRT_ID' => !empty( $prc['PRT_ID'] ) ? $prc['PRT_ID'] : NULL,
1177
				'PRC_amount' => !empty( $prc['PRC_amount'] ) ? $prc['PRC_amount'] : 0,
1178
				'PRC_name' => !empty( $prc['PRC_name'] ) ? $prc['PRC_name'] : '',
1179
				'PRC_desc' => !empty( $prc['PRC_desc'] ) ? $prc['PRC_desc'] : '',
1180
				'PRC_is_default' => 0, //make sure prices are NOT set as default from this context
1181
				'PRC_order' => $row
1182
			);
1183
1184 View Code Duplication
			if ( $new_prices || empty( $PRC_values['PRC_ID'] ) ) {
1185
				$PRC_values['PRC_ID'] = 0;
1186
				$PRC = EE_Registry::instance()->load_class('Price', array( $PRC_values ), FALSE, FALSE);
1187
			} else {
1188
				$PRC = EE_Registry::instance()->load_model( 'Price' )->get_one_by_ID( $prc['PRC_ID'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()->load_model('Price') (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...
1189
				//update this price with new values
1190
				foreach ( $PRC_values as $field => $newprc ) {
1191
					$PRC->set( $field, $newprc );
1192
				}
1193
				$PRC->save();
1194
			}
1195
1196
			$ticket->_add_relation_to( $PRC, 'Price' );
1197
		}
1198
	}
1199
1200
1201
1202
1203
	/**
1204
	 * Add in our autosave ajax handlers
1205
	 * @return void
1206
	 */
1207
	protected function _ee_autosave_create_new() {
1208
		$this->_ee_autosave_edit();
1209
	}
1210
1211
1212
1213
1214
1215
	protected function _ee_autosave_edit() {
1216
1217
		return; //TEMPORARILY EXITING CAUSE THIS IS A TODO
1218
1219
		$postid = isset( $this->_req_data['post_ID'] ) ? $this->_req_data['post_ID'] : NULL;
0 ignored issues
show
Unused Code introduced by
//TEMPORARILY EXITING CA...data['post_ID'] : NULL; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1220
1221
1222
		//if no postid then get out cause we need it for stuff in here
1223
		if ( empty( $postid ) ) return;
0 ignored issues
show
Bug introduced by
The variable $postid seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1224
1225
1226
		//handle datetime saves
1227
		$items = array();
0 ignored issues
show
Unused Code introduced by
$items is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1228
1229
		$get_one_where = array( $this->_event_model()->primary_key_name() => $postid );
1230
		$event = $this->_event_model()->get_one( array($get_one_where) );
1231
1232
		//now let's get the attached datetimes from the most recent autosave
1233
		$dtts = $event->get_many_related('Datetime');
1234
1235
		$dtt_ids = array();
1236
		foreach( $dtts as $dtt ) {
1237
			$dtt_ids[] = $dtt->ID();
1238
			$order = $dtt->order();
1239
			$this->_template_args['data']['items']['ID-'.$order] = $dtt->ID();
1240
		}
1241
		$this->_template_args['data']['items']['datetime_IDS'] = serialize( $dtt_ids );
1242
1243
		//handle DECAF venues
1244
		//we need to make sure that the venue_id gets updated in the form so that future autosaves will properly conntect that venue to the event.
1245
		if ( $do_venue_autosaves = apply_filters( 'FHEE__Events_Admin_Page__ee_autosave_edit_do_decaf_venue_save', TRUE ) ) {
0 ignored issues
show
Unused Code introduced by
$do_venue_autosaves is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1246
			$venue = $event->get_first_related('Venue');
1247
			$this->_template_args['data']['items']['venue-id'] = $venue->ID();
1248
		}
1249
1250
1251
		//handle ticket updates.
1252
		$tickets = $event->get_many_related('Ticket');
1253
1254
		$ticket_ids = array();
1255
		$price_ids = array();
1256
		foreach ( $tickets as $ticket ) {
1257
			$ticket_ids[] = $price->ID();
1258
			$ticket_order = $price->get('TKT_order');
1259
			$this->_template_args['data']['items']['edit-ticket-id-' . $ticket_order] = $ticket->ID();
1260
			$this->_template_args['data']['items']['edit-ticket-event-id-' . $order] = $event->ID();
1261
1262
			//now we have to make sure the prices are updated appropriately
1263
			$prices = $ticket->get_many_related('Prices');
1264
1265
			foreach ( $prices as $price ) {
1266
				$price_ids[] = $price->ID();
1267
				$price_order = $price->get('PRC_order');
1268
				$this->_template_args['data']['items']['quick-edit-ticket-price-id-ticketrow-' . $ticket_order . '-' . $price_order] = $price->ID();
1269
				$this->_template_args['data']['items']['edit-ticket-price-id-ticketrow-' . $ticket_row . '-' . $price_row] = $price->ID();
1270
				$this->_template_args['data']['items']['edit-ticket-price-is-default-ticketrow-' . $ticket_row . '-' . $price_row] = $price->get('PRC_is_default');
1271
			}
1272
			$this->_template_args['data']['items']['price-IDs-ticketrow-' . $ticket_row] = implode(',', $price_ids);
1273
		}
1274
		$this->_template_args['data']['items']['ticket-IDs'] = implode(',', $ticket_ids);
1275
	}
1276
1277
1278
1279
1280
1281
1282
	/**
1283
	 * 	_generate_publish_box_extra_content
1284
	 * 	@access private
1285
	 * @return void
1286
	 */
1287
	private function _generate_publish_box_extra_content() {
1288
1289
		//load formatter helper
1290
  		EE_Registry::instance()->load_helper( 'Formatter' );
1291
1292
  		//args for getting related registrations
1293
  		$approved_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_approved ) );
1294
  		$not_approved_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_not_approved ) );
1295
  		$pending_payment_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_pending_payment ) );
1296
1297
1298
		// publish box
1299
		$publish_box_extra_args = array(
1300
			'view_approved_reg_url' => add_query_arg(
1301
				array(
1302
					'action'      => 'default',
1303
					'event_id'    => $this->_cpt_model_obj->ID(),
1304
					'_reg_status' => EEM_Registration::status_id_approved
1305
				),
1306
			  REG_ADMIN_URL
1307
			),
1308
			'view_not_approved_reg_url' => add_query_arg(
1309
				array(
1310
					'action'      => 'default',
1311
					'event_id'    => $this->_cpt_model_obj->ID(),
1312
					'_reg_status' => EEM_Registration::status_id_not_approved
1313
				),
1314
				REG_ADMIN_URL
1315
			),
1316
			'view_pending_payment_reg_url' => add_query_arg(
1317
				array(
1318
					'action'      => 'default',
1319
					'event_id'    => $this->_cpt_model_obj->ID(),
1320
					'_reg_status' => EEM_Registration::status_id_pending_payment
1321
				),
1322
				REG_ADMIN_URL
1323
			),
1324
			'approved_regs' => $this->_cpt_model_obj->count_related( 'Registration', $approved_query_args ),
1325
			'not_approved_regs' => $this->_cpt_model_obj->count_related( 'Registration', $not_approved_query_args ),
1326
			'pending_payment_regs' => $this->_cpt_model_obj->count_related( 'Registration', $pending_payment_query_args ),
1327
			'misc_pub_section_class' => apply_filters(
1328
				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1329
				'misc-pub-section'
1330
			),
1331
			//'email_attendees_url' => add_query_arg(
1332
			//	array(
1333
			//		'event_admin_reports' => 'event_newsletter',
1334
			//		'event_id' => $this->_cpt_model_obj->id
1335
			//	),
1336
			//	'admin.php?page=espresso_registrations'
1337
			//),
1338
1339
		);
1340
		ob_start();
1341
		do_action(
1342
			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1343
			$this->_cpt_model_obj
1344
		);
1345
		$publish_box_extra_args[ 'event_editor_overview_add' ] = ob_get_clean();
1346
		// load template
1347
		EEH_Template::display_template( EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php', $publish_box_extra_args );
1348
	}
1349
1350
1351
1352
1353
1354
	/**
1355
	 * This just returns whatever is set as the _event object property
1356
	 *
1357
	 * //todo this will become obsolete once the models are in place
1358
	 * @return object
1359
	 */
1360
	public function get_event_object() {
1361
		return $this->_cpt_model_obj;
1362
	}
1363
1364
1365
1366
	/*	 * ************ */
1367
	/** METABOXES * */
1368
1369
	/**
1370
	 * _register_event_editor_meta_boxes
1371
	 * add all metaboxes related to the event_editor
1372
	 *
1373
	 * @return void
1374
	 */
1375
	protected function _register_event_editor_meta_boxes() {
1376
		$this->verify_cpt_object();
1377
		add_meta_box(
1378
			'espresso_event_editor_tickets',
1379
			__( 'Event Datetime & Ticket', 'event_espresso' ),
1380
			array( $this, 'ticket_metabox' ),
1381
			$this->page_slug,
1382
			'normal',
1383
			'high'
1384
		);
1385
		add_meta_box(
1386
			'espresso_event_editor_event_options',
1387
			__( 'Event Registration Options', 'event_espresso' ),
1388
			array( $this, 'registration_options_meta_box' ),
1389
			$this->page_slug,
1390
			'side',
1391
			'default'
1392
		);
1393
		// NOTE: if you're looking for other metaboxes in here,
1394
		// where a metabox has a related management page in the admin
1395
		// you will find it setup in the related management page's "_Hooks" file.
1396
		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1397
	}
1398
1399
1400
1401
1402
	public function ticket_metabox() {
1403
		$existing_datetime_ids = $existing_ticket_ids = array();
1404
		//defaults for template args
1405
		$template_args = array(
1406
			'existing_datetime_ids' => '',
1407
			'event_datetime_help_link' => '',
1408
			'ticket_options_help_link' => '',
1409
			'time' => null,
1410
			'ticket_rows' => '',
1411
			'existing_ticket_ids' => '',
1412
			'total_ticket_rows' => 1,
1413
			'ticket_js_structure' => '',
1414
			'trash_icon' => 'ee-lock-icon',
1415
			'disabled' => ''
1416
			);
1417
1418
		$event_id = is_object( $this->_cpt_model_obj ) ? $this->_cpt_model_obj->ID() : NULL;
1419
1420
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
1421
1422
		/**
1423
		 * 1. Start with retrieving Datetimes
1424
		 * 2. Fore each datetime get related tickets
1425
		 * 3. For each ticket get related prices
1426
		 */
1427
		$times = EE_Registry::instance()->load_model('Datetime' )->get_all_event_dates( $event_id );
0 ignored issues
show
Bug introduced by
The method get_all_event_dates cannot be called on \EE_Registry::instance()->load_model('Datetime') (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...
1428
		EE_Registry::instance()->load_helper('DTT_Helper' );
1429
		/** @type EE_Datetime $first_datetime */
1430
		$first_datetime = reset( $times );
1431
		//do we get related tickets?
1432
		if ( $first_datetime instanceof EE_Datetime 
1433
			&& $first_datetime->ID() !== 0 ) {
1434
			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1435
			$template_args['time'] = $first_datetime;
1436
			$related_tickets = $first_datetime->tickets(
1437
				array(
1438
					array( 'OR' => array( 'TKT_deleted' => 1, 'TKT_deleted*' => 0 ) ),
1439
					'default_where_conditions' => 'none'
1440
				)
1441
			);
1442
1443
			if ( !empty($related_tickets) ) {
1444
				$template_args['total_ticket_rows'] = count($related_tickets);
1445
				$row = 0;
1446
				foreach ( $related_tickets as $ticket ) {
1447
					$existing_ticket_ids[] = $ticket->get('TKT_ID');
1448
					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, FALSE, $row );
0 ignored issues
show
Compatibility introduced by
$ticket of type object<EE_Base_Class> is not a sub-type of object<EE_Ticket>. It seems like you assume a child class of the class EE_Base_Class to be always present.

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

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

Loading history...
1449
1450
					$row++;
1451
				}
1452 View Code Duplication
			} else {
1453
				$template_args['total_ticket_rows'] = 1;
1454
				/** @type EE_Ticket $ticket */
1455
				$ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
0 ignored issues
show
Bug introduced by
The method create_default_object 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...
1456
				$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket );
1457
			}
1458 View Code Duplication
		} else {
1459
			$template_args['time'] = $times[0];
1460
			/** @type EE_Ticket $ticket */
1461
			$ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
0 ignored issues
show
Bug introduced by
The method get_all_default_tickets 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...
1462
			$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket[1] );
1463
			// NOTE: we're just sending the first default row
1464
			// (decaf can't manage default tickets so this should be sufficient);
1465
		}
1466
1467
		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link('event_editor_event_datetimes_help_tab');
1468
		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1469
		$template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1470
		$template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1471
		$template_args['ticket_js_structure'] = $this->_get_ticket_row( EE_Registry::instance()->load_model('Ticket')->create_default_object(), TRUE );
0 ignored issues
show
Bug introduced by
The method create_default_object 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...
1472
		$template = apply_filters( 'FHEE__Events_Admin_Page__ticket_metabox__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php' );
1473
		EEH_Template::display_template($template, $template_args);
1474
	}
1475
1476
1477
1478
	/**
1479
	 * Setup an individual ticket form for the decaf event editor page
1480
	 *
1481
	 * @access private
1482
	 * @param  EE_Ticket $ticket   the ticket object
1483
	 * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1484
	 * @param int        $row
1485
	 * @return string generated html for the ticket row.
1486
	 */
1487
	private function _get_ticket_row( $ticket, $skeleton = FALSE, $row = 0 ) {
1488
		$template_args = array(
1489
			'tkt_status_class' => ' tkt-status-' . $ticket->ticket_status(),
1490
			'tkt_archive_class' => $ticket->ticket_status() === EE_Ticket::archived && !$skeleton ? ' tkt-archived' : '',
1491
			'ticketrow' => $skeleton ? 'TICKETNUM' : $row,
1492
			'TKT_ID' => $ticket->get('TKT_ID'),
1493
			'TKT_name' => $ticket->get('TKT_name'),
1494
			'TKT_start_date' => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1495
			'TKT_end_date' => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1496
			'TKT_is_default' => $ticket->get('TKT_is_default'),
1497
			'TKT_qty' => $ticket->get_pretty('TKT_qty','input'),
1498
			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1499
			'TKT_sold' => $skeleton ? 0 : $ticket->get('TKT_sold'),
1500
			'trash_icon' => ( $skeleton || ( !empty( $ticket ) && ! $ticket->get('TKT_deleted') ) ) && ( !empty( $ticket ) && $ticket->get('TKT_sold') === 0 ) ? 'trash-icon dashicons dashicons-post-trash clickable' : 'ee-lock-icon',
1501
			'disabled' => $skeleton || ( !empty( $ticket ) && ! $ticket->get('TKT_deleted' ) ) ? '' : ' disabled=disabled'
1502
			);
1503
1504
		$price = $ticket->ID() !== 0 ? $ticket->get_first_related('Price', array('default_where_conditions' => 'none')) : EE_Registry::instance()->load_model('Price')->create_default_object();
0 ignored issues
show
Bug introduced by
The method create_default_object cannot be called on \EE_Registry::instance()->load_model('Price') (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...
1505
1506
1507
		$price_args = array(
1508
			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1509
			'PRC_amount' => $price->get('PRC_amount'),
1510
			'PRT_ID' => $price->get('PRT_ID'),
1511
			'PRC_ID' => $price->get('PRC_ID'),
1512
			'PRC_is_default' => $price->get('PRC_is_default'),
1513
			);
1514
1515
		//make sure we have default start and end dates if skeleton
1516
		//handle rows that should NOT be empty
1517
		if ( empty( $template_args['TKT_start_date'] ) ) {
1518
			//if empty then the start date will be now.
1519
			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1520
		}
1521
1522
		if ( empty( $template_args['TKT_end_date'] ) ) {
1523
			//get the earliest datetime (if present);
1524
			$earliest_dtt = $this->_cpt_model_obj->ID() > 0 ? $this->_cpt_model_obj->get_first_related('Datetime', array('order_by'=> array('DTT_EVT_start' => 'ASC' ) ) ) : NULL;
1525
1526
			if ( !empty( $earliest_dtt ) )
1527
				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1528
			else
1529
				$template_args['TKT_end_date'] = date('Y-m-d h:i a', mktime(0, 0, 0, date("m"), date("d")+7, date("Y") ) );
1530
		}
1531
1532
		$template_args = array_merge( $template_args, $price_args );
1533
		$template = apply_filters( 'FHEE__Events_Admin_Page__get_ticket_row__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php', $ticket);
1534
		return EEH_Template::display_template($template, $template_args, TRUE);
1535
	}
1536
1537
1538
1539
	public function registration_options_meta_box() {
1540
1541
		$yes_no_values = array(
1542
			array('id' => true, 'text' => __('Yes', 'event_espresso')),
1543
			array('id' => false, 'text' => __('No', 'event_espresso'))
1544
		);
1545
1546
		$default_reg_status_values = EEM_Registration::reg_status_array(
1547
			array(
1548
				EEM_Registration::status_id_cancelled,
1549
				EEM_Registration::status_id_declined,
1550
				EEM_Registration::status_id_incomplete
1551
			),
1552
			TRUE
1553
		);
1554
1555
		//$template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1556
		$template_args['_event'] = $this->_cpt_model_obj;
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...
1557
		$template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(FALSE);
0 ignored issues
show
Bug introduced by
The method pretty_active_status() does not exist on EE_CPT_Base. Did you maybe mean status()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1558
		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
0 ignored issues
show
Documentation Bug introduced by
The method additional_limit does not exist on object<EE_CPT_Base>? 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...
1559
		$template_args['default_registration_status'] = EEH_Form_Fields::select_input('default_reg_status', $default_reg_status_values, $this->_cpt_model_obj->default_registration_status());
0 ignored issues
show
Bug introduced by
The method default_registration_status() does not exist on EE_CPT_Base. Did you maybe mean status()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1560
		$template_args['display_description'] = EEH_Form_Fields::select_input('display_desc', $yes_no_values, $this->_cpt_model_obj->display_description());
0 ignored issues
show
Documentation Bug introduced by
The method display_description does not exist on object<EE_CPT_Base>? 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...
1561
		$template_args['display_ticket_selector'] = EEH_Form_Fields::select_input('display_ticket_selector', $yes_no_values, $this->_cpt_model_obj->display_ticket_selector(), '', '', false);
0 ignored issues
show
Documentation Bug introduced by
The method display_ticket_selector does not exist on object<EE_CPT_Base>? 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...
1562
		$template_args['additional_registration_options'] = apply_filters( 'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options', '', $template_args, $yes_no_values, $default_reg_status_values );
1563
		$templatepath = EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php';
1564
		EEH_Template::display_template($templatepath, $template_args);
1565
	}
1566
1567
1568
1569
	/** end metaboxes * */
1570
	/*	 * **************** *
1571
1572
1573
1574
1575
	/**
1576
	 * _get_events()
1577
	 * This method simply returns all the events (for the given _view and paging)
1578
	 *
1579
	 * @access public
1580
	 *
1581
	 * @param int $per_page count of items per page (20 default);
1582
	 * @param int $current_page what is the current page being viewed.
1583
	 * @param bool $count if TRUE then we just return a count of ALL events matching the given _view.  If FALSE then we return an array of event objects that match the given _view and paging parameters.
1584
	 * @return array an array of event objects.
1585
	 */
1586
	public function get_events($per_page = 10, $current_page = 1, $count = FALSE) {
1587
1588
		$EEME = $this->_event_model();
1589
1590
		$offset = ($current_page - 1) * $per_page;
1591
		$limit = $count ? NULL : $offset . ',' . $per_page;
1592
		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1593
		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1594
1595
		if (isset($this->_req_data['month_range'])) {
1596
			$pieces = explode(' ', $this->_req_data['month_range'], 3);
1597
			$month_r = !empty($pieces[0]) ? date('m', strtotime($pieces[0])) : '';
1598
			$year_r = !empty($pieces[1]) ? $pieces[1] : '';
1599
		}
1600
1601
		$where = array();
1602
1603
		$status = isset( $this->_req_data['status'] ) ? $this->_req_data['status'] : NULL;
1604
		//determine what post_status our condition will have for the query.
1605
		switch ( $status ) {
1606
			case 'month' :
1607
			case 'today' :
1608
			case NULL :
1609
			case 'all' :
1610
				break;
1611
1612
			case 'draft' :
1613
				$where['status'] = array( 'IN', array('draft', 'auto-draft') );
1614
				break;
1615
1616
			default :
1617
				$where['status'] = $status;
1618
		}
1619
1620
		//categories?
1621
		$category = isset( $this->_req_data['EVT_CAT'] ) && $this->_req_data['EVT_CAT'] > 0 ? $this->_req_data['EVT_CAT'] : NULL;
1622
1623
		if ( !empty ( $category ) ) {
1624
			$where['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1625
			$where['Term_Taxonomy.term_id'] = $category;
1626
		}
1627
1628
		//date where conditions
1629
		$start_formats = EEM_Datetime::instance()->get_formats_for( 'DTT_EVT_start' );
1630
		if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1631
			$DateTime = new DateTime( $year_r . '-' . $month_r . '-01 00:00:00', new DateTimeZone( EEM_Datetime::instance()->get_timezone() ) );
0 ignored issues
show
Bug introduced by
The variable $year_r 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...
Bug introduced by
The variable $month_r 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...
1632
			$start = $DateTime->format( implode( ' ', $start_formats  ) );
1633
			$end = $DateTime->setDate( $year_r, $month_r, $DateTime->format('t') )->setTime(23,59,59)->format( implode( ' ', $start_formats ) );
1634
			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array( $start, $end ) );
1635
		} else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1636
			$DateTime = new DateTime( 'now', new DateTimeZone( EEM_Event::instance()->get_timezone() ) );
1637
			$start = $DateTime->setTime( 0,0,0 )->format( implode( ' ', $start_formats ) );
1638
			$end = $DateTime->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1639
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1640
		} else if ( isset($this->_req_data['status']) && $this->_req_data['status'] == 'month' ) {
1641
			$now = date( 'Y-m-01' );
1642
			$DateTime = new DateTime( $now, new DateTimeZone( EEM_Event::instance()->get_timezone() ) );
1643
			$start = $DateTime->setTime( 0, 0, 0 )->format( implode( ' ', $start_formats ) );
1644
			$end = $DateTime->setDate( date('Y'), date('m'), $DateTime->format('t' ) )->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1645
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1646
		}
1647
1648
1649 View Code Duplication
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1650
			$where['EVT_wp_user'] =  get_current_user_id();
1651
		} else {
1652
			if ( ! isset( $where['status'] ) ) {
1653
				if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_private_events', 'get_events' ) ) {
1654
					$where['OR'] = array(
1655
						'status*restrict_private' => array( '!=', 'private' ),
1656
						'AND' => array(
1657
							'status*inclusive' => array( '=', 'private' ),
1658
							'EVT_wp_user' => get_current_user_id()
1659
						)
1660
					);
1661
				}
1662
			}
1663
		}
1664
1665
		if ( isset( $this->_req_data['EVT_wp_user'] ) ) {
1666
			if ( $this->_req_data['EVT_wp_user'] != get_current_user_id() && EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1667
				$where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1668
			}
1669
		}
1670
1671
1672
		//search query handling
1673
		if ( isset( $this->_req_data['s'] ) ) {
1674
			$search_string = '%' . $this->_req_data['s'] . '%';
1675
			$where['OR'] = array(
1676
				'EVT_name' => array('LIKE', $search_string),
1677
				'EVT_desc' => array('LIKE', $search_string),
1678
				'EVT_short_desc' => array('LIKE', $search_string)
1679
				);
1680
		}
1681
1682
1683
		$where = apply_filters( 'FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data );
1684
		$query_params = apply_filters( 'FHEE__Events_Admin_Page__get_events__query_params', array($where, 'limit' => $limit, 'order_by' => $orderby, 'order' => $order, 'group_by' => 'EVT_ID' ), $this->_req_data );
1685
1686
1687
		//let's first check if we have special requests coming in.
1688
		if ( isset( $this->_req_data['active_status'] ) ) {
1689
			switch ( $this->_req_data['active_status'] ) {
1690
				case 'upcoming' :
1691
					return $EEME->get_upcoming_events( $query_params, $count );
1692
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1693
1694
				case 'expired' :
1695
					return $EEME->get_expired_events( $query_params, $count );
1696
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1697
1698
				case 'active' :
1699
					return $EEME->get_active_events( $query_params, $count );
1700
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1701
1702
				case 'inactive' :
1703
					return $EEME->get_inactive_events( $query_params, $count );
1704
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1705
			}
1706
		}
1707
1708
		$events = $count ? $EEME->count( array( $where ), 'EVT_ID', true ) : $EEME->get_all( $query_params );
1709
1710
		return $events;
1711
	}
1712
1713
1714
1715
1716
	//handling for WordPress CPT actions (trash, restore, delete)
1717
	public function trash_cpt_item( $post_id ) {
1718
		$this->_req_data['EVT_ID'] = $post_id;
1719
		$this->_trash_or_restore_event( 'trash', FALSE );
1720
	}
1721
1722
1723
1724
1725
	public function restore_cpt_item( $post_id ) {
1726
		$this->_req_data['EVT_ID'] = $post_id;
1727
		$this->_trash_or_restore_event( 'draft', FALSE );
1728
	}
1729
1730
1731
	public function delete_cpt_item( $post_id ) {
1732
		$this->_req_data['EVT_ID'] = $post_id;
1733
		$this->_delete_event( FALSE );
1734
	}
1735
1736
1737
1738
	/**
1739
	 * _trash_or_restore_event
1740
	 *
1741
	 * @access protected
1742
	 * @param  string $event_status
1743
	 * @return void
1744
	 */
1745 View Code Duplication
	protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = TRUE ) {
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...
1746
		//determine the event id and set to array.
1747
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : FALSE;
1748
		// loop thru events
1749
		if ($EVT_ID) {
1750
			// clean status
1751
			$event_status = sanitize_key($event_status);
1752
			// grab status
1753
			if (!empty($event_status)) {
1754
				$success = $this->_change_event_status($EVT_ID, $event_status);
1755
			} else {
1756
				$success = FALSE;
1757
				$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1758
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1759
			}
1760
		} else {
1761
			$success = FALSE;
1762
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.', 'event_espresso');
1763
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1764
		}
1765
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1766
1767
		if ( $redirect_after )
1768
			$this->_redirect_after_action($success, 'Event', $action, array('action' => 'default'));
0 ignored issues
show
Documentation introduced by
$success 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...
1769
	}
1770
1771
	/**
1772
	 * _trash_or_restore_events
1773
	 *
1774
	 * @access protected
1775
	 * @param  string $event_status
1776
	 * @return void
1777
	 */
1778 View Code Duplication
	protected function _trash_or_restore_events($event_status = 'trash') {
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...
1779
		// clean status
1780
		$event_status = sanitize_key($event_status);
1781
		// grab status
1782
		if (!empty($event_status)) {
1783
			$success = TRUE;
1784
			//determine the event id and set to array.
1785
			$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1786
			// loop thru events
1787
			foreach ($EVT_IDs as $EVT_ID) {
1788
				if ($EVT_ID = absint($EVT_ID)) {
1789
					$results = $this->_change_event_status($EVT_ID, $event_status);
1790
					$success = $results !== FALSE ? $success : FALSE;
1791
				} else {
1792
					$msg = sprintf(__('An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.', 'event_espresso'), $EVT_ID);
1793
					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1794
					$success = FALSE;
1795
				}
1796
			}
1797
		} else {
1798
			$success = FALSE;
1799
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1800
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1801
		}
1802
		// in order to force a pluralized result message we need to send back a success status greater than 1
1803
		$success = $success ? 2 : FALSE;
1804
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1805
1806
		$this->_redirect_after_action($success, 'Events', $action, array('action' => 'default'));
0 ignored issues
show
Security Bug introduced by
It seems like $success defined by $success ? 2 : FALSE on line 1803 can also be of type false; however, EE_Admin_Page::_redirect_after_action() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1807
	}
1808
1809
	/**
1810
	 * _trash_or_restore_events
1811
	 *
1812
	 * @access  private
1813
	 * @param  int $EVT_ID
1814
	 * @param  string $event_status
1815
	 * @return bool
1816
	 */
1817 View Code Duplication
	private function _change_event_status( $EVT_ID = 0, $event_status = '') {
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...
1818
		// grab event id
1819
		if (!$EVT_ID) {
1820
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1821
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1822
			return FALSE;
1823
		}
1824
1825
		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID( $EVT_ID );
0 ignored issues
show
Documentation Bug introduced by
It seems like \EEM_Event::instance()->get_one_by_ID($EVT_ID) can also be of type object<EE_Base_Class>. However, the property $_cpt_model_obj is declared as type object<EE_CPT_Base>. 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...
1826
1827
		// clean status
1828
		$event_status = sanitize_key($event_status);
1829
		// grab status
1830
		if (empty($event_status)) {
1831
			$msg = __('An error occurred. No Event Status or an invalid Event Status was received.', 'event_espresso');
1832
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1833
			return FALSE;
1834
		}
1835
1836
		// was event trashed or restored ?
1837
		switch ($event_status) {
1838
			case 'draft' :
1839
				$action = 'restored from the trash';
1840
				$hook = 'AHEE_event_restored_from_trash';
1841
				break;
1842
			case 'trash' :
1843
				$action = 'moved to the trash';
1844
				$hook = 'AHEE_event_moved_to_trash';
1845
				break;
1846
			default :
1847
				$action = 'updated';
1848
				$hook = FALSE;
1849
		}
1850
		//use class to change status
1851
		$this->_cpt_model_obj->set_status( $event_status );
0 ignored issues
show
Documentation Bug introduced by
The method set_status 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...
1852
		$success = $this->_cpt_model_obj->save();
1853
1854
		if ($success === FALSE) {
1855
			$msg = sprintf(__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
1856
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1857
			return FALSE;
1858
		}
1859
		if ($hook) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $hook 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...
1860
			do_action($hook);
1861
		}
1862
		return TRUE;
1863
	}
1864
1865
1866
1867
	/**
1868
	 * _delete_event
1869
	 *
1870
	 * @access protected
1871
	 * @param bool $redirect_after
1872
	 */
1873
	protected function _delete_event( $redirect_after = TRUE ) {
1874
		//determine the event id and set to array.
1875
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : NULL;
1876
		$EVT_ID = isset( $this->_req_data['post'] ) ? absint( $this->_req_data['post'] ) : $EVT_ID;
1877
1878
1879
		// loop thru events
1880
		if ($EVT_ID) {
1881
			$success = $this->_permanently_delete_event( $EVT_ID );
1882
			// get list of events with no prices
1883
			$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1884
			// remove this event from the list of events with no prices
1885
			if (isset($espresso_no_ticket_prices[$EVT_ID])) {
1886
				unset($espresso_no_ticket_prices[$EVT_ID]);
1887
			}
1888
			update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1889
		} else {
1890
			$success = FALSE;
1891
			$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1892
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1893
		}
1894
1895
		if ( $redirect_after )
1896
			$this->_redirect_after_action($success, 'Event', 'deleted', array('action' => 'default', 'status' => 'trash'));
0 ignored issues
show
Documentation introduced by
$success 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...
1897
	}
1898
1899
	/**
1900
	 * _delete_events
1901
	 *
1902
	 * @access protected
1903
	 * @return void
1904
	 */
1905
	protected function _delete_events() {
1906
		$success = TRUE;
1907
		// get list of events with no prices
1908
		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1909
		//determine the event id and set to array.
1910
		$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1911
		// loop thru events
1912
		foreach ($EVT_IDs as $EVT_ID) {
1913
			$EVT_ID = absint( $EVT_ID );
1914
			if ( $EVT_ID ) {
1915
				$results = $this->_permanently_delete_event( $EVT_ID );
1916
				$success = $results !== FALSE ? $success : FALSE;
1917
				// remove this event from the list of events with no prices
1918
				unset( $espresso_no_ticket_prices[ $EVT_ID ] );
1919
			} else {
1920
				$success = FALSE;
1921
				$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1922
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1923
			}
1924
		}
1925
		update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1926
		// in order to force a pluralized result message we need to send back a success status greater than 1
1927
		$success = $success ? 2 : FALSE;
1928
		$this->_redirect_after_action($success, 'Events', 'deleted', array('action' => 'default'));
0 ignored issues
show
Security Bug introduced by
It seems like $success defined by $success ? 2 : FALSE on line 1927 can also be of type false; however, EE_Admin_Page::_redirect_after_action() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1929
	}
1930
1931
	/**
1932
	 * _permanently_delete_event
1933
	 *
1934
	 * @access  private
1935
	 * @param  int $EVT_ID
1936
	 * @return bool
1937
	 */
1938
	private function _permanently_delete_event( $EVT_ID = 0 ) {
1939
		// grab event id
1940
		if ( ! $EVT_ID ) {
1941
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1942
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1943
			return FALSE;
1944
		}
1945
		if (
1946
			! $this->_cpt_model_obj instanceof EE_Event
1947
			|| $this->_cpt_model_obj->ID() !== $EVT_ID
1948
		) {
1949
			$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID( $EVT_ID );
0 ignored issues
show
Documentation Bug introduced by
It seems like \EEM_Event::instance()->get_one_by_ID($EVT_ID) can also be of type object<EE_Base_Class>. However, the property $_cpt_model_obj is declared as type object<EE_CPT_Base>. 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...
1950
		}
1951
1952
		if ( ! $this->_cpt_model instanceof EE_Event ) {
0 ignored issues
show
Bug introduced by
The property _cpt_model does not seem to exist. Did you mean _cpt_model_names?

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...
1953
			return false;
1954
		}
1955
1956
		//need to delete related tickets and prices first.
1957
		$datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
1958
		foreach ( $datetimes as $datetime ) {
1959
			$this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
1960
			$tickets = $datetime->get_many_related('Ticket');
1961
			foreach ( $tickets as $ticket ) {
1962
				$ticket->_remove_relation_to($datetime, 'Datetime');
1963
				$ticket->delete_related_permanently('Price');
1964
				$ticket->delete_permanently();
1965
			}
1966
			$datetime->delete();
1967
		}
1968
1969
		//what about related venues or terms?
1970
		$venues = $this->_cpt_model_obj->get_many_related('Venue');
1971
		foreach ( $venues as $venue ) {
1972
			$this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
1973
		}
1974
1975
		//any attached question groups?
1976
		$question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
1977
		if ( !empty( $question_groups ) ) {
1978
			foreach ( $question_groups as $question_group ) {
1979
				$this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
1980
			}
1981
		}
1982
1983
1984
1985
1986
		//Message Template Groups
1987
		$this->_cpt_model_obj->_remove_relations( 'Message_Template_Group' );
1988
1989
		/** @type EE_Term_Taxonomy[] $term_taxonomies */
1990
		$term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
0 ignored issues
show
Documentation Bug introduced by
The method term_taxonomies 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...
1991
1992
		foreach ( $term_taxonomies as $term_taxonomy ) {
1993
			$this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
0 ignored issues
show
Documentation Bug introduced by
The method remove_relation_to_term_taxonomy 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...
1994
		}
1995
1996
		$success = $this->_cpt_model_obj->delete_permanently();
1997
		// did it all go as planned ?
1998
		if ($success) {
1999
			$msg = sprintf(__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
2000
			EE_Error::add_success($msg);
2001
		} else {
2002
			$msg = sprintf(__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'), $EVT_ID);
2003
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2004
			return FALSE;
2005
		}
2006
		do_action( 'AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID );
2007
		return TRUE;
2008
	}
2009
2010
2011
2012
2013
2014
2015
	/**
2016
	 * get total number of events
2017
	 *
2018
	 * @access public
2019
	 * @return int
2020
	 */
2021
	public function total_events() {
2022
2023
		$count = EEM_Event::instance()->count( array( 'caps' => 'read_admin' ), 'EVT_ID', true );
2024
		return $count;
2025
	}
2026
2027
2028
2029
2030
	/**
2031
	 * get total number of draft events
2032
	 *
2033
	 * @access public
2034
	 * @return int
2035
	 */
2036
	public function total_events_draft() {
2037
		$where = array(
2038
			'status' => array( 'IN', array('draft', 'auto-draft' ) )
2039
			);
2040
2041
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
2042
		return $count;
2043
	}
2044
2045
2046
2047
2048
2049
	/**
2050
	 * get total number of trashed events
2051
	 *
2052
	 * @access public
2053
	 * @return int
2054
	 */
2055
	public function total_trashed_events() {
2056
		$where = array(
2057
			'status' => 'trash'
2058
			);
2059
2060
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
2061
		return $count;
2062
	}
2063
2064
2065
2066
2067
	/**
2068
	 * 	_default_event_settings
2069
	 *
2070
	 * 	This generates the Default Settings Tab
2071
	 *
2072
	 * 	@return string html for the settings page
2073
	 */
2074
	protected function _default_event_settings() {
2075
2076
		$this->_template_args['values'] = $this->_yes_no_values;
2077
2078
		$this->_template_args['reg_status_array'] = EEM_Registration::reg_status_array(
2079
			// exclude array
2080
			array(
2081
				EEM_Registration::status_id_cancelled,
2082
				EEM_Registration::status_id_declined,
2083
				EEM_Registration::status_id_incomplete
2084
			),
2085
			// translated
2086
			TRUE
2087
		);
2088
		$this->_template_args['default_reg_status'] = isset( EE_Registry::instance()->CFG->registration->default_STS_ID ) ? sanitize_text_field( EE_Registry::instance()->CFG->registration->default_STS_ID ) : EEM_Registration::status_id_pending_payment;
2089
2090
		$this->_set_add_edit_form_tags('update_default_event_settings');
2091
		$this->_set_publish_post_box_vars(NULL, FALSE, FALSE, NULL, FALSE);
2092
		$this->_template_args['admin_page_content'] = EEH_Template::display_template(EVENTS_TEMPLATE_PATH . 'event_settings.template.php', $this->_template_args, TRUE);
2093
		$this->display_admin_page_with_sidebar();
2094
	}
2095
2096
	/**
2097
	 * 		_update_default_event_settings
2098
	 * 		@access protected
2099
	 * 		@return array
2100
	 */
2101
	protected function _update_default_event_settings() {
2102
2103
		EE_Config::instance()->registration->default_STS_ID = isset($this->_req_data['default_reg_status']) ? sanitize_text_field($this->_req_data['default_reg_status']) : EEM_Registration::status_id_pending_payment;
2104
2105
		$what = 'Default Event Settings';
2106
		$success = $this->_update_espresso_configuration($what, EE_Config::instance(), __FILE__, __FUNCTION__, __LINE__);
2107
		$this->_redirect_after_action($success, $what, 'updated', array('action' => 'default_event_settings'));
0 ignored issues
show
Documentation introduced by
$success 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...
2108
	}
2109
2110
2111
2112
2113
	/*************		Templates 		*************/
2114
2115
2116
	protected function _template_settings() {
2117
		$this->_admin_page_title = __('Template Settings (Preview)', 'event_espresso');
2118
		$this->_template_args['preview_img'] = '<img src="' . EVENTS_ASSETS_URL . DS . 'images' . DS . 'caffeinated_template_features.jpg" alt="' . esc_attr__( 'Template Settings Preview screenshot', 'event_espresso' ) . '" />';
2119
		$this->_template_args['preview_text'] = '<strong>'.__( 'Template Settings is a feature that is only available in the Caffeinated version of Event Espresso. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.', 'event_espresso' ).'</strong>';
2120
		$this->display_admin_caf_preview_page( 'template_settings_tab' );
2121
	}
2122
2123
2124
	/** Event Category Stuff **/
2125
2126
	/**
2127
	 * set the _category property with the category object for the loaded page.
2128
	 *
2129
	 * @access private
2130
	 * @return void
2131
	 */
2132 View Code Duplication
	private function _set_category_object() {
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...
2133
		if ( isset( $this->_category->id ) && !empty( $this->_category->id ) )
2134
			return; //already have the category object so get out.
2135
2136
		//set default category object
2137
		$this->_set_empty_category_object();
2138
2139
		//only set if we've got an id
2140
		if ( !isset($this->_req_data['EVT_CAT_ID'] ) ) {
2141
			return;
2142
		}
2143
2144
		$category_id = absint($this->_req_data['EVT_CAT_ID']);
2145
2146
		$term = get_term( $category_id, 'espresso_event_categories' );
2147
2148
		if ( !empty( $term ) ) {
2149
			$this->_category->category_name = $term->name;
2150
			$this->_category->category_identifier = $term->slug;
2151
			$this->_category->category_desc = $term->description;
2152
			$this->_category->id = $term->term_id;
2153
			$this->_category->parent = $term->parent;
2154
		}
2155
	}
2156
2157
2158
2159
2160
	private function _set_empty_category_object() {
2161
		$this->_category = new stdClass();
2162
		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc  = '';
2163
		$this->_category->id = $this->_category->parent = 0;
2164
	}
2165
2166
2167 View Code Duplication
	protected function _category_list_table() {
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...
2168
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
2169
		$this->_search_btn_label = __('Categories', 'event_espresso');
2170
		$this->_admin_page_title .= $this->get_action_link_or_button('add_category', 'add_category', array(), 'add-new-h2');
2171
		$this->display_admin_list_table_page_with_sidebar();
2172
	}
2173
2174
2175 View Code Duplication
	protected function _category_details($view) {
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...
2176
2177
		//load formatter helper
2178
		EE_Registry::instance()->load_helper( 'Formatter' );
2179
		//load field generator helper
2180
		EE_Registry::instance()->load_helper( 'Form_Fields' );
2181
2182
		$route = $view == 'edit' ? 'update_category' : 'insert_category';
2183
		$this->_set_add_edit_form_tags($route);
2184
2185
		$this->_set_category_object();
2186
		$id = !empty($this->_category->id) ? $this->_category->id : '';
2187
2188
		$delete_action = 'delete_category';
2189
2190
		//custom redirect
2191
		$redirect = EE_Admin_Page::add_query_args_and_nonce( array('action' => 'category_list'), $this->_admin_base_url );
2192
2193
		$this->_set_publish_post_box_vars( 'EVT_CAT_ID', $id, $delete_action, $redirect );
2194
2195
		//take care of contents
2196
		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2197
		$this->display_admin_page_with_sidebar();
2198
	}
2199
2200
2201
2202 View Code Duplication
	protected function _category_details_content() {
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...
2203
		$editor_args['category_desc'] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$editor_args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $editor_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...
2204
			'type' => 'wp_editor',
2205
			'value' => EEH_Formatter::admin_format_content($this->_category->category_desc),
2206
			'class' => 'my_editor_custom',
2207
			'wpeditor_args' => array('media_buttons' => FALSE )
2208
		);
2209
		$_wp_editor = $this->_generate_admin_form_fields( $editor_args, 'array' );
2210
2211
		$all_terms = get_terms( array('espresso_event_categories' ), array( 'hide_empty' => 0, 'exclude' => array( $this->_category->id ) ) );
2212
2213
		//setup category select for term parents.
2214
		$category_select_values[] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$category_select_values was never initialized. Although not strictly required by PHP, it is generally a good practice to add $category_select_values = 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...
2215
			'text' => __('No Parent', 'event_espresso'),
2216
			'id' => 0
2217
			);
2218
		foreach ( $all_terms as $term ) {
2219
			$category_select_values[] = array(
2220
				'text' => $term->name,
2221
				'id' => $term->term_id
2222
				);
2223
		}
2224
2225
		$category_select = EEH_Form_Fields::select_input( 'category_parent', $category_select_values, $this->_category->parent );
2226
2227
		$template_args = array(
2228
			'category' => $this->_category,
2229
			'category_select' => $category_select,
2230
			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2231
			'category_desc_editor' =>  $_wp_editor['category_desc']['field'],
2232
			'disable' => '',
2233
			'disabled_message' => FALSE
2234
			);
2235
		$template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2236
		return EEH_Template::display_template($template, $template_args, TRUE );
2237
	}
2238
2239
2240 View Code Duplication
	protected function _delete_categories() {
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...
2241
		$cat_ids = isset( $this->_req_data['EVT_CAT_ID'] ) ? (array) $this->_req_data['EVT_CAT_ID'] : (array) $this->_req_data['category_id'];
2242
2243
		foreach ( $cat_ids as $cat_id ) {
2244
			$this->_delete_category($cat_id);
2245
		}
2246
2247
		//doesn't matter what page we're coming from... we're going to the same place after delete.
2248
		$query_args = array(
2249
			'action' => 'category_list'
2250
			);
2251
		$this->_redirect_after_action(0,'','',$query_args);
2252
2253
	}
2254
2255
2256
2257
2258
2259
	protected function _delete_category($cat_id) {
2260
		global $wpdb;
2261
		$cat_id = absint( $cat_id );
2262
		wp_delete_term( $cat_id, 'espresso_event_categories' );
2263
	}
2264
2265
2266
2267 View Code Duplication
	protected function _insert_or_update_category($new_category) {
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...
2268
2269
		$cat_id = $new_category ? $this->_insert_category() : $this->_insert_category( TRUE );
2270
		$success = 0; //we already have a success message so lets not send another.
2271
2272
		if ( $cat_id ) {
2273
			$query_args = array(
2274
				'action'     => 'edit_category',
2275
				'EVT_CAT_ID' => $cat_id
2276
			);
2277
		} else {
2278
			$query_args = array( 'action' => 'add_category' );
2279
		}
2280
		$this->_redirect_after_action( $success, '','', $query_args, TRUE );
2281
2282
	}
2283
2284
2285
2286
	private function _insert_category( $update = FALSE ) {
2287
		$cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2288
		$category_name= isset( $this->_req_data['category_name'] ) ? $this->_req_data['category_name'] : '';
2289
		$category_desc= isset( $this->_req_data['category_desc'] ) ? $this->_req_data['category_desc'] : '';
2290
		$category_parent = isset( $this->_req_data['category_parent'] ) ? $this->_req_data['category_parent'] : 0;
2291
2292
		if ( empty( $category_name ) ) {
2293
			$msg = __( 'You must add a name for the category.', 'event_espresso' );
2294
			EE_Error::add_error( $msg, __FILE__, __FUNCTION__, __LINE__ );
2295
			return false;
2296
		}
2297
2298
		$term_args=array(
2299
			'name'=>$category_name,
2300
			'description'=>$category_desc,
2301
			'parent'=>$category_parent
2302
		);
2303
		//was the category_identifier input disabled?
2304
		if(isset($this->_req_data['category_identifier'])){
2305
			$term_args['slug'] = $this->_req_data['category_identifier'];
2306
		}
2307
		$insert_ids = $update ? wp_update_term( $cat_id, 'espresso_event_categories', $term_args ) :wp_insert_term( $category_name, 'espresso_event_categories', $term_args );
2308
2309 View Code Duplication
		if ( !is_array( $insert_ids ) ) {
2310
			$msg = __( 'An error occurred and the category has not been saved to the database.', 'event_espresso' );
2311
			EE_Error::add_error( $msg, __FILE__, __FUNCTION__, __LINE__ );
2312
		} else {
2313
			$cat_id = $insert_ids['term_id'];
2314
			$msg = sprintf ( __('The category %s was successfuly saved', 'event_espresso'), $category_name );
2315
			EE_Error::add_success( $msg );
2316
		}
2317
2318
		return $cat_id;
2319
	}
2320
2321
2322
2323
2324 View Code Duplication
	public function get_categories( $per_page = 10, $current_page = 1, $count = 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...
2325
		global $wpdb;
2326
2327
		//testing term stuff
2328
		$orderby = isset( $this->_req_data['orderby'] ) ? $this->_req_data['orderby'] : 'Term.term_id';
2329
		$order = isset( $this->_req_data['order'] ) ? $this->_req_data['order'] : 'DESC';
2330
		$limit = ($current_page-1)*$per_page;
2331
2332
		$where = array( 'taxonomy' => 'espresso_event_categories' );
2333
2334
		if ( isset( $this->_req_data['s'] ) ) {
2335
			$sstr = '%' . $this->_req_data['s'] . '%';
2336
			$where['OR'] = array(
2337
				'Term.name' => array( 'LIKE', $sstr),
2338
				'description' => array( 'LIKE', $sstr )
2339
				);
2340
		}
2341
2342
		$query_params = array(
2343
			$where ,
2344
			'order_by' => array( $orderby => $order ),
2345
			'limit' => $limit . ',' . $per_page,
2346
			'force_join' => array('Term')
2347
			);
2348
2349
		$categories = $count ? EEM_Term_Taxonomy::instance()->count( $query_params, 'term_id' ) :EEM_Term_Taxonomy::instance()->get_all( $query_params );
2350
2351
		return $categories;
2352
	}
2353
2354
2355
2356
	/* end category stuff */
2357
	/**************/
2358
2359
}
2360
//end class Events_Admin_Page
2361