Completed
Branch TASK-9118-extensions-page (04eaec)
by
unknown
856:31 queued 840:33
created

EEM_Event   F

Complexity

Total Complexity 71

Size/Duplication

Total Lines 660
Duplicated Lines 17.27 %

Coupling/Cohesion

Components 2
Dependencies 29

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 114
loc 660
rs 1.1478
wmc 71
lcom 2
cbo 29

16 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 87 2
A instance() 12 12 2
A set_default_reg_status() 0 10 2
A get_all_question_groups() 0 6 1
A get_all_event_question_groups() 9 9 3
A get_event_question_groups() 9 9 3
A get_question_groups_for_event() 0 19 4
A get_questions_in_groups() 17 17 2
A get_options_for_question() 16 16 2
A _generate_question_input_name() 0 54 2
C get_active_events() 16 31 7
B get_upcoming_events() 11 25 6
D get_expired_events() 12 51 10
D get_inactive_events() 12 35 9
A add_relationship_to() 0 18 3
C assemble_array_of_groups_questions_and_options() 0 48 13

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

1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
2
require_once( EE_MODELS . 'EEM_CPT_Base.model.php');
3
/**
4
 *
5
 * EEM_Event Model
6
 *
7
 * extends EEM_CPT_Base which extends EEM_Base
8
 *
9
 * @package			Event Espresso
10
 * @subpackage		includes/models/
11
 * @author				Michael Nelson, Brent Christensen
12
 *
13
 */
14
class EEM_Event  extends EEM_CPT_Base{
15
16
	/**
17
	 * constant used by status(), indicating that no more tickets can be purchased for any of the datetimes for the event
18
	 */
19
	const sold_out = 'sold_out';
20
21
	/**
22
	 * constant used by status(), indicating that upcoming event dates have been postponed (may be pushed to a later date)
23
	 */
24
	const postponed = 'postponed';
25
26
	/**
27
	 * constant used by status(), indicating that the event will no longer occur
28
	 */
29
	const cancelled = 'cancelled';
30
31
32
33
	/**
34
	 * @var string
35
	 */
36
	protected static $_default_reg_status = NULL;
37
38
39
	/**
40
	 * private instance of the Event object
41
	 * @var EEM_Event
42
	 */
43
	protected static $_instance = NULL;
44
45
46
47
	/**
48
	 *        This function is a singleton method used to instantiate the EEM_Event object
49
	 *
50
	 * @access public
51
	 * @param string $timezone
52
	 * @return EEM_Event
53
	 */
54 View Code Duplication
	public static function instance( $timezone = NULL ){
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...
55
56
		// check if instance of EEM_Event already exists
57
		if ( ! self::$_instance instanceof EEM_Event ) {
58
			// instantiate Espresso_model
59
			self::$_instance = new self( $timezone );
60
		}
61
		//we might have a timezone set, let set_timezone decide what to do with it
62
		self::$_instance->set_timezone( $timezone );
63
		// EEM_Event object
64
		return self::$_instance;
65
	}
66
67
68
	/**
69
	 * Adds a relationship to Term_Taxonomy for each CPT_Base
70
	 * @param string $timezone
71
	 * @return EEM_Event
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
72
	 */
73
	protected function __construct($timezone = null){
74
75
		EE_Registry::instance()->load_model( 'Registration' );
76
77
		$this->singular_item = __('Event','event_espresso');
78
		$this->plural_item = __('Events','event_espresso');
79
80
		// to remove Cancelled events from the frontend, copy the following filter to your functions.php file
81
		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
82
		// to remove Postponed events from the frontend, copy the following filter to your functions.php file
83
		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
84
		// to remove Sold Out events from the frontend, copy the following filter to your functions.php file
85
		//	add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
86
87
		$this->_custom_stati = apply_filters(
88
			'AFEE__EEM_Event__construct___custom_stati',
89
			array(
90
				EEM_Event::cancelled => array(
91
					'label' => __('Cancelled', 'event_espresso'),
92
					'public' => apply_filters( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', TRUE )
93
				),
94
				EEM_Event::postponed => array(
95
					'label' => __('Postponed', 'event_espresso'),
96
					'public' => apply_filters( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', TRUE )
97
				),
98
				EEM_Event::sold_out => array(
99
					'label' => __('Sold Out', 'event_espresso'),
100
					'public' => apply_filters( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', TRUE )
101
				)
102
			)
103
		);
104
105
		self::$_default_reg_status = empty( self::$_default_reg_status ) ? EEM_Registration::status_id_pending_payment : self::$_default_reg_status;
106
107
		$this->_tables = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Event_CPT' => new..., 'EVTM_ID', 'EVT_ID')) of type array<string,object<EE_P...<EE_Secondary_Table>"}> is incompatible with the declared type array<integer,object<EE_Table_Base>> of property $_tables.

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...
108
			'Event_CPT'=>new EE_Primary_Table( 'posts','ID' ),
109
			'Event_Meta'=> new EE_Secondary_Table( 'esp_event_meta', 'EVTM_ID', 'EVT_ID' )
110
		);
111
112
		$this->_fields = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Event_CPT' => arr...esso'), FALSE, FALSE))) of type array<string,array<strin...E_Boolean_Field>\"}>"}> is incompatible with the declared type array<integer,object<EE_Model_Field_Base>> of property $_fields.

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...
113
			'Event_CPT'=>array(
114
				'EVT_ID'=>new EE_Primary_Key_Int_Field( 'ID', __( 'Post ID for Event','event_espresso' )),
115
				'EVT_name'=>new EE_Plain_Text_Field( 'post_title', __( 'Event Name','event_espresso' ), FALSE, '' ),
116
				'EVT_desc'=>new EE_Post_Content_Field( 'post_content', __( 'Event Description', 'event_espresso' ), FALSE, '' ),
117
				'EVT_slug'=>new EE_Slug_Field( 'post_name', __( 'Event Slug', 'event_espresso' ), FALSE, '' ),
118
				'EVT_created'=>new EE_Datetime_Field( 'post_date', __( 'Date/Time Event Created', 'event_espresso' ), FALSE, time()),
119
				'EVT_short_desc'=>new EE_Simple_HTML_Field( 'post_excerpt', __( 'Event Short Description', 'event_espresso' ), FALSE,'' ),
120
				'EVT_modified'=>new EE_Datetime_Field( 'post_modified', __( 'Date/Time Event Modified', 'event_espresso' ), FALSE, time()),
121
				'EVT_wp_user'=>new EE_WP_User_Field( 'post_author', __( 'Event Creator ID', 'event_espresso'), FALSE),
122
				'parent'=>new EE_Integer_Field( 'post_parent', __( 'Event Parent ID', 'event_espresso' ), FALSE, 0 ),
123
				'EVT_order'=>new EE_Integer_Field( 'menu_order', __( 'Event Menu Order', 'event_espresso' ), FALSE, 1 ),
124
				'post_type'=>new EE_WP_Post_Type_Field('espresso_events'),// EE_Plain_Text_Field( 'post_type', __( 'Event Post Type', 'event_espresso' ), FALSE, 'espresso_events' ),
125
				'status' => new EE_WP_Post_Status_Field( 'post_status', __( 'Event Status', 'event_espresso' ), FALSE, 'draft', $this->_custom_stati )
126
			),
127
			'Event_Meta'=>array(
128
				'EVTM_ID'=> new EE_DB_Only_Float_Field( 'EVTM_ID', __( 'Event Meta Row ID','event_espresso' ), FALSE ),
129
				'EVT_ID_fk'=>new EE_DB_Only_Int_Field( 'EVT_ID', __( 'Foreign key to Event ID from Event Meta table', 'event_espresso' ), FALSE ),
130
				'EVT_display_desc'=>new EE_Boolean_Field( 'EVT_display_desc', __( 'Display Description Flag', 'event_espresso' ), FALSE, 1 ),
131
				'EVT_display_ticket_selector'=>new EE_Boolean_Field( 'EVT_display_ticket_selector', __( 'Display Ticket Selector Flag', 'event_espresso' ), FALSE, 1 ),
132
				'EVT_visible_on'=>new EE_Datetime_Field( 'EVT_visible_on', __( 'Event Visible Date', 'event_espresso' ), TRUE, time()),
133
				'EVT_additional_limit'=>new EE_Integer_Field( 'EVT_additional_limit', __( 'Limit of Additional Registrations on Same Transaction', 'event_espresso' ), TRUE, 10 ),
134
				'EVT_default_registration_status'=>new EE_Enum_Text_Field(
135
					'EVT_default_registration_status', __( 'Default Registration Status on this Event', 'event_espresso' ), FALSE, EEM_Event::$_default_reg_status, EEM_Registration::reg_status_array()
136
				),
137
				'EVT_member_only'=>new EE_Boolean_Field( 'EVT_member_only', __( 'Member-Only Event Flag', 'event_espresso' ), FALSE, FALSE ),
138
				'EVT_phone'=> new EE_Plain_Text_Field('EVT_phone', __( 'Event Phone Number', 'event_espresso' ), FALSE ),
139
				'EVT_allow_overflow'=>new EE_Boolean_Field(  'EVT_allow_overflow', __( 'Allow Overflow on Event', 'event_espresso' ), FALSE, FALSE ),
140
				'EVT_timezone_string'=>new EE_Plain_Text_Field( 'EVT_timezone_string', __( 'Timezone (name) for Event times', 'event_espresso' ), FALSE ),
141
				'EVT_external_URL'=>new EE_Plain_Text_Field( 'EVT_external_URL', __( 'URL of Event Page if hosted elsewhere', 'event_espresso' ), TRUE ),
142
				'EVT_donations'=>new EE_Boolean_Field( 'EVT_donations', __( 'Accept Donations?', 'event_espresso' ), FALSE, FALSE )
143
144
			));
145
146
		$this->_model_relations = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Registration' => ..._Belongs_To_Relation()) of type array<string,object<EE_H...Belongs_To_Relation>"}> is incompatible with the declared type array<integer,object<EE_Model_Relation_Base>> of property $_model_relations.

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...
147
			'Registration'=>new EE_Has_Many_Relation(),
148
			'Datetime'=>new EE_Has_Many_Relation(),
149
			'Question_Group'=>new EE_HABTM_Relation('Event_Question_Group'),
150
			'Venue'=>new EE_HABTM_Relation('Event_Venue'),
151
			'Term_Taxonomy'=>new EE_HABTM_Relation('Term_Relationship'),
152
			'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'),
153
			'Attendee'=>new EE_HABTM_Relation('Registration'),
154
			'WP_User' => new EE_Belongs_To_Relation(),
155
		);
156
		//this model is generally available for reading
157
		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
158
		parent::__construct( $timezone );
159
	}
160
161
162
163
	/**
164
	 * @param string $default_reg_status
165
	 */
166
	public static function set_default_reg_status( $default_reg_status ) {
167
		self::$_default_reg_status = $default_reg_status;
168
		//if EEM_Event has already been instantiated, then we need to reset the `EVT_default_reg_status` field to use the new default.
169
		if ( self::$_instance instanceof EEM_Event ) {
170
			self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = new EE_Enum_Text_Field(
171
				'EVT_default_registration_status', __( 'Default Registration Status on this Event', 'event_espresso' ), false, $default_reg_status, EEM_Registration::reg_status_array()
172
			);
173
			self::$_instance->_fields['Event_Meta']['EVT_default_registration_status']->_construct_finalize( 'Event_Meta', 'EVT_default_registration_status', 'EEM_Event' );
174
		}
175
	}
176
177
178
179
	/**
180
	*		get_question_groups
181
	*
182
	* 		@access		public
183
	*		@return 		array
184
	*/
185
	public function get_all_question_groups() {
186
		return EE_Registry::instance()->load_model( 'Question_Group' )->get_all( array(
0 ignored issues
show
Bug introduced by
The method get_all cannot be called on \EE_Registry::instance()...model('Question_Group') (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...
187
			array( 'QSG_deleted' => FALSE ),
188
			'order_by' => array( 'QSG_order' => 'ASC' )
189
		));
190
	}
191
192
193
194
195
196
197
	/**
198
	*		get_question_groups
199
	*
200
	* 		@access		public
201
	* 		@param		int $EVT_ID
202
	*		@return 		array
203
	*/
204 View Code Duplication
	public function get_all_event_question_groups( $EVT_ID = 0 ) {
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...
205
		if ( ! isset( $EVT_ID) || ! absint( $EVT_ID )) {
206
			EE_Error::add_error( __( 'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
207
			return FALSE;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by EEM_Event::get_all_event_question_groups of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
208
		}
209
		return EE_Registry::instance()->load_model( 'Event_Question_Group' )->get_all( array(
0 ignored issues
show
Bug introduced by
The method get_all cannot be called on \EE_Registry::instance()...'Event_Question_Group') (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...
210
			array( 'EVT_ID' => $EVT_ID )
211
		));
212
	}
213
214
215
216
217
218
	/**
219
	*		get_question_groups
220
	*
221
	* 		@access		public
222
	* 		@param		int $EVT_ID
223
	* 		@param		boolean	$for_primary_attendee
224
	*		@return 		array
225
	*/
226 View Code Duplication
	public function get_event_question_groups( $EVT_ID = 0, $for_primary_attendee = 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...
227
		if ( ! isset( $EVT_ID) || ! absint( $EVT_ID )) {
228
			EE_Error::add_error( __( 'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
229
			return FALSE;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by EEM_Event::get_event_question_groups of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
230
		}
231
		return EE_Registry::instance()->load_model( 'Event_Question_Group' )->get_all( array(
0 ignored issues
show
Bug introduced by
The method get_all cannot be called on \EE_Registry::instance()...'Event_Question_Group') (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...
232
			array( 'EVT_ID' => $EVT_ID, 'EQG_primary' => $for_primary_attendee )
233
		));
234
	}
235
236
237
238
239
240
241
	/**
242
	*		get_question_groups
243
	*
244
	* 		@access		public
245
	* 		@param		int $EVT_ID
246
	* 		@param		EE_Registration 	$registration
247
	*		@return 		array
248
	*/
249
	public function get_question_groups_for_event( $EVT_ID = 0, EE_Registration $registration ) {
250
251
		if ( ! isset( $EVT_ID) || ! absint( $EVT_ID )) {
252
			EE_Error::add_error( __( 'An error occurred. No Question Groups could be retrieved because an Event ID was not received.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
253
			return FALSE;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by EEM_Event::get_question_groups_for_event of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
254
		}
255
256
		$where_params = array(
257
			'Event_Question_Group.EVT_ID' => $EVT_ID,
258
			'Event_Question_Group.EQG_primary' => $registration->count() == 1 ? TRUE : FALSE,
259
			'QSG_deleted' => FALSE
260
		);
261
262
		return EE_Registry::instance()->load_model( 'Question_Group' )->get_all( array(
0 ignored issues
show
Bug introduced by
The method get_all cannot be called on \EE_Registry::instance()...model('Question_Group') (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...
263
			$where_params,
264
			'order_by' => array('QSG_order' => 'ASC')
265
		));
266
267
	}
268
269
270
271
272
273
274
275
	/**
276
	*		get_question_target_db_column
277
	*
278
	* 		@access		public
279
	* 		@param		string		$QSG_IDs  csv list of $QSG IDs
280
	*		@return 		array
281
	*/
282 View Code Duplication
	public function get_questions_in_groups( $QSG_IDs = '' ) {
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...
283
284
		if ( empty( $QSG_IDs )) {
285
			EE_Error::add_error( __( 'An error occurred. No Question Group IDs were received.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
286
			return FALSE;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by EEM_Event::get_questions_in_groups of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
287
		}
288
289
		return EE_Registry::instance()->load_model( 'Question' )->get_all( array(
0 ignored issues
show
Bug introduced by
The method get_all cannot be called on \EE_Registry::instance()->load_model('Question') (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...
290
			array(
291
				'Question_Group.QSG_ID' => array( 'IN', $QSG_IDs ),
292
				'QST_deleted' => FALSE,
293
				'QST_admin_only' => is_admin()
294
			),
295
			'order_by' => 'QST_order'
296
		));
297
298
	}
299
300
301
302
303
304
305
306
	/**
307
	*		get_options_for_question
308
	*
309
	* 		@access		public
310
	* 		@param		string		$QST_IDs  csv list of $QST IDs
311
	*		@return 		array
312
	*/
313 View Code Duplication
	public function get_options_for_question( $QST_IDs ) {
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...
314
315
		if ( empty( $QST_IDs )) {
316
			EE_Error::add_error( __( 'An error occurred. No Question IDs were received.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
317
			return FALSE;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by EEM_Event::get_options_for_question of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
318
		}
319
320
		return EE_Registry::instance()->load_model( 'Question_Option' )->get_all( array(
0 ignored issues
show
Bug introduced by
The method get_all cannot be called on \EE_Registry::instance()...odel('Question_Option') (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...
321
			array(
322
				'Question.QST_ID' => array( 'IN', $QST_IDs ),
323
				'QSO_deleted' => FALSE
324
			),
325
			'order_by' => 'QSO_ID'
326
		));
327
328
	}
329
330
331
332
	/**
333
	 *        _get_question_target_db_column
334
	 *
335
	 * @access 	public
336
	 * @param 	EE_Registration $registration (so existing answers for registration are included)
337
	 * @param 	int 	$EVT_ID 	so all question groups are included for event (not just answers from registration).
338
	 * @throws EE_Error
339
	 * @return 	array
340
	 */
341
	public function assemble_array_of_groups_questions_and_options( EE_Registration $registration, $EVT_ID = 0 ) {
342
343
		if ( empty( $EVT_ID ) ) {
344
			throw new EE_Error( __( 'An error occurred. No EVT_ID is included.  Needed to know which question groups to retrieve.', 'event_espresso' ) );
345
		}
346
347
		$questions = array();
348
349
		// get all question groups for event
350
		$qgs = $this->get_question_groups_for_event( $EVT_ID, $registration );
351
		if ( !empty( $qgs ) ) {
352
			foreach ( $qgs as $qg ) {
353
			 	$qsts = $qg->questions();
354
			 	$questions[ $qg->ID() ] = $qg->model_field_array();
355
			 	$questions[ $qg->ID() ]['QSG_questions'] = array();
356
			 	foreach ( $qsts as $qst ) {
357
			 		if ( $qst->is_system_question() )
358
			 			continue;
359
			 		$answer = EEM_Answer::instance()->get_one( array( array( 'QST_ID' => $qst->ID(), 'REG_ID' => $registration->ID() ) ) );
360
			 		$answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
361
			 		$qst_name = $qstn_id = $qst->ID();
362
			 		$ans_id = $answer->ID();
363
			 		$qst_name = !empty( $ans_id ) ?  '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
364
			 		$input_name = '';
365
			 		$input_id = sanitize_key( $qst->display_text() );
366
			 		$input_class = '';
367
			 		$questions[$qg->ID()]['QSG_questions'][$qst->ID()] = $qst->model_field_array();
368
		 			$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_name'] = 'qstn' . $input_name . $qst_name;
369
					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_id'] = $input_id . '-' . $qstn_id;
370
					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_class'] = $input_class;
371
					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'] = array();
372
					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['qst_obj'] = $qst;
373
					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['ans_obj'] = $answer;
374
375
					if ( $qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN' ) {
376
						$QSOs = $qst->options(TRUE,$answer->value());
377
						if ( is_array( $QSOs ) ) {
378
							foreach ( $QSOs as $QSO_ID => $QSO ) {
379
								$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'][ $QSO_ID ] = $QSO->model_field_array();
380
							}
381
						}
382
					}
383
384
			 	}
385
			}
386
		}
387
		return $questions;
388
	}
389
390
391
392
393
394
395
396
	/**
397
	*		_get_question_target_db_column
398
	*
399
	* 		@access		private
400
	* 		@param		$QST
401
	*		@return 		string		string
402
	*/
403
	private function _generate_question_input_name( $QST ) {
404
405
		if ( $QST->QST_system ) {
406
			$qst_name = $QST->QST_system;
407
/*			switch( $QST->QST_system ) {
408
409
				case 1 :
410
						$qst_name = $QST->QST_ID . '-fname';
411
					break;
412
413
				case 2 :
414
						$qst_name = $QST->QST_ID . '-lname';
415
					break;
416
417
				case 3 :
418
						$qst_name = $QST->QST_ID . '-email';
419
					break;
420
421
				case 4 :
422
						$qst_name = $QST->QST_ID . '-address';
423
					break;
424
425
				case 5 :
426
						$qst_name = $QST->QST_ID . '-address2';
427
					break;
428
429
				case  6  :
430
						$qst_name = $QST->QST_ID . '-city';
431
					break;
432
433
				case 7 :
434
						$qst_name = $QST->QST_ID . '-state';
435
					break;
436
437
				case 8 :
438
						$qst_name = $QST->QST_ID . '-zip';
439
					break;
440
441
				case 9 :
442
						$qst_name = $QST->QST_ID . '-country';
443
					break;
444
445
				case 10 :
446
						$qst_name = $QST->QST_ID . '-phone-' . $QST->QST_ID;
447
					break;
448
449
			}*/
450
451
		} else {
452
			//$qst_name = $QST->QST_ID . '-' . str_replace( array( ' ', '-', '.' ), '_', strtolower( $QST->QST_display_text ));
453
			$qst_name = $QST->QST_ID;
454
		}
455
		return $qst_name;
456
	}
457
458
459
460
461
462
463
464
	/**
465
	 * Gets all events that are published and have event start time earlier than now and an event end time later than now
466
	 *
467
	 * @access public
468
	 * @param  array  $query_params An array of query params to further filter on (note that status and DTT_EVT_start and DTT_EVT_end will be overridden)
469
	 * @param bool    $count whether to return the count or not (default FALSE)
470
	 * @return array 	EE_Event objects
471
	 */
472
	public function get_active_events( $query_params, $count = FALSE ) {
473 View Code Duplication
		if ( array_key_exists( 0, $query_params ) ) {
474
			$where_params = $query_params[0];
475
			unset( $query_params[0] );
476
		} else {
477
			$where_params = array();
478
		}
479
480
		//if we have count make sure we don't include group by
481
		if ( $count && isset( $query_params['group_by'] ) ) {
482
			unset( $query_params['group_by'] );
483
		}
484
485
		//let's add specific query_params for active_events - keep in mind this will override any sent status in the query AND any date queries.
486
		$where_params['status'] = 'publish';
487
		//if already have where params for DTT_EVT_start or DTT_EVT_end then append these conditions
488 View Code Duplication
		if ( isset( $where_params['Datetime.DTT_EVT_start'] ) ) {
489
			$where_params['Datetime.DTT_EVT_start******'] = array('<',  EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_start' ) );
490
		} else {
491
			$where_params['Datetime.DTT_EVT_start'] = array('<',  EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_start' ) );
492
		}
493
494 View Code Duplication
		if ( isset( $where_params['Datetime.DTT_EVT_end'] ) ) {
495
			$where_params['Datetime.DTT_EVT_end*****'] = array('>', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) );
496
		} else {
497
			$where_params['Datetime.DTT_EVT_end'] = array('>', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) );
498
		}
499
		$query_params[0] = $where_params;
500
		// don't use $query_params with count() because we don't want to include additional query clauses like "GROUP BY" 
501
		return $count ? $this->count( array( $where_params ), 'EVT_ID', true ) : $this->get_all( $query_params );
502
	}
503
504
505
506
507
508
	/**
509
	 * get all events that are published and have an event start time later than now
510
	 *
511
	 * @access public
512
	 * @param  array 	$query_params An array of query params to further filter on (Note that status and DTT_EVT_start will be overridden)
513
	 * @param bool    $count whether to return the count or not (default FALSE)
514
	 * @return array               EE_Event objects
515
	 */
516
	public function get_upcoming_events( $query_params, $count = FALSE ) {
517 View Code Duplication
		if ( array_key_exists( 0, $query_params ) ) {
518
			$where_params = $query_params[0];
519
			unset( $query_params[0] );
520
		} else {
521
			$where_params = array();
522
		}
523
524
		//if we have count make sure we don't include group by
525
		if ( $count && isset( $query_params['group_by'] ) ) {
526
			unset( $query_params['group_by'] );
527
		}
528
529
		//let's add specific query_params for active_events - keep in mind this will override any sent status in the query AND any date queries.
530
		$where_params['status'] = 'publish';
531
		//if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
532 View Code Duplication
		if ( isset( $where_params['Datetime.DTT_EVT_start'] ) ) {
533
			$where_params['Datetime.DTT_EVT_start*****'] = array('>', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_start' ) );
534
		} else {
535
			$where_params['Datetime.DTT_EVT_start'] = array('>', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_start' ) );
536
		}
537
		$query_params[0] = $where_params;
538
		// don't use $query_params with count() because we don't want to include additional query clauses like "GROUP BY" 
539
		return $count ? $this->count( array( $where_params ), 'EVT_ID', true ) : $this->get_all( $query_params );
540
	}
541
542
543
	/**
544
	 * This only returns events that are expired.  They may still be published but all their datetimes have expired.
545
	 *
546
	 * @access public
547
	 * @param  array  $query_params An array of query params to further filter on (note that status and DTT_EVT_end will be overridden)
548
	 * @param bool    $count whether to return the count or not (default FALSE)
549
	 * @return array 	EE_Event objects
550
	 */
551
	public function get_expired_events( $query_params, $count = FALSE ) {
552
553
		$where_params = isset( $query_params[0] ) ? $query_params[0] : array();
554
555
		//if we have count make sure we don't include group by
556
		if ( $count && isset( $query_params['group_by'] ) ) {
557
			unset( $query_params['group_by'] );
558
		}
559
560
		//let's add specific query_params for active_events - keep in mind this will override any sent status in the query AND any date queries.
561
		if ( isset( $where_params['status'] ) ) {
562
			unset( $where_params['status'] );
563
		}
564
		$exclude_query = $query_params;
565
		if ( isset( $exclude_query[0] ) ) {
566
			unset( $exclude_query[0] );
567
		}
568
		$exclude_query[0] = array( 'Datetime.DTT_EVT_end' => array( '>', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) ) );
569
		//first get all events that have datetimes where its not expired.
570
		$event_ids = $this->_get_all_wpdb_results( $exclude_query, OBJECT_K, 'Event_CPT.ID' );
571
		$event_ids = array_keys( $event_ids );
572
573
		//if we have any additional query_params, let's add them to the 'AND' condition
574
		$and_condition = array(
575
			'Datetime.DTT_EVT_end' => array( '<', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) ),
576
			'EVT_ID' =>  array( 'NOT IN', $event_ids )
577
			);
578
579 View Code Duplication
		if ( isset( $where_params['OR'] ) ) {
580
			$and_condition['OR'] = $where_params['OR'];
581
			unset( $where_params['OR'] );
582
		}
583
584 View Code Duplication
		if ( isset( $where_params['Datetime.DTT_EVT_end'] ) ) {
585
			$and_condition['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
586
			unset( $where_params['Datetime.DTT_EVT_end'] );
587
		}
588
589 View Code Duplication
		if ( isset( $where_params['Datetime.DTT_EVT_start'] ) ) {
590
			$and_condition['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
591
			unset( $where_params['Datetime.DTT_EVT_start'] );
592
		}
593
594
		//merge remaining $where params with the and conditions.
595
		$and_condtion = array_merge( $and_condition, $where_params );
0 ignored issues
show
Unused Code introduced by
$and_condtion 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...
596
597
		$where_params['AND'] = $and_condition;
598
		$query_params[0] = $where_params;
599
		// don't use $query_params with count() because we don't want to include additional query clauses like "GROUP BY" 
600
		return $count ? $this->count( array( $where_params ), 'EVT_ID', true ) : $this->get_all( $query_params );
601
	}
602
603
604
605
	/**
606
	 * This basically just returns the events that do not have the publish status.
607
	 * @param  array  $query_params  An array of query params to further filter on (note that status will be overwritten)
608
	 * @param  boolean $count        whether to return the count or not (default FALSE)
609
	 * @return EE_Event[]            array of EE_Event objects
610
	 */
611
	public function get_inactive_events( $query_params, $count = FALSE ) {
612
		$where_params = isset( $query_params[0] ) ? $query_params[0] : array();
613
614
		//let's add in specific query_params for inactive events.
615
		if ( isset( $where_params['status'] ) ) {
616
			unset( $where_params['status'] );
617
		}
618
619
		//if we have count make sure we don't include group by
620
		if ( $count && isset( $query_params['group_by'] ) ) {
621
			unset( $query_params['group_by'] );
622
		}
623
624
		//if we have any additional query_params, let's add them to the 'AND' condition
625
		$where_params['AND']['status'] = array( '!=', 'publish' );
626
627 View Code Duplication
		if ( isset( $where_params['OR'] ) ) {
628
			$where_params['AND']['OR'] = $where_params['OR'];
629
			unset( $where_params['OR'] );
630
		}
631
632 View Code Duplication
		if ( isset( $where_params['Datetime.DTT_EVT_end'] ) ) {
633
			$where_params['AND']['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
634
			unset( $where_params['Datetime.DTT_EVT_end'] );
635
		}
636
637 View Code Duplication
		if ( isset( $where_params['Datetime.DTT_EVT_start'] ) ) {
638
			$where_params['AND']['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
639
			unset( $where_params['Datetime.DTT_EVT_start'] );
640
		}
641
642
		$query_params[0] = $where_params;
643
		// don't use $query_params with count() because we don't want to include additional query clauses like "GROUP BY" 
644
		return $count ? $this->count( array( $where_params ), 'EVT_ID', true ) : $this->get_all( $query_params );
645
	}
646
647
648
	/**
649
	 * This is just injecting into the parent add_relationship_to so we do special handling on price relationships because we don't want to override any existing global default prices but instead insert NEW prices that get attached to the event.
650
	 * See parent for param descriptions
651
	 */
652
	public function add_relationship_to($id_or_obj,$other_model_id_or_obj, $relationName, $where_query = array()){
653
654
		if ( $relationName == 'Price' ) {
655
			//let's get the PRC object for the given ID to make sure that we aren't dealing with a default
656
			$prc_chk = $this->get_related_model_obj($relationName)->ensure_is_obj($other_model_id_or_obj);
657
			//if EVT_ID = 0, then this is a default
658
			if ( $prc_chk->get('EVT_ID') == 0 ) {
659
				//let's set the prc_id as 0 so we force an insert on the add_relation_to carried out by relation
660
				$prc_chk->set('PRC_ID', 0);
661
			}
662
663
			//run parent
664
			return parent::add_relationship_to($id_or_obj, $prc_chk, $relationName, $where_query);
665
		}
666
667
		//otherwise carry on as normal
668
		return parent::add_relationship_to($id_or_obj,$other_model_id_or_obj, $relationName, $where_query);
669
	}
670
671
672
673
}
674
// End of file EEM_Event.model.php
675
// Location: /includes/models/EEM_Event.model.php
676