Completed
Branch BUG-9623-config-log (1352ef)
by
unknown
891:17 queued 877:05
created

Events_Admin_Page   F

Complexity

Total Complexity 301

Size/Duplication

Total Lines 2282
Duplicated Lines 18.32 %

Coupling/Cohesion

Components 2
Dependencies 21

Importance

Changes 5
Bugs 1 Features 1
Metric Value
wmc 301
c 5
b 1
f 1
lcom 2
cbo 21
dl 418
loc 2282
rs 0.6314

65 Methods

Rating   Name   Duplication   Size   Complexity  
A _init_page_props() 0 14 1
C verify_event_edit() 17 47 12
A _edit_event_warning() 0 9 3
B _set_list_table_views_default() 0 32 2
A _ee_autosave_create_new() 0 3 1
A _ee_autosave_edit() 0 3 1
A _generate_publish_box_extra_content() 0 62 1
C _permanently_delete_event() 0 71 12
A _ajax_hooks() 0 3 1
A _define_page_props() 23 23 1
B _set_page_routes() 0 127 4
B _set_page_config() 0 256 3
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
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 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
	 * This will hold the event object for event_details screen.
34
	 *
35
	 * @access protected
36
	 * @var EE_Event $_event
37
	 */
38
	protected $_event;
39
40
41
	/**
42
	 * This will hold the category object for category_details screen.
43
	 *
44
	 * @var stdClass $_category
45
	 */
46
	protected $_category;
47
48
49
	/**
50
	 * This will hold the event model instance
51
	 *
52
	 * @var EEM_Event $_event_model
53
	 */
54
	protected $_event_model;
55
56
57
	protected function _init_page_props() {
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(
63
			'create_new' => 'EEM_Event',
64
			'edit' => 'EEM_Event'
65
		);
66
		$this->_cpt_edit_routes = array(
67
			'espresso_events' => 'edit'
68
		);
69
		add_action('AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object', array( $this, 'verify_event_edit' ) );
70
	}
71
72
	protected function _ajax_hooks() {
73
		//todo: all hooks for events ajax goes in here.
74
	}
75
76 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...
77
		$this->_admin_page_title = EVENTS_LABEL;
78
		$this->_labels = array(
79
			'buttons' => array(
80
				'add' => __('Add New Event', 'event_espresso'),
81
				'edit' => __('Edit Event', 'event_espresso'),
82
				'delete' => __('Delete Event', 'event_espresso'),
83
				'add_category' => __('Add New Category', 'event_espresso'),
84
				'edit_category' => __('Edit Category', 'event_espresso'),
85
				'delete_category' => __('Delete Category', 'event_espresso')
86
			),
87
			'editor_title' => array(
88
				'espresso_events' => __('Enter event title here', 'event_espresso')
89
				),
90
			'publishbox' => array(
91
				'create_new' => __('Save New Event', 'event_espresso'),
92
				'edit' => __('Update Event', 'event_espresso'),
93
				'add_category' => __('Save New Category', 'event_espresso'),
94
				'edit_category' => __('Update Category', 'event_espresso'),
95
				'template_settings' => __( 'Update Settings', 'event_espresso' )
96
				)
97
		);
98
	}
99
100
	protected function _set_page_routes() {
101
		//load formatter helper
102
		EE_Registry::instance()->load_helper( 'Formatter' );
103
		//load field generator helper
104
		EE_Registry::instance()->load_helper( 'Form_Fields' );
105
106
		//is there a evt_id in the request?
107
		$evt_id = ! empty( $this->_req_data['EVT_ID'] ) && ! is_array( $this->_req_data['EVT_ID'] ) ? $this->_req_data['EVT_ID'] : 0;
108
		$evt_id = ! empty( $this->_req_data['post'] ) ? $this->_req_data['post'] : $evt_id;
109
110
111
		$this->_page_routes = array(
112
			'default' => array(
113
				'func' => '_events_overview_list_table',
114
				'capability' => 'ee_read_events'
115
				),
116
			'create_new' => array(
117
				'func' => '_create_new_cpt_item',
118
				'capability' => 'ee_edit_events'
119
				),
120
			'edit' => array(
121
				'func' => '_edit_cpt_item',
122
				'capability' => 'ee_edit_event',
123
				'obj_id' => $evt_id
124
				),
125
			'copy_event' => array(
126
				'func' => '_copy_events',
127
				'capability' => 'ee_edit_event',
128
				'obj_id' => $evt_id,
129
				'noheader' => true
130
			),
131
			'trash_event' => array(
132
				'func' => '_trash_or_restore_event',
133
				'args' => array('event_status' => 'trash'),
134
				'capability' => 'ee_delete_event',
135
				'obj_id' => $evt_id,
136
				'noheader' => true
137
			),
138
			'trash_events' => array(
139
				'func' => '_trash_or_restore_events',
140
				'args' => array('event_status' => 'trash'),
141
				'capability' => 'ee_delete_events',
142
				'noheader' => true
143
			),
144
			'restore_event' => array(
145
				'func' => '_trash_or_restore_event',
146
				'args' => array('event_status' => 'draft'),
147
				'capability' => 'ee_delete_event',
148
				'obj_id' => $evt_id,
149
				'noheader' => true
150
			),
151
			'restore_events' => array(
152
				'func' => '_trash_or_restore_events',
153
				'args' => array('event_status' => 'draft'),
154
				'capability' => 'ee_delete_events',
155
				'noheader' => true
156
			),
157
			'delete_event' => array(
158
				'func' => '_delete_event',
159
				'capability' => 'ee_delete_event',
160
				'obj_id' => $evt_id,
161
				'noheader' => true
162
			),
163
			'delete_events' => array(
164
				'func' => '_delete_events',
165
				'capability' => 'ee_delete_events',
166
				'noheader' => true
167
			),
168
			'view_report' => array(
169
				'func' => '_view_report',
170
				'capablity' => 'ee_edit_events'
171
				),
172
			'default_event_settings' => array(
173
				'func' => '_default_event_settings',
174
				'capability' => 'manage_options'
175
				),
176
			'update_default_event_settings' => array(
177
				'func' => '_update_default_event_settings',
178
				'capability' => 'manage_options',
179
				'noheader' => TRUE,
180
				),
181
			'template_settings' => array(
182
				'func' => '_template_settings',
183
				'capability' => 'manage_options'
184
				),
185
			//event category tab related
186
			'add_category' => array(
187
				'func' => '_category_details',
188
				'capability' => 'ee_edit_event_category',
189
				'args' => array('add'),
190
				),
191
			'edit_category' => array(
192
				'func' => '_category_details',
193
				'capability' => 'ee_edit_event_category',
194
				'args' => array('edit')
195
				),
196
			'delete_categories' => array(
197
				'func' => '_delete_categories',
198
				'capability' => 'ee_delete_event_category',
199
				'noheader' => TRUE
200
				),
201
202
			'delete_category' => array(
203
				'func' => '_delete_categories',
204
				'capability' => 'ee_delete_event_category',
205
				'noheader' => TRUE
206
				),
207
208
			'insert_category' => array(
209
				'func' => '_insert_or_update_category',
210
				'args' => array('new_category' => TRUE),
211
				'capability' => 'ee_edit_event_category',
212
				'noheader' => TRUE
213
				),
214
215
			'update_category' => array(
216
				'func' => '_insert_or_update_category',
217
				'args' => array('new_category' => FALSE),
218
				'capability' => 'ee_edit_event_category',
219
				'noheader' => TRUE
220
				),
221
			'category_list' => array(
222
				'func' => '_category_list_table',
223
				'capability' => 'ee_manage_event_categories'
224
				)
225
		);
226
	}
227
228
	protected function _set_page_config() {
229
230
231
232
		$this->_page_config = array(
233
			'default' => array(
234
				'nav' => array(
235
					'label' => __('Overview', 'event_espresso'),
236
					'order' => 10
237
				),
238
				'list_table' => 'Events_Admin_List_Table',
239
				'help_tabs' => array(
240
					'events_overview_help_tab' => array(
241
						'title' => __('Events Overview', 'event_espresso'),
242
						'filename' => 'events_overview'
243
					),
244
					'events_overview_table_column_headings_help_tab' => array(
245
						'title' => __('Events Overview Table Column Headings', 'event_espresso'),
246
						'filename' => 'events_overview_table_column_headings'
247
					),
248
					'events_overview_filters_help_tab' => array(
249
						'title' => __('Events Overview Filters', 'event_espresso'),
250
						'filename' => 'events_overview_filters'
251
					),
252
					'events_overview_view_help_tab' => array(
253
						'title' => __('Events Overview Views', 'event_espresso'),
254
						'filename' => 'events_overview_views'
255
					),
256
					'events_overview_other_help_tab' => array(
257
						'title' => __('Events Overview Other', 'event_espresso'),
258
						'filename' => 'events_overview_other'
259
					)
260
				),
261
				'help_tour' => array(
262
					'Event_Overview_Help_Tour',
263
					//'New_Features_Test_Help_Tour' for testing multiple help tour
264
					),
265
				'qtips' => array(
266
					'EE_Event_List_Table_Tips'
267
					),
268
				'require_nonce' => FALSE
269
			),
270
			'create_new' => array(
271
				'nav' => array(
272
					'label' => __('Add Event', 'event_espresso'),
273
					'order' => 5,
274
					'persistent' => false
275
				),
276
				'metaboxes' => array('_register_event_editor_meta_boxes'),
277
				'help_tabs' => array(
278
					'event_editor_help_tab' => array(
279
						'title' => __('Event Editor', 'event_espresso'),
280
						'filename' => 'event_editor'
281
					),
282
					'event_editor_title_richtexteditor_help_tab' => array(
283
						'title' => __('Event Title & Rich Text Editor', 'event_espresso'),
284
						'filename' => 'event_editor_title_richtexteditor'
285
					),
286
					'event_editor_venue_details_help_tab' => array(
287
						'title' => __('Event Venue Details', 'event_espresso'),
288
						'filename' => 'event_editor_venue_details'
289
					),
290
					'event_editor_event_datetimes_help_tab' => array(
291
						'title' => __('Event Datetimes', 'event_espresso'),
292
						'filename' => 'event_editor_event_datetimes'
293
					),
294
					'event_editor_event_tickets_help_tab' => array(
295
						'title' => __('Event Tickets', 'event_espresso'),
296
						'filename' => 'event_editor_event_tickets'
297
					),
298
					'event_editor_event_registration_options_help_tab' => array(
299
						'title' => __('Event Registration Options', 'event_espresso'),
300
						'filename' => 'event_editor_event_registration_options'
301
					),
302
					'event_editor_tags_categories_help_tab' => array(
303
						'title' => __('Event Tags & Categories', 'event_espresso'),
304
						'filename' => 'event_editor_tags_categories'
305
					),
306
					'event_editor_questions_registrants_help_tab' => array(
307
						'title' => __('Questions for Registrants', 'event_espresso'),
308
						'filename' => 'event_editor_questions_registrants'
309
					),
310
					'event_editor_save_new_event_help_tab' => array(
311
						'title' => __('Save New Event', 'event_espresso'),
312
						'filename' => 'event_editor_save_new_event'
313
					),
314
					'event_editor_other_help_tab' => array(
315
						'title' => __('Event Other', 'event_espresso'),
316
						'filename' => 'event_editor_other'
317
					)
318
				),
319
				'help_tour' => array(
320
					'Event_Editor_Help_Tour'
321
					),
322
				'qtips' => array( 'EE_Event_Editor_Decaf_Tips' ),
323
				'require_nonce' => FALSE
324
			),
325
			'edit' => array(
326
				'nav' => array(
327
					'label' => __('Edit Event', 'event_espresso'),
328
					'order' => 5,
329
					'persistent' => false,
330
					'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
331
				),
332
				'metaboxes' => array('_register_event_editor_meta_boxes'),
333
				'help_tabs' => array(
334
					'event_editor_help_tab' => array(
335
						'title' => __('Event Editor', 'event_espresso'),
336
						'filename' => 'event_editor'
337
					),
338
					'event_editor_title_richtexteditor_help_tab' => array(
339
						'title' => __('Event Title & Rich Text Editor', 'event_espresso'),
340
						'filename' => 'event_editor_title_richtexteditor'
341
					),
342
					'event_editor_venue_details_help_tab' => array(
343
						'title' => __('Event Venue Details', 'event_espresso'),
344
						'filename' => 'event_editor_venue_details'
345
					),
346
					'event_editor_event_datetimes_help_tab' => array(
347
						'title' => __('Event Datetimes', 'event_espresso'),
348
						'filename' => 'event_editor_event_datetimes'
349
					),
350
					'event_editor_event_tickets_help_tab' => array(
351
						'title' => __('Event Tickets', 'event_espresso'),
352
						'filename' => 'event_editor_event_tickets'
353
					),
354
					'event_editor_event_registration_options_help_tab' => array(
355
						'title' => __('Event Registration Options', 'event_espresso'),
356
						'filename' => 'event_editor_event_registration_options'
357
					),
358
					'event_editor_tags_categories_help_tab' => array(
359
						'title' => __('Event Tags & Categories', 'event_espresso'),
360
						'filename' => 'event_editor_tags_categories'
361
					),
362
					'event_editor_questions_registrants_help_tab' => array(
363
						'title' => __('Questions for Registrants', 'event_espresso'),
364
						'filename' => 'event_editor_questions_registrants'
365
					),
366
					'event_editor_save_new_event_help_tab' => array(
367
						'title' => __('Save New Event', 'event_espresso'),
368
						'filename' => 'event_editor_save_new_event'
369
					),
370
					'event_editor_other_help_tab' => array(
371
						'title' => __('Event Other', 'event_espresso'),
372
						'filename' => 'event_editor_other'
373
					)
374
				),
375
				/*'help_tour' => array(
376
					'Event_Edit_Help_Tour'
377
				),*/
378
				'qtips' => array( 'EE_Event_Editor_Decaf_Tips' ),
379
				'require_nonce' => FALSE
380
			),
381
			'default_event_settings' => array(
382
				'nav' => array(
383
					'label' => __('Default Settings', 'event_espresso'),
384
					'order' => 40
385
				),
386
				'metaboxes' => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
387
				'labels' => array(
388
					'publishbox' => __('Update Settings', 'event_espresso')
389
				),
390
				'help_tabs' => array(
391
					'default_settings_help_tab' => array(
392
						'title' => __('Default Event Settings', 'event_espresso'),
393
						'filename' => 'events_default_settings'
394
					),
395
					'default_settings_status_help_tab' => array(
396
						'title' => __('Default Registration Status', 'event_espresso'),
397
						'filename' => 'events_default_settings_status'
398
					)
399
				),
400
				'help_tour' => array( 'Event_Default_Settings_Help_Tour'),
401
				'require_nonce' => FALSE
402
			),
403
			//template settings
404
			'template_settings' => array(
405
				'nav' => array(
406
					'label' => __('Templates', 'event_espresso'),
407
					'order' => 30
408
				),
409
				'metaboxes' => $this->_default_espresso_metaboxes,
410
				'help_tabs' => array(
411
					'general_settings_templates_help_tab' => array(
412
						'title' => __('Templates', 'event_espresso'),
413
						'filename' => 'general_settings_templates'
414
					)
415
				),
416
				'help_tour' => array( 'Templates_Help_Tour' ),
417
				'require_nonce' => FALSE
418
			),
419
			//event category stuff
420
			'add_category' => array(
421
				'nav' => array(
422
					'label' => __('Add Category', 'event_espresso'),
423
					'order' => 15,
424
					'persistent' => false),
425
				'help_tabs' => array(
426
					'add_category_help_tab' => array(
427
						'title' => __('Add New Event Category', 'event_espresso'),
428
						'filename' => 'events_add_category'
429
						)
430
					),
431
			'help_tour' => array('Event_Add_Category_Help_Tour'),
432
				'metaboxes' => array('_publish_post_box'),
433
				'require_nonce' => FALSE
434
				),
435
			'edit_category' => array(
436
				'nav' => array(
437
					'label' => __('Edit Category', 'event_espresso'),
438
					'order' => 15,
439
					'persistent' => FALSE,
440
					'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
441
					),
442
				'help_tabs' => array(
443
					'edit_category_help_tab' => array(
444
						'title' => __('Edit Event Category', 'event_espresso'),
445
						'filename' => 'events_edit_category'
446
						)
447
					),
448
				/*'help_tour' => array('Event_Edit_Category_Help_Tour'),*/
449
					'metaboxes' => array('_publish_post_box'),
450
					'require_nonce' => FALSE
451
					),
452
			'category_list' => array(
453
				'nav' => array(
454
					'label' => __('Categories', 'event_espresso'),
455
					'order' => 20
456
					),
457
				'list_table' => 'Event_Categories_Admin_List_Table',
458
				'help_tabs' => array(
459
					'events_categories_help_tab' => array(
460
						'title' => __('Event Categories', 'event_espresso'),
461
						'filename' => 'events_categories'
462
					),
463
					'events_categories_table_column_headings_help_tab' => array(
464
						'title' => __('Event Categories Table Column Headings', 'event_espresso'),
465
						'filename' => 'events_categories_table_column_headings'
466
					),
467
					'events_categories_view_help_tab' => array(
468
						'title' => __('Event Categories Views', 'event_espresso'),
469
						'filename' => 'events_categories_views'
470
					),
471
					'events_categories_other_help_tab' => array(
472
						'title' => __('Event Categories Other', 'event_espresso'),
473
						'filename' => 'events_categories_other'
474
					)
475
				),
476
				'help_tour' => array(
477
					'Event_Categories_Help_Tour'
478
					),
479
				'metaboxes' => $this->_default_espresso_metaboxes,
480
				'require_nonce' => FALSE
481
				),
482
		);
483
	}
484
485
486
	protected function _add_screen_options() {
487
		//todo
488
	}
489
490
	protected function _add_screen_options_default() {
491
		$this->_per_page_screen_option();
492
	}
493
494 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...
495
		$page_title = $this->_admin_page_title;
496
		$this->_admin_page_title = __('Categories', 'event_espresso');
497
		$this->_per_page_screen_option();
498
		$this->_admin_page_title = $page_title;
499
	}
500
501
	protected function _add_feature_pointers() {
502
		//todo
503
	}
504
505
506
507
508
	public function load_scripts_styles() {
509
510
		wp_register_style('events-admin-css', EVENTS_ASSETS_URL . 'events-admin-page.css', array(), EVENT_ESPRESSO_VERSION);
511
		wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION );
512
		wp_enqueue_style('events-admin-css');
513
		wp_enqueue_style('ee-cat-admin');
514
		//todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
515
		//registers for all views
516
		//scripts
517
		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);
518
	}
519
520
	/**
521
	 * enqueuing scripts and styles specific to this view
522
	 * @return void
523
	 */
524
	public function load_scripts_styles_create_new() {
525
		$this->load_scripts_styles_edit();
526
	}
527
528
	/**
529
	 * enqueuing scripts and styles specific to this view
530
	 * @return void
531
	 */
532 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...
533
		//styles
534
		wp_enqueue_style('espresso-ui-theme');
535
		wp_register_style('event-editor-css', EVENTS_ASSETS_URL . 'event-editor.css', array('ee-admin-css'), EVENT_ESPRESSO_VERSION );
536
		wp_enqueue_style('event-editor-css');
537
538
		//scripts
539
		wp_register_script('event-datetime-metabox', EVENTS_ASSETS_URL . 'event-datetime-metabox.js', array('event_editor_js', 'ee-datepicker'), EVENT_ESPRESSO_VERSION );
540
		wp_enqueue_script('event-datetime-metabox');
541
542
	}
543
544
545
546
	public function load_scripts_styles_add_category() {
547
		$this->load_scripts_styles_edit_category();
548
	}
549
550
551
552
553
554
	public function load_scripts_styles_edit_category() {}
555
556
557
558 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...
559
		$this->_views = array(
560
			'all' => array(
561
				'slug' => 'all',
562
				'label' => __('All', 'event_espresso'),
563
				'count' => 0,
564
				'bulk_action' => array(
565
					'delete_categories' => __('Delete Permanently', 'event_espresso')
566
					)
567
				)
568
		);
569
	}
570
571
572
573
	public function admin_init() {
574
		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' );
575
	}
576
577
578
579
	//nothing needed for events with these methods.
580
	public function admin_notices() {}
581
	public function admin_footer_scripts() {}
582
583
584
585
586
	/**
587
	 * 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());
588
	 *
589
	 * @param  EE_Event    $event 	Event object
590
	 * @access public
591
	 * @return void
592
	 */
593
	public function verify_event_edit($event = NULL) {
594
		// no event?
595
		if ( empty( $event )) {
596
			// set event
597
			$event = $this->_cpt_model_obj;
598
		}
599
		// STILL no event?
600
		if ( empty ( $event )) {
601
			return;
602
		}
603
		$orig_status = $event->status();
604
		// first check if event is active.
605
		if (
606
			$orig_status === EEM_Event::cancelled
607
		    || $orig_status === EEM_Event::postponed
608
		    || $event->is_expired()
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...
609
		    || $event->is_inactive()
0 ignored issues
show
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...
610
		) {
611
			return;
612
		}
613
		//made it here so it IS active... next check that any of the tickets are sold.
614
		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...
615 View Code Duplication
			if ( $orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status ) {
616
				EE_Error::add_attention(
617
					sprintf(
618
						__( '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' ),
619
						EEH_Template::pretty_status( EEM_Event::sold_out, FALSE, 'sentence' )
620
					)
621
				);
622
			}
623
			return;
624 View Code Duplication
		} else if ( $orig_status === EEM_Event::sold_out ) {
625
			EE_Error::add_attention(
626
				sprintf(
627
					__( '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.',
628
						'event_espresso' ),
629
					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...
630
				)
631
			);
632
		}
633
		//now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
634
		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...
635
			return;
636
		}
637
		//made it here so show warning
638
		$this->_edit_event_warning();
639
	}
640
641
642
643
644
	/**
645
	 * This is the text used for when an event is being edited that is public and has tickets for sale.
646
	 * When needed, hook this into a EE_Error::add_error() notice.
647
	 *
648
	 * @access protected
649
	 * @return string
650
	 */
651
	protected function _edit_event_warning() {
652
		// we don't want to add warnings during these requests
653
		if ( isset( $this->_req_data['action'] ) && $this->_req_data['action'] === 'editpost' ) {
654
			return;
655
		}
656
		EE_Error::add_attention(
657
			__('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')
658
		);
659
	}
660
661
662
663
664
	protected function _set_list_table_views_default() {
665
		$this->_views = array(
666
			'all' => array(
667
				'slug' => 'all',
668
				'label' => __('View All Events', 'event_espresso'),
669
				'count' => 0,
670
				'bulk_action' => array(
671
					'trash_events' => __('Move to Trash', 'event_espresso')
672
				)
673
			),
674
			'draft' => array(
675
				'slug' => 'draft',
676
				'label' => __('Draft', 'event_espresso'),
677
				'count' => 0,
678
				'bulk_action' => array(
679
					'trash_events' => __('Move to Trash', 'event_espresso'),
680
					)
681
			),
682
		);
683
684
		if ( EE_Registry::instance()->CAP->current_user_can( 'ee_delete_events', 'espresso_events_trash_events' ) ) {
685
			$this->_views['trash'] = array(
686
				'slug' => 'trash',
687
				'label' => __('Trash', 'event_espresso'),
688
				'count' => 0,
689
				'bulk_action' => array(
690
					'restore_events' => __('Restore From Trash', 'event_espresso'),
691
					'delete_events' => __('Delete Permanently', 'event_espresso')
692
					)
693
				);
694
		}
695
	}
696
697
698
699
	protected function _event_legend_items() {
700
		$items = array(
701
			'view_details' => array(
702
				'class' => 'dashicons dashicons-search',
703
				'desc' => __('View Event', 'event_espresso')
704
			),
705
			'edit_event' => array(
706
				'class' => 'ee-icon ee-icon-calendar-edit',
707
				'desc' => __('Edit Event Details', 'event_espresso')
708
			),
709
			'view_attendees' => array(
710
				'class' => 'dashicons dashicons-groups',
711
				'desc' => __('View Registrations for Event', 'event_espresso')
712
			)
713
		);
714
		$items  = apply_filters( 'FHEE__Events_Admin_Page___event_legend_items__items', $items );
715
		$statuses = array(
716
			'sold_out_status' => array(
717
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
718
				'desc' => EEH_Template::pretty_status( EE_Datetime::sold_out, FALSE, 'sentence' )
719
			),
720
			'active_status' => array(
721
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
722
				'desc' => EEH_Template::pretty_status( EE_Datetime::active, FALSE, 'sentence' )
723
			),
724
			'upcoming_status' => array(
725
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
726
				'desc' => EEH_Template::pretty_status( EE_Datetime::upcoming, FALSE, 'sentence' )
727
			),
728
			'postponed_status' => array(
729
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
730
				'desc' => EEH_Template::pretty_status( EE_Datetime::postponed, FALSE, 'sentence' )
731
			),
732
			'cancelled_status' => array(
733
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
734
				'desc' => EEH_Template::pretty_status( EE_Datetime::cancelled, FALSE, 'sentence' )
735
			),
736
			'expired_status' => array(
737
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
738
				'desc' => EEH_Template::pretty_status( EE_Datetime::expired, FALSE, 'sentence' )
739
			),
740
			'inactive_status' => array(
741
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
742
				'desc' => EEH_Template::pretty_status( EE_Datetime::inactive, FALSE, 'sentence' )
743
			)
744
		);
745
		$statuses = apply_filters( 'FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses );
746
		return array_merge( $items, $statuses );
747
	}
748
749
750
751
752
753
	/**
754
	 * _event_model
755
	 * @return EEM_Event
756
	 */
757
	private function _event_model() {
758
		if ( ! $this->_event_model instanceof EEM_Event ) {
759
			$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<EEM_Event> 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...
760
		}
761
		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 761 which is incompatible with the return type documented by Events_Admin_Page::_event_model of type EEM_Event.
Loading history...
762
	}
763
764
765
766
767
768
	/**
769
	 * Adds extra buttons to the WP CPT permalink field row.
770
	 *
771
	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
772
	 * @param  string $return    the current html
773
	 * @param  int    $id        the post id for the page
774
	 * @param  string $new_title What the title is
775
	 * @param  string $new_slug  what the slug is
776
	 * @return string            The new html string for the permalink area
777
	 */
778
	public function extra_permalink_field_buttons( $return, $id, $new_title, $new_slug ) {
779
		//make sure this is only when editing
780
		if ( !empty( $id ) ) {
781
			$post = get_post( $id );
782
			$return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">' . __('Shortcode', 'event_espresso') . '</a> ';
783
			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id=' . $post->ID . ']">';
784
		}
785
		return $return;
786
	}
787
788
789
790
791
	/**
792
	 * _events_overview_list_table
793
	 * This contains the logic for showing the events_overview list
794
	 *
795
	 * @access protected
796
	 * @return string html for generated table
797
	 */
798
	protected function _events_overview_list_table() {
799
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
800
		$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' ) .
801
		$this->_display_legend($this->_event_legend_items());
802
		$this->_admin_page_title .= $this->get_action_link_or_button('create_new', 'add', array(), 'add-new-h2');
803
		$this->display_admin_list_table_page_with_no_sidebar();
804
	}
805
806
807
	/**
808
	 * this allows for extra misc actions in the default WP publish box
809
	 * @return string html to add
810
	 */
811
	public function extra_misc_actions_publish_box() {
812
		$this->_generate_publish_box_extra_content();
813
	}
814
815
816
817
818
	protected function _insert_update_cpt_item( $post_id, $post ) {
819
820
		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...
821
			//getout we're not processing an event save.
822
			return;
823
		}
824
825
		$event_values = array(
826
			'EVT_display_desc' => !empty( $this->_req_data['display_desc'] ) ? 1 : 0,
827
			'EVT_display_ticket_selector' => !empty( $this->_req_data['display_ticket_selector'] ) ? 1 : 0,
828
			'EVT_additional_limit' => min(
829
					apply_filters( 'FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255 ),
830
					!empty( $this->_req_data['additional_limit'] ) ? $this->_req_data['additional_limit'] : NULL ),
831
			'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,
832
			'EVT_member_only' => !empty( $this->_req_data['member_only'] ) ? 1 : 0,
833
			'EVT_allow_overflow' => !empty( $this->_req_data['EVT_allow_overflow'] ) ? 1 : 0,
834
			'EVT_timezone_string' => !empty( $this->_req_data['timezone_string'] ) ? $this->_req_data['timezone_string'] : NULL,
835
			'EVT_external_URL' => !empty( $this->_req_data['externalURL'] ) ? $this->_req_data['externalURL'] : NULL,
836
			'EVT_phone' => !empty( $this->_req_data['event_phone'] ) ? $this->_req_data['event_phone'] : NULL
837
			);
838
839
		//update event
840
		$success = $this->_event_model()->update_by_ID( $event_values, $post_id );
841
842
843
		//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!
844
		$get_one_where = array( $this->_event_model()->primary_key_name() => $post_id, 'status' => $post->post_status );
845
		$event = $this->_event_model()->get_one( array($get_one_where) );
846
847
848
		//the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
849
		$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') ) );
850
851
		$att_success = TRUE;
852
853 View Code Duplication
		foreach ( $event_update_callbacks as $e_callback ) {
854
			$_succ = call_user_func_array( $e_callback, array( $event,  $this->_req_data ) );
855
			$att_success = !$att_success ? $att_success : $_succ; //if ANY of these updates fail then we want the appropriate global error message
856
		}
857
858
		//any errors?
859
		if ( $success && FALSE === $att_success ) {
860
			EE_Error::add_error( __('Event Details saved successfully but something went wrong with saving attachments.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
861
		} else if ( $success === FALSE ) {
862
			EE_Error::add_error( __('Event Details did not save successfully.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
863
		}
864
	}
865
866
867
868
869
	/**
870
	 * @see parent::restore_item()
871
	 */
872
	protected function _restore_cpt_item( $post_id, $revision_id ) {
873
		//copy existing event meta to new post
874
		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
875
		if ( $post_evt instanceof EE_Event ) {
876
			//meta revision restore
877
			$post_evt->restore_revision( $revision_id );
878
			//related objs restore
879
			$post_evt->restore_revision( $revision_id, array( 'Venue', 'Datetime', 'Price' ) );
880
		}
881
	}
882
883
884
885
886
	/**
887
	 * Attach the venue to the Event
888
	 * @param  object $evtobj Event Object to add the venue to
889
	 * @param  array  $data   The request data from the form
890
	 * @return bool           Success or fail.
891
	 */
892
	protected function _default_venue_update( $evtobj, $data ) {
893
		require_once( EE_MODELS . 'EEM_Venue.model.php' );
894
		$venue_model = EE_Registry::instance()->load_model('Venue');
895
		$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...
896
		$venue_id = !empty( $data['venue_id'] ) ? $data['venue_id'] : NULL;
897
898
		// very important.  If we don't have a venue name...
899
		// then we'll get out because not necessary to create empty venue
900
		if ( empty( $data['venue_title'] ) ) {
901
			return false;
902
		}
903
904
		$venue_array = array(
905
				'VNU_wp_user' => $evtobj->get('EVT_wp_user'),
906
				'VNU_name' => !empty( $data['venue_title'] ) ? $data['venue_title'] : NULL,
907
				'VNU_desc' => !empty( $data['venue_description'] ) ? $data['venue_description'] : NULL,
908
				'VNU_identifier' => !empty( $data['venue_identifier'] ) ? $data['venue_identifier'] : NULL,
909
				'VNU_short_desc' => !empty( $data['venue_short_description'] ) ? $data['venue_short_description'] : NULL,
910
				'VNU_address' => !empty( $data['address'] ) ? $data['address'] : NULL,
911
				'VNU_address2' => !empty( $data['address2'] ) ? $data['address2'] : NULL,
912
				'VNU_city' => !empty( $data['city'] ) ? $data['city'] : NULL,
913
				'STA_ID' => !empty( $data['state'] ) ? $data['state'] : NULL,
914
				'CNT_ISO' => !empty( $data['countries'] ) ? $data['countries'] : NULL,
915
				'VNU_zip' => !empty( $data['zip'] ) ? $data['zip'] : NULL,
916
				'VNU_phone' => !empty( $data['venue_phone'] ) ? $data['venue_phone'] : NULL,
917
				'VNU_capacity' => !empty( $data['venue_capacity'] ) ? $data['venue_capacity'] : NULL,
918
				'VNU_url' => !empty($data['venue_url'] ) ? $data['venue_url'] : NULL,
919
				'VNU_virtual_phone' => !empty($data['virtual_phone']) ? $data['virtual_phone'] : NULL,
920
				'VNU_virtual_url' => !empty( $data['virtual_url'] ) ? $data['virtual_url'] : NULL,
921
				'VNU_enable_for_gmap' => isset( $data['enable_for_gmap'] ) ? 1 : 0,
922
				'status' => 'publish'
923
			);
924
925
926
		//if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
927
		if ( !empty( $venue_id ) ) {
928
			$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...
929
			$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...
930
			//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.
931
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
932
			return $rows_affected > 0 ? TRUE : FALSE;
933
		} else {
934
			//we insert the venue
935
			$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...
936
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
937
			return !empty( $venue_id ) ? TRUE : FALSE;
938
		}
939
		//when we have the ancestor come in it's already been handled by the revision save.
940
	}
941
942
943
944
945
	/**
946
	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
947
	 * @param  EE_Event $evtobj The Event object we're attaching data to
948
	 * @param  array    $data   The request data from the form
949
	 * @return bool             success or fail
950
	 */
951
	protected function _default_tickets_update( EE_Event $evtobj, $data ) {
952
		$success = true;
953
		$saved_dtt = null;
954
		$saved_tickets = array();
955
		$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
956
957
		foreach ( $data['edit_event_datetimes'] as $row => $dtt ) {
958
			//trim all values to ensure any excess whitespace is removed.
959
			$dtt =  array_map( 'trim', $dtt );
960
			$dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty( $dtt['DTT_EVT_end'] ) ? $dtt['DTT_EVT_end'] : $dtt['DTT_EVT_start'];
961
			$datetime_values = array(
962
				'DTT_ID' 		=> ! empty( $dtt['DTT_ID'] ) ? $dtt['DTT_ID'] : NULL,
963
				'DTT_EVT_start' => $dtt['DTT_EVT_start'],
964
				'DTT_EVT_end' 	=> $dtt['DTT_EVT_end'],
965
				'DTT_reg_limit' => empty( $dtt['DTT_reg_limit'] ) ? EE_INF : $dtt['DTT_reg_limit'],
966
				'DTT_order' 	=> $row,
967
			);
968
969
			//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.
970
971
			if ( !empty( $dtt['DTT_ID'] ) ) {
972
				$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...
973
				$DTM->set_date_format( $incoming_date_formats[0] );
974
				$DTM->set_time_format( $incoming_date_formats[1] );
975
				foreach ( $datetime_values as $field => $value ) {
976
					$DTM->set( $field, $value );
977
				}
978
979
				//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.
980
				$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...
981
			} else {
982
				$DTM = EE_Registry::instance()->load_class('Datetime', array( $datetime_values ), FALSE, FALSE );
983
				$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...
984
				$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...
985
				$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...
986
				foreach ( $datetime_values as $field => $value ) {
987
					$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...
988
				}
989
			}
990
			$DTM->save();
991
992
			$DTT = $evtobj->_add_relation_to( $DTM, 'Datetime' );
993
994
			//load DTT helper
995
			EE_Registry::instance()->load_helper('DTT_Helper');
996
997
			//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.
998
			if( $DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end') ) {
999
				$DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start') );
1000
				$DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
1001
				$DTT->save();
1002
			}
1003
1004
			//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.
1005
			$saved_dtt = $DTT;
1006
1007
			$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.
1008
		}
1009
1010
		//no dtts get deleted so we don't do any of that logic here.
1011
		//update tickets next
1012
		$old_tickets = isset( $data['ticket_IDs'] ) ? explode(',', $data['ticket_IDs'] ) : array();
1013
		foreach ( $data['edit_tickets'] as $row => $tkt ) {
1014
			$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
1015
			$update_prices = false;
1016
			$ticket_price = isset( $data['edit_prices'][$row][1]['PRC_amount'] ) ? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
1017
1018
			// trim inputs to ensure any excess whitespace is removed.
1019
			$tkt = array_map( 'trim', $tkt );
1020
1021
			if ( empty( $tkt['TKT_start_date'] ) ) {
1022
				//let's use now in the set timezone.
1023
				$now = new DateTime( 'now', new DateTimeZone( $evtobj->get_timezone() ) );
1024
				$tkt['TKT_start_date'] = $now->format( $incoming_date_formats[0] . ' ' . $incoming_date_formats[1] );
1025
			}
1026
1027
			if ( empty( $tkt['TKT_end_date'] ) ) {
1028
				//use the start date of the first datetime
1029
				$dtt = $evtobj->first_datetime();
1030
				$tkt['TKT_end_date'] = $dtt->start_date_and_time( $incoming_date_formats[0], $incoming_date_formats[1] );
1031
			}
1032
1033
			$TKT_values = array(
1034
				'TKT_ID' 			=> !empty( $tkt['TKT_ID'] ) ? $tkt['TKT_ID'] : NULL,
1035
				'TTM_ID' 			=> !empty( $tkt['TTM_ID'] ) ? $tkt['TTM_ID'] : 0,
1036
				'TKT_name' 			=> !empty( $tkt['TKT_name'] ) ? $tkt['TKT_name'] : '',
1037
				'TKT_description' 	=> !empty( $tkt['TKT_description'] ) ? $tkt['TKT_description'] : '',
1038
				'TKT_start_date' 	=> $tkt['TKT_start_date'],
1039
				'TKT_end_date' 		=> $tkt['TKT_end_date'],
1040
				'TKT_qty' 			=> ! isset( $tkt[ 'TKT_qty' ] ) || $tkt[ 'TKT_qty' ] === '' ? EE_INF : $tkt['TKT_qty'],
1041
				'TKT_uses' 			=> ! isset( $tkt[ 'TKT_uses' ] ) || $tkt[ 'TKT_uses' ] === '' ? EE_INF : $tkt[ 'TKT_uses' ],
1042
				'TKT_min' 			=> empty( $tkt['TKT_min'] ) ? 0 : $tkt['TKT_min'],
1043
				'TKT_max' 			=> empty( $tkt['TKT_max'] ) ? EE_INF : $tkt['TKT_max'],
1044
				'TKT_row' 			=> $row,
1045
				'TKT_order' 		=> isset( $tkt['TKT_order'] ) ? $tkt['TKT_order'] : $row,
1046
				'TKT_price' 		=> $ticket_price
1047
			);
1048
1049
1050
1051
1052
			//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.
1053 View Code Duplication
			if ( isset( $tkt['TKT_is_default'] ) && $tkt['TKT_is_default'] ) {
1054
				$TKT_values['TKT_ID'] = 0;
1055
				$TKT_values['TKT_is_default'] = 0;
1056
				$TKT_values['TKT_price'] = $ticket_price;
1057
				$update_prices = TRUE;
1058
			}
1059
1060
			//if we have a TKT_ID then we need to get that existing TKT_obj and update it
1061
			//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.
1062
			//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.
1063
1064
			if ( !empty( $tkt['TKT_ID'] ) ) {
1065
				$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...
1066
				if ( $TKT instanceof EE_Ticket ) {
1067
					$ticket_sold = $TKT->count_related( 'Registration', array( array( 'STS_ID' => array( 'NOT IN', array( EEM_Registration::status_id_incomplete ) ) ) ) ) > 0 ? true : false;
1068
					//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.
1069
					$create_new_TKT = $ticket_sold && $ticket_price != $TKT->get( 'TKT_price' ) && ! $TKT->get( 'TKT_deleted' ) ? true : false;
1070
					$TKT->set_date_format( $incoming_date_formats[ 0 ] );
1071
					$TKT->set_time_format( $incoming_date_formats[ 1 ] );
1072
					//set new values
1073 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1074
						if ( $field == 'TKT_qty' ) {
1075
							$TKT->set_qty( $value );
1076
						} else {
1077
							$TKT->set( $field, $value );
1078
						}
1079
					}
1080
					//if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1081
					if ( $create_new_TKT ) {
1082
						//archive the old ticket first
1083
						$TKT->set( 'TKT_deleted', 1 );
1084
						$TKT->save();
1085
						//make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1086
						$saved_tickets[ $TKT->ID() ] = $TKT;
1087
						//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.
1088
						$TKT = clone $TKT;
1089
						$TKT->set( 'TKT_ID', 0 );
1090
						$TKT->set( 'TKT_deleted', 0 );
1091
						$TKT->set( 'TKT_price', $ticket_price );
1092
						$TKT->set( 'TKT_sold', 0 );
1093
						//now we need to make sure that $new prices are created as well and attached to new ticket.
1094
						$update_prices = true;
1095
					}
1096
					//make sure price is set if it hasn't been already
1097
					$TKT->set( 'TKT_price', $ticket_price );
1098
				}
1099
1100
			} else {
1101
				//no TKT_id so a new TKT
1102
				$TKT_values['TKT_price'] = $ticket_price;
1103
				$TKT = EE_Registry::instance()->load_class('Ticket', array( $TKT_values ), FALSE, FALSE );
1104
				if ( $TKT instanceof EE_Ticket ) {
1105
					//need to reset values to properly account for the date formats
1106
					$TKT->set_date_format( $incoming_date_formats[0] );
1107
					$TKT->set_time_format( $incoming_date_formats[1] );
1108
					$TKT->set_timezone( $evtobj->get_timezone() );
1109
1110
					//set new values
1111 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1112
						if ( $field == 'TKT_qty' ) {
1113
							$TKT->set_qty( $value );
1114
						} else {
1115
							$TKT->set( $field, $value );
1116
						}
1117
					}
1118
1119
					$update_prices = TRUE;
1120
				}
1121
			}
1122
			// cap ticket qty by datetime reg limits
1123
			$TKT->set_qty( min( $TKT->qty(), $TKT->qty( 'reg_limit' ) ) );
1124
			//update ticket.
1125
			$TKT->save();
1126
1127
			//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.
1128 View Code Duplication
			if( $TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date') ) {
1129
				$TKT->set('TKT_end_date', $TKT->get('TKT_start_date') );
1130
				EE_Registry::instance()->load_helper('DTT_Helper');
1131
				$TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1132
				$TKT->save();
1133
			}
1134
1135
			//initially let's add the ticket to the dtt
1136
			$saved_dtt->_add_relation_to( $TKT, 'Ticket' );
1137
1138
			$saved_tickets[$TKT->ID()] = $TKT;
1139
1140
			//add prices to ticket
1141
			$this->_add_prices_to_ticket( $data['edit_prices'][$row], $TKT, $update_prices );
1142
		}
1143
		//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.
1144
		$old_tickets = isset( $old_tickets[0] ) && $old_tickets[0] == '' ? array() : $old_tickets;
1145
		$tickets_removed = array_diff( $old_tickets, array_keys( $saved_tickets ) );
1146
1147 View Code Duplication
		foreach ( $tickets_removed as $id ) {
1148
			$id = absint( $id );
1149
1150
			//get the ticket for this id
1151
			$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...
1152
1153
			//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)
1154
			$dtts = $tkt_to_remove->get_many_related('Datetime');
1155
1156
			foreach( $dtts as $dtt ) {
1157
				$tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1158
			}
1159
1160
			//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))
1161
			$tkt_to_remove->delete_related_permanently('Price');
1162
1163
1164
			//finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1165
			$tkt_to_remove->delete_permanently();
1166
		}
1167
		return array( $saved_dtt, $saved_tickets );
1168
	}
1169
1170
1171
1172
	/**
1173
	 * This attaches a list of given prices to a ticket.
1174
	 * 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.
1175
	 *
1176
	 * @access  private
1177
	 * @param array  	$prices  	Array of prices from the form.
1178
	 * @param EE_Ticket $ticket  	EE_Ticket object that prices are being attached to.
1179
	 * @param bool 		$new_prices Whether attach existing incoming prices or create new ones.
1180
	 * @return  void
1181
	 */
1182
	private function  _add_prices_to_ticket( $prices, EE_Ticket $ticket, $new_prices = FALSE ) {
1183
		foreach ( $prices as $row => $prc ) {
1184
			$PRC_values = array(
1185
				'PRC_ID' => !empty( $prc['PRC_ID'] ) ? $prc['PRC_ID'] : NULL,
1186
				'PRT_ID' => !empty( $prc['PRT_ID'] ) ? $prc['PRT_ID'] : NULL,
1187
				'PRC_amount' => !empty( $prc['PRC_amount'] ) ? $prc['PRC_amount'] : 0,
1188
				'PRC_name' => !empty( $prc['PRC_name'] ) ? $prc['PRC_name'] : '',
1189
				'PRC_desc' => !empty( $prc['PRC_desc'] ) ? $prc['PRC_desc'] : '',
1190
				'PRC_is_default' => 0, //make sure prices are NOT set as default from this context
1191
				'PRC_order' => $row
1192
			);
1193
1194 View Code Duplication
			if ( $new_prices || empty( $PRC_values['PRC_ID'] ) ) {
1195
				$PRC_values['PRC_ID'] = 0;
1196
				$PRC = EE_Registry::instance()->load_class('Price', array( $PRC_values ), FALSE, FALSE);
1197
			} else {
1198
				$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...
1199
				//update this price with new values
1200
				foreach ( $PRC_values as $field => $newprc ) {
1201
					$PRC->set( $field, $newprc );
1202
				}
1203
				$PRC->save();
1204
			}
1205
1206
			$ticket->_add_relation_to( $PRC, 'Price' );
1207
		}
1208
	}
1209
1210
1211
1212
1213
	/**
1214
	 * Add in our autosave ajax handlers
1215
	 * @return void
1216
	 */
1217
	protected function _ee_autosave_create_new() {
1218
		// $this->_ee_autosave_edit();
1219
	}
1220
1221
1222
1223
1224
1225
	protected function _ee_autosave_edit() {
1226
		return; //TEMPORARILY EXITING CAUSE THIS IS A TODO
1227
	}
1228
1229
1230
1231
1232
1233
1234
	/**
1235
	 * 	_generate_publish_box_extra_content
1236
	 * 	@access private
1237
	 * @return void
1238
	 */
1239
	private function _generate_publish_box_extra_content() {
1240
1241
		//load formatter helper
1242
  		EE_Registry::instance()->load_helper( 'Formatter' );
1243
1244
  		//args for getting related registrations
1245
  		$approved_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_approved ) );
1246
  		$not_approved_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_not_approved ) );
1247
  		$pending_payment_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_pending_payment ) );
1248
1249
1250
		// publish box
1251
		$publish_box_extra_args = array(
1252
			'view_approved_reg_url' => add_query_arg(
1253
				array(
1254
					'action'      => 'default',
1255
					'event_id'    => $this->_cpt_model_obj->ID(),
1256
					'_reg_status' => EEM_Registration::status_id_approved
1257
				),
1258
			  REG_ADMIN_URL
1259
			),
1260
			'view_not_approved_reg_url' => add_query_arg(
1261
				array(
1262
					'action'      => 'default',
1263
					'event_id'    => $this->_cpt_model_obj->ID(),
1264
					'_reg_status' => EEM_Registration::status_id_not_approved
1265
				),
1266
				REG_ADMIN_URL
1267
			),
1268
			'view_pending_payment_reg_url' => add_query_arg(
1269
				array(
1270
					'action'      => 'default',
1271
					'event_id'    => $this->_cpt_model_obj->ID(),
1272
					'_reg_status' => EEM_Registration::status_id_pending_payment
1273
				),
1274
				REG_ADMIN_URL
1275
			),
1276
			'approved_regs' => $this->_cpt_model_obj->count_related( 'Registration', $approved_query_args ),
1277
			'not_approved_regs' => $this->_cpt_model_obj->count_related( 'Registration', $not_approved_query_args ),
1278
			'pending_payment_regs' => $this->_cpt_model_obj->count_related( 'Registration', $pending_payment_query_args ),
1279
			'misc_pub_section_class' => apply_filters(
1280
				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1281
				'misc-pub-section'
1282
			),
1283
			//'email_attendees_url' => add_query_arg(
1284
			//	array(
1285
			//		'event_admin_reports' => 'event_newsletter',
1286
			//		'event_id' => $this->_cpt_model_obj->id
1287
			//	),
1288
			//	'admin.php?page=espresso_registrations'
1289
			//),
1290
1291
		);
1292
		ob_start();
1293
		do_action(
1294
			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1295
			$this->_cpt_model_obj
1296
		);
1297
		$publish_box_extra_args[ 'event_editor_overview_add' ] = ob_get_clean();
1298
		// load template
1299
		EEH_Template::display_template( EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php', $publish_box_extra_args );
1300
	}
1301
1302
1303
1304
1305
1306
	/**
1307
	 * This just returns whatever is set as the _event object property
1308
	 *
1309
	 * //todo this will become obsolete once the models are in place
1310
	 * @return object
1311
	 */
1312
	public function get_event_object() {
1313
		return $this->_cpt_model_obj;
1314
	}
1315
1316
1317
1318
	/*	 * ************ */
1319
	/** METABOXES * */
1320
1321
	/**
1322
	 * _register_event_editor_meta_boxes
1323
	 * add all metaboxes related to the event_editor
1324
	 *
1325
	 * @return void
1326
	 */
1327
	protected function _register_event_editor_meta_boxes() {
1328
		$this->verify_cpt_object();
1329
		add_meta_box(
1330
			'espresso_event_editor_tickets',
1331
			__( 'Event Datetime & Ticket', 'event_espresso' ),
1332
			array( $this, 'ticket_metabox' ),
1333
			$this->page_slug,
1334
			'normal',
1335
			'high'
1336
		);
1337
		add_meta_box(
1338
			'espresso_event_editor_event_options',
1339
			__( 'Event Registration Options', 'event_espresso' ),
1340
			array( $this, 'registration_options_meta_box' ),
1341
			$this->page_slug,
1342
			'side',
1343
			'default'
1344
		);
1345
		// NOTE: if you're looking for other metaboxes in here,
1346
		// where a metabox has a related management page in the admin
1347
		// you will find it setup in the related management page's "_Hooks" file.
1348
		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1349
	}
1350
1351
1352
1353
1354
	public function ticket_metabox() {
1355
		$existing_datetime_ids = $existing_ticket_ids = array();
1356
		//defaults for template args
1357
		$template_args = array(
1358
			'existing_datetime_ids' => '',
1359
			'event_datetime_help_link' => '',
1360
			'ticket_options_help_link' => '',
1361
			'time' => null,
1362
			'ticket_rows' => '',
1363
			'existing_ticket_ids' => '',
1364
			'total_ticket_rows' => 1,
1365
			'ticket_js_structure' => '',
1366
			'trash_icon' => 'ee-lock-icon',
1367
			'disabled' => ''
1368
			);
1369
1370
		$event_id = is_object( $this->_cpt_model_obj ) ? $this->_cpt_model_obj->ID() : NULL;
1371
1372
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
1373
1374
		/**
1375
		 * 1. Start with retrieving Datetimes
1376
		 * 2. Fore each datetime get related tickets
1377
		 * 3. For each ticket get related prices
1378
		 */
1379
		$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...
1380
		EE_Registry::instance()->load_helper('DTT_Helper' );
1381
		/** @type EE_Datetime $first_datetime */
1382
		$first_datetime = reset( $times );
1383
		//do we get related tickets?
1384
		if ( $first_datetime instanceof EE_Datetime
1385
			&& $first_datetime->ID() !== 0 ) {
1386
			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1387
			$template_args['time'] = $first_datetime;
1388
			$related_tickets = $first_datetime->tickets(
1389
				array(
1390
					array( 'OR' => array( 'TKT_deleted' => 1, 'TKT_deleted*' => 0 ) ),
1391
					'default_where_conditions' => 'none'
1392
				)
1393
			);
1394
1395
			if ( !empty($related_tickets) ) {
1396
				$template_args['total_ticket_rows'] = count($related_tickets);
1397
				$row = 0;
1398
				foreach ( $related_tickets as $ticket ) {
1399
					$existing_ticket_ids[] = $ticket->get('TKT_ID');
1400
					$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...
1401
1402
					$row++;
1403
				}
1404 View Code Duplication
			} else {
1405
				$template_args['total_ticket_rows'] = 1;
1406
				/** @type EE_Ticket $ticket */
1407
				$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...
1408
				$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket );
1409
			}
1410 View Code Duplication
		} else {
1411
			$template_args['time'] = $times[0];
1412
			/** @type EE_Ticket $ticket */
1413
			$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...
1414
			$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket[1] );
1415
			// NOTE: we're just sending the first default row
1416
			// (decaf can't manage default tickets so this should be sufficient);
1417
		}
1418
1419
		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link('event_editor_event_datetimes_help_tab');
1420
		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1421
		$template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1422
		$template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1423
		$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...
1424
		$template = apply_filters( 'FHEE__Events_Admin_Page__ticket_metabox__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php' );
1425
		EEH_Template::display_template($template, $template_args);
1426
	}
1427
1428
1429
1430
	/**
1431
	 * Setup an individual ticket form for the decaf event editor page
1432
	 *
1433
	 * @access private
1434
	 * @param  EE_Ticket $ticket   the ticket object
1435
	 * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1436
	 * @param int        $row
1437
	 * @return string generated html for the ticket row.
1438
	 */
1439
	private function _get_ticket_row( $ticket, $skeleton = FALSE, $row = 0 ) {
1440
		$template_args = array(
1441
			'tkt_status_class' => ' tkt-status-' . $ticket->ticket_status(),
1442
			'tkt_archive_class' => $ticket->ticket_status() === EE_Ticket::archived && !$skeleton ? ' tkt-archived' : '',
1443
			'ticketrow' => $skeleton ? 'TICKETNUM' : $row,
1444
			'TKT_ID' => $ticket->get('TKT_ID'),
1445
			'TKT_name' => $ticket->get('TKT_name'),
1446
			'TKT_start_date' => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1447
			'TKT_end_date' => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1448
			'TKT_is_default' => $ticket->get('TKT_is_default'),
1449
			'TKT_qty' => $ticket->get_pretty('TKT_qty','input'),
1450
			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1451
			'TKT_sold' => $skeleton ? 0 : $ticket->get('TKT_sold'),
1452
			'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',
1453
			'disabled' => $skeleton || ( !empty( $ticket ) && ! $ticket->get('TKT_deleted' ) ) ? '' : ' disabled=disabled'
1454
			);
1455
1456
		$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...
1457
1458
1459
		$price_args = array(
1460
			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1461
			'PRC_amount' => $price->get('PRC_amount'),
1462
			'PRT_ID' => $price->get('PRT_ID'),
1463
			'PRC_ID' => $price->get('PRC_ID'),
1464
			'PRC_is_default' => $price->get('PRC_is_default'),
1465
			);
1466
1467
		//make sure we have default start and end dates if skeleton
1468
		//handle rows that should NOT be empty
1469
		if ( empty( $template_args['TKT_start_date'] ) ) {
1470
			//if empty then the start date will be now.
1471
			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1472
		}
1473
1474
		if ( empty( $template_args['TKT_end_date'] ) ) {
1475
			//get the earliest datetime (if present);
1476
			$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;
1477
1478
			if ( !empty( $earliest_dtt ) )
1479
				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1480
			else
1481
				$template_args['TKT_end_date'] = date('Y-m-d h:i a', mktime(0, 0, 0, date("m"), date("d")+7, date("Y") ) );
1482
		}
1483
1484
		$template_args = array_merge( $template_args, $price_args );
1485
		$template = apply_filters( 'FHEE__Events_Admin_Page__get_ticket_row__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php', $ticket);
1486
		return EEH_Template::display_template($template, $template_args, TRUE);
1487
	}
1488
1489
1490
1491
	public function registration_options_meta_box() {
1492
1493
		$yes_no_values = array(
1494
			array('id' => true, 'text' => __('Yes', 'event_espresso')),
1495
			array('id' => false, 'text' => __('No', 'event_espresso'))
1496
		);
1497
1498
		$default_reg_status_values = EEM_Registration::reg_status_array(
1499
			array(
1500
				EEM_Registration::status_id_cancelled,
1501
				EEM_Registration::status_id_declined,
1502
				EEM_Registration::status_id_incomplete
1503
			),
1504
			TRUE
1505
		);
1506
1507
		//$template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1508
		$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...
1509
		$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...
1510
		$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...
1511
		$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...
1512
		$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...
1513
		$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...
1514
		$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 );
1515
		$templatepath = EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php';
1516
		EEH_Template::display_template($templatepath, $template_args);
1517
	}
1518
1519
1520
1521
	/** end metaboxes * */
1522
	/*	 * **************** *
1523
1524
1525
1526
1527
	/**
1528
	 * _get_events()
1529
	 * This method simply returns all the events (for the given _view and paging)
1530
	 *
1531
	 * @access public
1532
	 *
1533
	 * @param int $per_page count of items per page (20 default);
1534
	 * @param int $current_page what is the current page being viewed.
1535
	 * @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.
1536
	 * @return array an array of event objects.
1537
	 */
1538
	public function get_events($per_page = 10, $current_page = 1, $count = FALSE) {
1539
1540
		$EEME = $this->_event_model();
1541
1542
		$offset = ($current_page - 1) * $per_page;
1543
		$limit = $count ? NULL : $offset . ',' . $per_page;
1544
		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1545
		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1546
1547
		if (isset($this->_req_data['month_range'])) {
1548
			$pieces = explode(' ', $this->_req_data['month_range'], 3);
1549
			$month_r = !empty($pieces[0]) ? date('m', strtotime($pieces[0])) : '';
1550
			$year_r = !empty($pieces[1]) ? $pieces[1] : '';
1551
		}
1552
1553
		$where = array();
1554
1555
		$status = isset( $this->_req_data['status'] ) ? $this->_req_data['status'] : NULL;
1556
		//determine what post_status our condition will have for the query.
1557
		switch ( $status ) {
1558
			case 'month' :
1559
			case 'today' :
1560
			case NULL :
1561
			case 'all' :
1562
				break;
1563
1564
			case 'draft' :
1565
				$where['status'] = array( 'IN', array('draft', 'auto-draft') );
1566
				break;
1567
1568
			default :
1569
				$where['status'] = $status;
1570
		}
1571
1572
		//categories?
1573
		$category = isset( $this->_req_data['EVT_CAT'] ) && $this->_req_data['EVT_CAT'] > 0 ? $this->_req_data['EVT_CAT'] : NULL;
1574
1575
		if ( !empty ( $category ) ) {
1576
			$where['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1577
			$where['Term_Taxonomy.term_id'] = $category;
1578
		}
1579
1580
		//date where conditions
1581
		$start_formats = EEM_Datetime::instance()->get_formats_for( 'DTT_EVT_start' );
1582
		if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1583
			$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...
1584
			$start = $DateTime->format( implode( ' ', $start_formats  ) );
1585
			$end = $DateTime->setDate( $year_r, $month_r, $DateTime->format('t') )->setTime(23,59,59)->format( implode( ' ', $start_formats ) );
1586
			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array( $start, $end ) );
1587
		} else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1588
			$DateTime = new DateTime( 'now', new DateTimeZone( EEM_Event::instance()->get_timezone() ) );
1589
			$start = $DateTime->setTime( 0,0,0 )->format( implode( ' ', $start_formats ) );
1590
			$end = $DateTime->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1591
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1592
		} else if ( isset($this->_req_data['status']) && $this->_req_data['status'] == 'month' ) {
1593
			$now = date( 'Y-m-01' );
1594
			$DateTime = new DateTime( $now, new DateTimeZone( EEM_Event::instance()->get_timezone() ) );
1595
			$start = $DateTime->setTime( 0, 0, 0 )->format( implode( ' ', $start_formats ) );
1596
			$end = $DateTime->setDate( date('Y'), date('m'), $DateTime->format('t' ) )->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1597
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1598
		}
1599
1600
1601 View Code Duplication
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1602
			$where['EVT_wp_user'] =  get_current_user_id();
1603
		} else {
1604
			if ( ! isset( $where['status'] ) ) {
1605
				if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_private_events', 'get_events' ) ) {
1606
					$where['OR'] = array(
1607
						'status*restrict_private' => array( '!=', 'private' ),
1608
						'AND' => array(
1609
							'status*inclusive' => array( '=', 'private' ),
1610
							'EVT_wp_user' => get_current_user_id()
1611
						)
1612
					);
1613
				}
1614
			}
1615
		}
1616
1617
		if ( isset( $this->_req_data['EVT_wp_user'] ) ) {
1618
			if ( $this->_req_data['EVT_wp_user'] != get_current_user_id() && EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1619
				$where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1620
			}
1621
		}
1622
1623
1624
		//search query handling
1625
		if ( isset( $this->_req_data['s'] ) ) {
1626
			$search_string = '%' . $this->_req_data['s'] . '%';
1627
			$where['OR'] = array(
1628
				'EVT_name' => array('LIKE', $search_string),
1629
				'EVT_desc' => array('LIKE', $search_string),
1630
				'EVT_short_desc' => array('LIKE', $search_string)
1631
				);
1632
		}
1633
1634
1635
		$where = apply_filters( 'FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data );
1636
		$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 );
1637
1638
1639
		//let's first check if we have special requests coming in.
1640
		if ( isset( $this->_req_data['active_status'] ) ) {
1641
			switch ( $this->_req_data['active_status'] ) {
1642
				case 'upcoming' :
1643
					return $EEME->get_upcoming_events( $query_params, $count );
1644
					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...
1645
1646
				case 'expired' :
1647
					return $EEME->get_expired_events( $query_params, $count );
1648
					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...
1649
1650
				case 'active' :
1651
					return $EEME->get_active_events( $query_params, $count );
1652
					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...
1653
1654
				case 'inactive' :
1655
					return $EEME->get_inactive_events( $query_params, $count );
1656
					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...
1657
			}
1658
		}
1659
1660
		$events = $count ? $EEME->count( array( $where ), 'EVT_ID', true ) : $EEME->get_all( $query_params );
1661
1662
		return $events;
1663
	}
1664
1665
1666
1667
1668
	//handling for WordPress CPT actions (trash, restore, delete)
1669
	public function trash_cpt_item( $post_id ) {
1670
		$this->_req_data['EVT_ID'] = $post_id;
1671
		$this->_trash_or_restore_event( 'trash', FALSE );
1672
	}
1673
1674
1675
1676
1677
	public function restore_cpt_item( $post_id ) {
1678
		$this->_req_data['EVT_ID'] = $post_id;
1679
		$this->_trash_or_restore_event( 'draft', FALSE );
1680
	}
1681
1682
1683
	public function delete_cpt_item( $post_id ) {
1684
		$this->_req_data['EVT_ID'] = $post_id;
1685
		$this->_delete_event( FALSE );
1686
	}
1687
1688
1689
1690
	/**
1691
	 * _trash_or_restore_event
1692
	 *
1693
	 * @access protected
1694
	 * @param  string $event_status
1695
	 * @return void
1696
	 */
1697 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...
1698
		//determine the event id and set to array.
1699
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : FALSE;
1700
		// loop thru events
1701
		if ($EVT_ID) {
1702
			// clean status
1703
			$event_status = sanitize_key($event_status);
1704
			// grab status
1705
			if (!empty($event_status)) {
1706
				$success = $this->_change_event_status($EVT_ID, $event_status);
1707
			} else {
1708
				$success = FALSE;
1709
				$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1710
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1711
			}
1712
		} else {
1713
			$success = FALSE;
1714
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.', 'event_espresso');
1715
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1716
		}
1717
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1718
1719
		if ( $redirect_after )
1720
			$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...
1721
	}
1722
1723
	/**
1724
	 * _trash_or_restore_events
1725
	 *
1726
	 * @access protected
1727
	 * @param  string $event_status
1728
	 * @return void
1729
	 */
1730 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...
1731
		// clean status
1732
		$event_status = sanitize_key($event_status);
1733
		// grab status
1734
		if (!empty($event_status)) {
1735
			$success = TRUE;
1736
			//determine the event id and set to array.
1737
			$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1738
			// loop thru events
1739
			foreach ($EVT_IDs as $EVT_ID) {
1740
				if ($EVT_ID = absint($EVT_ID)) {
1741
					$results = $this->_change_event_status($EVT_ID, $event_status);
1742
					$success = $results !== FALSE ? $success : FALSE;
1743
				} else {
1744
					$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);
1745
					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1746
					$success = FALSE;
1747
				}
1748
			}
1749
		} else {
1750
			$success = FALSE;
1751
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1752
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1753
		}
1754
		// in order to force a pluralized result message we need to send back a success status greater than 1
1755
		$success = $success ? 2 : FALSE;
1756
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1757
1758
		$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 1755 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...
1759
	}
1760
1761
	/**
1762
	 * _trash_or_restore_events
1763
	 *
1764
	 * @access  private
1765
	 * @param  int $EVT_ID
1766
	 * @param  string $event_status
1767
	 * @return bool
1768
	 */
1769 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...
1770
		// grab event id
1771
		if (!$EVT_ID) {
1772
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1773
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1774
			return FALSE;
1775
		}
1776
1777
		$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...
1778
1779
		// clean status
1780
		$event_status = sanitize_key($event_status);
1781
		// grab status
1782
		if (empty($event_status)) {
1783
			$msg = __('An error occurred. No Event Status or an invalid Event Status was received.', 'event_espresso');
1784
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1785
			return FALSE;
1786
		}
1787
1788
		// was event trashed or restored ?
1789
		switch ($event_status) {
1790
			case 'draft' :
1791
				$action = 'restored from the trash';
1792
				$hook = 'AHEE_event_restored_from_trash';
1793
				break;
1794
			case 'trash' :
1795
				$action = 'moved to the trash';
1796
				$hook = 'AHEE_event_moved_to_trash';
1797
				break;
1798
			default :
1799
				$action = 'updated';
1800
				$hook = FALSE;
1801
		}
1802
		//use class to change status
1803
		$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...
1804
		$success = $this->_cpt_model_obj->save();
1805
1806
		if ($success === FALSE) {
1807
			$msg = sprintf(__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
1808
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1809
			return FALSE;
1810
		}
1811
		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...
1812
			do_action($hook);
1813
		}
1814
		return TRUE;
1815
	}
1816
1817
1818
1819
	/**
1820
	 * _delete_event
1821
	 *
1822
	 * @access protected
1823
	 * @param bool $redirect_after
1824
	 */
1825
	protected function _delete_event( $redirect_after = TRUE ) {
1826
		//determine the event id and set to array.
1827
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : NULL;
1828
		$EVT_ID = isset( $this->_req_data['post'] ) ? absint( $this->_req_data['post'] ) : $EVT_ID;
1829
1830
1831
		// loop thru events
1832
		if ($EVT_ID) {
1833
			$success = $this->_permanently_delete_event( $EVT_ID );
1834
			// get list of events with no prices
1835
			$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1836
			// remove this event from the list of events with no prices
1837
			if (isset($espresso_no_ticket_prices[$EVT_ID])) {
1838
				unset($espresso_no_ticket_prices[$EVT_ID]);
1839
			}
1840
			update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1841
		} else {
1842
			$success = FALSE;
1843
			$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1844
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1845
		}
1846
1847
		if ( $redirect_after )
1848
			$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...
1849
	}
1850
1851
	/**
1852
	 * _delete_events
1853
	 *
1854
	 * @access protected
1855
	 * @return void
1856
	 */
1857
	protected function _delete_events() {
1858
		$success = TRUE;
1859
		// get list of events with no prices
1860
		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1861
		//determine the event id and set to array.
1862
		$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1863
		// loop thru events
1864
		foreach ($EVT_IDs as $EVT_ID) {
1865
			$EVT_ID = absint( $EVT_ID );
1866
			if ( $EVT_ID ) {
1867
				$results = $this->_permanently_delete_event( $EVT_ID );
1868
				$success = $results !== FALSE ? $success : FALSE;
1869
				// remove this event from the list of events with no prices
1870
				unset( $espresso_no_ticket_prices[ $EVT_ID ] );
1871
			} else {
1872
				$success = FALSE;
1873
				$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1874
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1875
			}
1876
		}
1877
		update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1878
		// in order to force a pluralized result message we need to send back a success status greater than 1
1879
		$success = $success ? 2 : FALSE;
1880
		$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 1879 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...
1881
	}
1882
1883
	/**
1884
	 * _permanently_delete_event
1885
	 *
1886
	 * @access  private
1887
	 * @param  int $EVT_ID
1888
	 * @return bool
1889
	 */
1890
	private function _permanently_delete_event( $EVT_ID = 0 ) {
1891
		// grab event id
1892
		if ( ! $EVT_ID ) {
1893
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1894
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1895
			return FALSE;
1896
		}
1897
		if (
1898
			! $this->_cpt_model_obj instanceof EE_Event
1899
			|| $this->_cpt_model_obj->ID() !== $EVT_ID
1900
		) {
1901
			$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...
1902
		}
1903
1904
		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...
1905
			return false;
1906
		}
1907
1908
		//need to delete related tickets and prices first.
1909
		$datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
1910
		foreach ( $datetimes as $datetime ) {
1911
			$this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
1912
			$tickets = $datetime->get_many_related('Ticket');
1913
			foreach ( $tickets as $ticket ) {
1914
				$ticket->_remove_relation_to($datetime, 'Datetime');
1915
				$ticket->delete_related_permanently('Price');
1916
				$ticket->delete_permanently();
1917
			}
1918
			$datetime->delete();
1919
		}
1920
1921
		//what about related venues or terms?
1922
		$venues = $this->_cpt_model_obj->get_many_related('Venue');
1923
		foreach ( $venues as $venue ) {
1924
			$this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
1925
		}
1926
1927
		//any attached question groups?
1928
		$question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
1929
		if ( !empty( $question_groups ) ) {
1930
			foreach ( $question_groups as $question_group ) {
1931
				$this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
1932
			}
1933
		}
1934
1935
1936
1937
1938
		//Message Template Groups
1939
		$this->_cpt_model_obj->_remove_relations( 'Message_Template_Group' );
1940
1941
		/** @type EE_Term_Taxonomy[] $term_taxonomies */
1942
		$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...
1943
1944
		foreach ( $term_taxonomies as $term_taxonomy ) {
1945
			$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...
1946
		}
1947
1948
		$success = $this->_cpt_model_obj->delete_permanently();
1949
		// did it all go as planned ?
1950
		if ($success) {
1951
			$msg = sprintf(__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
1952
			EE_Error::add_success($msg);
1953
		} else {
1954
			$msg = sprintf(__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'), $EVT_ID);
1955
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1956
			return FALSE;
1957
		}
1958
		do_action( 'AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID );
1959
		return TRUE;
1960
	}
1961
1962
1963
1964
1965
1966
1967
	/**
1968
	 * get total number of events
1969
	 *
1970
	 * @access public
1971
	 * @return int
1972
	 */
1973
	public function total_events() {
1974
1975
		$count = EEM_Event::instance()->count( array( 'caps' => 'read_admin' ), 'EVT_ID', true );
1976
		return $count;
1977
	}
1978
1979
1980
1981
1982
	/**
1983
	 * get total number of draft events
1984
	 *
1985
	 * @access public
1986
	 * @return int
1987
	 */
1988
	public function total_events_draft() {
1989
		$where = array(
1990
			'status' => array( 'IN', array('draft', 'auto-draft' ) )
1991
			);
1992
1993
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
1994
		return $count;
1995
	}
1996
1997
1998
1999
2000
2001
	/**
2002
	 * get total number of trashed events
2003
	 *
2004
	 * @access public
2005
	 * @return int
2006
	 */
2007
	public function total_trashed_events() {
2008
		$where = array(
2009
			'status' => 'trash'
2010
			);
2011
2012
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
2013
		return $count;
2014
	}
2015
2016
2017
2018
2019
	/**
2020
	 * 	_default_event_settings
2021
	 *
2022
	 * 	This generates the Default Settings Tab
2023
	 *
2024
	 * 	@return string html for the settings page
2025
	 */
2026
	protected function _default_event_settings() {
2027
2028
		$this->_template_args['values'] = $this->_yes_no_values;
2029
2030
		$this->_template_args['reg_status_array'] = EEM_Registration::reg_status_array(
2031
			// exclude array
2032
			array(
2033
				EEM_Registration::status_id_cancelled,
2034
				EEM_Registration::status_id_declined,
2035
				EEM_Registration::status_id_incomplete
2036
			),
2037
			// translated
2038
			TRUE
2039
		);
2040
		$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;
2041
2042
		$this->_set_add_edit_form_tags('update_default_event_settings');
2043
		$this->_set_publish_post_box_vars(NULL, FALSE, FALSE, NULL, FALSE);
2044
		$this->_template_args['admin_page_content'] = EEH_Template::display_template(EVENTS_TEMPLATE_PATH . 'event_settings.template.php', $this->_template_args, TRUE);
2045
		$this->display_admin_page_with_sidebar();
2046
	}
2047
2048
	/**
2049
	 * 		_update_default_event_settings
2050
	 * 		@access protected
2051
	 * 		@return array
2052
	 */
2053
	protected function _update_default_event_settings() {
2054
2055
		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;
2056
2057
		$what = 'Default Event Settings';
2058
		$success = $this->_update_espresso_configuration($what, EE_Config::instance(), __FILE__, __FUNCTION__, __LINE__);
2059
		$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...
2060
	}
2061
2062
2063
2064
2065
	/*************		Templates 		*************/
2066
2067
2068
	protected function _template_settings() {
2069
		$this->_admin_page_title = __('Template Settings (Preview)', 'event_espresso');
2070
		$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' ) . '" />';
2071
		$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>';
2072
		$this->display_admin_caf_preview_page( 'template_settings_tab' );
2073
	}
2074
2075
2076
	/** Event Category Stuff **/
2077
2078
	/**
2079
	 * set the _category property with the category object for the loaded page.
2080
	 *
2081
	 * @access private
2082
	 * @return void
2083
	 */
2084 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...
2085
		if ( isset( $this->_category->id ) && !empty( $this->_category->id ) )
2086
			return; //already have the category object so get out.
2087
2088
		//set default category object
2089
		$this->_set_empty_category_object();
2090
2091
		//only set if we've got an id
2092
		if ( !isset($this->_req_data['EVT_CAT_ID'] ) ) {
2093
			return;
2094
		}
2095
2096
		$category_id = absint($this->_req_data['EVT_CAT_ID']);
2097
2098
		$term = get_term( $category_id, 'espresso_event_categories' );
2099
2100
		if ( !empty( $term ) ) {
2101
			$this->_category->category_name = $term->name;
2102
			$this->_category->category_identifier = $term->slug;
2103
			$this->_category->category_desc = $term->description;
2104
			$this->_category->id = $term->term_id;
2105
			$this->_category->parent = $term->parent;
2106
		}
2107
	}
2108
2109
2110
2111
2112
	private function _set_empty_category_object() {
2113
		$this->_category = new stdClass();
2114
		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc  = '';
2115
		$this->_category->id = $this->_category->parent = 0;
2116
	}
2117
2118
2119 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...
2120
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
2121
		$this->_search_btn_label = __('Categories', 'event_espresso');
2122
		$this->_admin_page_title .= $this->get_action_link_or_button('add_category', 'add_category', array(), 'add-new-h2');
2123
		$this->display_admin_list_table_page_with_sidebar();
2124
	}
2125
2126
2127 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...
2128
2129
		//load formatter helper
2130
		EE_Registry::instance()->load_helper( 'Formatter' );
2131
		//load field generator helper
2132
		EE_Registry::instance()->load_helper( 'Form_Fields' );
2133
2134
		$route = $view == 'edit' ? 'update_category' : 'insert_category';
2135
		$this->_set_add_edit_form_tags($route);
2136
2137
		$this->_set_category_object();
2138
		$id = !empty($this->_category->id) ? $this->_category->id : '';
2139
2140
		$delete_action = 'delete_category';
2141
2142
		//custom redirect
2143
		$redirect = EE_Admin_Page::add_query_args_and_nonce( array('action' => 'category_list'), $this->_admin_base_url );
2144
2145
		$this->_set_publish_post_box_vars( 'EVT_CAT_ID', $id, $delete_action, $redirect );
2146
2147
		//take care of contents
2148
		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2149
		$this->display_admin_page_with_sidebar();
2150
	}
2151
2152
2153
2154 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...
2155
		$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...
2156
			'type' => 'wp_editor',
2157
			'value' => EEH_Formatter::admin_format_content($this->_category->category_desc),
2158
			'class' => 'my_editor_custom',
2159
			'wpeditor_args' => array('media_buttons' => FALSE )
2160
		);
2161
		$_wp_editor = $this->_generate_admin_form_fields( $editor_args, 'array' );
2162
2163
		$all_terms = get_terms( array('espresso_event_categories' ), array( 'hide_empty' => 0, 'exclude' => array( $this->_category->id ) ) );
2164
2165
		//setup category select for term parents.
2166
		$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...
2167
			'text' => __('No Parent', 'event_espresso'),
2168
			'id' => 0
2169
			);
2170
		foreach ( $all_terms as $term ) {
2171
			$category_select_values[] = array(
2172
				'text' => $term->name,
2173
				'id' => $term->term_id
2174
				);
2175
		}
2176
2177
		$category_select = EEH_Form_Fields::select_input( 'category_parent', $category_select_values, $this->_category->parent );
2178
2179
		$template_args = array(
2180
			'category' => $this->_category,
2181
			'category_select' => $category_select,
2182
			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2183
			'category_desc_editor' =>  $_wp_editor['category_desc']['field'],
2184
			'disable' => '',
2185
			'disabled_message' => FALSE
2186
			);
2187
		$template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2188
		return EEH_Template::display_template($template, $template_args, TRUE );
2189
	}
2190
2191
2192 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...
2193
		$cat_ids = isset( $this->_req_data['EVT_CAT_ID'] ) ? (array) $this->_req_data['EVT_CAT_ID'] : (array) $this->_req_data['category_id'];
2194
2195
		foreach ( $cat_ids as $cat_id ) {
2196
			$this->_delete_category($cat_id);
2197
		}
2198
2199
		//doesn't matter what page we're coming from... we're going to the same place after delete.
2200
		$query_args = array(
2201
			'action' => 'category_list'
2202
			);
2203
		$this->_redirect_after_action(0,'','',$query_args);
2204
2205
	}
2206
2207
2208
2209
2210
2211
	protected function _delete_category($cat_id) {
2212
		global $wpdb;
2213
		$cat_id = absint( $cat_id );
2214
		wp_delete_term( $cat_id, 'espresso_event_categories' );
2215
	}
2216
2217
2218
2219 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...
2220
2221
		$cat_id = $new_category ? $this->_insert_category() : $this->_insert_category( TRUE );
2222
		$success = 0; //we already have a success message so lets not send another.
2223
2224
		if ( $cat_id ) {
2225
			$query_args = array(
2226
				'action'     => 'edit_category',
2227
				'EVT_CAT_ID' => $cat_id
2228
			);
2229
		} else {
2230
			$query_args = array( 'action' => 'add_category' );
2231
		}
2232
		$this->_redirect_after_action( $success, '','', $query_args, TRUE );
2233
2234
	}
2235
2236
2237
2238
	private function _insert_category( $update = FALSE ) {
2239
		$cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2240
		$category_name= isset( $this->_req_data['category_name'] ) ? $this->_req_data['category_name'] : '';
2241
		$category_desc= isset( $this->_req_data['category_desc'] ) ? $this->_req_data['category_desc'] : '';
2242
		$category_parent = isset( $this->_req_data['category_parent'] ) ? $this->_req_data['category_parent'] : 0;
2243
2244
		if ( empty( $category_name ) ) {
2245
			$msg = __( 'You must add a name for the category.', 'event_espresso' );
2246
			EE_Error::add_error( $msg, __FILE__, __FUNCTION__, __LINE__ );
2247
			return false;
2248
		}
2249
2250
		$term_args=array(
2251
			'name'=>$category_name,
2252
			'description'=>$category_desc,
2253
			'parent'=>$category_parent
2254
		);
2255
		//was the category_identifier input disabled?
2256
		if(isset($this->_req_data['category_identifier'])){
2257
			$term_args['slug'] = $this->_req_data['category_identifier'];
2258
		}
2259
		$insert_ids = $update ? wp_update_term( $cat_id, 'espresso_event_categories', $term_args ) :wp_insert_term( $category_name, 'espresso_event_categories', $term_args );
2260
2261 View Code Duplication
		if ( !is_array( $insert_ids ) ) {
2262
			$msg = __( 'An error occurred and the category has not been saved to the database.', 'event_espresso' );
2263
			EE_Error::add_error( $msg, __FILE__, __FUNCTION__, __LINE__ );
2264
		} else {
2265
			$cat_id = $insert_ids['term_id'];
2266
			$msg = sprintf ( __('The category %s was successfuly saved', 'event_espresso'), $category_name );
2267
			EE_Error::add_success( $msg );
2268
		}
2269
2270
		return $cat_id;
2271
	}
2272
2273
2274
2275
2276 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...
2277
		global $wpdb;
2278
2279
		//testing term stuff
2280
		$orderby = isset( $this->_req_data['orderby'] ) ? $this->_req_data['orderby'] : 'Term.term_id';
2281
		$order = isset( $this->_req_data['order'] ) ? $this->_req_data['order'] : 'DESC';
2282
		$limit = ($current_page-1)*$per_page;
2283
2284
		$where = array( 'taxonomy' => 'espresso_event_categories' );
2285
2286
		if ( isset( $this->_req_data['s'] ) ) {
2287
			$sstr = '%' . $this->_req_data['s'] . '%';
2288
			$where['OR'] = array(
2289
				'Term.name' => array( 'LIKE', $sstr),
2290
				'description' => array( 'LIKE', $sstr )
2291
				);
2292
		}
2293
2294
		$query_params = array(
2295
			$where ,
2296
			'order_by' => array( $orderby => $order ),
2297
			'limit' => $limit . ',' . $per_page,
2298
			'force_join' => array('Term')
2299
			);
2300
2301
		$categories = $count ? EEM_Term_Taxonomy::instance()->count( $query_params, 'term_id' ) :EEM_Term_Taxonomy::instance()->get_all( $query_params );
2302
2303
		return $categories;
2304
	}
2305
2306
2307
2308
	/* end category stuff */
2309
	/**************/
2310
2311
}
2312
//end class Events_Admin_Page
2313