Completed
Branch FET-9784-autopopulate-forms (4bc800)
by
unknown
1438:07 queued 1423:17
created

Events_Admin_Page   F

Complexity

Total Complexity 301

Size/Duplication

Total Lines 2274
Duplicated Lines 18.95 %

Coupling/Cohesion

Components 2
Dependencies 21

Importance

Changes 0
Metric Value
dl 431
loc 2274
rs 0.6314
c 0
b 0
f 0
wmc 301
lcom 2
cbo 21

65 Methods

Rating   Name   Duplication   Size   Complexity  
A _ajax_hooks() 0 3 1
A _define_page_props() 23 23 1
B _set_page_routes() 0 125 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() 11 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() 50 216 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 72 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
A _category_details() 22 22 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
C _permanently_delete_event() 0 71 12
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 61 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

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

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
758
		}
759
		return $this->_event_model;
760
	}
761
762
763
764
765
766
	/**
767
	 * Adds extra buttons to the WP CPT permalink field row.
768
	 *
769
	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
770
	 * @param  string $return    the current html
771
	 * @param  int    $id        the post id for the page
772
	 * @param  string $new_title What the title is
773
	 * @param  string $new_slug  what the slug is
774
	 * @return string            The new html string for the permalink area
775
	 */
776
	public function extra_permalink_field_buttons( $return, $id, $new_title, $new_slug ) {
777
		//make sure this is only when editing
778
		if ( !empty( $id ) ) {
779
			$post = get_post( $id );
780
			$return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">' . __('Shortcode', 'event_espresso') . '</a> ';
781
			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id=' . $post->ID . ']">';
782
		}
783
		return $return;
784
	}
785
786
787
788
789
	/**
790
	 * _events_overview_list_table
791
	 * This contains the logic for showing the events_overview list
792
	 *
793
	 * @access protected
794
	 * @return string html for generated table
795
	 */
796
	protected function _events_overview_list_table() {
797
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
798
		$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' ) .
799
		$this->_display_legend($this->_event_legend_items());
800
		$this->_admin_page_title .= $this->get_action_link_or_button('create_new', 'add', array(), 'add-new-h2');
801
		$this->display_admin_list_table_page_with_no_sidebar();
802
	}
803
804
805
	/**
806
	 * this allows for extra misc actions in the default WP publish box
807
	 * @return string html to add
808
	 */
809
	public function extra_misc_actions_publish_box() {
810
		$this->_generate_publish_box_extra_content();
811
	}
812
813
814
815
816
	protected function _insert_update_cpt_item( $post_id, $post ) {
817
818
		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...
819
			//getout we're not processing an event save.
820
			return;
821
		}
822
823
		$event_values = array(
824
			'EVT_display_desc' => !empty( $this->_req_data['display_desc'] ) ? 1 : 0,
825
			'EVT_display_ticket_selector' => !empty( $this->_req_data['display_ticket_selector'] ) ? 1 : 0,
826
			'EVT_additional_limit' => min(
827
					apply_filters( 'FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255 ),
828
					!empty( $this->_req_data['additional_limit'] ) ? $this->_req_data['additional_limit'] : NULL ),
829
			'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,
830
			'EVT_member_only' => !empty( $this->_req_data['member_only'] ) ? 1 : 0,
831
			'EVT_allow_overflow' => !empty( $this->_req_data['EVT_allow_overflow'] ) ? 1 : 0,
832
			'EVT_timezone_string' => !empty( $this->_req_data['timezone_string'] ) ? $this->_req_data['timezone_string'] : NULL,
833
			'EVT_external_URL' => !empty( $this->_req_data['externalURL'] ) ? $this->_req_data['externalURL'] : NULL,
834
			'EVT_phone' => !empty( $this->_req_data['event_phone'] ) ? $this->_req_data['event_phone'] : NULL
835
			);
836
837
		//update event
838
		$success = $this->_event_model()->update_by_ID( $event_values, $post_id );
839
840
841
		//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!
842
		$get_one_where = array( $this->_event_model()->primary_key_name() => $post_id, 'status' => $post->post_status );
843
		$event = $this->_event_model()->get_one( array($get_one_where) );
844
845
846
		//the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
847
		$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') ) );
848
849
		$att_success = TRUE;
850
851 View Code Duplication
		foreach ( $event_update_callbacks as $e_callback ) {
852
			$_succ = call_user_func_array( $e_callback, array( $event,  $this->_req_data ) );
853
			$att_success = !$att_success ? $att_success : $_succ; //if ANY of these updates fail then we want the appropriate global error message
854
		}
855
856
		//any errors?
857
		if ( $success && FALSE === $att_success ) {
858
			EE_Error::add_error( __('Event Details saved successfully but something went wrong with saving attachments.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
859
		} else if ( $success === FALSE ) {
860
			EE_Error::add_error( __('Event Details did not save successfully.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
861
		}
862
	}
863
864
865
866
867
	/**
868
	 * @see parent::restore_item()
869
	 */
870
	protected function _restore_cpt_item( $post_id, $revision_id ) {
871
		//copy existing event meta to new post
872
		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
873
		if ( $post_evt instanceof EE_Event ) {
874
			//meta revision restore
875
			$post_evt->restore_revision( $revision_id );
876
			//related objs restore
877
			$post_evt->restore_revision( $revision_id, array( 'Venue', 'Datetime', 'Price' ) );
878
		}
879
	}
880
881
882
883
884
	/**
885
	 * Attach the venue to the Event
886
	 * @param  object $evtobj Event Object to add the venue to
887
	 * @param  array  $data   The request data from the form
888
	 * @return bool           Success or fail.
889
	 */
890
	protected function _default_venue_update( $evtobj, $data ) {
891
		require_once( EE_MODELS . 'EEM_Venue.model.php' );
892
		$venue_model = EE_Registry::instance()->load_model('Venue');
893
		$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...
894
		$venue_id = !empty( $data['venue_id'] ) ? $data['venue_id'] : NULL;
895
896
		// very important.  If we don't have a venue name...
897
		// then we'll get out because not necessary to create empty venue
898
		if ( empty( $data['venue_title'] ) ) {
899
			return false;
900
		}
901
902
		$venue_array = array(
903
				'VNU_wp_user' => $evtobj->get('EVT_wp_user'),
904
				'VNU_name' => !empty( $data['venue_title'] ) ? $data['venue_title'] : NULL,
905
				'VNU_desc' => !empty( $data['venue_description'] ) ? $data['venue_description'] : NULL,
906
				'VNU_identifier' => !empty( $data['venue_identifier'] ) ? $data['venue_identifier'] : NULL,
907
				'VNU_short_desc' => !empty( $data['venue_short_description'] ) ? $data['venue_short_description'] : NULL,
908
				'VNU_address' => !empty( $data['address'] ) ? $data['address'] : NULL,
909
				'VNU_address2' => !empty( $data['address2'] ) ? $data['address2'] : NULL,
910
				'VNU_city' => !empty( $data['city'] ) ? $data['city'] : NULL,
911
				'STA_ID' => !empty( $data['state'] ) ? $data['state'] : NULL,
912
				'CNT_ISO' => !empty( $data['countries'] ) ? $data['countries'] : NULL,
913
				'VNU_zip' => !empty( $data['zip'] ) ? $data['zip'] : NULL,
914
				'VNU_phone' => !empty( $data['venue_phone'] ) ? $data['venue_phone'] : NULL,
915
				'VNU_capacity' => !empty( $data['venue_capacity'] ) ? $data['venue_capacity'] : NULL,
916
				'VNU_url' => !empty($data['venue_url'] ) ? $data['venue_url'] : NULL,
917
				'VNU_virtual_phone' => !empty($data['virtual_phone']) ? $data['virtual_phone'] : NULL,
918
				'VNU_virtual_url' => !empty( $data['virtual_url'] ) ? $data['virtual_url'] : NULL,
919
				'VNU_enable_for_gmap' => isset( $data['enable_for_gmap'] ) ? 1 : 0,
920
				'status' => 'publish'
921
			);
922
923
924
		//if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
925
		if ( !empty( $venue_id ) ) {
926
			$update_where = array( $venue_model->primary_key_name() => $venue_id );
927
			$rows_affected = $venue_model->update( $venue_array, array( $update_where ) );
928
			//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.
929
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
930
			return $rows_affected > 0 ? TRUE : FALSE;
931
		} else {
932
			//we insert the venue
933
			$venue_id = $venue_model->insert( $venue_array );
934
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
935
			return !empty( $venue_id ) ? TRUE : FALSE;
936
		}
937
		//when we have the ancestor come in it's already been handled by the revision save.
938
	}
939
940
941
942
943
	/**
944
	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
945
	 * @param  EE_Event $evtobj The Event object we're attaching data to
946
	 * @param  array    $data   The request data from the form
947
	 * @return bool             success or fail
948
	 */
949
	protected function _default_tickets_update( EE_Event $evtobj, $data ) {
950
		$success = true;
951
		$saved_dtt = null;
952
		$saved_tickets = array();
953
		$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
954
955
		foreach ( $data['edit_event_datetimes'] as $row => $dtt ) {
956
			//trim all values to ensure any excess whitespace is removed.
957
			$dtt =  array_map( 'trim', $dtt );
958
			$dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty( $dtt['DTT_EVT_end'] ) ? $dtt['DTT_EVT_end'] : $dtt['DTT_EVT_start'];
959
			$datetime_values = array(
960
				'DTT_ID' 		=> ! empty( $dtt['DTT_ID'] ) ? $dtt['DTT_ID'] : NULL,
961
				'DTT_EVT_start' => $dtt['DTT_EVT_start'],
962
				'DTT_EVT_end' 	=> $dtt['DTT_EVT_end'],
963
				'DTT_reg_limit' => empty( $dtt['DTT_reg_limit'] ) ? EE_INF : $dtt['DTT_reg_limit'],
964
				'DTT_order' 	=> $row,
965
			);
966
967
			//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.
968
969
			if ( !empty( $dtt['DTT_ID'] ) ) {
970
				$DTM = EE_Registry::instance()->load_model('Datetime', array( $evtobj->get_timezone() ) )->get_one_by_ID($dtt['DTT_ID'] );
971
				$DTM->set_date_format( $incoming_date_formats[0] );
972
				$DTM->set_time_format( $incoming_date_formats[1] );
973
				foreach ( $datetime_values as $field => $value ) {
974
					$DTM->set( $field, $value );
975
				}
976
977
				//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.
978
				$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...
979
			} else {
980
				$DTM = EE_Registry::instance()->load_class('Datetime', array( $datetime_values ), FALSE, FALSE );
981
				$DTM->set_date_format( $incoming_date_formats[0] );
982
				$DTM->set_time_format( $incoming_date_formats[1] );
983
				$DTM->set_timezone( $evtobj->get_timezone() );
984
				foreach ( $datetime_values as $field => $value ) {
985
					$DTM->set( $field, $value );
986
				}
987
			}
988
			$DTM->save();
989
990
			$DTT = $evtobj->_add_relation_to( $DTM, 'Datetime' );
991
992
			//load DTT helper
993
994
			//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.
995 View Code Duplication
			if( $DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end') ) {
996
				$DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start') );
997
				$DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
998
				$DTT->save();
999
			}
1000
1001
			//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.
1002
			$saved_dtt = $DTT;
1003
1004
			$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.
1005
		}
1006
1007
		//no dtts get deleted so we don't do any of that logic here.
1008
		//update tickets next
1009
		$old_tickets = isset( $data['ticket_IDs'] ) ? explode(',', $data['ticket_IDs'] ) : array();
1010
		foreach ( $data['edit_tickets'] as $row => $tkt ) {
1011
			$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
1012
			$update_prices = false;
1013
			$ticket_price = isset( $data['edit_prices'][$row][1]['PRC_amount'] ) ? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
1014
1015
			// trim inputs to ensure any excess whitespace is removed.
1016
			$tkt = array_map( 'trim', $tkt );
1017
1018
			if ( empty( $tkt['TKT_start_date'] ) ) {
1019
				//let's use now in the set timezone.
1020
				$now = new DateTime( 'now', new DateTimeZone( $evtobj->get_timezone() ) );
1021
				$tkt['TKT_start_date'] = $now->format( $incoming_date_formats[0] . ' ' . $incoming_date_formats[1] );
1022
			}
1023
1024
			if ( empty( $tkt['TKT_end_date'] ) ) {
1025
				//use the start date of the first datetime
1026
				$dtt = $evtobj->first_datetime();
1027
				$tkt['TKT_end_date'] = $dtt->start_date_and_time( $incoming_date_formats[0], $incoming_date_formats[1] );
1028
			}
1029
1030
			$TKT_values = array(
1031
				'TKT_ID' 			=> !empty( $tkt['TKT_ID'] ) ? $tkt['TKT_ID'] : NULL,
1032
				'TTM_ID' 			=> !empty( $tkt['TTM_ID'] ) ? $tkt['TTM_ID'] : 0,
1033
				'TKT_name' 			=> !empty( $tkt['TKT_name'] ) ? $tkt['TKT_name'] : '',
1034
				'TKT_description' 	=> !empty( $tkt['TKT_description'] ) ? $tkt['TKT_description'] : '',
1035
				'TKT_start_date' 	=> $tkt['TKT_start_date'],
1036
				'TKT_end_date' 		=> $tkt['TKT_end_date'],
1037
				'TKT_qty' 			=> ! isset( $tkt[ 'TKT_qty' ] ) || $tkt[ 'TKT_qty' ] === '' ? EE_INF : $tkt['TKT_qty'],
1038
				'TKT_uses' 			=> ! isset( $tkt[ 'TKT_uses' ] ) || $tkt[ 'TKT_uses' ] === '' ? EE_INF : $tkt[ 'TKT_uses' ],
1039
				'TKT_min' 			=> empty( $tkt['TKT_min'] ) ? 0 : $tkt['TKT_min'],
1040
				'TKT_max' 			=> empty( $tkt['TKT_max'] ) ? EE_INF : $tkt['TKT_max'],
1041
				'TKT_row' 			=> $row,
1042
				'TKT_order' 		=> isset( $tkt['TKT_order'] ) ? $tkt['TKT_order'] : $row,
1043
				'TKT_price' 		=> $ticket_price
1044
			);
1045
1046
1047
1048
1049
			//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.
1050 View Code Duplication
			if ( isset( $tkt['TKT_is_default'] ) && $tkt['TKT_is_default'] ) {
1051
				$TKT_values['TKT_ID'] = 0;
1052
				$TKT_values['TKT_is_default'] = 0;
1053
				$TKT_values['TKT_price'] = $ticket_price;
1054
				$update_prices = TRUE;
1055
			}
1056
1057
			//if we have a TKT_ID then we need to get that existing TKT_obj and update it
1058
			//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.
1059
			//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.
1060
1061
			if ( !empty( $tkt['TKT_ID'] ) ) {
1062
				$TKT = EE_Registry::instance()->load_model( 'Ticket', array( $evtobj->get_timezone() ) )->get_one_by_ID( $tkt['TKT_ID'] );
1063
				if ( $TKT instanceof EE_Ticket ) {
1064
					$ticket_sold = $TKT->count_related( 'Registration', array( array( 'STS_ID' => array( 'NOT IN', array( EEM_Registration::status_id_incomplete ) ) ) ) ) > 0 ? true : false;
1065
					//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.
1066
					$create_new_TKT = $ticket_sold && $ticket_price != $TKT->get( 'TKT_price' ) && ! $TKT->get( 'TKT_deleted' ) ? true : false;
1067
					$TKT->set_date_format( $incoming_date_formats[ 0 ] );
1068
					$TKT->set_time_format( $incoming_date_formats[ 1 ] );
1069
					//set new values
1070 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1071
						if ( $field == 'TKT_qty' ) {
1072
							$TKT->set_qty( $value );
1073
						} else {
1074
							$TKT->set( $field, $value );
1075
						}
1076
					}
1077
					//if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1078
					if ( $create_new_TKT ) {
1079
						//archive the old ticket first
1080
						$TKT->set( 'TKT_deleted', 1 );
1081
						$TKT->save();
1082
						//make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1083
						$saved_tickets[ $TKT->ID() ] = $TKT;
1084
						//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.
1085
						$TKT = clone $TKT;
1086
						$TKT->set( 'TKT_ID', 0 );
1087
						$TKT->set( 'TKT_deleted', 0 );
1088
						$TKT->set( 'TKT_price', $ticket_price );
1089
						$TKT->set( 'TKT_sold', 0 );
1090
						//now we need to make sure that $new prices are created as well and attached to new ticket.
1091
						$update_prices = true;
1092
					}
1093
					//make sure price is set if it hasn't been already
1094
					$TKT->set( 'TKT_price', $ticket_price );
1095
				}
1096
1097
			} else {
1098
				//no TKT_id so a new TKT
1099
				$TKT_values['TKT_price'] = $ticket_price;
1100
				$TKT = EE_Registry::instance()->load_class('Ticket', array( $TKT_values ), FALSE, FALSE );
1101
				if ( $TKT instanceof EE_Ticket ) {
1102
					//need to reset values to properly account for the date formats
1103
					$TKT->set_date_format( $incoming_date_formats[0] );
1104
					$TKT->set_time_format( $incoming_date_formats[1] );
1105
					$TKT->set_timezone( $evtobj->get_timezone() );
1106
1107
					//set new values
1108 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1109
						if ( $field == 'TKT_qty' ) {
1110
							$TKT->set_qty( $value );
1111
						} else {
1112
							$TKT->set( $field, $value );
1113
						}
1114
					}
1115
1116
					$update_prices = TRUE;
1117
				}
1118
			}
1119
			// cap ticket qty by datetime reg limits
1120
			$TKT->set_qty( min( $TKT->qty(), $TKT->qty( 'reg_limit' ) ) );
1121
			//update ticket.
1122
			$TKT->save();
1123
1124
			//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.
1125 View Code Duplication
			if( $TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date') ) {
1126
				$TKT->set('TKT_end_date', $TKT->get('TKT_start_date') );
1127
				$TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1128
				$TKT->save();
1129
			}
1130
1131
			//initially let's add the ticket to the dtt
1132
			$saved_dtt->_add_relation_to( $TKT, 'Ticket' );
1133
1134
			$saved_tickets[$TKT->ID()] = $TKT;
1135
1136
			//add prices to ticket
1137
			$this->_add_prices_to_ticket( $data['edit_prices'][$row], $TKT, $update_prices );
1138
		}
1139
		//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.
1140
		$old_tickets = isset( $old_tickets[0] ) && $old_tickets[0] == '' ? array() : $old_tickets;
1141
		$tickets_removed = array_diff( $old_tickets, array_keys( $saved_tickets ) );
1142
1143 View Code Duplication
		foreach ( $tickets_removed as $id ) {
1144
			$id = absint( $id );
1145
1146
			//get the ticket for this id
1147
			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
1148
1149
			//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)
1150
			$dtts = $tkt_to_remove->get_many_related('Datetime');
1151
1152
			foreach( $dtts as $dtt ) {
1153
				$tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1154
			}
1155
1156
			//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))
1157
			$tkt_to_remove->delete_related_permanently('Price');
1158
1159
1160
			//finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1161
			$tkt_to_remove->delete_permanently();
1162
		}
1163
		return array( $saved_dtt, $saved_tickets );
1164
	}
1165
1166
1167
1168
	/**
1169
	 * This attaches a list of given prices to a ticket.
1170
	 * 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.
1171
	 *
1172
	 * @access  private
1173
	 * @param array  	$prices  	Array of prices from the form.
1174
	 * @param EE_Ticket $ticket  	EE_Ticket object that prices are being attached to.
1175
	 * @param bool 		$new_prices Whether attach existing incoming prices or create new ones.
1176
	 * @return  void
1177
	 */
1178
	private function  _add_prices_to_ticket( $prices, EE_Ticket $ticket, $new_prices = FALSE ) {
1179
		foreach ( $prices as $row => $prc ) {
1180
			$PRC_values = array(
1181
				'PRC_ID' => !empty( $prc['PRC_ID'] ) ? $prc['PRC_ID'] : NULL,
1182
				'PRT_ID' => !empty( $prc['PRT_ID'] ) ? $prc['PRT_ID'] : NULL,
1183
				'PRC_amount' => !empty( $prc['PRC_amount'] ) ? $prc['PRC_amount'] : 0,
1184
				'PRC_name' => !empty( $prc['PRC_name'] ) ? $prc['PRC_name'] : '',
1185
				'PRC_desc' => !empty( $prc['PRC_desc'] ) ? $prc['PRC_desc'] : '',
1186
				'PRC_is_default' => 0, //make sure prices are NOT set as default from this context
1187
				'PRC_order' => $row
1188
			);
1189
1190 View Code Duplication
			if ( $new_prices || empty( $PRC_values['PRC_ID'] ) ) {
1191
				$PRC_values['PRC_ID'] = 0;
1192
				$PRC = EE_Registry::instance()->load_class('Price', array( $PRC_values ), FALSE, FALSE);
1193
			} else {
1194
				$PRC = EE_Registry::instance()->load_model( 'Price' )->get_one_by_ID( $prc['PRC_ID'] );
1195
				//update this price with new values
1196
				foreach ( $PRC_values as $field => $newprc ) {
1197
					$PRC->set( $field, $newprc );
1198
				}
1199
				$PRC->save();
1200
			}
1201
1202
			$ticket->_add_relation_to( $PRC, 'Price' );
1203
		}
1204
	}
1205
1206
1207
1208
1209
	/**
1210
	 * Add in our autosave ajax handlers
1211
	 * @return void
1212
	 */
1213
	protected function _ee_autosave_create_new() {
1214
		// $this->_ee_autosave_edit();
1215
	}
1216
1217
1218
1219
1220
1221
	protected function _ee_autosave_edit() {
1222
		return; //TEMPORARILY EXITING CAUSE THIS IS A TODO
1223
	}
1224
1225
1226
1227
1228
1229
1230
	/**
1231
	 * 	_generate_publish_box_extra_content
1232
	 * 	@access private
1233
	 * @return void
1234
	 */
1235
	private function _generate_publish_box_extra_content() {
1236
1237
		//load formatter helper
1238
1239
  		//args for getting related registrations
1240
  		$approved_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_approved ) );
1241
  		$not_approved_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_not_approved ) );
1242
  		$pending_payment_query_args = array( array( 'REG_deleted' => 0, 'STS_ID' => EEM_Registration::status_id_pending_payment ) );
1243
1244
1245
		// publish box
1246
		$publish_box_extra_args = array(
1247
			'view_approved_reg_url' => add_query_arg(
1248
				array(
1249
					'action'      => 'default',
1250
					'event_id'    => $this->_cpt_model_obj->ID(),
1251
					'_reg_status' => EEM_Registration::status_id_approved
1252
				),
1253
			  REG_ADMIN_URL
1254
			),
1255
			'view_not_approved_reg_url' => add_query_arg(
1256
				array(
1257
					'action'      => 'default',
1258
					'event_id'    => $this->_cpt_model_obj->ID(),
1259
					'_reg_status' => EEM_Registration::status_id_not_approved
1260
				),
1261
				REG_ADMIN_URL
1262
			),
1263
			'view_pending_payment_reg_url' => add_query_arg(
1264
				array(
1265
					'action'      => 'default',
1266
					'event_id'    => $this->_cpt_model_obj->ID(),
1267
					'_reg_status' => EEM_Registration::status_id_pending_payment
1268
				),
1269
				REG_ADMIN_URL
1270
			),
1271
			'approved_regs' => $this->_cpt_model_obj->count_related( 'Registration', $approved_query_args ),
1272
			'not_approved_regs' => $this->_cpt_model_obj->count_related( 'Registration', $not_approved_query_args ),
1273
			'pending_payment_regs' => $this->_cpt_model_obj->count_related( 'Registration', $pending_payment_query_args ),
1274
			'misc_pub_section_class' => apply_filters(
1275
				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1276
				'misc-pub-section'
1277
			),
1278
			//'email_attendees_url' => add_query_arg(
1279
			//	array(
1280
			//		'event_admin_reports' => 'event_newsletter',
1281
			//		'event_id' => $this->_cpt_model_obj->id
1282
			//	),
1283
			//	'admin.php?page=espresso_registrations'
1284
			//),
1285
1286
		);
1287
		ob_start();
1288
		do_action(
1289
			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1290
			$this->_cpt_model_obj
1291
		);
1292
		$publish_box_extra_args[ 'event_editor_overview_add' ] = ob_get_clean();
1293
		// load template
1294
		EEH_Template::display_template( EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php', $publish_box_extra_args );
1295
	}
1296
1297
1298
1299
1300
1301
	/**
1302
	 * This just returns whatever is set as the _event object property
1303
	 *
1304
	 * //todo this will become obsolete once the models are in place
1305
	 * @return object
1306
	 */
1307
	public function get_event_object() {
1308
		return $this->_cpt_model_obj;
1309
	}
1310
1311
1312
1313
	/*	 * ************ */
1314
	/** METABOXES * */
1315
1316
	/**
1317
	 * _register_event_editor_meta_boxes
1318
	 * add all metaboxes related to the event_editor
1319
	 *
1320
	 * @return void
1321
	 */
1322
	protected function _register_event_editor_meta_boxes() {
1323
		$this->verify_cpt_object();
1324
		add_meta_box(
1325
			'espresso_event_editor_tickets',
1326
			__( 'Event Datetime & Ticket', 'event_espresso' ),
1327
			array( $this, 'ticket_metabox' ),
1328
			$this->page_slug,
1329
			'normal',
1330
			'high'
1331
		);
1332
		add_meta_box(
1333
			'espresso_event_editor_event_options',
1334
			__( 'Event Registration Options', 'event_espresso' ),
1335
			array( $this, 'registration_options_meta_box' ),
1336
			$this->page_slug,
1337
			'side',
1338
			'default'
1339
		);
1340
		// NOTE: if you're looking for other metaboxes in here,
1341
		// where a metabox has a related management page in the admin
1342
		// you will find it setup in the related management page's "_Hooks" file.
1343
		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1344
	}
1345
1346
1347
1348
1349
	public function ticket_metabox() {
1350
		$existing_datetime_ids = $existing_ticket_ids = array();
1351
		//defaults for template args
1352
		$template_args = array(
1353
			'existing_datetime_ids' => '',
1354
			'event_datetime_help_link' => '',
1355
			'ticket_options_help_link' => '',
1356
			'time' => null,
1357
			'ticket_rows' => '',
1358
			'existing_ticket_ids' => '',
1359
			'total_ticket_rows' => 1,
1360
			'ticket_js_structure' => '',
1361
			'trash_icon' => 'ee-lock-icon',
1362
			'disabled' => ''
1363
			);
1364
1365
		$event_id = is_object( $this->_cpt_model_obj ) ? $this->_cpt_model_obj->ID() : NULL;
1366
1367
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
1368
1369
		/**
1370
		 * 1. Start with retrieving Datetimes
1371
		 * 2. Fore each datetime get related tickets
1372
		 * 3. For each ticket get related prices
1373
		 */
1374
		$times = EE_Registry::instance()->load_model('Datetime' )->get_all_event_dates( $event_id );
0 ignored issues
show
Documentation Bug introduced by
The method get_all_event_dates does not exist on object<EEM_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...
1375
		/** @type EE_Datetime $first_datetime */
1376
		$first_datetime = reset( $times );
1377
		//do we get related tickets?
1378
		if ( $first_datetime instanceof EE_Datetime
1379
			&& $first_datetime->ID() !== 0 ) {
1380
			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1381
			$template_args['time'] = $first_datetime;
1382
			$related_tickets = $first_datetime->tickets(
1383
				array(
1384
					array( 'OR' => array( 'TKT_deleted' => 1, 'TKT_deleted*' => 0 ) ),
1385
					'default_where_conditions' => 'none'
1386
				)
1387
			);
1388
1389
			if ( !empty($related_tickets) ) {
1390
				$template_args['total_ticket_rows'] = count($related_tickets);
1391
				$row = 0;
1392
				foreach ( $related_tickets as $ticket ) {
1393
					$existing_ticket_ids[] = $ticket->get('TKT_ID');
1394
					$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...
1395
1396
					$row++;
1397
				}
1398 View Code Duplication
			} else {
1399
				$template_args['total_ticket_rows'] = 1;
1400
				/** @type EE_Ticket $ticket */
1401
				$ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
1402
				$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket );
1403
			}
1404 View Code Duplication
		} else {
1405
			$template_args['time'] = $times[0];
1406
			/** @type EE_Ticket $ticket */
1407
			$ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
0 ignored issues
show
Documentation Bug introduced by
The method get_all_default_tickets does not exist on object<EEM_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...
1408
			$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket[1] );
1409
			// NOTE: we're just sending the first default row
1410
			// (decaf can't manage default tickets so this should be sufficient);
1411
		}
1412
1413
		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link('event_editor_event_datetimes_help_tab');
1414
		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1415
		$template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1416
		$template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1417
		$template_args['ticket_js_structure'] = $this->_get_ticket_row( EE_Registry::instance()->load_model('Ticket')->create_default_object(), TRUE );
1418
		$template = apply_filters( 'FHEE__Events_Admin_Page__ticket_metabox__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php' );
1419
		EEH_Template::display_template($template, $template_args);
1420
	}
1421
1422
1423
1424
	/**
1425
	 * Setup an individual ticket form for the decaf event editor page
1426
	 *
1427
	 * @access private
1428
	 * @param  EE_Ticket $ticket   the ticket object
1429
	 * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1430
	 * @param int        $row
1431
	 * @return string generated html for the ticket row.
1432
	 */
1433
	private function _get_ticket_row( $ticket, $skeleton = FALSE, $row = 0 ) {
1434
		$template_args = array(
1435
			'tkt_status_class' => ' tkt-status-' . $ticket->ticket_status(),
1436
			'tkt_archive_class' => $ticket->ticket_status() === EE_Ticket::archived && !$skeleton ? ' tkt-archived' : '',
1437
			'ticketrow' => $skeleton ? 'TICKETNUM' : $row,
1438
			'TKT_ID' => $ticket->get('TKT_ID'),
1439
			'TKT_name' => $ticket->get('TKT_name'),
1440
			'TKT_start_date' => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1441
			'TKT_end_date' => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1442
			'TKT_is_default' => $ticket->get('TKT_is_default'),
1443
			'TKT_qty' => $ticket->get_pretty('TKT_qty','input'),
1444
			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1445
			'TKT_sold' => $skeleton ? 0 : $ticket->get('TKT_sold'),
1446
			'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',
1447
			'disabled' => $skeleton || ( !empty( $ticket ) && ! $ticket->get('TKT_deleted' ) ) ? '' : ' disabled=disabled'
1448
			);
1449
1450
		$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
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $ticket->ID() (string) and 0 (integer) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
1451
1452
1453
		$price_args = array(
1454
			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1455
			'PRC_amount' => $price->get('PRC_amount'),
1456
			'PRT_ID' => $price->get('PRT_ID'),
1457
			'PRC_ID' => $price->get('PRC_ID'),
1458
			'PRC_is_default' => $price->get('PRC_is_default'),
1459
			);
1460
1461
		//make sure we have default start and end dates if skeleton
1462
		//handle rows that should NOT be empty
1463
		if ( empty( $template_args['TKT_start_date'] ) ) {
1464
			//if empty then the start date will be now.
1465
			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1466
		}
1467
1468
		if ( empty( $template_args['TKT_end_date'] ) ) {
1469
			//get the earliest datetime (if present);
1470
			$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;
1471
1472
			if ( !empty( $earliest_dtt ) )
1473
				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1474
			else
1475
				$template_args['TKT_end_date'] = date('Y-m-d h:i a', mktime(0, 0, 0, date("m"), date("d")+7, date("Y") ) );
1476
		}
1477
1478
		$template_args = array_merge( $template_args, $price_args );
1479
		$template = apply_filters( 'FHEE__Events_Admin_Page__get_ticket_row__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php', $ticket);
1480
		return EEH_Template::display_template($template, $template_args, TRUE);
1481
	}
1482
1483
1484
1485
	public function registration_options_meta_box() {
1486
1487
		$yes_no_values = array(
1488
			array('id' => true, 'text' => __('Yes', 'event_espresso')),
1489
			array('id' => false, 'text' => __('No', 'event_espresso'))
1490
		);
1491
1492
		$default_reg_status_values = EEM_Registration::reg_status_array(
1493
			array(
1494
				EEM_Registration::status_id_cancelled,
1495
				EEM_Registration::status_id_declined,
1496
				EEM_Registration::status_id_incomplete
1497
			),
1498
			TRUE
1499
		);
1500
1501
		//$template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1502
		$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...
1503
		$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...
1504
		$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...
1505
		$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...
1506
		$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...
1507
		$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...
1508
		$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 );
1509
		$templatepath = EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php';
1510
		EEH_Template::display_template($templatepath, $template_args);
1511
	}
1512
1513
1514
1515
	/** end metaboxes * */
1516
	/*	 * **************** *
1517
1518
1519
1520
1521
	/**
1522
	 * _get_events()
1523
	 * This method simply returns all the events (for the given _view and paging)
1524
	 *
1525
	 * @access public
1526
	 *
1527
	 * @param int $per_page count of items per page (20 default);
1528
	 * @param int $current_page what is the current page being viewed.
1529
	 * @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.
1530
	 * @return array an array of event objects.
1531
	 */
1532
	public function get_events($per_page = 10, $current_page = 1, $count = FALSE) {
1533
1534
		$EEME = $this->_event_model();
1535
1536
		$offset = ($current_page - 1) * $per_page;
1537
		$limit = $count ? NULL : $offset . ',' . $per_page;
1538
		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1539
		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1540
1541
		if (isset($this->_req_data['month_range'])) {
1542
			$pieces = explode(' ', $this->_req_data['month_range'], 3);
1543
			$month_r = !empty($pieces[0]) ? date('m', strtotime($pieces[0])) : '';
1544
			$year_r = !empty($pieces[1]) ? $pieces[1] : '';
1545
		}
1546
1547
		$where = array();
1548
1549
		$status = isset( $this->_req_data['status'] ) ? $this->_req_data['status'] : NULL;
1550
		//determine what post_status our condition will have for the query.
1551
		switch ( $status ) {
1552
			case 'month' :
1553
			case 'today' :
1554
			case NULL :
1555
			case 'all' :
1556
				break;
1557
1558
			case 'draft' :
1559
				$where['status'] = array( 'IN', array('draft', 'auto-draft') );
1560
				break;
1561
1562
			default :
1563
				$where['status'] = $status;
1564
		}
1565
1566
		//categories?
1567
		$category = isset( $this->_req_data['EVT_CAT'] ) && $this->_req_data['EVT_CAT'] > 0 ? $this->_req_data['EVT_CAT'] : NULL;
1568
1569
		if ( !empty ( $category ) ) {
1570
			$where['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1571
			$where['Term_Taxonomy.term_id'] = $category;
1572
		}
1573
1574
		//date where conditions
1575
		$start_formats = EEM_Datetime::instance()->get_formats_for( 'DTT_EVT_start' );
1576
		if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1577
			$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...
1578
			$start = $DateTime->format( implode( ' ', $start_formats  ) );
1579
			$end = $DateTime->setDate( $year_r, $month_r, $DateTime->format('t') )->setTime(23,59,59)->format( implode( ' ', $start_formats ) );
1580
			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array( $start, $end ) );
1581
		} else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1582
			$DateTime = new DateTime( 'now', new DateTimeZone( EEM_Event::instance()->get_timezone() ) );
1583
			$start = $DateTime->setTime( 0,0,0 )->format( implode( ' ', $start_formats ) );
1584
			$end = $DateTime->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1585
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1586
		} else if ( isset($this->_req_data['status']) && $this->_req_data['status'] == 'month' ) {
1587
			$now = date( 'Y-m-01' );
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->setDate( date('Y'), date('m'), $DateTime->format('t' ) )->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1591
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1592
		}
1593
1594
1595 View Code Duplication
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1596
			$where['EVT_wp_user'] =  get_current_user_id();
1597
		} else {
1598
			if ( ! isset( $where['status'] ) ) {
1599
				if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_private_events', 'get_events' ) ) {
1600
					$where['OR'] = array(
1601
						'status*restrict_private' => array( '!=', 'private' ),
1602
						'AND' => array(
1603
							'status*inclusive' => array( '=', 'private' ),
1604
							'EVT_wp_user' => get_current_user_id()
1605
						)
1606
					);
1607
				}
1608
			}
1609
		}
1610
1611
		if ( isset( $this->_req_data['EVT_wp_user'] ) ) {
1612
			if ( $this->_req_data['EVT_wp_user'] != get_current_user_id() && EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1613
				$where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1614
			}
1615
		}
1616
1617
1618
		//search query handling
1619
		if ( isset( $this->_req_data['s'] ) ) {
1620
			$search_string = '%' . $this->_req_data['s'] . '%';
1621
			$where['OR'] = array(
1622
				'EVT_name' => array('LIKE', $search_string),
1623
				'EVT_desc' => array('LIKE', $search_string),
1624
				'EVT_short_desc' => array('LIKE', $search_string)
1625
				);
1626
		}
1627
1628
1629
		$where = apply_filters( 'FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data );
1630
		$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 );
1631
1632
1633
		//let's first check if we have special requests coming in.
1634
		if ( isset( $this->_req_data['active_status'] ) ) {
1635
			switch ( $this->_req_data['active_status'] ) {
1636
				case 'upcoming' :
1637
					return $EEME->get_upcoming_events( $query_params, $count );
1638
					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...
1639
1640
				case 'expired' :
1641
					return $EEME->get_expired_events( $query_params, $count );
1642
					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...
1643
1644
				case 'active' :
1645
					return $EEME->get_active_events( $query_params, $count );
1646
					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...
1647
1648
				case 'inactive' :
1649
					return $EEME->get_inactive_events( $query_params, $count );
1650
					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...
1651
			}
1652
		}
1653
1654
		$events = $count ? $EEME->count( array( $where ), 'EVT_ID', true ) : $EEME->get_all( $query_params );
1655
1656
		return $events;
1657
	}
1658
1659
1660
1661
1662
	//handling for WordPress CPT actions (trash, restore, delete)
1663
	public function trash_cpt_item( $post_id ) {
1664
		$this->_req_data['EVT_ID'] = $post_id;
1665
		$this->_trash_or_restore_event( 'trash', FALSE );
1666
	}
1667
1668
1669
1670
1671
	public function restore_cpt_item( $post_id ) {
1672
		$this->_req_data['EVT_ID'] = $post_id;
1673
		$this->_trash_or_restore_event( 'draft', FALSE );
1674
	}
1675
1676
1677
	public function delete_cpt_item( $post_id ) {
1678
		$this->_req_data['EVT_ID'] = $post_id;
1679
		$this->_delete_event( FALSE );
1680
	}
1681
1682
1683
1684
	/**
1685
	 * _trash_or_restore_event
1686
	 *
1687
	 * @access protected
1688
	 * @param  string $event_status
1689
	 * @return void
1690
	 */
1691 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...
1692
		//determine the event id and set to array.
1693
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : FALSE;
1694
		// loop thru events
1695
		if ($EVT_ID) {
1696
			// clean status
1697
			$event_status = sanitize_key($event_status);
1698
			// grab status
1699
			if (!empty($event_status)) {
1700
				$success = $this->_change_event_status($EVT_ID, $event_status);
1701
			} else {
1702
				$success = FALSE;
1703
				$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1704
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1705
			}
1706
		} else {
1707
			$success = FALSE;
1708
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.', 'event_espresso');
1709
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1710
		}
1711
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1712
1713
		if ( $redirect_after )
1714
			$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...
1715
	}
1716
1717
	/**
1718
	 * _trash_or_restore_events
1719
	 *
1720
	 * @access protected
1721
	 * @param  string $event_status
1722
	 * @return void
1723
	 */
1724 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...
1725
		// clean status
1726
		$event_status = sanitize_key($event_status);
1727
		// grab status
1728
		if (!empty($event_status)) {
1729
			$success = TRUE;
1730
			//determine the event id and set to array.
1731
			$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1732
			// loop thru events
1733
			foreach ($EVT_IDs as $EVT_ID) {
1734
				if ($EVT_ID = absint($EVT_ID)) {
1735
					$results = $this->_change_event_status($EVT_ID, $event_status);
1736
					$success = $results !== FALSE ? $success : FALSE;
1737
				} else {
1738
					$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);
1739
					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1740
					$success = FALSE;
1741
				}
1742
			}
1743
		} else {
1744
			$success = FALSE;
1745
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1746
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1747
		}
1748
		// in order to force a pluralized result message we need to send back a success status greater than 1
1749
		$success = $success ? 2 : FALSE;
1750
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1751
1752
		$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 1749 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...
1753
	}
1754
1755
	/**
1756
	 * _trash_or_restore_events
1757
	 *
1758
	 * @access  private
1759
	 * @param  int $EVT_ID
1760
	 * @param  string $event_status
1761
	 * @return bool
1762
	 */
1763 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...
1764
		// grab event id
1765
		if (!$EVT_ID) {
1766
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1767
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1768
			return FALSE;
1769
		}
1770
1771
		$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...
1772
1773
		// clean status
1774
		$event_status = sanitize_key($event_status);
1775
		// grab status
1776
		if (empty($event_status)) {
1777
			$msg = __('An error occurred. No Event Status or an invalid Event Status was received.', 'event_espresso');
1778
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1779
			return FALSE;
1780
		}
1781
1782
		// was event trashed or restored ?
1783
		switch ($event_status) {
1784
			case 'draft' :
1785
				$action = 'restored from the trash';
1786
				$hook = 'AHEE_event_restored_from_trash';
1787
				break;
1788
			case 'trash' :
1789
				$action = 'moved to the trash';
1790
				$hook = 'AHEE_event_moved_to_trash';
1791
				break;
1792
			default :
1793
				$action = 'updated';
1794
				$hook = FALSE;
1795
		}
1796
		//use class to change status
1797
		$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...
1798
		$success = $this->_cpt_model_obj->save();
1799
1800
		if ($success === FALSE) {
1801
			$msg = sprintf(__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
1802
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1803
			return FALSE;
1804
		}
1805
		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...
1806
			do_action($hook);
1807
		}
1808
		return TRUE;
1809
	}
1810
1811
1812
1813
	/**
1814
	 * _delete_event
1815
	 *
1816
	 * @access protected
1817
	 * @param bool $redirect_after
1818
	 */
1819
	protected function _delete_event( $redirect_after = TRUE ) {
1820
		//determine the event id and set to array.
1821
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : NULL;
1822
		$EVT_ID = isset( $this->_req_data['post'] ) ? absint( $this->_req_data['post'] ) : $EVT_ID;
1823
1824
1825
		// loop thru events
1826
		if ($EVT_ID) {
1827
			$success = $this->_permanently_delete_event( $EVT_ID );
1828
			// get list of events with no prices
1829
			$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1830
			// remove this event from the list of events with no prices
1831
			if (isset($espresso_no_ticket_prices[$EVT_ID])) {
1832
				unset($espresso_no_ticket_prices[$EVT_ID]);
1833
			}
1834
			update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1835
		} else {
1836
			$success = FALSE;
1837
			$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1838
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1839
		}
1840
1841
		if ( $redirect_after )
1842
			$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...
1843
	}
1844
1845
	/**
1846
	 * _delete_events
1847
	 *
1848
	 * @access protected
1849
	 * @return void
1850
	 */
1851
	protected function _delete_events() {
1852
		$success = TRUE;
1853
		// get list of events with no prices
1854
		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1855
		//determine the event id and set to array.
1856
		$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1857
		// loop thru events
1858
		foreach ($EVT_IDs as $EVT_ID) {
1859
			$EVT_ID = absint( $EVT_ID );
1860
			if ( $EVT_ID ) {
1861
				$results = $this->_permanently_delete_event( $EVT_ID );
1862
				$success = $results !== FALSE ? $success : FALSE;
1863
				// remove this event from the list of events with no prices
1864
				unset( $espresso_no_ticket_prices[ $EVT_ID ] );
1865
			} else {
1866
				$success = FALSE;
1867
				$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1868
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1869
			}
1870
		}
1871
		update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1872
		// in order to force a pluralized result message we need to send back a success status greater than 1
1873
		$success = $success ? 2 : FALSE;
1874
		$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 1873 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...
1875
	}
1876
1877
	/**
1878
	 * _permanently_delete_event
1879
	 *
1880
	 * @access  private
1881
	 * @param  int $EVT_ID
1882
	 * @return bool
1883
	 */
1884
	private function _permanently_delete_event( $EVT_ID = 0 ) {
1885
		// grab event id
1886
		if ( ! $EVT_ID ) {
1887
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1888
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1889
			return FALSE;
1890
		}
1891
		if (
1892
			! $this->_cpt_model_obj instanceof EE_Event
1893
			|| $this->_cpt_model_obj->ID() !== $EVT_ID
1894
		) {
1895
			$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...
1896
		}
1897
1898
		if ( ! $this->_cpt_model_obj instanceof EE_Event ) {
1899
			return false;
1900
		}
1901
1902
		//need to delete related tickets and prices first.
1903
		$datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
1904
		foreach ( $datetimes as $datetime ) {
1905
			$this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
1906
			$tickets = $datetime->get_many_related('Ticket');
1907
			foreach ( $tickets as $ticket ) {
1908
				$ticket->_remove_relation_to($datetime, 'Datetime');
1909
				$ticket->delete_related_permanently('Price');
1910
				$ticket->delete_permanently();
1911
			}
1912
			$datetime->delete();
1913
		}
1914
1915
		//what about related venues or terms?
1916
		$venues = $this->_cpt_model_obj->get_many_related('Venue');
1917
		foreach ( $venues as $venue ) {
1918
			$this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
1919
		}
1920
1921
		//any attached question groups?
1922
		$question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
1923
		if ( !empty( $question_groups ) ) {
1924
			foreach ( $question_groups as $question_group ) {
1925
				$this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
1926
			}
1927
		}
1928
1929
1930
1931
1932
		//Message Template Groups
1933
		$this->_cpt_model_obj->_remove_relations( 'Message_Template_Group' );
1934
1935
		/** @type EE_Term_Taxonomy[] $term_taxonomies */
1936
		$term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
1937
1938
		foreach ( $term_taxonomies as $term_taxonomy ) {
1939
			$this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
1940
		}
1941
1942
		$success = $this->_cpt_model_obj->delete_permanently();
1943
		// did it all go as planned ?
1944
		if ($success) {
1945
			$msg = sprintf(__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
1946
			EE_Error::add_success($msg);
1947
		} else {
1948
			$msg = sprintf(__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'), $EVT_ID);
1949
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1950
			return FALSE;
1951
		}
1952
		do_action( 'AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID );
1953
		return TRUE;
1954
	}
1955
1956
1957
1958
1959
1960
1961
	/**
1962
	 * get total number of events
1963
	 *
1964
	 * @access public
1965
	 * @return int
1966
	 */
1967
	public function total_events() {
1968
1969
		$count = EEM_Event::instance()->count( array( 'caps' => 'read_admin' ), 'EVT_ID', true );
1970
		return $count;
1971
	}
1972
1973
1974
1975
1976
	/**
1977
	 * get total number of draft events
1978
	 *
1979
	 * @access public
1980
	 * @return int
1981
	 */
1982
	public function total_events_draft() {
1983
		$where = array(
1984
			'status' => array( 'IN', array('draft', 'auto-draft' ) )
1985
			);
1986
1987
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
1988
		return $count;
1989
	}
1990
1991
1992
1993
1994
1995
	/**
1996
	 * get total number of trashed events
1997
	 *
1998
	 * @access public
1999
	 * @return int
2000
	 */
2001
	public function total_trashed_events() {
2002
		$where = array(
2003
			'status' => 'trash'
2004
			);
2005
2006
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
2007
		return $count;
2008
	}
2009
2010
2011
2012
2013
	/**
2014
	 * 	_default_event_settings
2015
	 *
2016
	 * 	This generates the Default Settings Tab
2017
	 *
2018
	 * 	@return string html for the settings page
2019
	 */
2020
	protected function _default_event_settings() {
2021
2022
		$this->_template_args['values'] = $this->_yes_no_values;
2023
2024
		$this->_template_args['reg_status_array'] = EEM_Registration::reg_status_array(
2025
			// exclude array
2026
			array(
2027
				EEM_Registration::status_id_cancelled,
2028
				EEM_Registration::status_id_declined,
2029
				EEM_Registration::status_id_incomplete
2030
			),
2031
			// translated
2032
			TRUE
2033
		);
2034
		$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;
2035
2036
		$this->_set_add_edit_form_tags('update_default_event_settings');
2037
		$this->_set_publish_post_box_vars(NULL, FALSE, FALSE, NULL, FALSE);
2038
		$this->_template_args['admin_page_content'] = EEH_Template::display_template(EVENTS_TEMPLATE_PATH . 'event_settings.template.php', $this->_template_args, TRUE);
2039
		$this->display_admin_page_with_sidebar();
2040
	}
2041
2042
	/**
2043
	 * 		_update_default_event_settings
2044
	 * 		@access protected
2045
	 * 		@return array
2046
	 */
2047
	protected function _update_default_event_settings() {
2048
2049
		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;
2050
2051
		$what = 'Default Event Settings';
2052
		$success = $this->_update_espresso_configuration($what, EE_Config::instance(), __FILE__, __FUNCTION__, __LINE__);
2053
		$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...
2054
	}
2055
2056
2057
2058
2059
	/*************		Templates 		*************/
2060
2061
2062
	protected function _template_settings() {
2063
		$this->_admin_page_title = __('Template Settings (Preview)', 'event_espresso');
2064
		$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' ) . '" />';
2065
		$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>';
2066
		$this->display_admin_caf_preview_page( 'template_settings_tab' );
2067
	}
2068
2069
2070
	/** Event Category Stuff **/
2071
2072
	/**
2073
	 * set the _category property with the category object for the loaded page.
2074
	 *
2075
	 * @access private
2076
	 * @return void
2077
	 */
2078 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...
2079
		if ( isset( $this->_category->id ) && !empty( $this->_category->id ) )
2080
			return; //already have the category object so get out.
2081
2082
		//set default category object
2083
		$this->_set_empty_category_object();
2084
2085
		//only set if we've got an id
2086
		if ( !isset($this->_req_data['EVT_CAT_ID'] ) ) {
2087
			return;
2088
		}
2089
2090
		$category_id = absint($this->_req_data['EVT_CAT_ID']);
2091
2092
		$term = get_term( $category_id, 'espresso_event_categories' );
2093
2094
		if ( !empty( $term ) ) {
2095
			$this->_category->category_name = $term->name;
2096
			$this->_category->category_identifier = $term->slug;
2097
			$this->_category->category_desc = $term->description;
2098
			$this->_category->id = $term->term_id;
2099
			$this->_category->parent = $term->parent;
2100
		}
2101
	}
2102
2103
2104
2105
2106
	private function _set_empty_category_object() {
2107
		$this->_category = new stdClass();
2108
		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc  = '';
2109
		$this->_category->id = $this->_category->parent = 0;
2110
	}
2111
2112
2113 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...
2114
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
2115
		$this->_search_btn_label = __('Categories', 'event_espresso');
2116
		$this->_admin_page_title .= $this->get_action_link_or_button('add_category', 'add_category', array(), 'add-new-h2');
2117
		$this->display_admin_list_table_page_with_sidebar();
2118
	}
2119
2120
2121 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...
2122
2123
		//load formatter helper
2124
		//load field generator helper
2125
2126
		$route = $view == 'edit' ? 'update_category' : 'insert_category';
2127
		$this->_set_add_edit_form_tags($route);
2128
2129
		$this->_set_category_object();
2130
		$id = !empty($this->_category->id) ? $this->_category->id : '';
2131
2132
		$delete_action = 'delete_category';
2133
2134
		//custom redirect
2135
		$redirect = EE_Admin_Page::add_query_args_and_nonce( array('action' => 'category_list'), $this->_admin_base_url );
2136
2137
		$this->_set_publish_post_box_vars( 'EVT_CAT_ID', $id, $delete_action, $redirect );
2138
2139
		//take care of contents
2140
		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2141
		$this->display_admin_page_with_sidebar();
2142
	}
2143
2144
2145
2146 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...
2147
		$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...
2148
			'type' => 'wp_editor',
2149
			'value' => EEH_Formatter::admin_format_content($this->_category->category_desc),
2150
			'class' => 'my_editor_custom',
2151
			'wpeditor_args' => array('media_buttons' => FALSE )
2152
		);
2153
		$_wp_editor = $this->_generate_admin_form_fields( $editor_args, 'array' );
2154
2155
		$all_terms = get_terms( array('espresso_event_categories' ), array( 'hide_empty' => 0, 'exclude' => array( $this->_category->id ) ) );
2156
2157
		//setup category select for term parents.
2158
		$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...
2159
			'text' => __('No Parent', 'event_espresso'),
2160
			'id' => 0
2161
			);
2162
		foreach ( $all_terms as $term ) {
2163
			$category_select_values[] = array(
2164
				'text' => $term->name,
2165
				'id' => $term->term_id
2166
				);
2167
		}
2168
2169
		$category_select = EEH_Form_Fields::select_input( 'category_parent', $category_select_values, $this->_category->parent );
2170
2171
		$template_args = array(
2172
			'category' => $this->_category,
2173
			'category_select' => $category_select,
2174
			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2175
			'category_desc_editor' =>  $_wp_editor['category_desc']['field'],
2176
			'disable' => '',
2177
			'disabled_message' => FALSE
2178
			);
2179
		$template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2180
		return EEH_Template::display_template($template, $template_args, TRUE );
2181
	}
2182
2183
2184 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...
2185
		$cat_ids = isset( $this->_req_data['EVT_CAT_ID'] ) ? (array) $this->_req_data['EVT_CAT_ID'] : (array) $this->_req_data['category_id'];
2186
2187
		foreach ( $cat_ids as $cat_id ) {
2188
			$this->_delete_category($cat_id);
2189
		}
2190
2191
		//doesn't matter what page we're coming from... we're going to the same place after delete.
2192
		$query_args = array(
2193
			'action' => 'category_list'
2194
			);
2195
		$this->_redirect_after_action(0,'','',$query_args);
2196
2197
	}
2198
2199
2200
2201
2202
2203
	protected function _delete_category($cat_id) {
2204
		global $wpdb;
2205
		$cat_id = absint( $cat_id );
2206
		wp_delete_term( $cat_id, 'espresso_event_categories' );
2207
	}
2208
2209
2210
2211 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...
2212
2213
		$cat_id = $new_category ? $this->_insert_category() : $this->_insert_category( TRUE );
2214
		$success = 0; //we already have a success message so lets not send another.
2215
2216
		if ( $cat_id ) {
2217
			$query_args = array(
2218
				'action'     => 'edit_category',
2219
				'EVT_CAT_ID' => $cat_id
2220
			);
2221
		} else {
2222
			$query_args = array( 'action' => 'add_category' );
2223
		}
2224
		$this->_redirect_after_action( $success, '','', $query_args, TRUE );
2225
2226
	}
2227
2228
2229
2230
	private function _insert_category( $update = FALSE ) {
2231
		$cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2232
		$category_name= isset( $this->_req_data['category_name'] ) ? $this->_req_data['category_name'] : '';
2233
		$category_desc= isset( $this->_req_data['category_desc'] ) ? $this->_req_data['category_desc'] : '';
2234
		$category_parent = isset( $this->_req_data['category_parent'] ) ? $this->_req_data['category_parent'] : 0;
2235
2236
		if ( empty( $category_name ) ) {
2237
			$msg = __( 'You must add a name for the category.', 'event_espresso' );
2238
			EE_Error::add_error( $msg, __FILE__, __FUNCTION__, __LINE__ );
2239
			return false;
2240
		}
2241
2242
		$term_args=array(
2243
			'name'=>$category_name,
2244
			'description'=>$category_desc,
2245
			'parent'=>$category_parent
2246
		);
2247
		//was the category_identifier input disabled?
2248
		if(isset($this->_req_data['category_identifier'])){
2249
			$term_args['slug'] = $this->_req_data['category_identifier'];
2250
		}
2251
		$insert_ids = $update ? wp_update_term( $cat_id, 'espresso_event_categories', $term_args ) :wp_insert_term( $category_name, 'espresso_event_categories', $term_args );
2252
2253 View Code Duplication
		if ( !is_array( $insert_ids ) ) {
2254
			$msg = __( 'An error occurred and the category has not been saved to the database.', 'event_espresso' );
2255
			EE_Error::add_error( $msg, __FILE__, __FUNCTION__, __LINE__ );
2256
		} else {
2257
			$cat_id = $insert_ids['term_id'];
2258
			$msg = sprintf ( __('The category %s was successfuly saved', 'event_espresso'), $category_name );
2259
			EE_Error::add_success( $msg );
2260
		}
2261
2262
		return $cat_id;
2263
	}
2264
2265
2266
2267
2268 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...
2269
		global $wpdb;
2270
2271
		//testing term stuff
2272
		$orderby = isset( $this->_req_data['orderby'] ) ? $this->_req_data['orderby'] : 'Term.term_id';
2273
		$order = isset( $this->_req_data['order'] ) ? $this->_req_data['order'] : 'DESC';
2274
		$limit = ($current_page-1)*$per_page;
2275
2276
		$where = array( 'taxonomy' => 'espresso_event_categories' );
2277
2278
		if ( isset( $this->_req_data['s'] ) ) {
2279
			$sstr = '%' . $this->_req_data['s'] . '%';
2280
			$where['OR'] = array(
2281
				'Term.name' => array( 'LIKE', $sstr),
2282
				'description' => array( 'LIKE', $sstr )
2283
				);
2284
		}
2285
2286
		$query_params = array(
2287
			$where ,
2288
			'order_by' => array( $orderby => $order ),
2289
			'limit' => $limit . ',' . $per_page,
2290
			'force_join' => array('Term')
2291
			);
2292
2293
		$categories = $count ? EEM_Term_Taxonomy::instance()->count( $query_params, 'term_id' ) :EEM_Term_Taxonomy::instance()->get_all( $query_params );
2294
2295
		return $categories;
2296
	}
2297
2298
2299
2300
	/* end category stuff */
2301
	/**************/
2302
2303
}
2304
//end class Events_Admin_Page
2305