Completed
Branch TASK-9118-extensions-page (04eaec)
by
unknown
833:21 queued 818:09
created

Events_Admin_Page   F

Complexity

Total Complexity 303

Size/Duplication

Total Lines 2324
Duplicated Lines 17.99 %

Coupling/Cohesion

Components 2
Dependencies 21
Metric Value
wmc 303
lcom 2
cbo 21
dl 418
loc 2324
rs 0.6314

65 Methods

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

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

Complex classes like Events_Admin_Page often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Events_Admin_Page, and based on these observations, apply Extract Interface, too.

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

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

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

Loading history...
63
			'create_new' => 'EEM_Event',
64
			'edit' => 'EEM_Event'
65
			);
66
		$this->_cpt_edit_routes = array(
67
			'espresso_events' => 'edit'
68
			);
69
70
		add_action('AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object', array( $this, 'verify_event_edit' ) );
71
	}
72
73
	protected function _ajax_hooks() {
74
		//todo: all hooks for events ajax goes in here.
75
	}
76
77 View Code Duplication
	protected function _define_page_props() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
78
		$this->_admin_page_title = EVENTS_LABEL;
79
		$this->_labels = array(
80
			'buttons' => array(
81
				'add' => __('Add New Event', 'event_espresso'),
82
				'edit' => __('Edit Event', 'event_espresso'),
83
				'delete' => __('Delete Event', 'event_espresso'),
84
				'add_category' => __('Add New Category', 'event_espresso'),
85
				'edit_category' => __('Edit Category', 'event_espresso'),
86
				'delete_category' => __('Delete Category', 'event_espresso')
87
			),
88
			'editor_title' => array(
89
				'espresso_events' => __('Enter event title here', 'event_espresso')
90
				),
91
			'publishbox' => array(
92
				'create_new' => __('Save New Event', 'event_espresso'),
93
				'edit' => __('Update Event', 'event_espresso'),
94
				'add_category' => __('Save New Category', 'event_espresso'),
95
				'edit_category' => __('Update Category', 'event_espresso'),
96
				'template_settings' => __( 'Update Settings', 'event_espresso' )
97
				)
98
		);
99
	}
100
101
	protected function _set_page_routes() {
102
		//load formatter helper
103
		EE_Registry::instance()->load_helper( 'Formatter' );
104
		//load field generator helper
105
		EE_Registry::instance()->load_helper( 'Form_Fields' );
106
107
		//is there a evt_id in the request?
108
		$evt_id = ! empty( $this->_req_data['EVT_ID'] ) && ! is_array( $this->_req_data['EVT_ID'] ) ? $this->_req_data['EVT_ID'] : 0;
109
		$evt_id = ! empty( $this->_req_data['post'] ) ? $this->_req_data['post'] : $evt_id;
110
111
112
		$this->_page_routes = array(
113
			'default' => array(
114
				'func' => '_events_overview_list_table',
115
				'capability' => 'ee_read_events'
116
				),
117
			'create_new' => array(
118
				'func' => '_create_new_cpt_item',
119
				'capability' => 'ee_edit_events'
120
				),
121
			'edit' => array(
122
				'func' => '_edit_cpt_item',
123
				'capability' => 'ee_edit_event',
124
				'obj_id' => $evt_id
125
				),
126
			'copy_event' => array(
127
				'func' => '_copy_events',
128
				'capability' => 'ee_edit_event',
129
				'obj_id' => $evt_id,
130
				'noheader' => true
131
			),
132
			'trash_event' => array(
133
				'func' => '_trash_or_restore_event',
134
				'args' => array('event_status' => 'trash'),
135
				'capability' => 'ee_delete_event',
136
				'obj_id' => $evt_id,
137
				'noheader' => true
138
			),
139
			'trash_events' => array(
140
				'func' => '_trash_or_restore_events',
141
				'args' => array('event_status' => 'trash'),
142
				'capability' => 'ee_delete_events',
143
				'noheader' => true
144
			),
145
			'restore_event' => array(
146
				'func' => '_trash_or_restore_event',
147
				'args' => array('event_status' => 'draft'),
148
				'capability' => 'ee_delete_event',
149
				'obj_id' => $evt_id,
150
				'noheader' => true
151
			),
152
			'restore_events' => array(
153
				'func' => '_trash_or_restore_events',
154
				'args' => array('event_status' => 'draft'),
155
				'capability' => 'ee_delete_events',
156
				'noheader' => true
157
			),
158
			'delete_event' => array(
159
				'func' => '_delete_event',
160
				'capability' => 'ee_delete_event',
161
				'obj_id' => $evt_id,
162
				'noheader' => true
163
			),
164
			'delete_events' => array(
165
				'func' => '_delete_events',
166
				'capability' => 'ee_delete_events',
167
				'noheader' => true
168
			),
169
			'view_report' => array(
170
				'func' => '_view_report',
171
				'capablity' => 'ee_edit_events'
172
				),
173
			'default_event_settings' => array(
174
				'func' => '_default_event_settings',
175
				'capability' => 'manage_options'
176
				),
177
			'update_default_event_settings' => array(
178
				'func' => '_update_default_event_settings',
179
				'capability' => 'manage_options',
180
				'noheader' => TRUE,
181
				),
182
			'template_settings' => array(
183
				'func' => '_template_settings',
184
				'capability' => 'manage_options'
185
				),
186
			//event category tab related
187
			'add_category' => array(
188
				'func' => '_category_details',
189
				'capability' => 'ee_edit_event_category',
190
				'args' => array('add'),
191
				),
192
			'edit_category' => array(
193
				'func' => '_category_details',
194
				'capability' => 'ee_edit_event_category',
195
				'args' => array('edit')
196
				),
197
			'delete_categories' => array(
198
				'func' => '_delete_categories',
199
				'capability' => 'ee_delete_event_category',
200
				'noheader' => TRUE
201
				),
202
203
			'delete_category' => array(
204
				'func' => '_delete_categories',
205
				'capability' => 'ee_delete_event_category',
206
				'noheader' => TRUE
207
				),
208
209
			'insert_category' => array(
210
				'func' => '_insert_or_update_category',
211
				'args' => array('new_category' => TRUE),
212
				'capability' => 'ee_edit_event_category',
213
				'noheader' => TRUE
214
				),
215
216
			'update_category' => array(
217
				'func' => '_insert_or_update_category',
218
				'args' => array('new_category' => FALSE),
219
				'capability' => 'ee_edit_event_category',
220
				'noheader' => TRUE
221
				),
222
			'category_list' => array(
223
				'func' => '_category_list_table',
224
				'capability' => 'ee_manage_event_categories'
225
				)
226
		);
227
	}
228
229
	protected function _set_page_config() {
230
231
232
233
		$this->_page_config = array(
234
			'default' => array(
235
				'nav' => array(
236
					'label' => __('Overview', 'event_espresso'),
237
					'order' => 10
238
				),
239
				'list_table' => 'Events_Admin_List_Table',
240
				'help_tabs' => array(
241
					'events_overview_help_tab' => array(
242
						'title' => __('Events Overview', 'event_espresso'),
243
						'filename' => 'events_overview'
244
					),
245
					'events_overview_table_column_headings_help_tab' => array(
246
						'title' => __('Events Overview Table Column Headings', 'event_espresso'),
247
						'filename' => 'events_overview_table_column_headings'
248
					),
249
					'events_overview_filters_help_tab' => array(
250
						'title' => __('Events Overview Filters', 'event_espresso'),
251
						'filename' => 'events_overview_filters'
252
					),
253
					'events_overview_view_help_tab' => array(
254
						'title' => __('Events Overview Views', 'event_espresso'),
255
						'filename' => 'events_overview_views'
256
					),
257
					'events_overview_other_help_tab' => array(
258
						'title' => __('Events Overview Other', 'event_espresso'),
259
						'filename' => 'events_overview_other'
260
					)
261
				),
262
				'help_tour' => array(
263
					'Event_Overview_Help_Tour',
264
					//'New_Features_Test_Help_Tour' for testing multiple help tour
265
					),
266
				'qtips' => array(
267
					'EE_Event_List_Table_Tips'
268
					),
269
				'require_nonce' => FALSE
270
			),
271
			'create_new' => array(
272
				'nav' => array(
273
					'label' => __('Add Event', 'event_espresso'),
274
					'order' => 5,
275
					'persistent' => false
276
				),
277
				'metaboxes' => array('_register_event_editor_meta_boxes'),
278
				'help_tabs' => array(
279
					'event_editor_help_tab' => array(
280
						'title' => __('Event Editor', 'event_espresso'),
281
						'filename' => 'event_editor'
282
					),
283
					'event_editor_title_richtexteditor_help_tab' => array(
284
						'title' => __('Event Title & Rich Text Editor', 'event_espresso'),
285
						'filename' => 'event_editor_title_richtexteditor'
286
					),
287
					'event_editor_venue_details_help_tab' => array(
288
						'title' => __('Event Venue Details', 'event_espresso'),
289
						'filename' => 'event_editor_venue_details'
290
					),
291
					'event_editor_event_datetimes_help_tab' => array(
292
						'title' => __('Event Datetimes', 'event_espresso'),
293
						'filename' => 'event_editor_event_datetimes'
294
					),
295
					'event_editor_event_tickets_help_tab' => array(
296
						'title' => __('Event Tickets', 'event_espresso'),
297
						'filename' => 'event_editor_event_tickets'
298
					),
299
					'event_editor_event_registration_options_help_tab' => array(
300
						'title' => __('Event Registration Options', 'event_espresso'),
301
						'filename' => 'event_editor_event_registration_options'
302
					),
303
					'event_editor_tags_categories_help_tab' => array(
304
						'title' => __('Event Tags & Categories', 'event_espresso'),
305
						'filename' => 'event_editor_tags_categories'
306
					),
307
					'event_editor_questions_registrants_help_tab' => array(
308
						'title' => __('Questions for Registrants', 'event_espresso'),
309
						'filename' => 'event_editor_questions_registrants'
310
					),
311
					'event_editor_save_new_event_help_tab' => array(
312
						'title' => __('Save New Event', 'event_espresso'),
313
						'filename' => 'event_editor_save_new_event'
314
					),
315
					'event_editor_other_help_tab' => array(
316
						'title' => __('Event Other', 'event_espresso'),
317
						'filename' => 'event_editor_other'
318
					)
319
				),
320
				'help_tour' => array(
321
					'Event_Editor_Help_Tour'
322
					),
323
				'qtips' => array( 'EE_Event_Editor_Decaf_Tips' ),
324
				'require_nonce' => FALSE
325
			),
326
			'edit' => array(
327
				'nav' => array(
328
					'label' => __('Edit Event', 'event_espresso'),
329
					'order' => 5,
330
					'persistent' => false,
331
					'url' => isset($this->_req_data['post']) ? EE_Admin_Page::add_query_args_and_nonce(array('post' => $this->_req_data['post'], 'action' => 'edit'), $this->_current_page_view_url) : $this->_admin_base_url
332
				),
333
				'metaboxes' => array('_register_event_editor_meta_boxes'),
334
				'help_tabs' => array(
335
					'event_editor_help_tab' => array(
336
						'title' => __('Event Editor', 'event_espresso'),
337
						'filename' => 'event_editor'
338
					),
339
					'event_editor_title_richtexteditor_help_tab' => array(
340
						'title' => __('Event Title & Rich Text Editor', 'event_espresso'),
341
						'filename' => 'event_editor_title_richtexteditor'
342
					),
343
					'event_editor_venue_details_help_tab' => array(
344
						'title' => __('Event Venue Details', 'event_espresso'),
345
						'filename' => 'event_editor_venue_details'
346
					),
347
					'event_editor_event_datetimes_help_tab' => array(
348
						'title' => __('Event Datetimes', 'event_espresso'),
349
						'filename' => 'event_editor_event_datetimes'
350
					),
351
					'event_editor_event_tickets_help_tab' => array(
352
						'title' => __('Event Tickets', 'event_espresso'),
353
						'filename' => 'event_editor_event_tickets'
354
					),
355
					'event_editor_event_registration_options_help_tab' => array(
356
						'title' => __('Event Registration Options', 'event_espresso'),
357
						'filename' => 'event_editor_event_registration_options'
358
					),
359
					'event_editor_tags_categories_help_tab' => array(
360
						'title' => __('Event Tags & Categories', 'event_espresso'),
361
						'filename' => 'event_editor_tags_categories'
362
					),
363
					'event_editor_questions_registrants_help_tab' => array(
364
						'title' => __('Questions for Registrants', 'event_espresso'),
365
						'filename' => 'event_editor_questions_registrants'
366
					),
367
					'event_editor_save_new_event_help_tab' => array(
368
						'title' => __('Save New Event', 'event_espresso'),
369
						'filename' => 'event_editor_save_new_event'
370
					),
371
					'event_editor_other_help_tab' => array(
372
						'title' => __('Event Other', 'event_espresso'),
373
						'filename' => 'event_editor_other'
374
					)
375
				),
376
				'help_tour' => array(
377
					'Event_Edit_Help_Tour'
378
				),
379
				'qtips' => array( 'EE_Event_Editor_Decaf_Tips' ),
380
				'require_nonce' => FALSE
381
			),
382
			'default_event_settings' => array(
383
				'nav' => array(
384
					'label' => __('Default Settings', 'event_espresso'),
385
					'order' => 40
386
				),
387
				'metaboxes' => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
388
				'labels' => array(
389
					'publishbox' => __('Update Settings', 'event_espresso')
390
				),
391
				'help_tabs' => array(
392
					'default_settings_help_tab' => array(
393
						'title' => __('Default Event Settings', 'event_espresso'),
394
						'filename' => 'events_default_settings'
395
					),
396
					'default_settings_status_help_tab' => array(
397
						'title' => __('Default Registration Status', 'event_espresso'),
398
						'filename' => 'events_default_settings_status'
399
					)
400
				),
401
				'help_tour' => array( 'Event_Default_Settings_Help_Tour'),
402
				'require_nonce' => FALSE
403
			),
404
			//template settings
405
			'template_settings' => array(
406
				'nav' => array(
407
					'label' => __('Templates', 'event_espresso'),
408
					'order' => 30
409
				),
410
				'metaboxes' => $this->_default_espresso_metaboxes,
411
				'help_tabs' => array(
412
					'general_settings_templates_help_tab' => array(
413
						'title' => __('Templates', 'event_espresso'),
414
						'filename' => 'general_settings_templates'
415
					)
416
				),
417
				'help_tour' => array( 'Templates_Help_Tour' ),
418
				'require_nonce' => FALSE
419
			),
420
			//event category stuff
421
			'add_category' => array(
422
				'nav' => array(
423
					'label' => __('Add Category', 'event_espresso'),
424
					'order' => 15,
425
					'persistent' => false),
426
				'help_tabs' => array(
427
					'add_category_help_tab' => array(
428
						'title' => __('Add New Event Category', 'event_espresso'),
429
						'filename' => 'events_add_category'
430
						)
431
					),
432
			'help_tour' => array('Event_Add_Category_Help_Tour'),
433
				'metaboxes' => array('_publish_post_box'),
434
				'require_nonce' => FALSE
435
				),
436
			'edit_category' => array(
437
				'nav' => array(
438
					'label' => __('Edit Category', 'event_espresso'),
439
					'order' => 15,
440
					'persistent' => FALSE,
441
					'url' => isset($this->_req_data['EVT_CAT_ID']) ? add_query_arg(array('EVT_CAT_ID' => $this->_req_data['EVT_CAT_ID'] ), $this->_current_page_view_url )  : $this->_admin_base_url
442
					),
443
				'help_tabs' => array(
444
					'edit_category_help_tab' => array(
445
						'title' => __('Edit Event Category', 'event_espresso'),
446
						'filename' => 'events_edit_category'
447
						)
448
					),
449
				'help_tour' => array('Event_Edit_Category_Help_Tour'),
450
					'metaboxes' => array('_publish_post_box'),
451
					'require_nonce' => FALSE
452
					),
453
			'category_list' => array(
454
				'nav' => array(
455
					'label' => __('Categories', 'event_espresso'),
456
					'order' => 20
457
					),
458
				'list_table' => 'Event_Categories_Admin_List_Table',
459
				'help_tabs' => array(
460
					'events_categories_help_tab' => array(
461
						'title' => __('Event Categories', 'event_espresso'),
462
						'filename' => 'events_categories'
463
					),
464
					'events_categories_table_column_headings_help_tab' => array(
465
						'title' => __('Event Categories Table Column Headings', 'event_espresso'),
466
						'filename' => 'events_categories_table_column_headings'
467
					),
468
					'events_categories_view_help_tab' => array(
469
						'title' => __('Event Categories Views', 'event_espresso'),
470
						'filename' => 'events_categories_views'
471
					),
472
					'events_categories_other_help_tab' => array(
473
						'title' => __('Event Categories Other', 'event_espresso'),
474
						'filename' => 'events_categories_other'
475
					)
476
				),
477
				'help_tour' => array(
478
					'Event_Categories_Help_Tour'
479
					),
480
				'metaboxes' => $this->_default_espresso_metaboxes,
481
				'require_nonce' => FALSE
482
				),
483
		);
484
	}
485
486
487
	protected function _add_screen_options() {
488
		//todo
489
	}
490
491
	protected function _add_screen_options_default() {
492
		$this->_per_page_screen_option();
493
	}
494
495 View Code Duplication
	protected function _add_screen_options_category_list() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
496
		$page_title = $this->_admin_page_title;
497
		$this->_admin_page_title = __('Categories', 'event_espresso');
498
		$this->_per_page_screen_option();
499
		$this->_admin_page_title = $page_title;
500
	}
501
502
	protected function _add_feature_pointers() {
503
		//todo
504
	}
505
506
507
508
509
	public function load_scripts_styles() {
510
511
		wp_register_style('events-admin-css', EVENTS_ASSETS_URL . 'events-admin-page.css', array(), EVENT_ESPRESSO_VERSION);
512
		wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION );
513
		wp_enqueue_style('events-admin-css');
514
		wp_enqueue_style('ee-cat-admin');
515
		//todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
516
		//registers for all views
517
		//scripts
518
		wp_register_script('event_editor_js', EVENTS_ASSETS_URL . 'event_editor.js', array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'), EVENT_ESPRESSO_VERSION, TRUE);
519
	}
520
521
	/**
522
	 * enqueuing scripts and styles specific to this view
523
	 * @return void
524
	 */
525
	public function load_scripts_styles_create_new() {
526
		$this->load_scripts_styles_edit();
527
	}
528
529
	/**
530
	 * enqueuing scripts and styles specific to this view
531
	 * @return void
532
	 */
533 View Code Duplication
	public function load_scripts_styles_edit() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
534
		//styles
535
		wp_enqueue_style('espresso-ui-theme');
536
		wp_register_style('event-editor-css', EVENTS_ASSETS_URL . 'event-editor.css', array('ee-admin-css'), EVENT_ESPRESSO_VERSION );
537
		wp_enqueue_style('event-editor-css');
538
539
		//scripts
540
		wp_register_script('event-datetime-metabox', EVENTS_ASSETS_URL . 'event-datetime-metabox.js', array('event_editor_js', 'ee-datepicker'), EVENT_ESPRESSO_VERSION );
541
		wp_enqueue_script('event-datetime-metabox');
542
543
	}
544
545
546
547
	public function load_scripts_styles_add_category() {
548
		$this->load_scripts_styles_edit_category();
549
	}
550
551
552
553
554
555
	public function load_scripts_styles_edit_category() {}
556
557
558
559 View Code Duplication
	protected function _set_list_table_views_category_list() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
560
		$this->_views = array(
561
			'all' => array(
562
				'slug' => 'all',
563
				'label' => __('All', 'event_espresso'),
564
				'count' => 0,
565
				'bulk_action' => array(
566
					'delete_categories' => __('Delete Permanently', 'event_espresso')
567
					)
568
				)
569
		);
570
	}
571
572
573
574
	public function admin_init() {
575
		EE_Registry::$i18n_js_strings[ 'image_confirm' ] = __( 'Do you really want to delete this image? Please remember to update your event to complete the removal.', 'event_espresso' );
576
	}
577
578
579
580
	//nothing needed for events with these methods.
581
	public function admin_notices() {}
582
	public function admin_footer_scripts() {}
583
584
585
586
587
	/**
588
	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a warning (via EE_Error::add_error());
589
	 *
590
	 * @param  EE_Event    $event 	Event object
591
	 * @access public
592
	 * @return void
593
	 */
594
	public function verify_event_edit($event = NULL) {
595
		// no event?
596
		if ( empty( $event )) {
597
			// set event
598
			$event = $this->_cpt_model_obj;
599
		}
600
		// STILL no event?
601
		if ( empty ( $event )) {
602
			return;
603
		}
604
		// first check if event is active.
605
		if ( $event->is_expired() || $event->is_inactive() || $event->status() == EEM_Event::cancelled || $event->status() == EEM_Event::postponed ) {
0 ignored issues
show
Documentation Bug introduced by
The method is_expired does not exist on object<EE_CPT_Base>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
Documentation Bug introduced by
The method is_inactive does not exist on object<EE_CPT_Base>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
606
			return;
607
		}
608
		$orig_status = $event->status();
609
		//made it here so it IS active... next check that any of the tickets are sold.
610
		if ( $event->is_sold_out( true ) ) {
0 ignored issues
show
Documentation Bug introduced by
The method is_sold_out does not exist on object<EE_CPT_Base>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
611 View Code Duplication
			if ( $event->status() !== $orig_status && $orig_status !== EEM_Event::sold_out  ) {
612
				EE_Error::add_attention(
613
					sprintf(
614
						__( 'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.', 'event_espresso' ),
615
						EEH_Template::pretty_status( EEM_Event::sold_out, FALSE, 'sentence' )
616
					)
617
				);
618
			}
619
			return;
620 View Code Duplication
		} else if ( $orig_status === EEM_Event::sold_out ) {
621
			EE_Error::add_attention(
622
				sprintf(
623
					__( 'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
624
						'event_espresso' ),
625
					EEH_Template::pretty_status( $event->status(), false, 'sentence' )
0 ignored issues
show
Documentation introduced by
$event->status() is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
626
				)
627
			);
628
		}
629
		//now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
630
		if ( ! $event->tickets_on_sale() ) {
0 ignored issues
show
Documentation Bug introduced by
The method tickets_on_sale does not exist on object<EE_CPT_Base>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
631
			return;
632
		}
633
		//made it here so show warning
634
		EE_Error::add_attention( $this->_edit_event_warning() );
635
	}
636
637
638
639
640
	/**
641
	 * This is the text used for when an event is being edited that is public and has tickets for sale.
642
	 * When needed, hook this into a EE_Error::add_error() notice.
643
	 *
644
	 * @access protected
645
	 * @return string
646
	 */
647
	protected function _edit_event_warning() {
648
		return __('Please be advised that this event has been published and is open for registrations on your website. If you update any registration-related details (i.e. custom questions, messages, tickets, datetimes, etc.) while a registration is in process, the registration process could be interrupted and result in errors for the person registering and potentially incorrect registration or transaction data inside Event Espresso. We recommend editing events during a period of slow traffic, or even temporarily changing the status of an event to "Draft" until your edits are complete.', 'event_espresso');
649
	}
650
651
652
653
654
	protected function _set_list_table_views_default() {
655
		$this->_views = array(
656
			'all' => array(
657
				'slug' => 'all',
658
				'label' => __('View All Events', 'event_espresso'),
659
				'count' => 0,
660
				'bulk_action' => array(
661
					'trash_events' => __('Move to Trash', 'event_espresso')
662
				)
663
			),
664
			'draft' => array(
665
				'slug' => 'draft',
666
				'label' => __('Draft', 'event_espresso'),
667
				'count' => 0,
668
				'bulk_action' => array(
669
					'trash_events' => __('Move to Trash', 'event_espresso'),
670
					)
671
			),
672
		);
673
674
		if ( EE_Registry::instance()->CAP->current_user_can( 'ee_delete_events', 'espresso_events_trash_events' ) ) {
675
			$this->_views['trash'] = array(
676
				'slug' => 'trash',
677
				'label' => __('Trash', 'event_espresso'),
678
				'count' => 0,
679
				'bulk_action' => array(
680
					'restore_events' => __('Restore From Trash', 'event_espresso'),
681
					'delete_events' => __('Delete Permanently', 'event_espresso')
682
					)
683
				);
684
		}
685
	}
686
687
688
689
	protected function _event_legend_items() {
690
		$items = array(
691
			'view_details' => array(
692
				'class' => 'dashicons dashicons-search',
693
				'desc' => __('View Event', 'event_espresso')
694
			),
695
			'edit_event' => array(
696
				'class' => 'ee-icon ee-icon-calendar-edit',
697
				'desc' => __('Edit Event Details', 'event_espresso')
698
			),
699
			'view_attendees' => array(
700
				'class' => 'dashicons dashicons-groups',
701
				'desc' => __('View Registrations for Event', 'event_espresso')
702
			)
703
		);
704
		$items  = apply_filters( 'FHEE__Events_Admin_Page___event_legend_items__items', $items );
705
		$statuses = array(
706
			'sold_out_status' => array(
707
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
708
				'desc' => EEH_Template::pretty_status( EE_Datetime::sold_out, FALSE, 'sentence' )
709
			),
710
			'active_status' => array(
711
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
712
				'desc' => EEH_Template::pretty_status( EE_Datetime::active, FALSE, 'sentence' )
713
			),
714
			'upcoming_status' => array(
715
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
716
				'desc' => EEH_Template::pretty_status( EE_Datetime::upcoming, FALSE, 'sentence' )
717
			),
718
			'postponed_status' => array(
719
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
720
				'desc' => EEH_Template::pretty_status( EE_Datetime::postponed, FALSE, 'sentence' )
721
			),
722
			'cancelled_status' => array(
723
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
724
				'desc' => EEH_Template::pretty_status( EE_Datetime::cancelled, FALSE, 'sentence' )
725
			),
726
			'expired_status' => array(
727
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
728
				'desc' => EEH_Template::pretty_status( EE_Datetime::expired, FALSE, 'sentence' )
729
			),
730
			'inactive_status' => array(
731
				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
732
				'desc' => EEH_Template::pretty_status( EE_Datetime::inactive, FALSE, 'sentence' )
733
			)
734
		);
735
		$statuses = apply_filters( 'FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses );
736
		return array_merge( $items, $statuses );
737
	}
738
739
740
741
742
743
	/**
744
	 * _event_model
745
	 * @return EEM_Event
746
	 */
747
	private function _event_model() {
748
		if ( ! $this->_event_model instanceof EEM_Event ) {
749
			$this->_event_model = EE_Registry::instance()->load_model( 'Event' );
0 ignored issues
show
Documentation Bug introduced by
It seems like \EE_Registry::instance()->load_model('Event') of type boolean is incompatible with the declared type object of property $_event_model.

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

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

Loading history...
750
		}
751
		return $this->_event_model;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_event_model; of type boolean|EEM_Event adds the type boolean to the return on line 751 which is incompatible with the return type documented by Events_Admin_Page::_event_model of type EEM_Event.
Loading history...
752
	}
753
754
755
756
757
758
	/**
759
	 * Adds extra buttons to the WP CPT permalink field row.
760
	 *
761
	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
762
	 * @param  string $return    the current html
763
	 * @param  int    $id        the post id for the page
764
	 * @param  string $new_title What the title is
765
	 * @param  string $new_slug  what the slug is
766
	 * @return string            The new html string for the permalink area
767
	 */
768
	public function extra_permalink_field_buttons( $return, $id, $new_title, $new_slug ) {
769
		//make sure this is only when editing
770
		if ( !empty( $id ) ) {
771
			$post = get_post( $id );
772
			$return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">' . __('Shortcode', 'event_espresso') . '</a> ';
773
			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id=\'' . $post->ID . '\']"">';
774
		}
775
		return $return;
776
	}
777
778
779
780
781
	/**
782
	 * _events_overview_list_table
783
	 * This contains the logic for showing the events_overview list
784
	 *
785
	 * @access protected
786
	 * @return string html for generated table
787
	 */
788
	protected function _events_overview_list_table() {
789
		do_action( 'AHEE_log', __FILE__, __FUNCTION__, '' );
790
		$this->_template_args['after_list_table'] = EEH_Template::get_button_or_link( get_post_type_archive_link('espresso_events'), __("View Event Archive Page", "event_espresso"), 'button' ) .
791
		$this->_display_legend($this->_event_legend_items());
792
		$this->_admin_page_title .= $this->get_action_link_or_button('create_new', 'add', array(), 'add-new-h2');
793
		$this->display_admin_list_table_page_with_no_sidebar();
794
	}
795
796
797
	/**
798
	 * this allows for extra misc actions in the default WP publish box
799
	 * @return string html to add
800
	 */
801
	public function extra_misc_actions_publish_box() {
802
		$this->_generate_publish_box_extra_content();
803
	}
804
805
806
807
808
	protected function _insert_update_cpt_item( $post_id, $post ) {
809
810
		if ( $post instanceof WP_Post && $post->post_type !== 'espresso_events' ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

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

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

2. Missing use statement

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

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

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

Loading history...
811
			//getout we're not processing an event save.
812
			return;
813
		}
814
815
		$event_values = array(
816
			'EVT_display_desc' => !empty( $this->_req_data['display_desc'] ) ? 1 : 0,
817
			'EVT_display_ticket_selector' => !empty( $this->_req_data['display_ticket_selector'] ) ? 1 : 0,
818
			'EVT_additional_limit' => min(
819
					apply_filters( 'FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255 ),
820
					!empty( $this->_req_data['additional_limit'] ) ? $this->_req_data['additional_limit'] : NULL ),
821
			'EVT_default_registration_status' => !empty( $this->_req_data['EVT_default_registration_status'] ) ? $this->_req_data['EVT_default_registration_status'] : EE_Registry::instance()->CFG->registration->default_STS_ID,
822
			'EVT_member_only' => !empty( $this->_req_data['member_only'] ) ? 1 : 0,
823
			'EVT_allow_overflow' => !empty( $this->_req_data['EVT_allow_overflow'] ) ? 1 : 0,
824
			'EVT_timezone_string' => !empty( $this->_req_data['timezone_string'] ) ? $this->_req_data['timezone_string'] : NULL,
825
			'EVT_external_URL' => !empty( $this->_req_data['externalURL'] ) ? $this->_req_data['externalURL'] : NULL,
826
			'EVT_phone' => !empty( $this->_req_data['event_phone'] ) ? $this->_req_data['event_phone'] : NULL
827
			);
828
829
		//update event
830
		$success = $this->_event_model()->update_by_ID( $event_values, $post_id );
831
832
833
		//get event_object for other metaboxes... though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id ).. i have to setup where conditions to override the filters in the model that filter out autodraft and inherit statuses so we GET the inherit id!
834
		$get_one_where = array( $this->_event_model()->primary_key_name() => $post_id, 'status' => $post->post_status );
835
		$event = $this->_event_model()->get_one( array($get_one_where) );
836
837
838
		//the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
839
		$event_update_callbacks = apply_filters( 'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks', array( array($this, '_default_venue_update' ), array( $this, '_default_tickets_update') ) );
840
841
		$att_success = TRUE;
842
843 View Code Duplication
		foreach ( $event_update_callbacks as $e_callback ) {
844
			$_succ = call_user_func_array( $e_callback, array( $event,  $this->_req_data ) );
845
			$att_success = !$att_success ? $att_success : $_succ; //if ANY of these updates fail then we want the appropriate global error message
846
		}
847
848
		//any errors?
849
		if ( $success && FALSE === $att_success ) {
850
			EE_Error::add_error( __('Event Details saved successfully but something went wrong with saving attachments.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
851
		} else if ( $success === FALSE ) {
852
			EE_Error::add_error( __('Event Details did not save successfully.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
853
		}
854
	}
855
856
857
858
859
	/**
860
	 * @see parent::restore_item()
861
	 */
862
	protected function _restore_cpt_item( $post_id, $revision_id ) {
863
		//copy existing event meta to new post
864
		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
865
		if ( $post_evt instanceof EE_Event ) {
866
			//meta revision restore
867
			$post_evt->restore_revision( $revision_id );
868
			//related objs restore
869
			$post_evt->restore_revision( $revision_id, array( 'Venue', 'Datetime', 'Price' ) );
870
		}
871
	}
872
873
874
875
876
	/**
877
	 * Attach the venue to the Event
878
	 * @param  object $evtobj Event Object to add the venue to
879
	 * @param  array  $data   The request data from the form
880
	 * @return bool           Success or fail.
881
	 */
882
	protected function _default_venue_update( $evtobj, $data ) {
883
		require_once( EE_MODELS . 'EEM_Venue.model.php' );
884
		$venue_model = EE_Registry::instance()->load_model('Venue');
885
		$rows_affected = NULL;
0 ignored issues
show
Unused Code introduced by
$rows_affected is not used, you could remove the assignment.

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

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

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

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

Loading history...
886
		$venue_id = !empty( $data['venue_id'] ) ? $data['venue_id'] : NULL;
887
888
		// very important.  If we don't have a venue name...
889
		// then we'll get out because not necessary to create empty venue
890
		if ( empty( $data['venue_title'] ) ) {
891
			return false;
892
		}
893
894
		$venue_array = array(
895
				'VNU_wp_user' => $evtobj->get('EVT_wp_user'),
896
				'VNU_name' => !empty( $data['venue_title'] ) ? $data['venue_title'] : NULL,
897
				'VNU_desc' => !empty( $data['venue_description'] ) ? $data['venue_description'] : NULL,
898
				'VNU_identifier' => !empty( $data['venue_identifier'] ) ? $data['venue_identifier'] : NULL,
899
				'VNU_short_desc' => !empty( $data['venue_short_description'] ) ? $data['venue_short_description'] : NULL,
900
				'VNU_address' => !empty( $data['address'] ) ? $data['address'] : NULL,
901
				'VNU_address2' => !empty( $data['address2'] ) ? $data['address2'] : NULL,
902
				'VNU_city' => !empty( $data['city'] ) ? $data['city'] : NULL,
903
				'STA_ID' => !empty( $data['state'] ) ? $data['state'] : NULL,
904
				'CNT_ISO' => !empty( $data['countries'] ) ? $data['countries'] : NULL,
905
				'VNU_zip' => !empty( $data['zip'] ) ? $data['zip'] : NULL,
906
				'VNU_phone' => !empty( $data['venue_phone'] ) ? $data['venue_phone'] : NULL,
907
				'VNU_capacity' => !empty( $data['venue_capacity'] ) ? $data['venue_capacity'] : NULL,
908
				'VNU_url' => !empty($data['venue_url'] ) ? $data['venue_url'] : NULL,
909
				'VNU_virtual_phone' => !empty($data['virtual_phone']) ? $data['virtual_phone'] : NULL,
910
				'VNU_virtual_url' => !empty( $data['virtual_url'] ) ? $data['virtual_url'] : NULL,
911
				'VNU_enable_for_gmap' => isset( $data['enable_for_gmap'] ) ? 1 : 0,
912
				'status' => 'publish'
913
			);
914
915
916
		//if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
917
		if ( !empty( $venue_id ) ) {
918
			$update_where = array( $venue_model->primary_key_name() => $venue_id );
0 ignored issues
show
Bug introduced by
The method primary_key_name cannot be called on $venue_model (of type boolean).

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

Loading history...
919
			$rows_affected = $venue_model->update( $venue_array, array( $update_where ) );
0 ignored issues
show
Bug introduced by
The method update cannot be called on $venue_model (of type boolean).

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

Loading history...
920
			//we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
921
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
922
			return $rows_affected > 0 ? TRUE : FALSE;
923
		} else {
924
			//we insert the venue
925
			$venue_id = $venue_model->insert( $venue_array );
0 ignored issues
show
Bug introduced by
The method insert cannot be called on $venue_model (of type boolean).

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

Loading history...
926
			$evtobj->_add_relation_to( $venue_id, 'Venue' );
927
			return !empty( $venue_id ) ? TRUE : FALSE;
928
		}
929
		//when we have the ancestor come in it's already been handled by the revision save.
930
	}
931
932
933
934
935
	/**
936
	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
937
	 * @param  EE_Event $evtobj The Event object we're attaching data to
938
	 * @param  array    $data   The request data from the form
939
	 * @return bool             success or fail
940
	 */
941
	protected function _default_tickets_update( EE_Event $evtobj, $data ) {
942
		$success = true;
943
		$saved_dtt = null;
944
		$saved_tickets = array();
945
		$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
946
947
		foreach ( $data['edit_event_datetimes'] as $row => $dtt ) {
948
			//trim all values to ensure any excess whitespace is removed.
949
			$dtt =  array_map( 'trim', $dtt );
950
			$dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty( $dtt['DTT_EVT_end'] ) ? $dtt['DTT_EVT_end'] : $dtt['DTT_EVT_start'];
951
			$datetime_values = array(
952
				'DTT_ID' 		=> ! empty( $dtt['DTT_ID'] ) ? $dtt['DTT_ID'] : NULL,
953
				'DTT_EVT_start' => $dtt['DTT_EVT_start'],
954
				'DTT_EVT_end' 	=> $dtt['DTT_EVT_end'],
955
				'DTT_reg_limit' => empty( $dtt['DTT_reg_limit'] ) ? EE_INF : $dtt['DTT_reg_limit'],
956
				'DTT_order' 	=> $row,
957
			);
958
959
			//if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
960
961
			if ( !empty( $dtt['DTT_ID'] ) ) {
962
				$DTM = EE_Registry::instance()->load_model('Datetime', array( $evtobj->get_timezone() ) )->get_one_by_ID($dtt['DTT_ID'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()...vtobj->get_timezone())) (of type boolean).

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

Loading history...
963
				$DTM->set_date_format( $incoming_date_formats[0] );
964
				$DTM->set_time_format( $incoming_date_formats[1] );
965
				foreach ( $datetime_values as $field => $value ) {
966
					$DTM->set( $field, $value );
967
				}
968
969
				//make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
970
				$saved_dtts[$DTM->ID()] = $DTM;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$saved_dtts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $saved_dtts = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
971
			} else {
972
				$DTM = EE_Registry::instance()->load_class('Datetime', array( $datetime_values ), FALSE, FALSE );
973
				$DTM->set_date_format( $incoming_date_formats[0] );
0 ignored issues
show
Bug introduced by
The method set_date_format cannot be called on $DTM (of type boolean).

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

Loading history...
974
				$DTM->set_time_format( $incoming_date_formats[1] );
0 ignored issues
show
Bug introduced by
The method set_time_format cannot be called on $DTM (of type boolean).

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

Loading history...
975
				$DTM->set_timezone( $evtobj->get_timezone() );
0 ignored issues
show
Bug introduced by
The method set_timezone cannot be called on $DTM (of type boolean).

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

Loading history...
976
				foreach ( $datetime_values as $field => $value ) {
977
					$DTM->set( $field, $value );
0 ignored issues
show
Bug introduced by
The method set cannot be called on $DTM (of type boolean).

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

Loading history...
978
				}
979
			}
980
			$DTM->save();
981
982
			$DTT = $evtobj->_add_relation_to( $DTM, 'Datetime' );
983
984
			//load DTT helper
985
			EE_Registry::instance()->load_helper('DTT_Helper');
986
987
			//before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
988
			if( $DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end') ) {
989
				$DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start') );
990
				$DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
991
				$DTT->save();
992
			}
993
994
			//now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
995
			$saved_dtt = $DTT;
996
997
			$success = !$success ? $success : $DTT; //if ANY of these updates fail then we want the appropriate global error message. //todod this is actually sucky we need a better error message but this is what it is for now.
998
		}
999
1000
		//no dtts get deleted so we don't do any of that logic here.
1001
		//update tickets next
1002
		$old_tickets = isset( $data['ticket_IDs'] ) ? explode(',', $data['ticket_IDs'] ) : array();
1003
		foreach ( $data['edit_tickets'] as $row => $tkt ) {
1004
			$incoming_date_formats = array( 'Y-m-d', 'h:i a' );
1005
			$update_prices = false;
1006
			$ticket_price = isset( $data['edit_prices'][$row][1]['PRC_amount'] ) ? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
1007
1008
			// trim inputs to ensure any excess whitespace is removed.
1009
			$tkt = array_map( 'trim', $tkt );
1010
1011
			if ( empty( $tkt['TKT_start_date'] ) ) {
1012
				//let's use now in the set timezone.
1013
				$now = new DateTime( 'now', new DateTimeZone( $evtobj->get_timezone() ) );
1014
				$tkt['TKT_start_date'] = $now->format( $incoming_date_formats[0] . ' ' . $incoming_date_formats[1] );
1015
			}
1016
1017
			if ( empty( $tkt['TKT_end_date'] ) ) {
1018
				//use the start date of the first datetime
1019
				$dtt = $evtobj->first_datetime();
1020
				$tkt['TKT_end_date'] = $dtt->start_date_and_time( $incoming_date_formats[0], $incoming_date_formats[1] );
1021
			}
1022
1023
			$TKT_values = array(
1024
				'TKT_ID' 			=> !empty( $tkt['TKT_ID'] ) ? $tkt['TKT_ID'] : NULL,
1025
				'TTM_ID' 			=> !empty( $tkt['TTM_ID'] ) ? $tkt['TTM_ID'] : 0,
1026
				'TKT_name' 			=> !empty( $tkt['TKT_name'] ) ? $tkt['TKT_name'] : '',
1027
				'TKT_description' 	=> !empty( $tkt['TKT_description'] ) ? $tkt['TKT_description'] : '',
1028
				'TKT_start_date' 	=> $tkt['TKT_start_date'],
1029
				'TKT_end_date' 		=> $tkt['TKT_end_date'],
1030
				'TKT_qty' 			=> ! isset( $tkt[ 'TKT_qty' ] ) || $tkt[ 'TKT_qty' ] === '' ? EE_INF : $tkt['TKT_qty'],
1031
				'TKT_uses' 			=> ! isset( $tkt[ 'TKT_uses' ] ) || $tkt[ 'TKT_uses' ] === '' ? EE_INF : $tkt[ 'TKT_uses' ],
1032
				'TKT_min' 			=> empty( $tkt['TKT_min'] ) ? 0 : $tkt['TKT_min'],
1033
				'TKT_max' 			=> empty( $tkt['TKT_max'] ) ? EE_INF : $tkt['TKT_max'],
1034
				'TKT_row' 			=> $row,
1035
				'TKT_order' 		=> isset( $tkt['TKT_order'] ) ? $tkt['TKT_order'] : $row,
1036
				'TKT_price' 		=> $ticket_price
1037
			);
1038
1039
1040
1041
1042
			//if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
1043 View Code Duplication
			if ( isset( $tkt['TKT_is_default'] ) && $tkt['TKT_is_default'] ) {
1044
				$TKT_values['TKT_ID'] = 0;
1045
				$TKT_values['TKT_is_default'] = 0;
1046
				$TKT_values['TKT_price'] = $ticket_price;
1047
				$update_prices = TRUE;
1048
			}
1049
1050
			//if we have a TKT_ID then we need to get that existing TKT_obj and update it
1051
			//we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1052
			//keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1053
1054
			if ( !empty( $tkt['TKT_ID'] ) ) {
1055
				$TKT = EE_Registry::instance()->load_model( 'Ticket', array( $evtobj->get_timezone() ) )->get_one_by_ID( $tkt['TKT_ID'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()...vtobj->get_timezone())) (of type boolean).

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

Loading history...
1056
				if ( $TKT instanceof EE_Ticket ) {
1057
					$ticket_sold = $TKT->count_related( 'Registration', array( array( 'STS_ID' => array( 'NOT IN', array( EEM_Registration::status_id_incomplete ) ) ) ) ) > 0 ? true : false;
1058
					//let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
1059
					$create_new_TKT = $ticket_sold && $ticket_price != $TKT->get( 'TKT_price' ) && ! $TKT->get( 'TKT_deleted' ) ? true : false;
1060
					$TKT->set_date_format( $incoming_date_formats[ 0 ] );
1061
					$TKT->set_time_format( $incoming_date_formats[ 1 ] );
1062
					//set new values
1063 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1064
						if ( $field == 'TKT_qty' ) {
1065
							$TKT->set_qty( $value );
1066
						} else {
1067
							$TKT->set( $field, $value );
1068
						}
1069
					}
1070
					//if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1071
					if ( $create_new_TKT ) {
1072
						//archive the old ticket first
1073
						$TKT->set( 'TKT_deleted', 1 );
1074
						$TKT->save();
1075
						//make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1076
						$saved_tickets[ $TKT->ID() ] = $TKT;
1077
						//create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1078
						$TKT = clone $TKT;
1079
						$TKT->set( 'TKT_ID', 0 );
1080
						$TKT->set( 'TKT_deleted', 0 );
1081
						$TKT->set( 'TKT_price', $ticket_price );
1082
						$TKT->set( 'TKT_sold', 0 );
1083
						//now we need to make sure that $new prices are created as well and attached to new ticket.
1084
						$update_prices = true;
1085
					}
1086
					//make sure price is set if it hasn't been already
1087
					$TKT->set( 'TKT_price', $ticket_price );
1088
				}
1089
1090
			} else {
1091
				//no TKT_id so a new TKT
1092
				$TKT_values['TKT_price'] = $ticket_price;
1093
				$TKT = EE_Registry::instance()->load_class('Ticket', array( $TKT_values ), FALSE, FALSE );
1094
				if ( $TKT instanceof EE_Ticket ) {
1095
					//need to reset values to properly account for the date formats
1096
					$TKT->set_date_format( $incoming_date_formats[0] );
1097
					$TKT->set_time_format( $incoming_date_formats[1] );
1098
					$TKT->set_timezone( $evtobj->get_timezone() );
1099
1100
					//set new values
1101 View Code Duplication
					foreach ( $TKT_values as $field => $value ) {
1102
						if ( $field == 'TKT_qty' ) {
1103
							$TKT->set_qty( $value );
1104
						} else {
1105
							$TKT->set( $field, $value );
1106
						}
1107
					}
1108
1109
					$update_prices = TRUE;
1110
				}
1111
			}
1112
			// cap ticket qty by datetime reg limits
1113
			$TKT->set_qty( min( $TKT->qty(), $TKT->qty( 'reg_limit' ) ) );
1114
			//update ticket.
1115
			$TKT->save();
1116
1117
			//before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1118 View Code Duplication
			if( $TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date') ) {
1119
				$TKT->set('TKT_end_date', $TKT->get('TKT_start_date') );
1120
				EE_Registry::instance()->load_helper('DTT_Helper');
1121
				$TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1122
				$TKT->save();
1123
			}
1124
1125
			//initially let's add the ticket to the dtt
1126
			$saved_dtt->_add_relation_to( $TKT, 'Ticket' );
1127
1128
			$saved_tickets[$TKT->ID()] = $TKT;
1129
1130
			//add prices to ticket
1131
			$this->_add_prices_to_ticket( $data['edit_prices'][$row], $TKT, $update_prices );
1132
		}
1133
		//however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1134
		$old_tickets = isset( $old_tickets[0] ) && $old_tickets[0] == '' ? array() : $old_tickets;
1135
		$tickets_removed = array_diff( $old_tickets, array_keys( $saved_tickets ) );
1136
1137 View Code Duplication
		foreach ( $tickets_removed as $id ) {
1138
			$id = absint( $id );
1139
1140
			//get the ticket for this id
1141
			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()->load_model('Ticket') (of type boolean).

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

Loading history...
1142
1143
			//need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
1144
			$dtts = $tkt_to_remove->get_many_related('Datetime');
1145
1146
			foreach( $dtts as $dtt ) {
1147
				$tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1148
			}
1149
1150
			//need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1151
			$tkt_to_remove->delete_related_permanently('Price');
1152
1153
1154
			//finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1155
			$tkt_to_remove->delete_permanently();
1156
		}
1157
		return array( $saved_dtt, $saved_tickets );
1158
	}
1159
1160
1161
1162
	/**
1163
	 * This attaches a list of given prices to a ticket.
1164
	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1165
	 *
1166
	 * @access  private
1167
	 * @param array  	$prices  	Array of prices from the form.
1168
	 * @param EE_Ticket $ticket  	EE_Ticket object that prices are being attached to.
1169
	 * @param bool 		$new_prices Whether attach existing incoming prices or create new ones.
1170
	 * @return  void
1171
	 */
1172
	private function  _add_prices_to_ticket( $prices, EE_Ticket $ticket, $new_prices = FALSE ) {
1173
		foreach ( $prices as $row => $prc ) {
1174
			$PRC_values = array(
1175
				'PRC_ID' => !empty( $prc['PRC_ID'] ) ? $prc['PRC_ID'] : NULL,
1176
				'PRT_ID' => !empty( $prc['PRT_ID'] ) ? $prc['PRT_ID'] : NULL,
1177
				'PRC_amount' => !empty( $prc['PRC_amount'] ) ? $prc['PRC_amount'] : 0,
1178
				'PRC_name' => !empty( $prc['PRC_name'] ) ? $prc['PRC_name'] : '',
1179
				'PRC_desc' => !empty( $prc['PRC_desc'] ) ? $prc['PRC_desc'] : '',
1180
				'PRC_is_default' => 0, //make sure prices are NOT set as default from this context
1181
				'PRC_order' => $row
1182
			);
1183
1184 View Code Duplication
			if ( $new_prices || empty( $PRC_values['PRC_ID'] ) ) {
1185
				$PRC_values['PRC_ID'] = 0;
1186
				$PRC = EE_Registry::instance()->load_class('Price', array( $PRC_values ), FALSE, FALSE);
1187
			} else {
1188
				$PRC = EE_Registry::instance()->load_model( 'Price' )->get_one_by_ID( $prc['PRC_ID'] );
0 ignored issues
show
Bug introduced by
The method get_one_by_ID cannot be called on \EE_Registry::instance()->load_model('Price') (of type boolean).

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

Loading history...
1189
				//update this price with new values
1190
				foreach ( $PRC_values as $field => $newprc ) {
1191
					$PRC->set( $field, $newprc );
1192
				}
1193
				$PRC->save();
1194
			}
1195
1196
			$ticket->_add_relation_to( $PRC, 'Price' );
1197
		}
1198
	}
1199
1200
1201
1202
1203
	/**
1204
	 * Add in our autosave ajax handlers
1205
	 * @return void
1206
	 */
1207
	protected function _ee_autosave_create_new() {
1208
		$this->_ee_autosave_edit();
1209
	}
1210
1211
1212
1213
1214
1215
	protected function _ee_autosave_edit() {
1216
1217
		return; //TEMPORARILY EXITING CAUSE THIS IS A TODO
1218
1219
		$postid = isset( $this->_req_data['post_ID'] ) ? $this->_req_data['post_ID'] : NULL;
0 ignored issues
show
Unused Code introduced by
//TEMPORARILY EXITING CA...data['post_ID'] : NULL; does not seem to be reachable.

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

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

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

    return false;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1428
		EE_Registry::instance()->load_helper('DTT_Helper' );
1429
		/** @type EE_Datetime $first_datetime */
1430
		$first_datetime = array_slice( $times, 0, 1 );
1431
		//do we get related tickets?
1432
		if ( $first_datetime[ 0 ]->get( 'DTT_ID' ) !== 0 ) {
1433
			foreach ( $times as $time ) {
1434
				if ( $time instanceof EE_Datetime ) {
1435
					$existing_datetime_ids[] = $time->get('DTT_ID');
1436
					$template_args['time'] = $time;
1437
					$related_tickets = $time->tickets(
1438
						array(
1439
							array( 'OR' => array( 'TKT_deleted' => 1, 'TKT_deleted*' => 0 ) ),
1440
							'default_where_conditions' => 'none'
1441
						)
1442
					);
1443
1444
					if ( !empty($related_tickets) ) {
1445
						$template_args['total_ticket_rows'] = count($related_tickets);
1446
						$row = 0;
1447
						foreach ( $related_tickets as $ticket ) {
1448
							$existing_ticket_ids[] = $ticket->get('TKT_ID');
1449
							$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...
1450
1451
							$row++;
1452
						}
1453 View Code Duplication
					} else {
1454
						$template_args['total_ticket_rows'] = 1;
1455
						/** @type EE_Ticket $ticket */
1456
						$ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
0 ignored issues
show
Bug introduced by
The method create_default_object cannot be called on \EE_Registry::instance()->load_model('Ticket') (of type boolean).

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

Loading history...
1457
						$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket );
1458
					}
1459
				}
1460
			}
1461 View Code Duplication
		} else {
1462
			$template_args['time'] = $times[0];
1463
			/** @type EE_Ticket $ticket */
1464
			$ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
0 ignored issues
show
Bug introduced by
The method get_all_default_tickets cannot be called on \EE_Registry::instance()->load_model('Ticket') (of type boolean).

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

Loading history...
1465
			$template_args['ticket_rows'] .= $this->_get_ticket_row( $ticket[1] );
1466
			// NOTE: we're just sending the first default row
1467
			// (decaf can't manage default tickets so this should be sufficient);
1468
		}
1469
1470
		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link('event_editor_event_datetimes_help_tab');
1471
		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1472
		$template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1473
		$template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1474
		$template_args['ticket_js_structure'] = $this->_get_ticket_row( EE_Registry::instance()->load_model('Ticket')->create_default_object(), TRUE );
0 ignored issues
show
Bug introduced by
The method create_default_object cannot be called on \EE_Registry::instance()->load_model('Ticket') (of type boolean).

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

Loading history...
1475
		$template = apply_filters( 'FHEE__Events_Admin_Page__ticket_metabox__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php' );
1476
		EEH_Template::display_template($template, $template_args);
1477
	}
1478
1479
1480
1481
	/**
1482
	 * Setup an individual ticket form for the decaf event editor page
1483
	 *
1484
	 * @access private
1485
	 * @param  EE_Ticket $ticket   the ticket object
1486
	 * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1487
	 * @param int        $row
1488
	 * @return string generated html for the ticket row.
1489
	 */
1490
	private function _get_ticket_row( $ticket, $skeleton = FALSE, $row = 0 ) {
1491
		$template_args = array(
1492
			'tkt_status_class' => ' tkt-status-' . $ticket->ticket_status(),
1493
			'tkt_archive_class' => $ticket->ticket_status() === EE_Ticket::archived && !$skeleton ? ' tkt-archived' : '',
1494
			'ticketrow' => $skeleton ? 'TICKETNUM' : $row,
1495
			'TKT_ID' => $ticket->get('TKT_ID'),
1496
			'TKT_name' => $ticket->get('TKT_name'),
1497
			'TKT_start_date' => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1498
			'TKT_end_date' => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1499
			'TKT_is_default' => $ticket->get('TKT_is_default'),
1500
			'TKT_qty' => $ticket->get_pretty('TKT_qty','input'),
1501
			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1502
			'TKT_sold' => $skeleton ? 0 : $ticket->get('TKT_sold'),
1503
			'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',
1504
			'disabled' => $skeleton || ( !empty( $ticket ) && ! $ticket->get('TKT_deleted' ) ) ? '' : ' disabled=disabled'
1505
			);
1506
1507
		$price = $ticket->ID() !== 0 ? $ticket->get_first_related('Price', array('default_where_conditions' => 'none')) : EE_Registry::instance()->load_model('Price')->create_default_object();
0 ignored issues
show
Bug introduced by
The method create_default_object cannot be called on \EE_Registry::instance()->load_model('Price') (of type boolean).

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

Loading history...
1508
1509
1510
		$price_args = array(
1511
			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1512
			'PRC_amount' => $price->get('PRC_amount'),
1513
			'PRT_ID' => $price->get('PRT_ID'),
1514
			'PRC_ID' => $price->get('PRC_ID'),
1515
			'PRC_is_default' => $price->get('PRC_is_default'),
1516
			);
1517
1518
		//make sure we have default start and end dates if skeleton
1519
		//handle rows that should NOT be empty
1520
		if ( empty( $template_args['TKT_start_date'] ) ) {
1521
			//if empty then the start date will be now.
1522
			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1523
		}
1524
1525
		if ( empty( $template_args['TKT_end_date'] ) ) {
1526
			//get the earliest datetime (if present);
1527
			$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;
1528
1529
			if ( !empty( $earliest_dtt ) )
1530
				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1531
			else
1532
				$template_args['TKT_end_date'] = date('Y-m-d h:i a', mktime(0, 0, 0, date("m"), date("d")+7, date("Y") ) );
1533
		}
1534
1535
		$template_args = array_merge( $template_args, $price_args );
1536
		$template = apply_filters( 'FHEE__Events_Admin_Page__get_ticket_row__template', EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php', $ticket);
1537
		return EEH_Template::display_template($template, $template_args, TRUE);
1538
	}
1539
1540
1541
1542
	public function registration_options_meta_box() {
1543
1544
		$yes_no_values = array(
1545
			array('id' => true, 'text' => __('Yes', 'event_espresso')),
1546
			array('id' => false, 'text' => __('No', 'event_espresso'))
1547
		);
1548
1549
		$default_reg_status_values = EEM_Registration::reg_status_array(
1550
			array(
1551
				EEM_Registration::status_id_cancelled,
1552
				EEM_Registration::status_id_declined,
1553
				EEM_Registration::status_id_incomplete
1554
			),
1555
			TRUE
1556
		);
1557
1558
		//$template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1559
		$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...
1560
		$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...
1561
		$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...
1562
		$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...
1563
		$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...
1564
		$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...
1565
		$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 );
1566
		$templatepath = EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php';
1567
		EEH_Template::display_template($templatepath, $template_args);
1568
	}
1569
1570
1571
1572
	/** end metaboxes * */
1573
	/*	 * **************** *
1574
1575
1576
1577
1578
	/**
1579
	 * _get_events()
1580
	 * This method simply returns all the events (for the given _view and paging)
1581
	 *
1582
	 * @access public
1583
	 *
1584
	 * @param int $per_page count of items per page (20 default);
1585
	 * @param int $current_page what is the current page being viewed.
1586
	 * @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.
1587
	 * @return array an array of event objects.
1588
	 */
1589
	public function get_events($per_page = 10, $current_page = 1, $count = FALSE) {
1590
1591
		$EEME = $this->_event_model();
1592
1593
		$offset = ($current_page - 1) * $per_page;
1594
		$limit = $count ? NULL : $offset . ',' . $per_page;
1595
		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1596
		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1597
1598
		if (isset($this->_req_data['month_range'])) {
1599
			$pieces = explode(' ', $this->_req_data['month_range'], 3);
1600
			$month_r = !empty($pieces[0]) ? date('m', strtotime($pieces[0])) : '';
1601
			$year_r = !empty($pieces[1]) ? $pieces[1] : '';
1602
		}
1603
1604
		$where = array();
1605
1606
		$status = isset( $this->_req_data['status'] ) ? $this->_req_data['status'] : NULL;
1607
		//determine what post_status our condition will have for the query.
1608
		switch ( $status ) {
1609
			case 'month' :
1610
			case 'today' :
1611
			case NULL :
1612
			case 'all' :
1613
				break;
1614
1615
			case 'draft' :
1616
				$where['status'] = array( 'IN', array('draft', 'auto-draft') );
1617
				break;
1618
1619
			default :
1620
				$where['status'] = $status;
1621
		}
1622
1623
		//categories?
1624
		$category = isset( $this->_req_data['EVT_CAT'] ) && $this->_req_data['EVT_CAT'] > 0 ? $this->_req_data['EVT_CAT'] : NULL;
1625
1626
		if ( !empty ( $category ) ) {
1627
			$where['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1628
			$where['Term_Taxonomy.term_id'] = $category;
1629
		}
1630
1631
		//date where conditions
1632
		$start_formats = EEM_Datetime::instance()->get_formats_for( 'DTT_EVT_start' );
1633
		if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1634
			$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...
1635
			$start = $DateTime->format( implode( ' ', $start_formats  ) );
1636
			$end = $DateTime->setDate( $year_r, $month_r, $DateTime->format('t') )->setTime(23,59,59)->format( implode( ' ', $start_formats ) );
1637
			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array( $start, $end ) );
1638
		} else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1639
			$DateTime = new DateTime( 'now', new DateTimeZone( EEM_Event::instance()->get_timezone() ) );
1640
			$start = $DateTime->setTime( 0,0,0 )->format( implode( ' ', $start_formats ) );
1641
			$end = $DateTime->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1642
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1643
		} else if ( isset($this->_req_data['status']) && $this->_req_data['status'] == 'month' ) {
1644
			$now = date( 'Y-m-01' );
1645
			$DateTime = new DateTime( $now, new DateTimeZone( EEM_Event::instance()->get_timezone() ) );
1646
			$start = $DateTime->setTime( 0, 0, 0 )->format( implode( ' ', $start_formats ) );
1647
			$end = $DateTime->setDate( date('Y'), date('m'), $DateTime->format('t' ) )->setTime( 23, 59, 59 )->format( implode( ' ', $start_formats ) );
1648
			$where['Datetime.DTT_EVT_start'] = array( 'BETWEEN', array( $start, $end ) );
1649
		}
1650
1651
1652 View Code Duplication
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1653
			$where['EVT_wp_user'] =  get_current_user_id();
1654
		} else {
1655
			if ( ! isset( $where['status'] ) ) {
1656
				if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_private_events', 'get_events' ) ) {
1657
					$where['OR'] = array(
1658
						'status*restrict_private' => array( '!=', 'private' ),
1659
						'AND' => array(
1660
							'status*inclusive' => array( '=', 'private' ),
1661
							'EVT_wp_user' => get_current_user_id()
1662
						)
1663
					);
1664
				}
1665
			}
1666
		}
1667
1668
		if ( isset( $this->_req_data['EVT_wp_user'] ) ) {
1669
			if ( $this->_req_data['EVT_wp_user'] != get_current_user_id() && EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_events', 'get_events' ) ) {
1670
				$where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1671
			}
1672
		}
1673
1674
1675
		//search query handling
1676
		if ( isset( $this->_req_data['s'] ) ) {
1677
			$search_string = '%' . $this->_req_data['s'] . '%';
1678
			$where['OR'] = array(
1679
				'EVT_name' => array('LIKE', $search_string),
1680
				'EVT_desc' => array('LIKE', $search_string),
1681
				'EVT_short_desc' => array('LIKE', $search_string)
1682
				);
1683
		}
1684
1685
1686
		$where = apply_filters( 'FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data );
1687
		$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 );
1688
1689
1690
		//let's first check if we have special requests coming in.
1691
		if ( isset( $this->_req_data['active_status'] ) ) {
1692
			switch ( $this->_req_data['active_status'] ) {
1693
				case 'upcoming' :
1694
					return $EEME->get_upcoming_events( $query_params, $count );
1695
					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...
1696
1697
				case 'expired' :
1698
					return $EEME->get_expired_events( $query_params, $count );
1699
					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...
1700
1701
				case 'active' :
1702
					return $EEME->get_active_events( $query_params, $count );
1703
					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...
1704
1705
				case 'inactive' :
1706
					return $EEME->get_inactive_events( $query_params, $count );
1707
					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...
1708
			}
1709
		}
1710
1711
		$events = $count ? $EEME->count( array( $where ), 'EVT_ID', true ) : $EEME->get_all( $query_params );
1712
1713
		return $events;
1714
	}
1715
1716
1717
1718
1719
	//handling for WordPress CPT actions (trash, restore, delete)
1720
	public function trash_cpt_item( $post_id ) {
1721
		$this->_req_data['EVT_ID'] = $post_id;
1722
		$this->_trash_or_restore_event( 'trash', FALSE );
1723
	}
1724
1725
1726
1727
1728
	public function restore_cpt_item( $post_id ) {
1729
		$this->_req_data['EVT_ID'] = $post_id;
1730
		$this->_trash_or_restore_event( 'draft', FALSE );
1731
	}
1732
1733
1734
	public function delete_cpt_item( $post_id ) {
1735
		$this->_req_data['EVT_ID'] = $post_id;
1736
		$this->_delete_event( FALSE );
1737
	}
1738
1739
1740
1741
	/**
1742
	 * _trash_or_restore_event
1743
	 *
1744
	 * @access protected
1745
	 * @param  string $event_status
1746
	 * @return void
1747
	 */
1748 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...
1749
		//determine the event id and set to array.
1750
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : FALSE;
1751
		// loop thru events
1752
		if ($EVT_ID) {
1753
			// clean status
1754
			$event_status = sanitize_key($event_status);
1755
			// grab status
1756
			if (!empty($event_status)) {
1757
				$success = $this->_change_event_status($EVT_ID, $event_status);
1758
			} else {
1759
				$success = FALSE;
1760
				$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1761
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1762
			}
1763
		} else {
1764
			$success = FALSE;
1765
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.', 'event_espresso');
1766
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1767
		}
1768
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1769
1770
		if ( $redirect_after )
1771
			$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 false|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...
1772
	}
1773
1774
	/**
1775
	 * _trash_or_restore_events
1776
	 *
1777
	 * @access protected
1778
	 * @param  string $event_status
1779
	 * @return void
1780
	 */
1781 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...
1782
		// clean status
1783
		$event_status = sanitize_key($event_status);
1784
		// grab status
1785
		if (!empty($event_status)) {
1786
			$success = TRUE;
1787
			//determine the event id and set to array.
1788
			$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1789
			// loop thru events
1790
			foreach ($EVT_IDs as $EVT_ID) {
1791
				if ($EVT_ID = absint($EVT_ID)) {
1792
					$results = $this->_change_event_status($EVT_ID, $event_status);
1793
					$success = $results !== FALSE ? $success : FALSE;
1794
				} else {
1795
					$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);
1796
					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1797
					$success = FALSE;
1798
				}
1799
			}
1800
		} else {
1801
			$success = FALSE;
1802
			$msg = __('An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.', 'event_espresso');
1803
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1804
		}
1805
		// in order to force a pluralized result message we need to send back a success status greater than 1
1806
		$success = $success ? 2 : FALSE;
1807
		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1808
1809
		$this->_redirect_after_action($success, 'Events', $action, array('action' => 'default'));
1810
	}
1811
1812
	/**
1813
	 * _trash_or_restore_events
1814
	 *
1815
	 * @access  private
1816
	 * @param  int $EVT_ID
1817
	 * @param  string $event_status
1818
	 * @return bool
1819
	 */
1820 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...
1821
		// grab event id
1822
		if (!$EVT_ID) {
1823
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1824
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1825
			return FALSE;
1826
		}
1827
1828
		$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...
1829
1830
		// clean status
1831
		$event_status = sanitize_key($event_status);
1832
		// grab status
1833
		if (empty($event_status)) {
1834
			$msg = __('An error occurred. No Event Status or an invalid Event Status was received.', 'event_espresso');
1835
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1836
			return FALSE;
1837
		}
1838
1839
		// was event trashed or restored ?
1840
		switch ($event_status) {
1841
			case 'draft' :
1842
				$action = 'restored from the trash';
1843
				$hook = 'AHEE_event_restored_from_trash';
1844
				break;
1845
			case 'trash' :
1846
				$action = 'moved to the trash';
1847
				$hook = 'AHEE_event_moved_to_trash';
1848
				break;
1849
			default :
1850
				$action = 'updated';
1851
				$hook = FALSE;
1852
		}
1853
		//use class to change status
1854
		$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...
1855
		$success = $this->_cpt_model_obj->save();
1856
1857
		if ($success === FALSE) {
1858
			$msg = sprintf(__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
1859
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1860
			return FALSE;
1861
		}
1862
		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...
1863
			do_action($hook);
1864
		}
1865
		return TRUE;
1866
	}
1867
1868
1869
1870
	/**
1871
	 * _delete_event
1872
	 *
1873
	 * @access protected
1874
	 * @param bool $redirect_after
1875
	 */
1876
	protected function _delete_event( $redirect_after = TRUE ) {
1877
		//determine the event id and set to array.
1878
		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : NULL;
1879
		$EVT_ID = isset( $this->_req_data['post'] ) ? absint( $this->_req_data['post'] ) : $EVT_ID;
1880
1881
1882
		// loop thru events
1883
		if ($EVT_ID) {
1884
			$success = $this->_permanently_delete_event( $EVT_ID );
1885
			// get list of events with no prices
1886
			$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1887
			// remove this event from the list of events with no prices
1888
			if (isset($espresso_no_ticket_prices[$EVT_ID])) {
1889
				unset($espresso_no_ticket_prices[$EVT_ID]);
1890
			}
1891
			update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1892
		} else {
1893
			$success = FALSE;
1894
			$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1895
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1896
		}
1897
1898
		if ( $redirect_after )
1899
			$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 false|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...
1900
	}
1901
1902
	/**
1903
	 * _delete_events
1904
	 *
1905
	 * @access protected
1906
	 * @return void
1907
	 */
1908
	protected function _delete_events() {
1909
		$success = TRUE;
1910
		// get list of events with no prices
1911
		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
1912
		//determine the event id and set to array.
1913
		$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1914
		// loop thru events
1915
		foreach ($EVT_IDs as $EVT_ID) {
1916
			$EVT_ID = absint( $EVT_ID );
1917
			if ( $EVT_ID ) {
1918
				$results = $this->_permanently_delete_event( $EVT_ID );
1919
				$success = $results !== FALSE ? $success : FALSE;
1920
				// remove this event from the list of events with no prices
1921
				unset( $espresso_no_ticket_prices[ $EVT_ID ] );
1922
			} else {
1923
				$success = FALSE;
1924
				$msg = __('An error occurred. An event could not be deleted because a valid event ID was not not supplied.', 'event_espresso');
1925
				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1926
			}
1927
		}
1928
		update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
1929
		// in order to force a pluralized result message we need to send back a success status greater than 1
1930
		$success = $success ? 2 : FALSE;
1931
		$this->_redirect_after_action($success, 'Events', 'deleted', array('action' => 'default'));
1932
	}
1933
1934
	/**
1935
	 * _permanently_delete_event
1936
	 *
1937
	 * @access  private
1938
	 * @param  int $EVT_ID
1939
	 * @return bool
1940
	 */
1941
	private function _permanently_delete_event( $EVT_ID = 0 ) {
1942
		// grab event id
1943
		if ( ! $EVT_ID ) {
1944
			$msg = __('An error occurred. No Event ID or an invalid Event ID was received.', 'event_espresso');
1945
			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1946
			return FALSE;
1947
		}
1948
		$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...
1949
1950
		//need to delete related tickets and prices first.
1951
		$datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
1952
		foreach ( $datetimes as $datetime ) {
1953
			$this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
1954
			$tickets = $datetime->get_many_related('Ticket');
1955
			foreach ( $tickets as $ticket ) {
1956
				$ticket->_remove_relation_to($datetime, 'Datetime');
1957
				$ticket->delete_related_permanently('Price');
1958
				$ticket->delete_permanently();
1959
			}
1960
			$datetime->delete();
1961
		}
1962
1963
		//what about related venues or terms?
1964
		$venues = $this->_cpt_model_obj->get_many_related('Venue');
1965
		foreach ( $venues as $venue ) {
1966
			$this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
1967
		}
1968
1969
		//any attached question groups?
1970
		$question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
1971
		if ( !empty( $question_groups ) ) {
1972
			foreach ( $question_groups as $question_group ) {
1973
				$this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
1974
			}
1975
		}
1976
1977
1978
1979
1980
		//Message Template Groups
1981
		$this->_cpt_model_obj->_remove_relations( 'Message_Template_Group' );
1982
1983
		/** @type EE_Term_Taxonomy[] $term_taxonomies */
1984
		$term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
0 ignored issues
show
Documentation Bug introduced by
The method term_taxonomies does not exist on object<EE_Base_Class>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1985
1986
		foreach ( $term_taxonomies as $term_taxonomy ) {
1987
			$this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
0 ignored issues
show
Documentation Bug introduced by
The method remove_relation_to_term_taxonomy does not exist on object<EE_Base_Class>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

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