@@ -11,93 +11,93 @@ discard block |
||
11 | 11 | class EEM_Change_Log extends EEM_Base |
12 | 12 | { |
13 | 13 | |
14 | - /** |
|
15 | - * the related object was created log type |
|
16 | - */ |
|
17 | - const type_create = 'create'; |
|
18 | - /** |
|
19 | - * the related object was updated (changed, or soft-deleted) |
|
20 | - */ |
|
21 | - const type_update = 'update'; |
|
22 | - /** |
|
23 | - * the related object was deleted permanently |
|
24 | - */ |
|
25 | - const type_delete = 'delete'; |
|
26 | - /** |
|
27 | - * the related item had something worth noting happen on it, but |
|
28 | - * only for the purposes of debugging problems |
|
29 | - */ |
|
30 | - const type_debug = 'debug'; |
|
31 | - /** |
|
32 | - * the related item had an error occur on it |
|
33 | - */ |
|
34 | - const type_error = 'error'; |
|
35 | - /** |
|
36 | - * the related item is regarding some gateway interaction, like an IPN |
|
37 | - * or request to process a payment |
|
38 | - */ |
|
39 | - const type_gateway = 'gateway'; |
|
14 | + /** |
|
15 | + * the related object was created log type |
|
16 | + */ |
|
17 | + const type_create = 'create'; |
|
18 | + /** |
|
19 | + * the related object was updated (changed, or soft-deleted) |
|
20 | + */ |
|
21 | + const type_update = 'update'; |
|
22 | + /** |
|
23 | + * the related object was deleted permanently |
|
24 | + */ |
|
25 | + const type_delete = 'delete'; |
|
26 | + /** |
|
27 | + * the related item had something worth noting happen on it, but |
|
28 | + * only for the purposes of debugging problems |
|
29 | + */ |
|
30 | + const type_debug = 'debug'; |
|
31 | + /** |
|
32 | + * the related item had an error occur on it |
|
33 | + */ |
|
34 | + const type_error = 'error'; |
|
35 | + /** |
|
36 | + * the related item is regarding some gateway interaction, like an IPN |
|
37 | + * or request to process a payment |
|
38 | + */ |
|
39 | + const type_gateway = 'gateway'; |
|
40 | 40 | |
41 | - /** |
|
42 | - * private instance of the EEM_Change_Log object |
|
43 | - * |
|
44 | - * @access private |
|
45 | - * @var EEM_Change_Log $_instance |
|
46 | - */ |
|
47 | - protected static $_instance = null; |
|
41 | + /** |
|
42 | + * private instance of the EEM_Change_Log object |
|
43 | + * |
|
44 | + * @access private |
|
45 | + * @var EEM_Change_Log $_instance |
|
46 | + */ |
|
47 | + protected static $_instance = null; |
|
48 | 48 | |
49 | 49 | |
50 | - /** |
|
51 | - * constructor |
|
52 | - * |
|
53 | - * @access protected |
|
54 | - * @param null $timezone |
|
55 | - * @throws EE_Error |
|
56 | - */ |
|
57 | - protected function __construct($timezone = null) |
|
58 | - { |
|
59 | - global $current_user; |
|
60 | - $this->singular_item = esc_html__('Log', 'event_espresso'); |
|
61 | - $this->plural_item = esc_html__('Logs', 'event_espresso'); |
|
62 | - $this->_tables = array( |
|
63 | - 'Log' => new EE_Primary_Table('esp_log', 'LOG_ID'), |
|
64 | - ); |
|
65 | - $models_this_can_attach_to = array_keys(EE_Registry::instance()->non_abstract_db_models); |
|
66 | - $this->_fields = array( |
|
67 | - 'Log' => array( |
|
68 | - 'LOG_ID' => new EE_Primary_Key_Int_Field('LOG_ID', esc_html__('Log ID', 'event_espresso')), |
|
69 | - 'LOG_time' => new EE_Datetime_Field( |
|
70 | - 'LOG_time', |
|
71 | - esc_html__("Log Time", 'event_espresso'), |
|
72 | - false, |
|
73 | - EE_Datetime_Field::now |
|
74 | - ), |
|
75 | - 'OBJ_ID' => new EE_Foreign_Key_String_Field( |
|
76 | - 'OBJ_ID', |
|
77 | - esc_html__("Object ID (int or string)", 'event_espresso'), |
|
78 | - true, |
|
79 | - null, |
|
80 | - $models_this_can_attach_to |
|
81 | - ), |
|
82 | - 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field( |
|
83 | - 'OBJ_type', |
|
84 | - esc_html__("Object Type", 'event_espresso'), |
|
85 | - true, |
|
86 | - null, |
|
87 | - $models_this_can_attach_to |
|
88 | - ), |
|
89 | - 'LOG_type' => new EE_Plain_Text_Field( |
|
90 | - 'LOG_type', |
|
91 | - esc_html__("Type of log entry", "event_espresso"), |
|
92 | - false, |
|
93 | - self::type_debug |
|
94 | - ), |
|
95 | - 'LOG_message' => new EE_Maybe_Serialized_Text_Field( |
|
96 | - 'LOG_message', |
|
97 | - esc_html__("Log Message (body)", 'event_espresso'), |
|
98 | - true |
|
99 | - ), |
|
100 | - /* |
|
50 | + /** |
|
51 | + * constructor |
|
52 | + * |
|
53 | + * @access protected |
|
54 | + * @param null $timezone |
|
55 | + * @throws EE_Error |
|
56 | + */ |
|
57 | + protected function __construct($timezone = null) |
|
58 | + { |
|
59 | + global $current_user; |
|
60 | + $this->singular_item = esc_html__('Log', 'event_espresso'); |
|
61 | + $this->plural_item = esc_html__('Logs', 'event_espresso'); |
|
62 | + $this->_tables = array( |
|
63 | + 'Log' => new EE_Primary_Table('esp_log', 'LOG_ID'), |
|
64 | + ); |
|
65 | + $models_this_can_attach_to = array_keys(EE_Registry::instance()->non_abstract_db_models); |
|
66 | + $this->_fields = array( |
|
67 | + 'Log' => array( |
|
68 | + 'LOG_ID' => new EE_Primary_Key_Int_Field('LOG_ID', esc_html__('Log ID', 'event_espresso')), |
|
69 | + 'LOG_time' => new EE_Datetime_Field( |
|
70 | + 'LOG_time', |
|
71 | + esc_html__("Log Time", 'event_espresso'), |
|
72 | + false, |
|
73 | + EE_Datetime_Field::now |
|
74 | + ), |
|
75 | + 'OBJ_ID' => new EE_Foreign_Key_String_Field( |
|
76 | + 'OBJ_ID', |
|
77 | + esc_html__("Object ID (int or string)", 'event_espresso'), |
|
78 | + true, |
|
79 | + null, |
|
80 | + $models_this_can_attach_to |
|
81 | + ), |
|
82 | + 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field( |
|
83 | + 'OBJ_type', |
|
84 | + esc_html__("Object Type", 'event_espresso'), |
|
85 | + true, |
|
86 | + null, |
|
87 | + $models_this_can_attach_to |
|
88 | + ), |
|
89 | + 'LOG_type' => new EE_Plain_Text_Field( |
|
90 | + 'LOG_type', |
|
91 | + esc_html__("Type of log entry", "event_espresso"), |
|
92 | + false, |
|
93 | + self::type_debug |
|
94 | + ), |
|
95 | + 'LOG_message' => new EE_Maybe_Serialized_Text_Field( |
|
96 | + 'LOG_message', |
|
97 | + esc_html__("Log Message (body)", 'event_espresso'), |
|
98 | + true |
|
99 | + ), |
|
100 | + /* |
|
101 | 101 | * Note: when querying for a change log's user, the OBJ_ID and OBJ_type fields are used, |
102 | 102 | * not the LOG_wp_user field. E.g., |
103 | 103 | * `EEM_Change_Log::instance()->get_all(array(array('WP_User.ID'=>1)))` will actually return |
@@ -106,158 +106,158 @@ discard block |
||
106 | 106 | * If you want the latter, you can't use the model's magic joining. E.g, you would need to do |
107 | 107 | * `EEM_Change_Log::instance()->get_all(array(array('LOG_wp_user' => 1)))`. |
108 | 108 | */ |
109 | - 'LOG_wp_user' => new EE_WP_User_Field( |
|
110 | - 'LOG_wp_user', |
|
111 | - esc_html__("User who was logged in while this occurred", 'event_espresso'), |
|
112 | - true |
|
113 | - ), |
|
114 | - ), |
|
115 | - ); |
|
116 | - $this->_model_relations = array(); |
|
117 | - foreach ($models_this_can_attach_to as $model) { |
|
118 | - if ($model != 'Change_Log') { |
|
119 | - $this->_model_relations[ $model ] = new EE_Belongs_To_Any_Relation(); |
|
120 | - } |
|
121 | - } |
|
122 | - // use completely custom caps for this |
|
123 | - $this->_cap_restriction_generators = false; |
|
124 | - // caps-wise this is all-or-nothing: if you have the default role you can access anything, otherwise nothing |
|
125 | - foreach ($this->_cap_contexts_to_cap_action_map as $cap_context => $action) { |
|
126 | - $this->_cap_restrictions[ $cap_context ][ EE_Restriction_Generator_Base::get_default_restrictions_cap() ] |
|
127 | - = new EE_Return_None_Where_Conditions(); |
|
128 | - } |
|
129 | - parent::__construct($timezone); |
|
130 | - } |
|
109 | + 'LOG_wp_user' => new EE_WP_User_Field( |
|
110 | + 'LOG_wp_user', |
|
111 | + esc_html__("User who was logged in while this occurred", 'event_espresso'), |
|
112 | + true |
|
113 | + ), |
|
114 | + ), |
|
115 | + ); |
|
116 | + $this->_model_relations = array(); |
|
117 | + foreach ($models_this_can_attach_to as $model) { |
|
118 | + if ($model != 'Change_Log') { |
|
119 | + $this->_model_relations[ $model ] = new EE_Belongs_To_Any_Relation(); |
|
120 | + } |
|
121 | + } |
|
122 | + // use completely custom caps for this |
|
123 | + $this->_cap_restriction_generators = false; |
|
124 | + // caps-wise this is all-or-nothing: if you have the default role you can access anything, otherwise nothing |
|
125 | + foreach ($this->_cap_contexts_to_cap_action_map as $cap_context => $action) { |
|
126 | + $this->_cap_restrictions[ $cap_context ][ EE_Restriction_Generator_Base::get_default_restrictions_cap() ] |
|
127 | + = new EE_Return_None_Where_Conditions(); |
|
128 | + } |
|
129 | + parent::__construct($timezone); |
|
130 | + } |
|
131 | 131 | |
132 | - /** |
|
133 | - * @param string $log_type !see the acceptable values of LOG_type in EEM__Change_Log::__construct |
|
134 | - * @param mixed $message array|string of the message you want to record |
|
135 | - * @param EE_Base_Class $related_model_obj |
|
136 | - * @return EE_Change_Log |
|
137 | - * @throws EE_Error |
|
138 | - */ |
|
139 | - public function log($log_type, $message, $related_model_obj) |
|
140 | - { |
|
141 | - if ($related_model_obj instanceof EE_Base_Class) { |
|
142 | - $obj_id = $related_model_obj->ID(); |
|
143 | - $obj_type = $related_model_obj->get_model()->get_this_model_name(); |
|
144 | - } else { |
|
145 | - $obj_id = null; |
|
146 | - $obj_type = null; |
|
147 | - } |
|
148 | - /** @var EE_Change_Log $log */ |
|
149 | - $log = EE_Change_Log::new_instance(array( |
|
150 | - 'LOG_type' => $log_type, |
|
151 | - 'LOG_message' => $message, |
|
152 | - 'OBJ_ID' => $obj_id, |
|
153 | - 'OBJ_type' => $obj_type, |
|
154 | - )); |
|
155 | - $log->save(); |
|
156 | - return $log; |
|
157 | - } |
|
132 | + /** |
|
133 | + * @param string $log_type !see the acceptable values of LOG_type in EEM__Change_Log::__construct |
|
134 | + * @param mixed $message array|string of the message you want to record |
|
135 | + * @param EE_Base_Class $related_model_obj |
|
136 | + * @return EE_Change_Log |
|
137 | + * @throws EE_Error |
|
138 | + */ |
|
139 | + public function log($log_type, $message, $related_model_obj) |
|
140 | + { |
|
141 | + if ($related_model_obj instanceof EE_Base_Class) { |
|
142 | + $obj_id = $related_model_obj->ID(); |
|
143 | + $obj_type = $related_model_obj->get_model()->get_this_model_name(); |
|
144 | + } else { |
|
145 | + $obj_id = null; |
|
146 | + $obj_type = null; |
|
147 | + } |
|
148 | + /** @var EE_Change_Log $log */ |
|
149 | + $log = EE_Change_Log::new_instance(array( |
|
150 | + 'LOG_type' => $log_type, |
|
151 | + 'LOG_message' => $message, |
|
152 | + 'OBJ_ID' => $obj_id, |
|
153 | + 'OBJ_type' => $obj_type, |
|
154 | + )); |
|
155 | + $log->save(); |
|
156 | + return $log; |
|
157 | + } |
|
158 | 158 | |
159 | 159 | |
160 | - /** |
|
161 | - * Adds a gateway log for the specified object, given its ID and type |
|
162 | - * |
|
163 | - * @param string $message |
|
164 | - * @param mixed $related_obj_id |
|
165 | - * @param string $related_obj_type |
|
166 | - * @throws EE_Error |
|
167 | - * @return EE_Change_Log |
|
168 | - */ |
|
169 | - public function gateway_log($message, $related_obj_id, $related_obj_type) |
|
170 | - { |
|
171 | - if (! EE_Registry::instance()->is_model_name($related_obj_type)) { |
|
172 | - throw new EE_Error( |
|
173 | - sprintf( |
|
174 | - esc_html__( |
|
175 | - "'%s' is not a model name. A model name must be provided when making a gateway log. Eg, 'Payment', 'Payment_Method', etc", |
|
176 | - "event_espresso" |
|
177 | - ), |
|
178 | - $related_obj_type |
|
179 | - ) |
|
180 | - ); |
|
181 | - } |
|
182 | - /** @var EE_Change_Log $log */ |
|
183 | - $log = EE_Change_Log::new_instance(array( |
|
184 | - 'LOG_type' => EEM_Change_Log::type_gateway, |
|
185 | - 'LOG_message' => $message, |
|
186 | - 'OBJ_ID' => $related_obj_id, |
|
187 | - 'OBJ_type' => $related_obj_type, |
|
188 | - )); |
|
189 | - $log->save(); |
|
190 | - return $log; |
|
191 | - } |
|
160 | + /** |
|
161 | + * Adds a gateway log for the specified object, given its ID and type |
|
162 | + * |
|
163 | + * @param string $message |
|
164 | + * @param mixed $related_obj_id |
|
165 | + * @param string $related_obj_type |
|
166 | + * @throws EE_Error |
|
167 | + * @return EE_Change_Log |
|
168 | + */ |
|
169 | + public function gateway_log($message, $related_obj_id, $related_obj_type) |
|
170 | + { |
|
171 | + if (! EE_Registry::instance()->is_model_name($related_obj_type)) { |
|
172 | + throw new EE_Error( |
|
173 | + sprintf( |
|
174 | + esc_html__( |
|
175 | + "'%s' is not a model name. A model name must be provided when making a gateway log. Eg, 'Payment', 'Payment_Method', etc", |
|
176 | + "event_espresso" |
|
177 | + ), |
|
178 | + $related_obj_type |
|
179 | + ) |
|
180 | + ); |
|
181 | + } |
|
182 | + /** @var EE_Change_Log $log */ |
|
183 | + $log = EE_Change_Log::new_instance(array( |
|
184 | + 'LOG_type' => EEM_Change_Log::type_gateway, |
|
185 | + 'LOG_message' => $message, |
|
186 | + 'OBJ_ID' => $related_obj_id, |
|
187 | + 'OBJ_type' => $related_obj_type, |
|
188 | + )); |
|
189 | + $log->save(); |
|
190 | + return $log; |
|
191 | + } |
|
192 | 192 | |
193 | 193 | |
194 | - /** |
|
195 | - * Just gets the bare-bones wpdb results as an array in cases where efficiency is essential |
|
196 | - * |
|
197 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
198 | - * @return array of arrays |
|
199 | - * @throws EE_Error |
|
200 | - */ |
|
201 | - public function get_all_efficiently($query_params) |
|
202 | - { |
|
203 | - return $this->_get_all_wpdb_results($query_params); |
|
204 | - } |
|
194 | + /** |
|
195 | + * Just gets the bare-bones wpdb results as an array in cases where efficiency is essential |
|
196 | + * |
|
197 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
198 | + * @return array of arrays |
|
199 | + * @throws EE_Error |
|
200 | + */ |
|
201 | + public function get_all_efficiently($query_params) |
|
202 | + { |
|
203 | + return $this->_get_all_wpdb_results($query_params); |
|
204 | + } |
|
205 | 205 | |
206 | 206 | |
207 | - /** |
|
208 | - * Executes a database query to delete gateway logs. Does not affect model objects, so if you attempt to use |
|
209 | - * models after this, they may be out-of-sync with the database |
|
210 | - * |
|
211 | - * @param DateTime $datetime |
|
212 | - * @return false|int |
|
213 | - * @throws EE_Error |
|
214 | - */ |
|
215 | - public function delete_gateway_logs_older_than(DateTime $datetime) |
|
216 | - { |
|
217 | - global $wpdb; |
|
218 | - return $wpdb->query( |
|
219 | - $wpdb->prepare( |
|
220 | - 'DELETE FROM ' . $this->table() . ' WHERE LOG_type = %s AND LOG_time < %s', |
|
221 | - EEM_Change_Log::type_gateway, |
|
222 | - $datetime->format(EE_Datetime_Field::mysql_timestamp_format) |
|
223 | - ) |
|
224 | - ); |
|
225 | - } |
|
207 | + /** |
|
208 | + * Executes a database query to delete gateway logs. Does not affect model objects, so if you attempt to use |
|
209 | + * models after this, they may be out-of-sync with the database |
|
210 | + * |
|
211 | + * @param DateTime $datetime |
|
212 | + * @return false|int |
|
213 | + * @throws EE_Error |
|
214 | + */ |
|
215 | + public function delete_gateway_logs_older_than(DateTime $datetime) |
|
216 | + { |
|
217 | + global $wpdb; |
|
218 | + return $wpdb->query( |
|
219 | + $wpdb->prepare( |
|
220 | + 'DELETE FROM ' . $this->table() . ' WHERE LOG_type = %s AND LOG_time < %s', |
|
221 | + EEM_Change_Log::type_gateway, |
|
222 | + $datetime->format(EE_Datetime_Field::mysql_timestamp_format) |
|
223 | + ) |
|
224 | + ); |
|
225 | + } |
|
226 | 226 | |
227 | 227 | |
228 | - /** |
|
229 | - * Returns the map of type to pretty label for identifiers used for `LOG_type`. Client code can register their own |
|
230 | - * map vai the given filter. |
|
231 | - * |
|
232 | - * @return array |
|
233 | - */ |
|
234 | - public static function get_pretty_label_map_for_registered_types() |
|
235 | - { |
|
236 | - return apply_filters( |
|
237 | - 'FHEE__EEM_Change_Log__get_pretty_label_map_for_registered_types', |
|
238 | - array( |
|
239 | - self::type_create=> esc_html__("Create", "event_espresso"), |
|
240 | - self::type_update=> esc_html__("Update", "event_espresso"), |
|
241 | - self::type_delete => esc_html__("Delete", "event_espresso"), |
|
242 | - self::type_debug=> esc_html__("Debug", "event_espresso"), |
|
243 | - self::type_error=> esc_html__("Error", "event_espresso"), |
|
244 | - self::type_gateway=> esc_html__("Gateway Interaction (IPN or Direct Payment)", 'event_espresso') |
|
245 | - ) |
|
246 | - ); |
|
247 | - } |
|
228 | + /** |
|
229 | + * Returns the map of type to pretty label for identifiers used for `LOG_type`. Client code can register their own |
|
230 | + * map vai the given filter. |
|
231 | + * |
|
232 | + * @return array |
|
233 | + */ |
|
234 | + public static function get_pretty_label_map_for_registered_types() |
|
235 | + { |
|
236 | + return apply_filters( |
|
237 | + 'FHEE__EEM_Change_Log__get_pretty_label_map_for_registered_types', |
|
238 | + array( |
|
239 | + self::type_create=> esc_html__("Create", "event_espresso"), |
|
240 | + self::type_update=> esc_html__("Update", "event_espresso"), |
|
241 | + self::type_delete => esc_html__("Delete", "event_espresso"), |
|
242 | + self::type_debug=> esc_html__("Debug", "event_espresso"), |
|
243 | + self::type_error=> esc_html__("Error", "event_espresso"), |
|
244 | + self::type_gateway=> esc_html__("Gateway Interaction (IPN or Direct Payment)", 'event_espresso') |
|
245 | + ) |
|
246 | + ); |
|
247 | + } |
|
248 | 248 | |
249 | 249 | |
250 | - /** |
|
251 | - * Return the pretty (localized) label for the given log type identifier. |
|
252 | - * @param string $type_identifier |
|
253 | - * @return string |
|
254 | - */ |
|
255 | - public static function get_pretty_label_for_type($type_identifier) |
|
256 | - { |
|
257 | - $type_identifier_map = self::get_pretty_label_map_for_registered_types(); |
|
258 | - // we fallback to the incoming type identifier if there is no localized label for it. |
|
259 | - return isset($type_identifier_map[ $type_identifier ]) |
|
260 | - ? $type_identifier_map[ $type_identifier ] |
|
261 | - : $type_identifier; |
|
262 | - } |
|
250 | + /** |
|
251 | + * Return the pretty (localized) label for the given log type identifier. |
|
252 | + * @param string $type_identifier |
|
253 | + * @return string |
|
254 | + */ |
|
255 | + public static function get_pretty_label_for_type($type_identifier) |
|
256 | + { |
|
257 | + $type_identifier_map = self::get_pretty_label_map_for_registered_types(); |
|
258 | + // we fallback to the incoming type identifier if there is no localized label for it. |
|
259 | + return isset($type_identifier_map[ $type_identifier ]) |
|
260 | + ? $type_identifier_map[ $type_identifier ] |
|
261 | + : $type_identifier; |
|
262 | + } |
|
263 | 263 | } |
@@ -9,233 +9,233 @@ |
||
9 | 9 | class EEM_Term_Relationship extends EEM_Base |
10 | 10 | { |
11 | 11 | |
12 | - // private instance of the Attendee object |
|
13 | - protected static $_instance = null; |
|
14 | - |
|
15 | - |
|
16 | - |
|
17 | - /** |
|
18 | - * EEM_Term_Relationship constructor. |
|
19 | - * |
|
20 | - * @param string $timezone |
|
21 | - */ |
|
22 | - protected function __construct($timezone = null) |
|
23 | - { |
|
24 | - $this->singular_item = __('Term Relationship', 'event_espresso'); |
|
25 | - $this->plural_item = __('Term Relationships', 'event_espresso'); |
|
26 | - $this->_tables = array( |
|
27 | - 'Term_Relationship' => new EE_Primary_Table('term_relationships'), |
|
28 | - ); |
|
29 | - $models_this_can_attach_to = array_keys(EE_Registry::instance()->cpt_models()); |
|
30 | - $this->_fields = array( |
|
31 | - 'Term_Relationship' => array( |
|
32 | - 'object_id' => new EE_Foreign_Key_Int_Field( |
|
33 | - 'object_id', |
|
34 | - __('Object(Post) ID', 'event_espresso'), |
|
35 | - false, |
|
36 | - 0, |
|
37 | - $models_this_can_attach_to |
|
38 | - ), |
|
39 | - 'term_taxonomy_id' => new EE_Foreign_Key_Int_Field( |
|
40 | - 'term_taxonomy_id', |
|
41 | - __( |
|
42 | - 'Term (in context of a taxonomy) ID', |
|
43 | - 'event_espresso' |
|
44 | - ), |
|
45 | - false, |
|
46 | - 0, |
|
47 | - 'Term_Taxonomy' |
|
48 | - ), |
|
49 | - 'term_order' => new EE_Integer_Field( |
|
50 | - 'term_order', |
|
51 | - __('Term Order', 'event_espresso'), |
|
52 | - false, |
|
53 | - 0 |
|
54 | - ), |
|
55 | - ), |
|
56 | - ); |
|
57 | - $this->_model_relations = array( |
|
58 | - 'Term_Taxonomy' => new EE_Belongs_To_Relation(), |
|
59 | - ); |
|
60 | - foreach ($models_this_can_attach_to as $model_name) { |
|
61 | - $this->_model_relations[ $model_name ] = new EE_Belongs_To_Relation(); |
|
62 | - } |
|
63 | - $this->_wp_core_model = true; |
|
64 | - $this->_indexes = array( |
|
65 | - 'PRIMARY' => new EE_Primary_Key_Index(array('object_id', 'term_taxonomy_id')), |
|
66 | - ); |
|
67 | - $path_to_event_model = 'Event.'; |
|
68 | - $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public( |
|
69 | - $path_to_event_model |
|
70 | - ); |
|
71 | - $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = |
|
72 | - new EE_Restriction_Generator_Event_Related_Protected( |
|
73 | - $path_to_event_model |
|
74 | - ); |
|
75 | - $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
76 | - $path_to_event_model |
|
77 | - ); |
|
78 | - $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = |
|
79 | - new EE_Restriction_Generator_Event_Related_Protected( |
|
80 | - $path_to_event_model, |
|
81 | - EEM_Base::caps_edit |
|
82 | - ); |
|
83 | - $path_to_tax_model = 'Term_Taxonomy.'; |
|
84 | - // add cap restrictions for editing term relations to the "ee_assign_*" |
|
85 | - // and for deleting term relations too |
|
86 | - $cap_contexts_affected = array(EEM_Base::caps_edit, EEM_Base::caps_delete); |
|
87 | - foreach ($cap_contexts_affected as $cap_context_affected) { |
|
88 | - $this->_cap_restrictions[ $cap_context_affected ]['ee_assign_event_category'] = |
|
89 | - new EE_Default_Where_Conditions( |
|
90 | - array( |
|
91 | - $path_to_tax_model . 'taxonomy*ee_assign_event_category' => array( |
|
92 | - '!=', |
|
93 | - 'espresso_event_categories', |
|
94 | - ), |
|
95 | - ) |
|
96 | - ); |
|
97 | - $this->_cap_restrictions[ $cap_context_affected ]['ee_assign_venue_category'] = |
|
98 | - new EE_Default_Where_Conditions( |
|
99 | - array( |
|
100 | - $path_to_tax_model . 'taxonomy*ee_assign_venue_category' => array( |
|
101 | - '!=', |
|
102 | - 'espresso_venue_categories', |
|
103 | - ), |
|
104 | - ) |
|
105 | - ); |
|
106 | - $this->_cap_restrictions[ $cap_context_affected ]['ee_assign_event_type'] = new EE_Default_Where_Conditions( |
|
107 | - array( |
|
108 | - $path_to_tax_model . 'taxonomy*ee_assign_event_type' => array('!=', 'espresso_event_type'), |
|
109 | - ) |
|
110 | - ); |
|
111 | - } |
|
112 | - parent::__construct($timezone); |
|
113 | - add_filter( |
|
114 | - 'FHEE__Read__create_model_query_params', |
|
115 | - array('EEM_Term_Relationship', 'rest_api_query_params'), |
|
116 | - 10, |
|
117 | - 3 |
|
118 | - ); |
|
119 | - } |
|
120 | - |
|
121 | - |
|
122 | - /** |
|
123 | - * Makes sure all term-taxonomy counts are correct |
|
124 | - * |
|
125 | - * @param int $term_taxonomy_id the id of the term taxonomy to update. If NULL, updates ALL |
|
126 | - * @global wpdb $wpdb |
|
127 | - * @return int the number of rows affected |
|
128 | - * @throws EE_Error |
|
129 | - */ |
|
130 | - public function update_term_taxonomy_counts($term_taxonomy_id = null) |
|
131 | - { |
|
132 | - // because this uses a subquery and sometimes assigning to column to be another column's |
|
133 | - // value, we just write the SQL directly. |
|
134 | - global $wpdb; |
|
135 | - |
|
136 | - $query = " |
|
12 | + // private instance of the Attendee object |
|
13 | + protected static $_instance = null; |
|
14 | + |
|
15 | + |
|
16 | + |
|
17 | + /** |
|
18 | + * EEM_Term_Relationship constructor. |
|
19 | + * |
|
20 | + * @param string $timezone |
|
21 | + */ |
|
22 | + protected function __construct($timezone = null) |
|
23 | + { |
|
24 | + $this->singular_item = __('Term Relationship', 'event_espresso'); |
|
25 | + $this->plural_item = __('Term Relationships', 'event_espresso'); |
|
26 | + $this->_tables = array( |
|
27 | + 'Term_Relationship' => new EE_Primary_Table('term_relationships'), |
|
28 | + ); |
|
29 | + $models_this_can_attach_to = array_keys(EE_Registry::instance()->cpt_models()); |
|
30 | + $this->_fields = array( |
|
31 | + 'Term_Relationship' => array( |
|
32 | + 'object_id' => new EE_Foreign_Key_Int_Field( |
|
33 | + 'object_id', |
|
34 | + __('Object(Post) ID', 'event_espresso'), |
|
35 | + false, |
|
36 | + 0, |
|
37 | + $models_this_can_attach_to |
|
38 | + ), |
|
39 | + 'term_taxonomy_id' => new EE_Foreign_Key_Int_Field( |
|
40 | + 'term_taxonomy_id', |
|
41 | + __( |
|
42 | + 'Term (in context of a taxonomy) ID', |
|
43 | + 'event_espresso' |
|
44 | + ), |
|
45 | + false, |
|
46 | + 0, |
|
47 | + 'Term_Taxonomy' |
|
48 | + ), |
|
49 | + 'term_order' => new EE_Integer_Field( |
|
50 | + 'term_order', |
|
51 | + __('Term Order', 'event_espresso'), |
|
52 | + false, |
|
53 | + 0 |
|
54 | + ), |
|
55 | + ), |
|
56 | + ); |
|
57 | + $this->_model_relations = array( |
|
58 | + 'Term_Taxonomy' => new EE_Belongs_To_Relation(), |
|
59 | + ); |
|
60 | + foreach ($models_this_can_attach_to as $model_name) { |
|
61 | + $this->_model_relations[ $model_name ] = new EE_Belongs_To_Relation(); |
|
62 | + } |
|
63 | + $this->_wp_core_model = true; |
|
64 | + $this->_indexes = array( |
|
65 | + 'PRIMARY' => new EE_Primary_Key_Index(array('object_id', 'term_taxonomy_id')), |
|
66 | + ); |
|
67 | + $path_to_event_model = 'Event.'; |
|
68 | + $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public( |
|
69 | + $path_to_event_model |
|
70 | + ); |
|
71 | + $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = |
|
72 | + new EE_Restriction_Generator_Event_Related_Protected( |
|
73 | + $path_to_event_model |
|
74 | + ); |
|
75 | + $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
76 | + $path_to_event_model |
|
77 | + ); |
|
78 | + $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = |
|
79 | + new EE_Restriction_Generator_Event_Related_Protected( |
|
80 | + $path_to_event_model, |
|
81 | + EEM_Base::caps_edit |
|
82 | + ); |
|
83 | + $path_to_tax_model = 'Term_Taxonomy.'; |
|
84 | + // add cap restrictions for editing term relations to the "ee_assign_*" |
|
85 | + // and for deleting term relations too |
|
86 | + $cap_contexts_affected = array(EEM_Base::caps_edit, EEM_Base::caps_delete); |
|
87 | + foreach ($cap_contexts_affected as $cap_context_affected) { |
|
88 | + $this->_cap_restrictions[ $cap_context_affected ]['ee_assign_event_category'] = |
|
89 | + new EE_Default_Where_Conditions( |
|
90 | + array( |
|
91 | + $path_to_tax_model . 'taxonomy*ee_assign_event_category' => array( |
|
92 | + '!=', |
|
93 | + 'espresso_event_categories', |
|
94 | + ), |
|
95 | + ) |
|
96 | + ); |
|
97 | + $this->_cap_restrictions[ $cap_context_affected ]['ee_assign_venue_category'] = |
|
98 | + new EE_Default_Where_Conditions( |
|
99 | + array( |
|
100 | + $path_to_tax_model . 'taxonomy*ee_assign_venue_category' => array( |
|
101 | + '!=', |
|
102 | + 'espresso_venue_categories', |
|
103 | + ), |
|
104 | + ) |
|
105 | + ); |
|
106 | + $this->_cap_restrictions[ $cap_context_affected ]['ee_assign_event_type'] = new EE_Default_Where_Conditions( |
|
107 | + array( |
|
108 | + $path_to_tax_model . 'taxonomy*ee_assign_event_type' => array('!=', 'espresso_event_type'), |
|
109 | + ) |
|
110 | + ); |
|
111 | + } |
|
112 | + parent::__construct($timezone); |
|
113 | + add_filter( |
|
114 | + 'FHEE__Read__create_model_query_params', |
|
115 | + array('EEM_Term_Relationship', 'rest_api_query_params'), |
|
116 | + 10, |
|
117 | + 3 |
|
118 | + ); |
|
119 | + } |
|
120 | + |
|
121 | + |
|
122 | + /** |
|
123 | + * Makes sure all term-taxonomy counts are correct |
|
124 | + * |
|
125 | + * @param int $term_taxonomy_id the id of the term taxonomy to update. If NULL, updates ALL |
|
126 | + * @global wpdb $wpdb |
|
127 | + * @return int the number of rows affected |
|
128 | + * @throws EE_Error |
|
129 | + */ |
|
130 | + public function update_term_taxonomy_counts($term_taxonomy_id = null) |
|
131 | + { |
|
132 | + // because this uses a subquery and sometimes assigning to column to be another column's |
|
133 | + // value, we just write the SQL directly. |
|
134 | + global $wpdb; |
|
135 | + |
|
136 | + $query = " |
|
137 | 137 | UPDATE {$wpdb->term_taxonomy} AS tt |
138 | 138 | SET count = ( |
139 | 139 | select count(*) as proper_count from {$wpdb->term_relationships} AS tr |
140 | 140 | WHERE tt.term_taxonomy_id = tr.term_taxonomy_id |
141 | 141 | )"; |
142 | 142 | |
143 | - if ($term_taxonomy_id) { |
|
144 | - $query .= ' WHERE tt.term_taxonomy_id = %d'; |
|
145 | - $query = $wpdb->prepare( |
|
146 | - $query, |
|
147 | - $term_taxonomy_id |
|
148 | - ); |
|
149 | - } |
|
150 | - $rows_affected = $this->_do_wpdb_query( |
|
151 | - 'query', |
|
152 | - array( |
|
153 | - $query, |
|
154 | - ) |
|
155 | - ); |
|
156 | - return $rows_affected; |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - |
|
161 | - /** |
|
162 | - * Overrides the parent to also make sure term-taxonomy counts are up-to-date after |
|
163 | - * inserting |
|
164 | - * |
|
165 | - * @param array $field_n_values @see EEM_Base::insert |
|
166 | - * @return boolean |
|
167 | - */ |
|
168 | - public function insert($field_n_values) |
|
169 | - { |
|
170 | - $return = parent::insert($field_n_values); |
|
171 | - if (isset($field_n_values['term_taxonomy_id'])) { |
|
172 | - $this->update_term_taxonomy_counts($field_n_values['term_taxonomy_id']); |
|
173 | - } |
|
174 | - return $return; |
|
175 | - } |
|
176 | - |
|
177 | - |
|
178 | - |
|
179 | - /** |
|
180 | - * Overrides parent so that after an update, we also check the term_taxonomy_counts are |
|
181 | - * all ok |
|
182 | - * |
|
183 | - * @param array $fields_n_values see EEM_Base::update |
|
184 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
185 | - * @param boolean $keep_model_objs_in_sync if TRUE, makes sure we ALSO update model objects |
|
186 | - * in this model's entity map according to $fields_n_values that match |
|
187 | - * $query_params. This obviously has some overhead, so you can disable it |
|
188 | - * by setting this to FALSE, but be aware that model objects being used |
|
189 | - * could get out-of-sync with the database |
|
190 | - * @return int |
|
191 | - */ |
|
192 | - public function update($fields_n_values, $query_params, $keep_model_objs_in_sync = true) |
|
193 | - { |
|
194 | - $count = parent::update($fields_n_values, $query_params, $keep_model_objs_in_sync); |
|
195 | - if ($count) { |
|
196 | - $this->update_term_taxonomy_counts(); |
|
197 | - } |
|
198 | - return $count; |
|
199 | - } |
|
200 | - |
|
201 | - |
|
202 | - |
|
203 | - /** |
|
204 | - * Overrides parent so that after running this, we also double-check |
|
205 | - * the term taxonomy counts are up-to-date |
|
206 | - * |
|
207 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
208 | - * @param boolean $allow_blocking |
|
209 | - * @return int @see EEM_Base::delete |
|
210 | - */ |
|
211 | - public function delete($query_params, $allow_blocking = true) |
|
212 | - { |
|
213 | - $count = parent::delete($query_params, $allow_blocking); |
|
214 | - if ($count) { |
|
215 | - $this->update_term_taxonomy_counts(); |
|
216 | - } |
|
217 | - return $count; |
|
218 | - } |
|
219 | - |
|
220 | - |
|
221 | - |
|
222 | - /** |
|
223 | - * Makes sure that during REST API queries, we only return term relationships |
|
224 | - * for term taxonomies which should be shown in the rest api |
|
225 | - * |
|
226 | - * @param array $model_query_params |
|
227 | - * @param array $querystring_query_params |
|
228 | - * @param EEM_Base $model |
|
229 | - * @return array |
|
230 | - */ |
|
231 | - public static function rest_api_query_params($model_query_params, $querystring_query_params, $model) |
|
232 | - { |
|
233 | - if ($model === EEM_Term_Relationship::instance()) { |
|
234 | - $taxonomies = get_taxonomies(array('show_in_rest' => true)); |
|
235 | - if (! empty($taxonomies)) { |
|
236 | - $model_query_params[0]['Term_Taxonomy.taxonomy'] = array('IN', $taxonomies); |
|
237 | - } |
|
238 | - } |
|
239 | - return $model_query_params; |
|
240 | - } |
|
143 | + if ($term_taxonomy_id) { |
|
144 | + $query .= ' WHERE tt.term_taxonomy_id = %d'; |
|
145 | + $query = $wpdb->prepare( |
|
146 | + $query, |
|
147 | + $term_taxonomy_id |
|
148 | + ); |
|
149 | + } |
|
150 | + $rows_affected = $this->_do_wpdb_query( |
|
151 | + 'query', |
|
152 | + array( |
|
153 | + $query, |
|
154 | + ) |
|
155 | + ); |
|
156 | + return $rows_affected; |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + |
|
161 | + /** |
|
162 | + * Overrides the parent to also make sure term-taxonomy counts are up-to-date after |
|
163 | + * inserting |
|
164 | + * |
|
165 | + * @param array $field_n_values @see EEM_Base::insert |
|
166 | + * @return boolean |
|
167 | + */ |
|
168 | + public function insert($field_n_values) |
|
169 | + { |
|
170 | + $return = parent::insert($field_n_values); |
|
171 | + if (isset($field_n_values['term_taxonomy_id'])) { |
|
172 | + $this->update_term_taxonomy_counts($field_n_values['term_taxonomy_id']); |
|
173 | + } |
|
174 | + return $return; |
|
175 | + } |
|
176 | + |
|
177 | + |
|
178 | + |
|
179 | + /** |
|
180 | + * Overrides parent so that after an update, we also check the term_taxonomy_counts are |
|
181 | + * all ok |
|
182 | + * |
|
183 | + * @param array $fields_n_values see EEM_Base::update |
|
184 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
185 | + * @param boolean $keep_model_objs_in_sync if TRUE, makes sure we ALSO update model objects |
|
186 | + * in this model's entity map according to $fields_n_values that match |
|
187 | + * $query_params. This obviously has some overhead, so you can disable it |
|
188 | + * by setting this to FALSE, but be aware that model objects being used |
|
189 | + * could get out-of-sync with the database |
|
190 | + * @return int |
|
191 | + */ |
|
192 | + public function update($fields_n_values, $query_params, $keep_model_objs_in_sync = true) |
|
193 | + { |
|
194 | + $count = parent::update($fields_n_values, $query_params, $keep_model_objs_in_sync); |
|
195 | + if ($count) { |
|
196 | + $this->update_term_taxonomy_counts(); |
|
197 | + } |
|
198 | + return $count; |
|
199 | + } |
|
200 | + |
|
201 | + |
|
202 | + |
|
203 | + /** |
|
204 | + * Overrides parent so that after running this, we also double-check |
|
205 | + * the term taxonomy counts are up-to-date |
|
206 | + * |
|
207 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
208 | + * @param boolean $allow_blocking |
|
209 | + * @return int @see EEM_Base::delete |
|
210 | + */ |
|
211 | + public function delete($query_params, $allow_blocking = true) |
|
212 | + { |
|
213 | + $count = parent::delete($query_params, $allow_blocking); |
|
214 | + if ($count) { |
|
215 | + $this->update_term_taxonomy_counts(); |
|
216 | + } |
|
217 | + return $count; |
|
218 | + } |
|
219 | + |
|
220 | + |
|
221 | + |
|
222 | + /** |
|
223 | + * Makes sure that during REST API queries, we only return term relationships |
|
224 | + * for term taxonomies which should be shown in the rest api |
|
225 | + * |
|
226 | + * @param array $model_query_params |
|
227 | + * @param array $querystring_query_params |
|
228 | + * @param EEM_Base $model |
|
229 | + * @return array |
|
230 | + */ |
|
231 | + public static function rest_api_query_params($model_query_params, $querystring_query_params, $model) |
|
232 | + { |
|
233 | + if ($model === EEM_Term_Relationship::instance()) { |
|
234 | + $taxonomies = get_taxonomies(array('show_in_rest' => true)); |
|
235 | + if (! empty($taxonomies)) { |
|
236 | + $model_query_params[0]['Term_Taxonomy.taxonomy'] = array('IN', $taxonomies); |
|
237 | + } |
|
238 | + } |
|
239 | + return $model_query_params; |
|
240 | + } |
|
241 | 241 | } |
@@ -9,659 +9,659 @@ |
||
9 | 9 | class EEM_Datetime extends EEM_Soft_Delete_Base |
10 | 10 | { |
11 | 11 | |
12 | - /** |
|
13 | - * @var EEM_Datetime $_instance |
|
14 | - */ |
|
15 | - protected static $_instance; |
|
16 | - |
|
17 | - |
|
18 | - /** |
|
19 | - * private constructor to prevent direct creation |
|
20 | - * |
|
21 | - * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings |
|
22 | - * (and any incoming timezone data that gets saved). |
|
23 | - * Note this just sends the timezone info to the date time model field objects. |
|
24 | - * Default is NULL |
|
25 | - * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
26 | - * @throws EE_Error |
|
27 | - * @throws InvalidArgumentException |
|
28 | - * @throws InvalidArgumentException |
|
29 | - */ |
|
30 | - protected function __construct($timezone) |
|
31 | - { |
|
32 | - $this->singular_item = esc_html__('Datetime', 'event_espresso'); |
|
33 | - $this->plural_item = esc_html__('Datetimes', 'event_espresso'); |
|
34 | - $this->_tables = array( |
|
35 | - 'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'), |
|
36 | - ); |
|
37 | - $this->_fields = array( |
|
38 | - 'Datetime' => array( |
|
39 | - 'DTT_ID' => new EE_Primary_Key_Int_Field( |
|
40 | - 'DTT_ID', |
|
41 | - esc_html__('Datetime ID', 'event_espresso') |
|
42 | - ), |
|
43 | - 'EVT_ID' => new EE_Foreign_Key_Int_Field( |
|
44 | - 'EVT_ID', |
|
45 | - esc_html__('Event ID', 'event_espresso'), |
|
46 | - false, |
|
47 | - 0, |
|
48 | - 'Event' |
|
49 | - ), |
|
50 | - 'DTT_name' => new EE_Plain_Text_Field( |
|
51 | - 'DTT_name', |
|
52 | - esc_html__('Datetime Name', 'event_espresso'), |
|
53 | - false, |
|
54 | - '' |
|
55 | - ), |
|
56 | - 'DTT_description' => new EE_Post_Content_Field( |
|
57 | - 'DTT_description', |
|
58 | - esc_html__('Description for Datetime', 'event_espresso'), |
|
59 | - false, |
|
60 | - '' |
|
61 | - ), |
|
62 | - 'DTT_EVT_start' => new EE_Datetime_Field( |
|
63 | - 'DTT_EVT_start', |
|
64 | - esc_html__('Start time/date of Event', 'event_espresso'), |
|
65 | - false, |
|
66 | - EE_Datetime_Field::now, |
|
67 | - $timezone |
|
68 | - ), |
|
69 | - 'DTT_EVT_end' => new EE_Datetime_Field( |
|
70 | - 'DTT_EVT_end', |
|
71 | - esc_html__('End time/date of Event', 'event_espresso'), |
|
72 | - false, |
|
73 | - EE_Datetime_Field::now, |
|
74 | - $timezone |
|
75 | - ), |
|
76 | - 'DTT_reg_limit' => new EE_Infinite_Integer_Field( |
|
77 | - 'DTT_reg_limit', |
|
78 | - esc_html__('Registration Limit for this time', 'event_espresso'), |
|
79 | - true, |
|
80 | - EE_INF |
|
81 | - ), |
|
82 | - 'DTT_sold' => new EE_Integer_Field( |
|
83 | - 'DTT_sold', |
|
84 | - esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'), |
|
85 | - true, |
|
86 | - 0 |
|
87 | - ), |
|
88 | - 'DTT_reserved' => new EE_Integer_Field( |
|
89 | - 'DTT_reserved', |
|
90 | - esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'), |
|
91 | - false, |
|
92 | - 0 |
|
93 | - ), |
|
94 | - 'DTT_is_primary' => new EE_Boolean_Field( |
|
95 | - 'DTT_is_primary', |
|
96 | - esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'), |
|
97 | - false, |
|
98 | - false |
|
99 | - ), |
|
100 | - 'DTT_order' => new EE_Integer_Field( |
|
101 | - 'DTT_order', |
|
102 | - esc_html__('The order in which the Datetime is displayed', 'event_espresso'), |
|
103 | - false, |
|
104 | - 0 |
|
105 | - ), |
|
106 | - 'DTT_parent' => new EE_Integer_Field( |
|
107 | - 'DTT_parent', |
|
108 | - esc_html__('Indicates what DTT_ID is the parent of this DTT_ID', 'event_espresso'), |
|
109 | - true, |
|
110 | - 0 |
|
111 | - ), |
|
112 | - 'DTT_deleted' => new EE_Trashed_Flag_Field( |
|
113 | - 'DTT_deleted', |
|
114 | - esc_html__('Flag indicating datetime is archived', 'event_espresso'), |
|
115 | - false, |
|
116 | - false |
|
117 | - ), |
|
118 | - ), |
|
119 | - ); |
|
120 | - $this->_model_relations = array( |
|
121 | - 'Ticket' => new EE_HABTM_Relation('Datetime_Ticket'), |
|
122 | - 'Event' => new EE_Belongs_To_Relation(), |
|
123 | - 'Checkin' => new EE_Has_Many_Relation(), |
|
124 | - ); |
|
125 | - $this->_model_chain_to_wp_user = 'Event'; |
|
126 | - // this model is generally available for reading |
|
127 | - $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public( |
|
128 | - 'Event' |
|
129 | - ); |
|
130 | - $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
131 | - 'Event' |
|
132 | - ); |
|
133 | - $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
134 | - 'Event' |
|
135 | - ); |
|
136 | - $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
137 | - 'Event', |
|
138 | - EEM_Base::caps_edit |
|
139 | - ); |
|
140 | - parent::__construct($timezone); |
|
141 | - } |
|
142 | - |
|
143 | - |
|
144 | - /** |
|
145 | - * create new blank datetime |
|
146 | - * |
|
147 | - * @access public |
|
148 | - * @return EE_Datetime[] array on success, FALSE on fail |
|
149 | - * @throws EE_Error |
|
150 | - */ |
|
151 | - public function create_new_blank_datetime() |
|
152 | - { |
|
153 | - // makes sure timezone is always set. |
|
154 | - $timezone_string = $this->get_timezone(); |
|
155 | - $blank_datetime = EE_Datetime::new_instance( |
|
156 | - array( |
|
157 | - 'DTT_EVT_start' => $this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS, |
|
158 | - 'DTT_EVT_end' => $this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS, |
|
159 | - 'DTT_order' => 1, |
|
160 | - 'DTT_reg_limit' => EE_INF, |
|
161 | - ), |
|
162 | - $timezone_string |
|
163 | - ); |
|
164 | - $blank_datetime->set_start_time( |
|
165 | - $this->convert_datetime_for_query( |
|
166 | - 'DTT_EVT_start', |
|
167 | - '8am', |
|
168 | - 'ga', |
|
169 | - $timezone_string |
|
170 | - ) |
|
171 | - ); |
|
172 | - $blank_datetime->set_end_time( |
|
173 | - $this->convert_datetime_for_query( |
|
174 | - 'DTT_EVT_end', |
|
175 | - '5pm', |
|
176 | - 'ga', |
|
177 | - $timezone_string |
|
178 | - ) |
|
179 | - ); |
|
180 | - return array($blank_datetime); |
|
181 | - } |
|
182 | - |
|
183 | - |
|
184 | - /** |
|
185 | - * get event start date from db |
|
186 | - * |
|
187 | - * @access public |
|
188 | - * @param int $EVT_ID |
|
189 | - * @return EE_Datetime[] array on success, FALSE on fail |
|
190 | - * @throws EE_Error |
|
191 | - */ |
|
192 | - public function get_all_event_dates($EVT_ID = 0) |
|
193 | - { |
|
194 | - if (! $EVT_ID) { // on add_new_event event_id gets set to 0 |
|
195 | - return $this->create_new_blank_datetime(); |
|
196 | - } |
|
197 | - $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID); |
|
198 | - if (empty($results)) { |
|
199 | - return $this->create_new_blank_datetime(); |
|
200 | - } |
|
201 | - return $results; |
|
202 | - } |
|
203 | - |
|
204 | - |
|
205 | - /** |
|
206 | - * get all datetimes attached to an event ordered by the DTT_order field |
|
207 | - * |
|
208 | - * @public |
|
209 | - * @param int $EVT_ID event id |
|
210 | - * @param boolean $include_expired |
|
211 | - * @param boolean $include_deleted |
|
212 | - * @param int $limit If included then limit the count of results by |
|
213 | - * the given number |
|
214 | - * @return EE_Datetime[] |
|
215 | - * @throws EE_Error |
|
216 | - */ |
|
217 | - public function get_datetimes_for_event_ordered_by_DTT_order( |
|
218 | - $EVT_ID, |
|
219 | - $include_expired = true, |
|
220 | - $include_deleted = true, |
|
221 | - $limit = null |
|
222 | - ) { |
|
223 | - // sanitize EVT_ID |
|
224 | - $EVT_ID = absint($EVT_ID); |
|
225 | - $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
226 | - $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
227 | - $where_params = array('Event.EVT_ID' => $EVT_ID); |
|
228 | - $query_params = ! empty($limit) |
|
229 | - ? array( |
|
230 | - $where_params, |
|
231 | - 'limit' => $limit, |
|
232 | - 'order_by' => array('DTT_order' => 'ASC'), |
|
233 | - 'default_where_conditions' => 'none', |
|
234 | - ) |
|
235 | - : array( |
|
236 | - $where_params, |
|
237 | - 'order_by' => array('DTT_order' => 'ASC'), |
|
238 | - 'default_where_conditions' => 'none', |
|
239 | - ); |
|
240 | - if (! $include_expired) { |
|
241 | - $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
242 | - } |
|
243 | - if ($include_deleted) { |
|
244 | - $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
245 | - } |
|
246 | - /** @var EE_Datetime[] $result */ |
|
247 | - $result = $this->get_all($query_params); |
|
248 | - $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
249 | - return $result; |
|
250 | - } |
|
251 | - |
|
252 | - |
|
253 | - /** |
|
254 | - * Gets the datetimes for the event (with the given limit), and orders them by "importance". |
|
255 | - * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW), |
|
256 | - * and then the earlier datetimes are the most important. |
|
257 | - * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet. |
|
258 | - * |
|
259 | - * @param int $EVT_ID |
|
260 | - * @param int $limit |
|
261 | - * @return EE_Datetime[]|EE_Base_Class[] |
|
262 | - * @throws EE_Error |
|
263 | - */ |
|
264 | - public function get_datetimes_for_event_ordered_by_importance($EVT_ID = 0, $limit = null) |
|
265 | - { |
|
266 | - return $this->get_all( |
|
267 | - array( |
|
268 | - array('Event.EVT_ID' => $EVT_ID), |
|
269 | - 'limit' => $limit, |
|
270 | - 'order_by' => array('DTT_EVT_start' => 'ASC'), |
|
271 | - 'default_where_conditions' => 'none', |
|
272 | - ) |
|
273 | - ); |
|
274 | - } |
|
275 | - |
|
276 | - |
|
277 | - /** |
|
278 | - * @param int $EVT_ID |
|
279 | - * @param boolean $include_expired |
|
280 | - * @param boolean $include_deleted |
|
281 | - * @return EE_Datetime |
|
282 | - * @throws EE_Error |
|
283 | - */ |
|
284 | - public function get_oldest_datetime_for_event($EVT_ID, $include_expired = false, $include_deleted = false) |
|
285 | - { |
|
286 | - $results = $this->get_datetimes_for_event_ordered_by_start_time( |
|
287 | - $EVT_ID, |
|
288 | - $include_expired, |
|
289 | - $include_deleted, |
|
290 | - 1 |
|
291 | - ); |
|
292 | - if ($results) { |
|
293 | - return array_shift($results); |
|
294 | - } |
|
295 | - return null; |
|
296 | - } |
|
297 | - |
|
298 | - |
|
299 | - /** |
|
300 | - * Gets the 'primary' datetime for an event. |
|
301 | - * |
|
302 | - * @param int $EVT_ID |
|
303 | - * @param bool $try_to_exclude_expired |
|
304 | - * @param bool $try_to_exclude_deleted |
|
305 | - * @return \EE_Datetime |
|
306 | - * @throws EE_Error |
|
307 | - */ |
|
308 | - public function get_primary_datetime_for_event( |
|
309 | - $EVT_ID, |
|
310 | - $try_to_exclude_expired = true, |
|
311 | - $try_to_exclude_deleted = true |
|
312 | - ) { |
|
313 | - if ($try_to_exclude_expired) { |
|
314 | - $non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false); |
|
315 | - if ($non_expired) { |
|
316 | - return $non_expired; |
|
317 | - } |
|
318 | - } |
|
319 | - if ($try_to_exclude_deleted) { |
|
320 | - $expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true); |
|
321 | - if ($expired_even) { |
|
322 | - return $expired_even; |
|
323 | - } |
|
324 | - } |
|
325 | - return $this->get_oldest_datetime_for_event($EVT_ID, true, true); |
|
326 | - } |
|
327 | - |
|
328 | - |
|
329 | - /** |
|
330 | - * Gets ALL the datetimes for an event (including trashed ones, for now), ordered |
|
331 | - * only by start date |
|
332 | - * |
|
333 | - * @param int $EVT_ID |
|
334 | - * @param boolean $include_expired |
|
335 | - * @param boolean $include_deleted |
|
336 | - * @param int $limit |
|
337 | - * @return EE_Datetime[] |
|
338 | - * @throws EE_Error |
|
339 | - */ |
|
340 | - public function get_datetimes_for_event_ordered_by_start_time( |
|
341 | - $EVT_ID, |
|
342 | - $include_expired = true, |
|
343 | - $include_deleted = true, |
|
344 | - $limit = null |
|
345 | - ) { |
|
346 | - // sanitize EVT_ID |
|
347 | - $EVT_ID = absint($EVT_ID); |
|
348 | - $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
349 | - $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
350 | - $query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc')); |
|
351 | - if (! $include_expired) { |
|
352 | - $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
353 | - } |
|
354 | - if ($include_deleted) { |
|
355 | - $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
356 | - } |
|
357 | - if ($limit) { |
|
358 | - $query_params['limit'] = $limit; |
|
359 | - } |
|
360 | - /** @var EE_Datetime[] $result */ |
|
361 | - $result = $this->get_all($query_params); |
|
362 | - $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
363 | - return $result; |
|
364 | - } |
|
365 | - |
|
366 | - |
|
367 | - /** |
|
368 | - * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered |
|
369 | - * only by start date |
|
370 | - * |
|
371 | - * @param int $TKT_ID |
|
372 | - * @param boolean $include_expired |
|
373 | - * @param boolean $include_deleted |
|
374 | - * @param int $limit |
|
375 | - * @return EE_Datetime[] |
|
376 | - * @throws EE_Error |
|
377 | - */ |
|
378 | - public function get_datetimes_for_ticket_ordered_by_start_time( |
|
379 | - $TKT_ID, |
|
380 | - $include_expired = true, |
|
381 | - $include_deleted = true, |
|
382 | - $limit = null |
|
383 | - ) { |
|
384 | - // sanitize TKT_ID |
|
385 | - $TKT_ID = absint($TKT_ID); |
|
386 | - $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
387 | - $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
388 | - $query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc')); |
|
389 | - if (! $include_expired) { |
|
390 | - $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
391 | - } |
|
392 | - if ($include_deleted) { |
|
393 | - $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
394 | - } |
|
395 | - if ($limit) { |
|
396 | - $query_params['limit'] = $limit; |
|
397 | - } |
|
398 | - /** @var EE_Datetime[] $result */ |
|
399 | - $result = $this->get_all($query_params); |
|
400 | - $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
401 | - return $result; |
|
402 | - } |
|
403 | - |
|
404 | - |
|
405 | - /** |
|
406 | - * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the |
|
407 | - * datetimes. |
|
408 | - * |
|
409 | - * @param int $TKT_ID ID of ticket to retrieve the datetimes for |
|
410 | - * @param boolean $include_expired whether to include expired datetimes or not |
|
411 | - * @param boolean $include_deleted whether to include trashed datetimes or not. |
|
412 | - * @param int|null $limit if null, no limit, if int then limit results by |
|
413 | - * that number |
|
414 | - * @return EE_Datetime[] |
|
415 | - * @throws EE_Error |
|
416 | - */ |
|
417 | - public function get_datetimes_for_ticket_ordered_by_DTT_order( |
|
418 | - $TKT_ID, |
|
419 | - $include_expired = true, |
|
420 | - $include_deleted = true, |
|
421 | - $limit = null |
|
422 | - ) { |
|
423 | - // sanitize id. |
|
424 | - $TKT_ID = absint($TKT_ID); |
|
425 | - $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
426 | - $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
427 | - $where_params = array('Ticket.TKT_ID' => $TKT_ID); |
|
428 | - $query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC')); |
|
429 | - if (! $include_expired) { |
|
430 | - $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
431 | - } |
|
432 | - if ($include_deleted) { |
|
433 | - $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
434 | - } |
|
435 | - if ($limit) { |
|
436 | - $query_params['limit'] = $limit; |
|
437 | - } |
|
438 | - /** @var EE_Datetime[] $result */ |
|
439 | - $result = $this->get_all($query_params); |
|
440 | - $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
441 | - return $result; |
|
442 | - } |
|
443 | - |
|
444 | - |
|
445 | - /** |
|
446 | - * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK |
|
447 | - * reason it doesn't exist, we consider the earliest event the most important) |
|
448 | - * |
|
449 | - * @param int $EVT_ID |
|
450 | - * @return EE_Datetime |
|
451 | - * @throws EE_Error |
|
452 | - */ |
|
453 | - public function get_most_important_datetime_for_event($EVT_ID) |
|
454 | - { |
|
455 | - $results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1); |
|
456 | - if ($results) { |
|
457 | - return array_shift($results); |
|
458 | - } |
|
459 | - return null; |
|
460 | - } |
|
461 | - |
|
462 | - |
|
463 | - /** |
|
464 | - * This returns a wpdb->results Array of all DTT month and years matching the incoming query params and |
|
465 | - * grouped by month and year. |
|
466 | - * |
|
467 | - * @param array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
468 | - * @param string $evt_active_status A string representing the evt active status to filter the months by. |
|
469 | - * Can be: |
|
470 | - * - '' = no filter |
|
471 | - * - upcoming = Published events with at least one upcoming datetime. |
|
472 | - * - expired = Events with all datetimes expired. |
|
473 | - * - active = Events that are published and have at least one datetime that |
|
474 | - * starts before now and ends after now. |
|
475 | - * - inactive = Events that are either not published. |
|
476 | - * @return EE_Base_Class[] |
|
477 | - * @throws EE_Error |
|
478 | - * @throws InvalidArgumentException |
|
479 | - * @throws InvalidArgumentException |
|
480 | - */ |
|
481 | - public function get_dtt_months_and_years($where_params, $evt_active_status = '') |
|
482 | - { |
|
483 | - $current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start'); |
|
484 | - $current_time_for_DTT_EVT_end = $this->current_time_for_query('DTT_EVT_end'); |
|
485 | - switch ($evt_active_status) { |
|
486 | - case 'upcoming': |
|
487 | - $where_params['Event.status'] = 'publish'; |
|
488 | - // if there are already query_params matching DTT_EVT_start then we need to modify that to add them. |
|
489 | - if (isset($where_params['DTT_EVT_start'])) { |
|
490 | - $where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start']; |
|
491 | - } |
|
492 | - $where_params['DTT_EVT_start'] = array('>', $current_time_for_DTT_EVT_start); |
|
493 | - break; |
|
494 | - case 'expired': |
|
495 | - if (isset($where_params['Event.status'])) { |
|
496 | - unset($where_params['Event.status']); |
|
497 | - } |
|
498 | - // get events to exclude |
|
499 | - $exclude_query[0] = array_merge( |
|
500 | - $where_params, |
|
501 | - array('DTT_EVT_end' => array('>', $current_time_for_DTT_EVT_end)) |
|
502 | - ); |
|
503 | - // first get all events that have datetimes where its not expired. |
|
504 | - $event_ids = $this->_get_all_wpdb_results( |
|
505 | - $exclude_query, |
|
506 | - OBJECT_K, |
|
507 | - 'Datetime.EVT_ID' |
|
508 | - ); |
|
509 | - $event_ids = array_keys($event_ids); |
|
510 | - if (isset($where_params['DTT_EVT_end'])) { |
|
511 | - $where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end']; |
|
512 | - } |
|
513 | - $where_params['DTT_EVT_end'] = array('<', $current_time_for_DTT_EVT_end); |
|
514 | - $where_params['Event.EVT_ID'] = array('NOT IN', $event_ids); |
|
515 | - break; |
|
516 | - case 'active': |
|
517 | - $where_params['Event.status'] = 'publish'; |
|
518 | - if (isset($where_params['DTT_EVT_start'])) { |
|
519 | - $where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start']; |
|
520 | - } |
|
521 | - if (isset($where_params['Datetime.DTT_EVT_end'])) { |
|
522 | - $where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end']; |
|
523 | - } |
|
524 | - $where_params['DTT_EVT_start'] = array('<', $current_time_for_DTT_EVT_start); |
|
525 | - $where_params['DTT_EVT_end'] = array('>', $current_time_for_DTT_EVT_end); |
|
526 | - break; |
|
527 | - case 'inactive': |
|
528 | - if (isset($where_params['Event.status'])) { |
|
529 | - unset($where_params['Event.status']); |
|
530 | - } |
|
531 | - if (isset($where_params['OR'])) { |
|
532 | - $where_params['AND']['OR'] = $where_params['OR']; |
|
533 | - } |
|
534 | - if (isset($where_params['DTT_EVT_end'])) { |
|
535 | - $where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end']; |
|
536 | - unset($where_params['DTT_EVT_end']); |
|
537 | - } |
|
538 | - if (isset($where_params['DTT_EVT_start'])) { |
|
539 | - $where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start']; |
|
540 | - unset($where_params['DTT_EVT_start']); |
|
541 | - } |
|
542 | - $where_params['AND']['Event.status'] = array('!=', 'publish'); |
|
543 | - break; |
|
544 | - } |
|
545 | - $query_params[0] = $where_params; |
|
546 | - $query_params['group_by'] = array('dtt_year', 'dtt_month'); |
|
547 | - $query_params['order_by'] = array('DTT_EVT_start' => 'DESC'); |
|
548 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset( |
|
549 | - $this->get_timezone(), |
|
550 | - 'DTT_EVT_start' |
|
551 | - ); |
|
552 | - $columns_to_select = array( |
|
553 | - 'dtt_year' => array('YEAR(' . $query_interval . ')', '%s'), |
|
554 | - 'dtt_month' => array('MONTHNAME(' . $query_interval . ')', '%s'), |
|
555 | - 'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'), |
|
556 | - ); |
|
557 | - return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select); |
|
558 | - } |
|
559 | - |
|
560 | - |
|
561 | - /** |
|
562 | - * Updates the DTT_sold attribute on each datetime (based on the registrations |
|
563 | - * for the tickets for each datetime) |
|
564 | - * |
|
565 | - * @param EE_Base_Class[]|EE_Datetime[] $datetimes |
|
566 | - * @throws EE_Error |
|
567 | - */ |
|
568 | - public function update_sold($datetimes) |
|
569 | - { |
|
570 | - EE_Error::doing_it_wrong( |
|
571 | - __FUNCTION__, |
|
572 | - esc_html__( |
|
573 | - 'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.', |
|
574 | - 'event_espresso' |
|
575 | - ), |
|
576 | - '4.9.32.rc.005' |
|
577 | - ); |
|
578 | - foreach ($datetimes as $datetime) { |
|
579 | - $datetime->update_sold(); |
|
580 | - } |
|
581 | - } |
|
582 | - |
|
583 | - |
|
584 | - /** |
|
585 | - * Gets the total number of tickets available at a particular datetime |
|
586 | - * (does NOT take into account the datetime's spaces available) |
|
587 | - * |
|
588 | - * @param int $DTT_ID |
|
589 | - * @param array $query_params |
|
590 | - * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF, IF there are NO |
|
591 | - * tickets attached to datetime then FALSE is returned. |
|
592 | - */ |
|
593 | - public function sum_tickets_currently_available_at_datetime($DTT_ID, array $query_params = array()) |
|
594 | - { |
|
595 | - $datetime = $this->get_one_by_ID($DTT_ID); |
|
596 | - if ($datetime instanceof EE_Datetime) { |
|
597 | - return $datetime->tickets_remaining($query_params); |
|
598 | - } |
|
599 | - return 0; |
|
600 | - } |
|
601 | - |
|
602 | - |
|
603 | - /** |
|
604 | - * This returns an array of counts of datetimes in the database for each Datetime status that can be queried. |
|
605 | - * |
|
606 | - * @param array $stati_to_include If included you can restrict the statuses we return counts for by including the |
|
607 | - * stati you want counts for as values in the array. An empty array returns counts |
|
608 | - * for all valid stati. |
|
609 | - * @param array $query_params If included can be used to refine the conditions for returning the count (i.e. |
|
610 | - * only for Datetimes connected to a specific event, or specific ticket. |
|
611 | - * @return array The value returned is an array indexed by Datetime Status and the values are the counts. The |
|
612 | - * @throws EE_Error |
|
613 | - * stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming |
|
614 | - * EE_Datetime::expired |
|
615 | - */ |
|
616 | - public function get_datetime_counts_by_status(array $stati_to_include = array(), array $query_params = array()) |
|
617 | - { |
|
618 | - // only accept where conditions for this query. |
|
619 | - $_where = isset($query_params[0]) ? $query_params[0] : array(); |
|
620 | - $status_query_args = array( |
|
621 | - EE_Datetime::active => array_merge( |
|
622 | - $_where, |
|
623 | - array('DTT_EVT_start' => array('<', time()), 'DTT_EVT_end' => array('>', time())) |
|
624 | - ), |
|
625 | - EE_Datetime::upcoming => array_merge( |
|
626 | - $_where, |
|
627 | - array('DTT_EVT_start' => array('>', time())) |
|
628 | - ), |
|
629 | - EE_Datetime::expired => array_merge( |
|
630 | - $_where, |
|
631 | - array('DTT_EVT_end' => array('<', time())) |
|
632 | - ), |
|
633 | - ); |
|
634 | - if (! empty($stati_to_include)) { |
|
635 | - foreach (array_keys($status_query_args) as $status) { |
|
636 | - if (! in_array($status, $stati_to_include, true)) { |
|
637 | - unset($status_query_args[ $status ]); |
|
638 | - } |
|
639 | - } |
|
640 | - } |
|
641 | - // loop through and query counts for each stati. |
|
642 | - $status_query_results = array(); |
|
643 | - foreach ($status_query_args as $status => $status_where_conditions) { |
|
644 | - $status_query_results[ $status ] = EEM_Datetime::count( |
|
645 | - array($status_where_conditions), |
|
646 | - 'DTT_ID', |
|
647 | - true |
|
648 | - ); |
|
649 | - } |
|
650 | - return $status_query_results; |
|
651 | - } |
|
652 | - |
|
653 | - |
|
654 | - /** |
|
655 | - * Returns the specific count for a given Datetime status matching any given query_params. |
|
656 | - * |
|
657 | - * @param string $status Valid string representation for Datetime status requested. (Defaults to Active). |
|
658 | - * @param array $query_params |
|
659 | - * @return int |
|
660 | - * @throws EE_Error |
|
661 | - */ |
|
662 | - public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array()) |
|
663 | - { |
|
664 | - $count = $this->get_datetime_counts_by_status(array($status), $query_params); |
|
665 | - return ! empty($count[ $status ]) ? $count[ $status ] : 0; |
|
666 | - } |
|
12 | + /** |
|
13 | + * @var EEM_Datetime $_instance |
|
14 | + */ |
|
15 | + protected static $_instance; |
|
16 | + |
|
17 | + |
|
18 | + /** |
|
19 | + * private constructor to prevent direct creation |
|
20 | + * |
|
21 | + * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings |
|
22 | + * (and any incoming timezone data that gets saved). |
|
23 | + * Note this just sends the timezone info to the date time model field objects. |
|
24 | + * Default is NULL |
|
25 | + * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
26 | + * @throws EE_Error |
|
27 | + * @throws InvalidArgumentException |
|
28 | + * @throws InvalidArgumentException |
|
29 | + */ |
|
30 | + protected function __construct($timezone) |
|
31 | + { |
|
32 | + $this->singular_item = esc_html__('Datetime', 'event_espresso'); |
|
33 | + $this->plural_item = esc_html__('Datetimes', 'event_espresso'); |
|
34 | + $this->_tables = array( |
|
35 | + 'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'), |
|
36 | + ); |
|
37 | + $this->_fields = array( |
|
38 | + 'Datetime' => array( |
|
39 | + 'DTT_ID' => new EE_Primary_Key_Int_Field( |
|
40 | + 'DTT_ID', |
|
41 | + esc_html__('Datetime ID', 'event_espresso') |
|
42 | + ), |
|
43 | + 'EVT_ID' => new EE_Foreign_Key_Int_Field( |
|
44 | + 'EVT_ID', |
|
45 | + esc_html__('Event ID', 'event_espresso'), |
|
46 | + false, |
|
47 | + 0, |
|
48 | + 'Event' |
|
49 | + ), |
|
50 | + 'DTT_name' => new EE_Plain_Text_Field( |
|
51 | + 'DTT_name', |
|
52 | + esc_html__('Datetime Name', 'event_espresso'), |
|
53 | + false, |
|
54 | + '' |
|
55 | + ), |
|
56 | + 'DTT_description' => new EE_Post_Content_Field( |
|
57 | + 'DTT_description', |
|
58 | + esc_html__('Description for Datetime', 'event_espresso'), |
|
59 | + false, |
|
60 | + '' |
|
61 | + ), |
|
62 | + 'DTT_EVT_start' => new EE_Datetime_Field( |
|
63 | + 'DTT_EVT_start', |
|
64 | + esc_html__('Start time/date of Event', 'event_espresso'), |
|
65 | + false, |
|
66 | + EE_Datetime_Field::now, |
|
67 | + $timezone |
|
68 | + ), |
|
69 | + 'DTT_EVT_end' => new EE_Datetime_Field( |
|
70 | + 'DTT_EVT_end', |
|
71 | + esc_html__('End time/date of Event', 'event_espresso'), |
|
72 | + false, |
|
73 | + EE_Datetime_Field::now, |
|
74 | + $timezone |
|
75 | + ), |
|
76 | + 'DTT_reg_limit' => new EE_Infinite_Integer_Field( |
|
77 | + 'DTT_reg_limit', |
|
78 | + esc_html__('Registration Limit for this time', 'event_espresso'), |
|
79 | + true, |
|
80 | + EE_INF |
|
81 | + ), |
|
82 | + 'DTT_sold' => new EE_Integer_Field( |
|
83 | + 'DTT_sold', |
|
84 | + esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'), |
|
85 | + true, |
|
86 | + 0 |
|
87 | + ), |
|
88 | + 'DTT_reserved' => new EE_Integer_Field( |
|
89 | + 'DTT_reserved', |
|
90 | + esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'), |
|
91 | + false, |
|
92 | + 0 |
|
93 | + ), |
|
94 | + 'DTT_is_primary' => new EE_Boolean_Field( |
|
95 | + 'DTT_is_primary', |
|
96 | + esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'), |
|
97 | + false, |
|
98 | + false |
|
99 | + ), |
|
100 | + 'DTT_order' => new EE_Integer_Field( |
|
101 | + 'DTT_order', |
|
102 | + esc_html__('The order in which the Datetime is displayed', 'event_espresso'), |
|
103 | + false, |
|
104 | + 0 |
|
105 | + ), |
|
106 | + 'DTT_parent' => new EE_Integer_Field( |
|
107 | + 'DTT_parent', |
|
108 | + esc_html__('Indicates what DTT_ID is the parent of this DTT_ID', 'event_espresso'), |
|
109 | + true, |
|
110 | + 0 |
|
111 | + ), |
|
112 | + 'DTT_deleted' => new EE_Trashed_Flag_Field( |
|
113 | + 'DTT_deleted', |
|
114 | + esc_html__('Flag indicating datetime is archived', 'event_espresso'), |
|
115 | + false, |
|
116 | + false |
|
117 | + ), |
|
118 | + ), |
|
119 | + ); |
|
120 | + $this->_model_relations = array( |
|
121 | + 'Ticket' => new EE_HABTM_Relation('Datetime_Ticket'), |
|
122 | + 'Event' => new EE_Belongs_To_Relation(), |
|
123 | + 'Checkin' => new EE_Has_Many_Relation(), |
|
124 | + ); |
|
125 | + $this->_model_chain_to_wp_user = 'Event'; |
|
126 | + // this model is generally available for reading |
|
127 | + $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public( |
|
128 | + 'Event' |
|
129 | + ); |
|
130 | + $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
131 | + 'Event' |
|
132 | + ); |
|
133 | + $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
134 | + 'Event' |
|
135 | + ); |
|
136 | + $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected( |
|
137 | + 'Event', |
|
138 | + EEM_Base::caps_edit |
|
139 | + ); |
|
140 | + parent::__construct($timezone); |
|
141 | + } |
|
142 | + |
|
143 | + |
|
144 | + /** |
|
145 | + * create new blank datetime |
|
146 | + * |
|
147 | + * @access public |
|
148 | + * @return EE_Datetime[] array on success, FALSE on fail |
|
149 | + * @throws EE_Error |
|
150 | + */ |
|
151 | + public function create_new_blank_datetime() |
|
152 | + { |
|
153 | + // makes sure timezone is always set. |
|
154 | + $timezone_string = $this->get_timezone(); |
|
155 | + $blank_datetime = EE_Datetime::new_instance( |
|
156 | + array( |
|
157 | + 'DTT_EVT_start' => $this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS, |
|
158 | + 'DTT_EVT_end' => $this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS, |
|
159 | + 'DTT_order' => 1, |
|
160 | + 'DTT_reg_limit' => EE_INF, |
|
161 | + ), |
|
162 | + $timezone_string |
|
163 | + ); |
|
164 | + $blank_datetime->set_start_time( |
|
165 | + $this->convert_datetime_for_query( |
|
166 | + 'DTT_EVT_start', |
|
167 | + '8am', |
|
168 | + 'ga', |
|
169 | + $timezone_string |
|
170 | + ) |
|
171 | + ); |
|
172 | + $blank_datetime->set_end_time( |
|
173 | + $this->convert_datetime_for_query( |
|
174 | + 'DTT_EVT_end', |
|
175 | + '5pm', |
|
176 | + 'ga', |
|
177 | + $timezone_string |
|
178 | + ) |
|
179 | + ); |
|
180 | + return array($blank_datetime); |
|
181 | + } |
|
182 | + |
|
183 | + |
|
184 | + /** |
|
185 | + * get event start date from db |
|
186 | + * |
|
187 | + * @access public |
|
188 | + * @param int $EVT_ID |
|
189 | + * @return EE_Datetime[] array on success, FALSE on fail |
|
190 | + * @throws EE_Error |
|
191 | + */ |
|
192 | + public function get_all_event_dates($EVT_ID = 0) |
|
193 | + { |
|
194 | + if (! $EVT_ID) { // on add_new_event event_id gets set to 0 |
|
195 | + return $this->create_new_blank_datetime(); |
|
196 | + } |
|
197 | + $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID); |
|
198 | + if (empty($results)) { |
|
199 | + return $this->create_new_blank_datetime(); |
|
200 | + } |
|
201 | + return $results; |
|
202 | + } |
|
203 | + |
|
204 | + |
|
205 | + /** |
|
206 | + * get all datetimes attached to an event ordered by the DTT_order field |
|
207 | + * |
|
208 | + * @public |
|
209 | + * @param int $EVT_ID event id |
|
210 | + * @param boolean $include_expired |
|
211 | + * @param boolean $include_deleted |
|
212 | + * @param int $limit If included then limit the count of results by |
|
213 | + * the given number |
|
214 | + * @return EE_Datetime[] |
|
215 | + * @throws EE_Error |
|
216 | + */ |
|
217 | + public function get_datetimes_for_event_ordered_by_DTT_order( |
|
218 | + $EVT_ID, |
|
219 | + $include_expired = true, |
|
220 | + $include_deleted = true, |
|
221 | + $limit = null |
|
222 | + ) { |
|
223 | + // sanitize EVT_ID |
|
224 | + $EVT_ID = absint($EVT_ID); |
|
225 | + $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
226 | + $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
227 | + $where_params = array('Event.EVT_ID' => $EVT_ID); |
|
228 | + $query_params = ! empty($limit) |
|
229 | + ? array( |
|
230 | + $where_params, |
|
231 | + 'limit' => $limit, |
|
232 | + 'order_by' => array('DTT_order' => 'ASC'), |
|
233 | + 'default_where_conditions' => 'none', |
|
234 | + ) |
|
235 | + : array( |
|
236 | + $where_params, |
|
237 | + 'order_by' => array('DTT_order' => 'ASC'), |
|
238 | + 'default_where_conditions' => 'none', |
|
239 | + ); |
|
240 | + if (! $include_expired) { |
|
241 | + $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
242 | + } |
|
243 | + if ($include_deleted) { |
|
244 | + $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
245 | + } |
|
246 | + /** @var EE_Datetime[] $result */ |
|
247 | + $result = $this->get_all($query_params); |
|
248 | + $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
249 | + return $result; |
|
250 | + } |
|
251 | + |
|
252 | + |
|
253 | + /** |
|
254 | + * Gets the datetimes for the event (with the given limit), and orders them by "importance". |
|
255 | + * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW), |
|
256 | + * and then the earlier datetimes are the most important. |
|
257 | + * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet. |
|
258 | + * |
|
259 | + * @param int $EVT_ID |
|
260 | + * @param int $limit |
|
261 | + * @return EE_Datetime[]|EE_Base_Class[] |
|
262 | + * @throws EE_Error |
|
263 | + */ |
|
264 | + public function get_datetimes_for_event_ordered_by_importance($EVT_ID = 0, $limit = null) |
|
265 | + { |
|
266 | + return $this->get_all( |
|
267 | + array( |
|
268 | + array('Event.EVT_ID' => $EVT_ID), |
|
269 | + 'limit' => $limit, |
|
270 | + 'order_by' => array('DTT_EVT_start' => 'ASC'), |
|
271 | + 'default_where_conditions' => 'none', |
|
272 | + ) |
|
273 | + ); |
|
274 | + } |
|
275 | + |
|
276 | + |
|
277 | + /** |
|
278 | + * @param int $EVT_ID |
|
279 | + * @param boolean $include_expired |
|
280 | + * @param boolean $include_deleted |
|
281 | + * @return EE_Datetime |
|
282 | + * @throws EE_Error |
|
283 | + */ |
|
284 | + public function get_oldest_datetime_for_event($EVT_ID, $include_expired = false, $include_deleted = false) |
|
285 | + { |
|
286 | + $results = $this->get_datetimes_for_event_ordered_by_start_time( |
|
287 | + $EVT_ID, |
|
288 | + $include_expired, |
|
289 | + $include_deleted, |
|
290 | + 1 |
|
291 | + ); |
|
292 | + if ($results) { |
|
293 | + return array_shift($results); |
|
294 | + } |
|
295 | + return null; |
|
296 | + } |
|
297 | + |
|
298 | + |
|
299 | + /** |
|
300 | + * Gets the 'primary' datetime for an event. |
|
301 | + * |
|
302 | + * @param int $EVT_ID |
|
303 | + * @param bool $try_to_exclude_expired |
|
304 | + * @param bool $try_to_exclude_deleted |
|
305 | + * @return \EE_Datetime |
|
306 | + * @throws EE_Error |
|
307 | + */ |
|
308 | + public function get_primary_datetime_for_event( |
|
309 | + $EVT_ID, |
|
310 | + $try_to_exclude_expired = true, |
|
311 | + $try_to_exclude_deleted = true |
|
312 | + ) { |
|
313 | + if ($try_to_exclude_expired) { |
|
314 | + $non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false); |
|
315 | + if ($non_expired) { |
|
316 | + return $non_expired; |
|
317 | + } |
|
318 | + } |
|
319 | + if ($try_to_exclude_deleted) { |
|
320 | + $expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true); |
|
321 | + if ($expired_even) { |
|
322 | + return $expired_even; |
|
323 | + } |
|
324 | + } |
|
325 | + return $this->get_oldest_datetime_for_event($EVT_ID, true, true); |
|
326 | + } |
|
327 | + |
|
328 | + |
|
329 | + /** |
|
330 | + * Gets ALL the datetimes for an event (including trashed ones, for now), ordered |
|
331 | + * only by start date |
|
332 | + * |
|
333 | + * @param int $EVT_ID |
|
334 | + * @param boolean $include_expired |
|
335 | + * @param boolean $include_deleted |
|
336 | + * @param int $limit |
|
337 | + * @return EE_Datetime[] |
|
338 | + * @throws EE_Error |
|
339 | + */ |
|
340 | + public function get_datetimes_for_event_ordered_by_start_time( |
|
341 | + $EVT_ID, |
|
342 | + $include_expired = true, |
|
343 | + $include_deleted = true, |
|
344 | + $limit = null |
|
345 | + ) { |
|
346 | + // sanitize EVT_ID |
|
347 | + $EVT_ID = absint($EVT_ID); |
|
348 | + $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
349 | + $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
350 | + $query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc')); |
|
351 | + if (! $include_expired) { |
|
352 | + $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
353 | + } |
|
354 | + if ($include_deleted) { |
|
355 | + $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
356 | + } |
|
357 | + if ($limit) { |
|
358 | + $query_params['limit'] = $limit; |
|
359 | + } |
|
360 | + /** @var EE_Datetime[] $result */ |
|
361 | + $result = $this->get_all($query_params); |
|
362 | + $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
363 | + return $result; |
|
364 | + } |
|
365 | + |
|
366 | + |
|
367 | + /** |
|
368 | + * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered |
|
369 | + * only by start date |
|
370 | + * |
|
371 | + * @param int $TKT_ID |
|
372 | + * @param boolean $include_expired |
|
373 | + * @param boolean $include_deleted |
|
374 | + * @param int $limit |
|
375 | + * @return EE_Datetime[] |
|
376 | + * @throws EE_Error |
|
377 | + */ |
|
378 | + public function get_datetimes_for_ticket_ordered_by_start_time( |
|
379 | + $TKT_ID, |
|
380 | + $include_expired = true, |
|
381 | + $include_deleted = true, |
|
382 | + $limit = null |
|
383 | + ) { |
|
384 | + // sanitize TKT_ID |
|
385 | + $TKT_ID = absint($TKT_ID); |
|
386 | + $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
387 | + $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
388 | + $query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc')); |
|
389 | + if (! $include_expired) { |
|
390 | + $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
391 | + } |
|
392 | + if ($include_deleted) { |
|
393 | + $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
394 | + } |
|
395 | + if ($limit) { |
|
396 | + $query_params['limit'] = $limit; |
|
397 | + } |
|
398 | + /** @var EE_Datetime[] $result */ |
|
399 | + $result = $this->get_all($query_params); |
|
400 | + $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
401 | + return $result; |
|
402 | + } |
|
403 | + |
|
404 | + |
|
405 | + /** |
|
406 | + * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the |
|
407 | + * datetimes. |
|
408 | + * |
|
409 | + * @param int $TKT_ID ID of ticket to retrieve the datetimes for |
|
410 | + * @param boolean $include_expired whether to include expired datetimes or not |
|
411 | + * @param boolean $include_deleted whether to include trashed datetimes or not. |
|
412 | + * @param int|null $limit if null, no limit, if int then limit results by |
|
413 | + * that number |
|
414 | + * @return EE_Datetime[] |
|
415 | + * @throws EE_Error |
|
416 | + */ |
|
417 | + public function get_datetimes_for_ticket_ordered_by_DTT_order( |
|
418 | + $TKT_ID, |
|
419 | + $include_expired = true, |
|
420 | + $include_deleted = true, |
|
421 | + $limit = null |
|
422 | + ) { |
|
423 | + // sanitize id. |
|
424 | + $TKT_ID = absint($TKT_ID); |
|
425 | + $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object(); |
|
426 | + $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db); |
|
427 | + $where_params = array('Ticket.TKT_ID' => $TKT_ID); |
|
428 | + $query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC')); |
|
429 | + if (! $include_expired) { |
|
430 | + $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true)); |
|
431 | + } |
|
432 | + if ($include_deleted) { |
|
433 | + $query_params[0]['DTT_deleted'] = array('IN', array(true, false)); |
|
434 | + } |
|
435 | + if ($limit) { |
|
436 | + $query_params['limit'] = $limit; |
|
437 | + } |
|
438 | + /** @var EE_Datetime[] $result */ |
|
439 | + $result = $this->get_all($query_params); |
|
440 | + $this->assume_values_already_prepared_by_model_object($old_assumption); |
|
441 | + return $result; |
|
442 | + } |
|
443 | + |
|
444 | + |
|
445 | + /** |
|
446 | + * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK |
|
447 | + * reason it doesn't exist, we consider the earliest event the most important) |
|
448 | + * |
|
449 | + * @param int $EVT_ID |
|
450 | + * @return EE_Datetime |
|
451 | + * @throws EE_Error |
|
452 | + */ |
|
453 | + public function get_most_important_datetime_for_event($EVT_ID) |
|
454 | + { |
|
455 | + $results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1); |
|
456 | + if ($results) { |
|
457 | + return array_shift($results); |
|
458 | + } |
|
459 | + return null; |
|
460 | + } |
|
461 | + |
|
462 | + |
|
463 | + /** |
|
464 | + * This returns a wpdb->results Array of all DTT month and years matching the incoming query params and |
|
465 | + * grouped by month and year. |
|
466 | + * |
|
467 | + * @param array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
468 | + * @param string $evt_active_status A string representing the evt active status to filter the months by. |
|
469 | + * Can be: |
|
470 | + * - '' = no filter |
|
471 | + * - upcoming = Published events with at least one upcoming datetime. |
|
472 | + * - expired = Events with all datetimes expired. |
|
473 | + * - active = Events that are published and have at least one datetime that |
|
474 | + * starts before now and ends after now. |
|
475 | + * - inactive = Events that are either not published. |
|
476 | + * @return EE_Base_Class[] |
|
477 | + * @throws EE_Error |
|
478 | + * @throws InvalidArgumentException |
|
479 | + * @throws InvalidArgumentException |
|
480 | + */ |
|
481 | + public function get_dtt_months_and_years($where_params, $evt_active_status = '') |
|
482 | + { |
|
483 | + $current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start'); |
|
484 | + $current_time_for_DTT_EVT_end = $this->current_time_for_query('DTT_EVT_end'); |
|
485 | + switch ($evt_active_status) { |
|
486 | + case 'upcoming': |
|
487 | + $where_params['Event.status'] = 'publish'; |
|
488 | + // if there are already query_params matching DTT_EVT_start then we need to modify that to add them. |
|
489 | + if (isset($where_params['DTT_EVT_start'])) { |
|
490 | + $where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start']; |
|
491 | + } |
|
492 | + $where_params['DTT_EVT_start'] = array('>', $current_time_for_DTT_EVT_start); |
|
493 | + break; |
|
494 | + case 'expired': |
|
495 | + if (isset($where_params['Event.status'])) { |
|
496 | + unset($where_params['Event.status']); |
|
497 | + } |
|
498 | + // get events to exclude |
|
499 | + $exclude_query[0] = array_merge( |
|
500 | + $where_params, |
|
501 | + array('DTT_EVT_end' => array('>', $current_time_for_DTT_EVT_end)) |
|
502 | + ); |
|
503 | + // first get all events that have datetimes where its not expired. |
|
504 | + $event_ids = $this->_get_all_wpdb_results( |
|
505 | + $exclude_query, |
|
506 | + OBJECT_K, |
|
507 | + 'Datetime.EVT_ID' |
|
508 | + ); |
|
509 | + $event_ids = array_keys($event_ids); |
|
510 | + if (isset($where_params['DTT_EVT_end'])) { |
|
511 | + $where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end']; |
|
512 | + } |
|
513 | + $where_params['DTT_EVT_end'] = array('<', $current_time_for_DTT_EVT_end); |
|
514 | + $where_params['Event.EVT_ID'] = array('NOT IN', $event_ids); |
|
515 | + break; |
|
516 | + case 'active': |
|
517 | + $where_params['Event.status'] = 'publish'; |
|
518 | + if (isset($where_params['DTT_EVT_start'])) { |
|
519 | + $where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start']; |
|
520 | + } |
|
521 | + if (isset($where_params['Datetime.DTT_EVT_end'])) { |
|
522 | + $where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end']; |
|
523 | + } |
|
524 | + $where_params['DTT_EVT_start'] = array('<', $current_time_for_DTT_EVT_start); |
|
525 | + $where_params['DTT_EVT_end'] = array('>', $current_time_for_DTT_EVT_end); |
|
526 | + break; |
|
527 | + case 'inactive': |
|
528 | + if (isset($where_params['Event.status'])) { |
|
529 | + unset($where_params['Event.status']); |
|
530 | + } |
|
531 | + if (isset($where_params['OR'])) { |
|
532 | + $where_params['AND']['OR'] = $where_params['OR']; |
|
533 | + } |
|
534 | + if (isset($where_params['DTT_EVT_end'])) { |
|
535 | + $where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end']; |
|
536 | + unset($where_params['DTT_EVT_end']); |
|
537 | + } |
|
538 | + if (isset($where_params['DTT_EVT_start'])) { |
|
539 | + $where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start']; |
|
540 | + unset($where_params['DTT_EVT_start']); |
|
541 | + } |
|
542 | + $where_params['AND']['Event.status'] = array('!=', 'publish'); |
|
543 | + break; |
|
544 | + } |
|
545 | + $query_params[0] = $where_params; |
|
546 | + $query_params['group_by'] = array('dtt_year', 'dtt_month'); |
|
547 | + $query_params['order_by'] = array('DTT_EVT_start' => 'DESC'); |
|
548 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset( |
|
549 | + $this->get_timezone(), |
|
550 | + 'DTT_EVT_start' |
|
551 | + ); |
|
552 | + $columns_to_select = array( |
|
553 | + 'dtt_year' => array('YEAR(' . $query_interval . ')', '%s'), |
|
554 | + 'dtt_month' => array('MONTHNAME(' . $query_interval . ')', '%s'), |
|
555 | + 'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'), |
|
556 | + ); |
|
557 | + return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select); |
|
558 | + } |
|
559 | + |
|
560 | + |
|
561 | + /** |
|
562 | + * Updates the DTT_sold attribute on each datetime (based on the registrations |
|
563 | + * for the tickets for each datetime) |
|
564 | + * |
|
565 | + * @param EE_Base_Class[]|EE_Datetime[] $datetimes |
|
566 | + * @throws EE_Error |
|
567 | + */ |
|
568 | + public function update_sold($datetimes) |
|
569 | + { |
|
570 | + EE_Error::doing_it_wrong( |
|
571 | + __FUNCTION__, |
|
572 | + esc_html__( |
|
573 | + 'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.', |
|
574 | + 'event_espresso' |
|
575 | + ), |
|
576 | + '4.9.32.rc.005' |
|
577 | + ); |
|
578 | + foreach ($datetimes as $datetime) { |
|
579 | + $datetime->update_sold(); |
|
580 | + } |
|
581 | + } |
|
582 | + |
|
583 | + |
|
584 | + /** |
|
585 | + * Gets the total number of tickets available at a particular datetime |
|
586 | + * (does NOT take into account the datetime's spaces available) |
|
587 | + * |
|
588 | + * @param int $DTT_ID |
|
589 | + * @param array $query_params |
|
590 | + * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF, IF there are NO |
|
591 | + * tickets attached to datetime then FALSE is returned. |
|
592 | + */ |
|
593 | + public function sum_tickets_currently_available_at_datetime($DTT_ID, array $query_params = array()) |
|
594 | + { |
|
595 | + $datetime = $this->get_one_by_ID($DTT_ID); |
|
596 | + if ($datetime instanceof EE_Datetime) { |
|
597 | + return $datetime->tickets_remaining($query_params); |
|
598 | + } |
|
599 | + return 0; |
|
600 | + } |
|
601 | + |
|
602 | + |
|
603 | + /** |
|
604 | + * This returns an array of counts of datetimes in the database for each Datetime status that can be queried. |
|
605 | + * |
|
606 | + * @param array $stati_to_include If included you can restrict the statuses we return counts for by including the |
|
607 | + * stati you want counts for as values in the array. An empty array returns counts |
|
608 | + * for all valid stati. |
|
609 | + * @param array $query_params If included can be used to refine the conditions for returning the count (i.e. |
|
610 | + * only for Datetimes connected to a specific event, or specific ticket. |
|
611 | + * @return array The value returned is an array indexed by Datetime Status and the values are the counts. The |
|
612 | + * @throws EE_Error |
|
613 | + * stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming |
|
614 | + * EE_Datetime::expired |
|
615 | + */ |
|
616 | + public function get_datetime_counts_by_status(array $stati_to_include = array(), array $query_params = array()) |
|
617 | + { |
|
618 | + // only accept where conditions for this query. |
|
619 | + $_where = isset($query_params[0]) ? $query_params[0] : array(); |
|
620 | + $status_query_args = array( |
|
621 | + EE_Datetime::active => array_merge( |
|
622 | + $_where, |
|
623 | + array('DTT_EVT_start' => array('<', time()), 'DTT_EVT_end' => array('>', time())) |
|
624 | + ), |
|
625 | + EE_Datetime::upcoming => array_merge( |
|
626 | + $_where, |
|
627 | + array('DTT_EVT_start' => array('>', time())) |
|
628 | + ), |
|
629 | + EE_Datetime::expired => array_merge( |
|
630 | + $_where, |
|
631 | + array('DTT_EVT_end' => array('<', time())) |
|
632 | + ), |
|
633 | + ); |
|
634 | + if (! empty($stati_to_include)) { |
|
635 | + foreach (array_keys($status_query_args) as $status) { |
|
636 | + if (! in_array($status, $stati_to_include, true)) { |
|
637 | + unset($status_query_args[ $status ]); |
|
638 | + } |
|
639 | + } |
|
640 | + } |
|
641 | + // loop through and query counts for each stati. |
|
642 | + $status_query_results = array(); |
|
643 | + foreach ($status_query_args as $status => $status_where_conditions) { |
|
644 | + $status_query_results[ $status ] = EEM_Datetime::count( |
|
645 | + array($status_where_conditions), |
|
646 | + 'DTT_ID', |
|
647 | + true |
|
648 | + ); |
|
649 | + } |
|
650 | + return $status_query_results; |
|
651 | + } |
|
652 | + |
|
653 | + |
|
654 | + /** |
|
655 | + * Returns the specific count for a given Datetime status matching any given query_params. |
|
656 | + * |
|
657 | + * @param string $status Valid string representation for Datetime status requested. (Defaults to Active). |
|
658 | + * @param array $query_params |
|
659 | + * @return int |
|
660 | + * @throws EE_Error |
|
661 | + */ |
|
662 | + public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array()) |
|
663 | + { |
|
664 | + $count = $this->get_datetime_counts_by_status(array($status), $query_params); |
|
665 | + return ! empty($count[ $status ]) ? $count[ $status ] : 0; |
|
666 | + } |
|
667 | 667 | } |
@@ -11,66 +11,66 @@ |
||
11 | 11 | */ |
12 | 12 | class EEM_Currency extends EEM_Base |
13 | 13 | { |
14 | - // private instance of the Attendee object |
|
15 | - protected static $_instance = null; |
|
14 | + // private instance of the Attendee object |
|
15 | + protected static $_instance = null; |
|
16 | 16 | |
17 | - protected function __construct($timezone = null) |
|
18 | - { |
|
19 | - $this->singular_item = __('Currency', 'event_espresso'); |
|
20 | - $this->plural_item = __('Currencies', 'event_espresso'); |
|
21 | - $this->_tables = array( |
|
22 | - 'Currency'=> new EE_Primary_Table('esp_currency', 'CUR_code') |
|
23 | - ); |
|
24 | - $this->_fields = array( |
|
25 | - 'Currency'=>array( |
|
26 | - 'CUR_code'=> new EE_Primary_Key_String_Field('CUR_code', __('Currency Code', 'event_espresso')), |
|
27 | - 'CUR_single' => new EE_Plain_Text_Field('CUR_single', __('Currency Name Singular', 'event_espresso'), false), |
|
28 | - 'CUR_plural' => new EE_Plain_Text_Field('CUR_plural', __('Currency Name Plural', 'event_espresso'), false), |
|
29 | - 'CUR_sign' => new EE_Plain_Text_Field('CUR_sign', __('Currency Sign', 'event_espresso'), false), |
|
30 | - 'CUR_dec_plc' => new EE_Integer_Field('CUR_dec_plc', __('Currency Decimal Places', 'event_espresso'), false, 2), |
|
31 | - 'CUR_active'=>new EE_Boolean_Field('CUR_active', __('Active?', 'event_espresso'), false, true), |
|
32 | - )); |
|
33 | - $this->_model_relations = array( |
|
34 | - 'Payment_Method'=>new EE_HABTM_Relation('Currency_Payment_Method'), |
|
35 | - ); |
|
36 | - // this model is generally available for reading |
|
37 | - $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public(); |
|
17 | + protected function __construct($timezone = null) |
|
18 | + { |
|
19 | + $this->singular_item = __('Currency', 'event_espresso'); |
|
20 | + $this->plural_item = __('Currencies', 'event_espresso'); |
|
21 | + $this->_tables = array( |
|
22 | + 'Currency'=> new EE_Primary_Table('esp_currency', 'CUR_code') |
|
23 | + ); |
|
24 | + $this->_fields = array( |
|
25 | + 'Currency'=>array( |
|
26 | + 'CUR_code'=> new EE_Primary_Key_String_Field('CUR_code', __('Currency Code', 'event_espresso')), |
|
27 | + 'CUR_single' => new EE_Plain_Text_Field('CUR_single', __('Currency Name Singular', 'event_espresso'), false), |
|
28 | + 'CUR_plural' => new EE_Plain_Text_Field('CUR_plural', __('Currency Name Plural', 'event_espresso'), false), |
|
29 | + 'CUR_sign' => new EE_Plain_Text_Field('CUR_sign', __('Currency Sign', 'event_espresso'), false), |
|
30 | + 'CUR_dec_plc' => new EE_Integer_Field('CUR_dec_plc', __('Currency Decimal Places', 'event_espresso'), false, 2), |
|
31 | + 'CUR_active'=>new EE_Boolean_Field('CUR_active', __('Active?', 'event_espresso'), false, true), |
|
32 | + )); |
|
33 | + $this->_model_relations = array( |
|
34 | + 'Payment_Method'=>new EE_HABTM_Relation('Currency_Payment_Method'), |
|
35 | + ); |
|
36 | + // this model is generally available for reading |
|
37 | + $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public(); |
|
38 | 38 | |
39 | - parent::__construct($timezone); |
|
40 | - } |
|
39 | + parent::__construct($timezone); |
|
40 | + } |
|
41 | 41 | |
42 | - /** |
|
43 | - * Gets all thea ctive currencies, and orders them by their singular name, and then their code |
|
44 | - * (may be overridden) |
|
45 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
46 | - * @return EE_Currency[] |
|
47 | - */ |
|
48 | - public function get_all_active($query_params = array()) |
|
49 | - { |
|
50 | - $query_params[0]['CUR_active'] = true; |
|
51 | - if (! isset($query_params['order_by'])) { |
|
52 | - $query_params['order_by'] = array('CUR_code'=>'ASC','CUR_single'=>'ASC'); |
|
53 | - } |
|
54 | - return $this->get_all($query_params); |
|
55 | - } |
|
56 | - /** |
|
57 | - * Gets all the currencies which can be used by that payment method type |
|
58 | - * @param EE_PMT_Base $payment_method_type |
|
59 | - * @return EE_Currency[] |
|
60 | - */ |
|
61 | - public function get_all_currencies_usable_by($payment_method_type) |
|
62 | - { |
|
63 | - if ($payment_method_type instanceof EE_PMT_Base && |
|
64 | - $payment_method_type->get_gateway()) { |
|
65 | - $currencies_supported = $payment_method_type->get_gateway()->currencies_supported(); |
|
66 | - } else { |
|
67 | - $currencies_supported = EE_Gateway::all_currencies_supported; |
|
68 | - } |
|
69 | - if ($currencies_supported == EE_Gateway::all_currencies_supported || empty($currencies_supported)) { |
|
70 | - $currencies = $this->get_all_active(); |
|
71 | - } else { |
|
72 | - $currencies = $this->get_all_active(array(array('CUR_code'=>array('IN',$currencies_supported)))); |
|
73 | - } |
|
74 | - return $currencies; |
|
75 | - } |
|
42 | + /** |
|
43 | + * Gets all thea ctive currencies, and orders them by their singular name, and then their code |
|
44 | + * (may be overridden) |
|
45 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
46 | + * @return EE_Currency[] |
|
47 | + */ |
|
48 | + public function get_all_active($query_params = array()) |
|
49 | + { |
|
50 | + $query_params[0]['CUR_active'] = true; |
|
51 | + if (! isset($query_params['order_by'])) { |
|
52 | + $query_params['order_by'] = array('CUR_code'=>'ASC','CUR_single'=>'ASC'); |
|
53 | + } |
|
54 | + return $this->get_all($query_params); |
|
55 | + } |
|
56 | + /** |
|
57 | + * Gets all the currencies which can be used by that payment method type |
|
58 | + * @param EE_PMT_Base $payment_method_type |
|
59 | + * @return EE_Currency[] |
|
60 | + */ |
|
61 | + public function get_all_currencies_usable_by($payment_method_type) |
|
62 | + { |
|
63 | + if ($payment_method_type instanceof EE_PMT_Base && |
|
64 | + $payment_method_type->get_gateway()) { |
|
65 | + $currencies_supported = $payment_method_type->get_gateway()->currencies_supported(); |
|
66 | + } else { |
|
67 | + $currencies_supported = EE_Gateway::all_currencies_supported; |
|
68 | + } |
|
69 | + if ($currencies_supported == EE_Gateway::all_currencies_supported || empty($currencies_supported)) { |
|
70 | + $currencies = $this->get_all_active(); |
|
71 | + } else { |
|
72 | + $currencies = $this->get_all_active(array(array('CUR_code'=>array('IN',$currencies_supported)))); |
|
73 | + } |
|
74 | + return $currencies; |
|
75 | + } |
|
76 | 76 | } |
@@ -20,381 +20,381 @@ |
||
20 | 20 | class EEM_Payment_Method extends EEM_Base |
21 | 21 | { |
22 | 22 | |
23 | - const scope_cart = 'CART'; |
|
24 | - |
|
25 | - const scope_admin = 'ADMIN'; |
|
26 | - |
|
27 | - const scope_api = 'API'; |
|
28 | - |
|
29 | - /** |
|
30 | - * |
|
31 | - * @type EEM_Payment_Method |
|
32 | - */ |
|
33 | - protected static $_instance = null; |
|
34 | - |
|
35 | - |
|
36 | - |
|
37 | - /** |
|
38 | - * private constructor to prevent direct creation |
|
39 | - * @Constructor |
|
40 | - * @access protected |
|
41 | - * @return EEM_Payment_Method |
|
42 | - */ |
|
43 | - protected function __construct($timezone = null) |
|
44 | - { |
|
45 | - $this->singlular_item = __('Payment Method', 'event_espresso'); |
|
46 | - $this->plural_item = __('Payment Methods', 'event_espresso'); |
|
47 | - $this->_tables = array( 'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID') ); |
|
48 | - $this->_fields = array( |
|
49 | - 'Payment_Method' => array( |
|
50 | - 'PMD_ID' => new EE_Primary_Key_Int_Field('PMD_ID', __("ID", 'event_espresso')), |
|
51 | - 'PMD_type' => new EE_Plain_Text_Field('PMD_type', __("Payment Method Type", 'event_espresso'), false, 'Admin_Only'), |
|
52 | - 'PMD_name' => new EE_Plain_Text_Field('PMD_name', __("Name", 'event_espresso'), false), |
|
53 | - 'PMD_desc' => new EE_Post_Content_Field('PMD_desc', __("Description", 'event_espresso'), false, ''), |
|
54 | - 'PMD_admin_name' => new EE_Plain_Text_Field('PMD_admin_name', __("Admin-Only Name", 'event_espresso'), true), |
|
55 | - 'PMD_admin_desc' => new EE_Post_Content_Field('PMD_admin_desc', __("Admin-Only Description", 'event_espresso'), true), |
|
56 | - 'PMD_slug' => new EE_Slug_Field('PMD_slug', __("Slug", 'event_espresso'), false), |
|
57 | - 'PMD_order' => new EE_Integer_Field('PMD_order', __("Order", 'event_espresso'), false, 0), |
|
58 | - 'PMD_debug_mode' => new EE_Boolean_Field('PMD_debug_mode', __("Debug Mode On?", 'event_espresso'), false, false), |
|
59 | - 'PMD_wp_user' => new EE_WP_User_Field('PMD_wp_user', __("Payment Method Creator ID", 'event_espresso'), false), |
|
60 | - 'PMD_open_by_default' => new EE_Boolean_Field('PMD_open_by_default', __("Open by Default?", 'event_espresso'), false, false), 'PMD_button_url' => new EE_Plain_Text_Field('PMD_button_url', __("Button URL", 'event_espresso'), true, ''), |
|
61 | - 'PMD_scope' => new EE_Serialized_Text_Field('PMD_scope', __("Usable From?", 'event_espresso'), false, array()), // possible values currently are 'CART','ADMIN','API' |
|
62 | - ) ); |
|
63 | - $this->_model_relations = array( |
|
23 | + const scope_cart = 'CART'; |
|
24 | + |
|
25 | + const scope_admin = 'ADMIN'; |
|
26 | + |
|
27 | + const scope_api = 'API'; |
|
28 | + |
|
29 | + /** |
|
30 | + * |
|
31 | + * @type EEM_Payment_Method |
|
32 | + */ |
|
33 | + protected static $_instance = null; |
|
34 | + |
|
35 | + |
|
36 | + |
|
37 | + /** |
|
38 | + * private constructor to prevent direct creation |
|
39 | + * @Constructor |
|
40 | + * @access protected |
|
41 | + * @return EEM_Payment_Method |
|
42 | + */ |
|
43 | + protected function __construct($timezone = null) |
|
44 | + { |
|
45 | + $this->singlular_item = __('Payment Method', 'event_espresso'); |
|
46 | + $this->plural_item = __('Payment Methods', 'event_espresso'); |
|
47 | + $this->_tables = array( 'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID') ); |
|
48 | + $this->_fields = array( |
|
49 | + 'Payment_Method' => array( |
|
50 | + 'PMD_ID' => new EE_Primary_Key_Int_Field('PMD_ID', __("ID", 'event_espresso')), |
|
51 | + 'PMD_type' => new EE_Plain_Text_Field('PMD_type', __("Payment Method Type", 'event_espresso'), false, 'Admin_Only'), |
|
52 | + 'PMD_name' => new EE_Plain_Text_Field('PMD_name', __("Name", 'event_espresso'), false), |
|
53 | + 'PMD_desc' => new EE_Post_Content_Field('PMD_desc', __("Description", 'event_espresso'), false, ''), |
|
54 | + 'PMD_admin_name' => new EE_Plain_Text_Field('PMD_admin_name', __("Admin-Only Name", 'event_espresso'), true), |
|
55 | + 'PMD_admin_desc' => new EE_Post_Content_Field('PMD_admin_desc', __("Admin-Only Description", 'event_espresso'), true), |
|
56 | + 'PMD_slug' => new EE_Slug_Field('PMD_slug', __("Slug", 'event_espresso'), false), |
|
57 | + 'PMD_order' => new EE_Integer_Field('PMD_order', __("Order", 'event_espresso'), false, 0), |
|
58 | + 'PMD_debug_mode' => new EE_Boolean_Field('PMD_debug_mode', __("Debug Mode On?", 'event_espresso'), false, false), |
|
59 | + 'PMD_wp_user' => new EE_WP_User_Field('PMD_wp_user', __("Payment Method Creator ID", 'event_espresso'), false), |
|
60 | + 'PMD_open_by_default' => new EE_Boolean_Field('PMD_open_by_default', __("Open by Default?", 'event_espresso'), false, false), 'PMD_button_url' => new EE_Plain_Text_Field('PMD_button_url', __("Button URL", 'event_espresso'), true, ''), |
|
61 | + 'PMD_scope' => new EE_Serialized_Text_Field('PMD_scope', __("Usable From?", 'event_espresso'), false, array()), // possible values currently are 'CART','ADMIN','API' |
|
62 | + ) ); |
|
63 | + $this->_model_relations = array( |
|
64 | 64 | // 'Event'=>new EE_HABTM_Relation('Event_Payment_Method'), |
65 | - 'Payment' => new EE_Has_Many_Relation(), |
|
66 | - 'Currency' => new EE_HABTM_Relation('Currency_Payment_Method'), |
|
67 | - 'Transaction' => new EE_Has_Many_Relation(), |
|
68 | - 'WP_User' => new EE_Belongs_To_Relation(), |
|
69 | - ); |
|
70 | - parent::__construct($timezone); |
|
71 | - } |
|
72 | - |
|
73 | - |
|
74 | - |
|
75 | - /** |
|
76 | - * Gets one by the slug provided |
|
77 | - * @param string $slug |
|
78 | - * @return EE_Payment_Method |
|
79 | - */ |
|
80 | - public function get_one_by_slug($slug) |
|
81 | - { |
|
82 | - return $this->get_one(array( array( 'PMD_slug' => $slug ) )); |
|
83 | - } |
|
84 | - |
|
85 | - |
|
86 | - |
|
87 | - /** |
|
88 | - * Gets all the acceptable scopes for payment methods. |
|
89 | - * Keys are their names as store din the DB, and values are nice names for displaying them |
|
90 | - * @return array |
|
91 | - */ |
|
92 | - public function scopes() |
|
93 | - { |
|
94 | - return apply_filters( |
|
95 | - 'FHEE__EEM_Payment_Method__scopes', |
|
96 | - array( |
|
97 | - self::scope_cart => __("Front-end Registration Page", 'event_espresso'), |
|
98 | - self::scope_admin => __("Admin Registration Page (no online processing)", 'event_espresso') |
|
99 | - ) |
|
100 | - ); |
|
101 | - } |
|
102 | - |
|
103 | - |
|
104 | - |
|
105 | - /** |
|
106 | - * Determines if this is an valid scope |
|
107 | - * @param string $scope like one of EEM_Payment_Method::instance()->scopes() |
|
108 | - * @return boolean |
|
109 | - */ |
|
110 | - public function is_valid_scope($scope) |
|
111 | - { |
|
112 | - $scopes = $this->scopes(); |
|
113 | - if (isset($scopes[ $scope ])) { |
|
114 | - return true; |
|
115 | - } else { |
|
116 | - return false; |
|
117 | - } |
|
118 | - } |
|
119 | - |
|
120 | - |
|
121 | - |
|
122 | - /** |
|
123 | - * Gets all active payment methods |
|
124 | - * @param string $scope one of |
|
125 | - * @param array $query_params |
|
126 | - * @throws EE_Error |
|
127 | - * @return EE_Payment_Method[] |
|
128 | - */ |
|
129 | - public function get_all_active($scope = null, $query_params = array()) |
|
130 | - { |
|
131 | - if (! isset($query_params['order_by']) && ! isset($query_params['order'])) { |
|
132 | - $query_params['order_by'] = array( 'PMD_order' => 'ASC', 'PMD_ID' => 'ASC' ); |
|
133 | - } |
|
134 | - return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params)); |
|
135 | - } |
|
136 | - |
|
137 | - /** |
|
138 | - * Counts all active gateways in the specified scope |
|
139 | - * @param string $scope one of EEM_Payment_Method::scope_* |
|
140 | - * @param array $query_params |
|
141 | - * @return int |
|
142 | - */ |
|
143 | - public function count_active($scope = null, $query_params = array()) |
|
144 | - { |
|
145 | - return $this->count($this->_get_query_params_for_all_active($scope, $query_params)); |
|
146 | - } |
|
147 | - |
|
148 | - /** |
|
149 | - * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params |
|
150 | - * argument to get all active for a given scope |
|
151 | - * @param string $scope one of the constants EEM_Payment_Method::scope_* |
|
152 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
153 | - * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
154 | - * @throws EE_Error |
|
155 | - */ |
|
156 | - protected function _get_query_params_for_all_active($scope = null, $query_params = array()) |
|
157 | - { |
|
158 | - if ($scope) { |
|
159 | - if ($this->is_valid_scope($scope)) { |
|
160 | - return array_replace_recursive(array( array( 'PMD_scope' => array( 'LIKE', "%$scope%" ) ) ), $query_params); |
|
161 | - } else { |
|
162 | - throw new EE_Error(sprintf(__("'%s' is not a valid scope for a payment method", "event_espresso"), $scope)); |
|
163 | - } |
|
164 | - } else { |
|
165 | - $acceptable_scopes = array(); |
|
166 | - $count = 0; |
|
167 | - foreach ($this->scopes() as $scope_name => $desc) { |
|
168 | - $count++; |
|
169 | - $acceptable_scopes[ 'PMD_scope*' . $count ] = array( 'LIKE', '%' . $scope_name . '%' ); |
|
170 | - } |
|
171 | - return array_replace_recursive(array( array( 'OR*active_scope' => $acceptable_scopes ) ), $query_params); |
|
172 | - } |
|
173 | - } |
|
174 | - |
|
175 | - /** |
|
176 | - * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params |
|
177 | - * argument to get all active for a given scope |
|
178 | - * @param string $scope one of the constants EEM_Payment_Method::scope_* |
|
179 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
180 | - * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
181 | - * @throws EE_Error |
|
182 | - */ |
|
183 | - public function get_query_params_for_all_active($scope = null, $query_params = array()) |
|
184 | - { |
|
185 | - return $this->_get_query_params_for_all_active($scope, $query_params); |
|
186 | - } |
|
187 | - |
|
188 | - |
|
189 | - /** |
|
190 | - * Gets one active payment method. see @get_all_active for documentation |
|
191 | - * @param string $scope |
|
192 | - * @param array $query_params |
|
193 | - * @return EE_Payment_Method |
|
194 | - */ |
|
195 | - public function get_one_active($scope = null, $query_params = array()) |
|
196 | - { |
|
197 | - return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params)); |
|
198 | - } |
|
199 | - |
|
200 | - |
|
201 | - |
|
202 | - /** |
|
203 | - * Gets one payment method of that type, regardless of whether its active or not |
|
204 | - * @param string $type |
|
205 | - * @return EE_Payment_Method |
|
206 | - */ |
|
207 | - public function get_one_of_type($type) |
|
208 | - { |
|
209 | - return $this->get_one(array( array( 'PMD_type' => $type ) )); |
|
210 | - } |
|
211 | - |
|
212 | - |
|
213 | - |
|
214 | - /** |
|
215 | - * Overrides parent ot also check by the slug |
|
216 | - * @see EEM_Base::ensure_is_obj() |
|
217 | - * @param string|int|EE_Payment_Method $base_class_obj_or_id |
|
218 | - * @param boolean $ensure_is_in_db |
|
219 | - * @return EE_Payment_Method |
|
220 | - * @throws EE_Error |
|
221 | - */ |
|
222 | - public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false) |
|
223 | - { |
|
224 | - // first: check if it's a slug |
|
225 | - if (is_string($base_class_obj_or_id)) { |
|
226 | - $obj = $this->get_one_by_slug($base_class_obj_or_id); |
|
227 | - if ($obj) { |
|
228 | - return $obj; |
|
229 | - } |
|
230 | - } |
|
231 | - // ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID) |
|
232 | - try { |
|
233 | - return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db); |
|
234 | - } catch (EE_Error $e) { |
|
235 | - // handle it outside the catch |
|
236 | - } |
|
237 | - throw new EE_Error(sprintf(__("'%s' is neither a Payment Method ID, slug, nor object.", "event_espresso"), $base_class_obj_or_id)); |
|
238 | - } |
|
239 | - |
|
240 | - |
|
241 | - |
|
242 | - /** |
|
243 | - * Gets the ID of this object, or if its a string finds the object's id |
|
244 | - * associated with that slug |
|
245 | - * @param mixed $base_obj_or_id_or_slug |
|
246 | - * @return int |
|
247 | - */ |
|
248 | - public function ensure_is_ID($base_obj_or_id_or_slug) |
|
249 | - { |
|
250 | - if (is_string($base_obj_or_id_or_slug)) { |
|
251 | - // assume it's a slug |
|
252 | - $base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug); |
|
253 | - } |
|
254 | - return parent::ensure_is_ID($base_obj_or_id_or_slug); |
|
255 | - } |
|
256 | - |
|
257 | - |
|
258 | - |
|
259 | - /** |
|
260 | - * Verifies the button urls on all the passed payment methods have a valid button url. If not, resets them to their default. |
|
261 | - * @param EE_Payment_Method[] $payment_methods. If NULL is provided defaults to all payment methods active in the cart |
|
262 | - */ |
|
263 | - public function verify_button_urls($payment_methods = null) |
|
264 | - { |
|
265 | - $payment_methods = is_array($payment_methods) ? $payment_methods : $this->get_all_active(EEM_Payment_Method::scope_cart); |
|
266 | - foreach ($payment_methods as $payment_method) { |
|
267 | - try { |
|
268 | - $current_button_url = $payment_method->button_url(); |
|
269 | - $buttons_urls_to_try = apply_filters('FHEE__EEM_Payment_Method__verify_button_urls__button_urls_to_try', array( |
|
270 | - 'current_ssl' => str_replace("http://", "https://", $current_button_url), |
|
271 | - 'current' => str_replace("https://", "http://", $current_button_url), |
|
272 | - 'default_ssl' => str_replace("http://", "https://", $payment_method->type_obj()->default_button_url()), |
|
273 | - 'default' => str_replace("https://", "http://", $payment_method->type_obj()->default_button_url()), |
|
274 | - )); |
|
275 | - foreach ($buttons_urls_to_try as $button_url_to_try) { |
|
276 | - if ((// this is the current url and it exists, regardless of SSL issues |
|
277 | - $button_url_to_try == $current_button_url && |
|
278 | - EEH_URL::remote_file_exists( |
|
279 | - $button_url_to_try, |
|
280 | - array( |
|
281 | - 'sslverify' => false, |
|
282 | - 'limit_response_size' => 4095,// we don't really care for a full response, but we do want headers at least. Lets just ask for a one block |
|
283 | - ) |
|
284 | - ) |
|
285 | - ) |
|
286 | - || |
|
287 | - (// this is NOT the current url and it exists with a working SSL cert |
|
288 | - $button_url_to_try != $current_button_url && |
|
289 | - EEH_URL::remote_file_exists($button_url_to_try) |
|
290 | - ) ) { |
|
291 | - if ($current_button_url != $button_url_to_try) { |
|
292 | - $payment_method->save(array( 'PMD_button_url' => $button_url_to_try )); |
|
293 | - EE_Error::add_attention(sprintf(__("Payment Method %s's button url was set to %s, because the old image either didnt exist or SSL was recently enabled.", "event_espresso"), $payment_method->name(), $button_url_to_try)); |
|
294 | - } |
|
295 | - // this image exists. So if wasn't set before, now it is; |
|
296 | - // or if it was already set, we have nothing to do |
|
297 | - break; |
|
298 | - } |
|
299 | - } |
|
300 | - } catch (EE_Error $e) { |
|
301 | - $payment_method->set_active(false); |
|
302 | - } |
|
303 | - } |
|
304 | - } |
|
305 | - |
|
306 | - |
|
307 | - |
|
308 | - /** |
|
309 | - * Overrides parent to not only turn wpdb results into EE_Payment_Method objects, |
|
310 | - * but also verifies the payment method type of each is a usable object. If not, |
|
311 | - * deactivate it, sets a notification, and deactivates it |
|
312 | - * |
|
313 | - * @param array $rows |
|
314 | - * @return EE_Payment_Method[] |
|
315 | - * @throws InvalidDataTypeException |
|
316 | - */ |
|
317 | - protected function _create_objects($rows = array()) |
|
318 | - { |
|
319 | - EE_Registry::instance()->load_lib('Payment_Method_Manager'); |
|
320 | - $payment_methods = parent::_create_objects($rows); |
|
321 | - /* @var $payment_methods EE_Payment_Method[] */ |
|
322 | - $usable_payment_methods = array(); |
|
323 | - foreach ($payment_methods as $key => $payment_method) { |
|
324 | - if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) { |
|
325 | - $usable_payment_methods[ $key ] = $payment_method; |
|
326 | - // some payment methods enqueue their scripts in EE_PMT_*::__construct |
|
327 | - // which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue |
|
328 | - // its scripts). but for backwards-compat we should continue to do that |
|
329 | - $payment_method->type_obj(); |
|
330 | - } elseif ($payment_method->active()) { |
|
331 | - // only deactivate and notify the admin if the payment is active somewhere |
|
332 | - $payment_method->deactivate(); |
|
333 | - $payment_method->save(); |
|
334 | - do_action( |
|
335 | - 'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method', |
|
336 | - $payment_method |
|
337 | - ); |
|
338 | - new PersistentAdminNotice( |
|
339 | - 'auto-deactivated-' . $payment_method->type(), |
|
340 | - sprintf( |
|
341 | - __( |
|
342 | - 'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.', |
|
343 | - 'event_espresso' |
|
344 | - ), |
|
345 | - $payment_method->admin_name(), |
|
346 | - '<br />', |
|
347 | - '<a href="' . admin_url('plugins.php') . '">', |
|
348 | - '</a>' |
|
349 | - ), |
|
350 | - true |
|
351 | - ); |
|
352 | - } |
|
353 | - } |
|
354 | - return $usable_payment_methods; |
|
355 | - } |
|
356 | - |
|
357 | - |
|
358 | - |
|
359 | - /** |
|
360 | - * Gets all the payment methods which can be used for transaction |
|
361 | - * (according to the relations between payment methods and events, and |
|
362 | - * the currencies used for the transaction and their relation to payment methods) |
|
363 | - * @param EE_Transaction $transaction |
|
364 | - * @param string $scope @see EEM_Payment_Method::get_all_for_events |
|
365 | - * @return EE_Payment_Method[] |
|
366 | - */ |
|
367 | - public function get_all_for_transaction($transaction, $scope) |
|
368 | - { |
|
369 | - // give addons a chance to override what payment methods are chosen based on the transaction |
|
370 | - return apply_filters( |
|
371 | - 'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods', |
|
372 | - $this->get_all_active($scope, array( 'group_by' => 'PMD_type' )), |
|
373 | - $transaction, |
|
374 | - $scope |
|
375 | - ); |
|
376 | - } |
|
377 | - |
|
378 | - |
|
379 | - /** |
|
380 | - * Returns the payment method used for the last payment made for a registration. |
|
381 | - * |
|
382 | - * Note: if an offline payment method was selected on the related transaction then this will have no payment methods returned. |
|
383 | - * It will ONLY return a payment method for a PAYMENT recorded against the registration. |
|
384 | - * |
|
385 | - * @param EE_Registration|int $registration_or_reg_id Either the EE_Registration object or the id for the registration. |
|
386 | - * @return EE_Payment|null |
|
387 | - */ |
|
388 | - public function get_last_used_for_registration($registration_or_reg_id) |
|
389 | - { |
|
390 | - $registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id); |
|
391 | - |
|
392 | - $query_params = array( |
|
393 | - 0 => array( |
|
394 | - 'Payment.Registration.REG_ID' => $registration_id, |
|
395 | - ), |
|
396 | - 'order_by' => array( 'Payment.PAY_ID' => 'DESC' ) |
|
397 | - ); |
|
398 | - return $this->get_one($query_params); |
|
399 | - } |
|
65 | + 'Payment' => new EE_Has_Many_Relation(), |
|
66 | + 'Currency' => new EE_HABTM_Relation('Currency_Payment_Method'), |
|
67 | + 'Transaction' => new EE_Has_Many_Relation(), |
|
68 | + 'WP_User' => new EE_Belongs_To_Relation(), |
|
69 | + ); |
|
70 | + parent::__construct($timezone); |
|
71 | + } |
|
72 | + |
|
73 | + |
|
74 | + |
|
75 | + /** |
|
76 | + * Gets one by the slug provided |
|
77 | + * @param string $slug |
|
78 | + * @return EE_Payment_Method |
|
79 | + */ |
|
80 | + public function get_one_by_slug($slug) |
|
81 | + { |
|
82 | + return $this->get_one(array( array( 'PMD_slug' => $slug ) )); |
|
83 | + } |
|
84 | + |
|
85 | + |
|
86 | + |
|
87 | + /** |
|
88 | + * Gets all the acceptable scopes for payment methods. |
|
89 | + * Keys are their names as store din the DB, and values are nice names for displaying them |
|
90 | + * @return array |
|
91 | + */ |
|
92 | + public function scopes() |
|
93 | + { |
|
94 | + return apply_filters( |
|
95 | + 'FHEE__EEM_Payment_Method__scopes', |
|
96 | + array( |
|
97 | + self::scope_cart => __("Front-end Registration Page", 'event_espresso'), |
|
98 | + self::scope_admin => __("Admin Registration Page (no online processing)", 'event_espresso') |
|
99 | + ) |
|
100 | + ); |
|
101 | + } |
|
102 | + |
|
103 | + |
|
104 | + |
|
105 | + /** |
|
106 | + * Determines if this is an valid scope |
|
107 | + * @param string $scope like one of EEM_Payment_Method::instance()->scopes() |
|
108 | + * @return boolean |
|
109 | + */ |
|
110 | + public function is_valid_scope($scope) |
|
111 | + { |
|
112 | + $scopes = $this->scopes(); |
|
113 | + if (isset($scopes[ $scope ])) { |
|
114 | + return true; |
|
115 | + } else { |
|
116 | + return false; |
|
117 | + } |
|
118 | + } |
|
119 | + |
|
120 | + |
|
121 | + |
|
122 | + /** |
|
123 | + * Gets all active payment methods |
|
124 | + * @param string $scope one of |
|
125 | + * @param array $query_params |
|
126 | + * @throws EE_Error |
|
127 | + * @return EE_Payment_Method[] |
|
128 | + */ |
|
129 | + public function get_all_active($scope = null, $query_params = array()) |
|
130 | + { |
|
131 | + if (! isset($query_params['order_by']) && ! isset($query_params['order'])) { |
|
132 | + $query_params['order_by'] = array( 'PMD_order' => 'ASC', 'PMD_ID' => 'ASC' ); |
|
133 | + } |
|
134 | + return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params)); |
|
135 | + } |
|
136 | + |
|
137 | + /** |
|
138 | + * Counts all active gateways in the specified scope |
|
139 | + * @param string $scope one of EEM_Payment_Method::scope_* |
|
140 | + * @param array $query_params |
|
141 | + * @return int |
|
142 | + */ |
|
143 | + public function count_active($scope = null, $query_params = array()) |
|
144 | + { |
|
145 | + return $this->count($this->_get_query_params_for_all_active($scope, $query_params)); |
|
146 | + } |
|
147 | + |
|
148 | + /** |
|
149 | + * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params |
|
150 | + * argument to get all active for a given scope |
|
151 | + * @param string $scope one of the constants EEM_Payment_Method::scope_* |
|
152 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
153 | + * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
154 | + * @throws EE_Error |
|
155 | + */ |
|
156 | + protected function _get_query_params_for_all_active($scope = null, $query_params = array()) |
|
157 | + { |
|
158 | + if ($scope) { |
|
159 | + if ($this->is_valid_scope($scope)) { |
|
160 | + return array_replace_recursive(array( array( 'PMD_scope' => array( 'LIKE', "%$scope%" ) ) ), $query_params); |
|
161 | + } else { |
|
162 | + throw new EE_Error(sprintf(__("'%s' is not a valid scope for a payment method", "event_espresso"), $scope)); |
|
163 | + } |
|
164 | + } else { |
|
165 | + $acceptable_scopes = array(); |
|
166 | + $count = 0; |
|
167 | + foreach ($this->scopes() as $scope_name => $desc) { |
|
168 | + $count++; |
|
169 | + $acceptable_scopes[ 'PMD_scope*' . $count ] = array( 'LIKE', '%' . $scope_name . '%' ); |
|
170 | + } |
|
171 | + return array_replace_recursive(array( array( 'OR*active_scope' => $acceptable_scopes ) ), $query_params); |
|
172 | + } |
|
173 | + } |
|
174 | + |
|
175 | + /** |
|
176 | + * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params |
|
177 | + * argument to get all active for a given scope |
|
178 | + * @param string $scope one of the constants EEM_Payment_Method::scope_* |
|
179 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
180 | + * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
181 | + * @throws EE_Error |
|
182 | + */ |
|
183 | + public function get_query_params_for_all_active($scope = null, $query_params = array()) |
|
184 | + { |
|
185 | + return $this->_get_query_params_for_all_active($scope, $query_params); |
|
186 | + } |
|
187 | + |
|
188 | + |
|
189 | + /** |
|
190 | + * Gets one active payment method. see @get_all_active for documentation |
|
191 | + * @param string $scope |
|
192 | + * @param array $query_params |
|
193 | + * @return EE_Payment_Method |
|
194 | + */ |
|
195 | + public function get_one_active($scope = null, $query_params = array()) |
|
196 | + { |
|
197 | + return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params)); |
|
198 | + } |
|
199 | + |
|
200 | + |
|
201 | + |
|
202 | + /** |
|
203 | + * Gets one payment method of that type, regardless of whether its active or not |
|
204 | + * @param string $type |
|
205 | + * @return EE_Payment_Method |
|
206 | + */ |
|
207 | + public function get_one_of_type($type) |
|
208 | + { |
|
209 | + return $this->get_one(array( array( 'PMD_type' => $type ) )); |
|
210 | + } |
|
211 | + |
|
212 | + |
|
213 | + |
|
214 | + /** |
|
215 | + * Overrides parent ot also check by the slug |
|
216 | + * @see EEM_Base::ensure_is_obj() |
|
217 | + * @param string|int|EE_Payment_Method $base_class_obj_or_id |
|
218 | + * @param boolean $ensure_is_in_db |
|
219 | + * @return EE_Payment_Method |
|
220 | + * @throws EE_Error |
|
221 | + */ |
|
222 | + public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false) |
|
223 | + { |
|
224 | + // first: check if it's a slug |
|
225 | + if (is_string($base_class_obj_or_id)) { |
|
226 | + $obj = $this->get_one_by_slug($base_class_obj_or_id); |
|
227 | + if ($obj) { |
|
228 | + return $obj; |
|
229 | + } |
|
230 | + } |
|
231 | + // ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID) |
|
232 | + try { |
|
233 | + return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db); |
|
234 | + } catch (EE_Error $e) { |
|
235 | + // handle it outside the catch |
|
236 | + } |
|
237 | + throw new EE_Error(sprintf(__("'%s' is neither a Payment Method ID, slug, nor object.", "event_espresso"), $base_class_obj_or_id)); |
|
238 | + } |
|
239 | + |
|
240 | + |
|
241 | + |
|
242 | + /** |
|
243 | + * Gets the ID of this object, or if its a string finds the object's id |
|
244 | + * associated with that slug |
|
245 | + * @param mixed $base_obj_or_id_or_slug |
|
246 | + * @return int |
|
247 | + */ |
|
248 | + public function ensure_is_ID($base_obj_or_id_or_slug) |
|
249 | + { |
|
250 | + if (is_string($base_obj_or_id_or_slug)) { |
|
251 | + // assume it's a slug |
|
252 | + $base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug); |
|
253 | + } |
|
254 | + return parent::ensure_is_ID($base_obj_or_id_or_slug); |
|
255 | + } |
|
256 | + |
|
257 | + |
|
258 | + |
|
259 | + /** |
|
260 | + * Verifies the button urls on all the passed payment methods have a valid button url. If not, resets them to their default. |
|
261 | + * @param EE_Payment_Method[] $payment_methods. If NULL is provided defaults to all payment methods active in the cart |
|
262 | + */ |
|
263 | + public function verify_button_urls($payment_methods = null) |
|
264 | + { |
|
265 | + $payment_methods = is_array($payment_methods) ? $payment_methods : $this->get_all_active(EEM_Payment_Method::scope_cart); |
|
266 | + foreach ($payment_methods as $payment_method) { |
|
267 | + try { |
|
268 | + $current_button_url = $payment_method->button_url(); |
|
269 | + $buttons_urls_to_try = apply_filters('FHEE__EEM_Payment_Method__verify_button_urls__button_urls_to_try', array( |
|
270 | + 'current_ssl' => str_replace("http://", "https://", $current_button_url), |
|
271 | + 'current' => str_replace("https://", "http://", $current_button_url), |
|
272 | + 'default_ssl' => str_replace("http://", "https://", $payment_method->type_obj()->default_button_url()), |
|
273 | + 'default' => str_replace("https://", "http://", $payment_method->type_obj()->default_button_url()), |
|
274 | + )); |
|
275 | + foreach ($buttons_urls_to_try as $button_url_to_try) { |
|
276 | + if ((// this is the current url and it exists, regardless of SSL issues |
|
277 | + $button_url_to_try == $current_button_url && |
|
278 | + EEH_URL::remote_file_exists( |
|
279 | + $button_url_to_try, |
|
280 | + array( |
|
281 | + 'sslverify' => false, |
|
282 | + 'limit_response_size' => 4095,// we don't really care for a full response, but we do want headers at least. Lets just ask for a one block |
|
283 | + ) |
|
284 | + ) |
|
285 | + ) |
|
286 | + || |
|
287 | + (// this is NOT the current url and it exists with a working SSL cert |
|
288 | + $button_url_to_try != $current_button_url && |
|
289 | + EEH_URL::remote_file_exists($button_url_to_try) |
|
290 | + ) ) { |
|
291 | + if ($current_button_url != $button_url_to_try) { |
|
292 | + $payment_method->save(array( 'PMD_button_url' => $button_url_to_try )); |
|
293 | + EE_Error::add_attention(sprintf(__("Payment Method %s's button url was set to %s, because the old image either didnt exist or SSL was recently enabled.", "event_espresso"), $payment_method->name(), $button_url_to_try)); |
|
294 | + } |
|
295 | + // this image exists. So if wasn't set before, now it is; |
|
296 | + // or if it was already set, we have nothing to do |
|
297 | + break; |
|
298 | + } |
|
299 | + } |
|
300 | + } catch (EE_Error $e) { |
|
301 | + $payment_method->set_active(false); |
|
302 | + } |
|
303 | + } |
|
304 | + } |
|
305 | + |
|
306 | + |
|
307 | + |
|
308 | + /** |
|
309 | + * Overrides parent to not only turn wpdb results into EE_Payment_Method objects, |
|
310 | + * but also verifies the payment method type of each is a usable object. If not, |
|
311 | + * deactivate it, sets a notification, and deactivates it |
|
312 | + * |
|
313 | + * @param array $rows |
|
314 | + * @return EE_Payment_Method[] |
|
315 | + * @throws InvalidDataTypeException |
|
316 | + */ |
|
317 | + protected function _create_objects($rows = array()) |
|
318 | + { |
|
319 | + EE_Registry::instance()->load_lib('Payment_Method_Manager'); |
|
320 | + $payment_methods = parent::_create_objects($rows); |
|
321 | + /* @var $payment_methods EE_Payment_Method[] */ |
|
322 | + $usable_payment_methods = array(); |
|
323 | + foreach ($payment_methods as $key => $payment_method) { |
|
324 | + if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) { |
|
325 | + $usable_payment_methods[ $key ] = $payment_method; |
|
326 | + // some payment methods enqueue their scripts in EE_PMT_*::__construct |
|
327 | + // which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue |
|
328 | + // its scripts). but for backwards-compat we should continue to do that |
|
329 | + $payment_method->type_obj(); |
|
330 | + } elseif ($payment_method->active()) { |
|
331 | + // only deactivate and notify the admin if the payment is active somewhere |
|
332 | + $payment_method->deactivate(); |
|
333 | + $payment_method->save(); |
|
334 | + do_action( |
|
335 | + 'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method', |
|
336 | + $payment_method |
|
337 | + ); |
|
338 | + new PersistentAdminNotice( |
|
339 | + 'auto-deactivated-' . $payment_method->type(), |
|
340 | + sprintf( |
|
341 | + __( |
|
342 | + 'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.', |
|
343 | + 'event_espresso' |
|
344 | + ), |
|
345 | + $payment_method->admin_name(), |
|
346 | + '<br />', |
|
347 | + '<a href="' . admin_url('plugins.php') . '">', |
|
348 | + '</a>' |
|
349 | + ), |
|
350 | + true |
|
351 | + ); |
|
352 | + } |
|
353 | + } |
|
354 | + return $usable_payment_methods; |
|
355 | + } |
|
356 | + |
|
357 | + |
|
358 | + |
|
359 | + /** |
|
360 | + * Gets all the payment methods which can be used for transaction |
|
361 | + * (according to the relations between payment methods and events, and |
|
362 | + * the currencies used for the transaction and their relation to payment methods) |
|
363 | + * @param EE_Transaction $transaction |
|
364 | + * @param string $scope @see EEM_Payment_Method::get_all_for_events |
|
365 | + * @return EE_Payment_Method[] |
|
366 | + */ |
|
367 | + public function get_all_for_transaction($transaction, $scope) |
|
368 | + { |
|
369 | + // give addons a chance to override what payment methods are chosen based on the transaction |
|
370 | + return apply_filters( |
|
371 | + 'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods', |
|
372 | + $this->get_all_active($scope, array( 'group_by' => 'PMD_type' )), |
|
373 | + $transaction, |
|
374 | + $scope |
|
375 | + ); |
|
376 | + } |
|
377 | + |
|
378 | + |
|
379 | + /** |
|
380 | + * Returns the payment method used for the last payment made for a registration. |
|
381 | + * |
|
382 | + * Note: if an offline payment method was selected on the related transaction then this will have no payment methods returned. |
|
383 | + * It will ONLY return a payment method for a PAYMENT recorded against the registration. |
|
384 | + * |
|
385 | + * @param EE_Registration|int $registration_or_reg_id Either the EE_Registration object or the id for the registration. |
|
386 | + * @return EE_Payment|null |
|
387 | + */ |
|
388 | + public function get_last_used_for_registration($registration_or_reg_id) |
|
389 | + { |
|
390 | + $registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id); |
|
391 | + |
|
392 | + $query_params = array( |
|
393 | + 0 => array( |
|
394 | + 'Payment.Registration.REG_ID' => $registration_id, |
|
395 | + ), |
|
396 | + 'order_by' => array( 'Payment.PAY_ID' => 'DESC' ) |
|
397 | + ); |
|
398 | + return $this->get_one($query_params); |
|
399 | + } |
|
400 | 400 | } |
@@ -32,443 +32,443 @@ |
||
32 | 32 | class EEM_Line_Item extends EEM_Base |
33 | 33 | { |
34 | 34 | |
35 | - /** |
|
36 | - * Tax sub-total is just the total of all the taxes, which should be children |
|
37 | - * of this line item. There should only ever be one tax sub-total, and it should |
|
38 | - * be a direct child of. Its quantity and LIN_unit_price = 1. |
|
39 | - */ |
|
40 | - const type_tax_sub_total = 'tax-sub-total'; |
|
41 | - |
|
42 | - /** |
|
43 | - * Tax line items indicate a tax applied to all the taxable line items. |
|
44 | - * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal |
|
45 | - * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1. |
|
46 | - */ |
|
47 | - const type_tax = 'tax'; |
|
48 | - |
|
49 | - /** |
|
50 | - * Indicating individual items purchased, or discounts or surcharges. |
|
51 | - * The sum of all the regular line items plus the tax items should equal |
|
52 | - * the grand total. |
|
53 | - * Possible children are sub-line-items and cancellations. |
|
54 | - * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children |
|
55 | - * LIN_totals. Its LIN_percent = 0. |
|
56 | - * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1). |
|
57 | - * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1. |
|
58 | - */ |
|
59 | - const type_line_item = 'line-item'; |
|
60 | - |
|
61 | - /** |
|
62 | - * Line item indicating all the factors that make a single line item. |
|
63 | - * Sub-line items should have NO children line items. |
|
64 | - * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's |
|
65 | - * contribution towards the price of ONE of their parent items, and its LIN_total should be |
|
66 | - * = LIN_quantity * LIN_unit_price. Its LIN_percent = 0. |
|
67 | - * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should |
|
68 | - * = LIN_percent / 100 * sum of lower-priority sibling line items.. |
|
69 | - */ |
|
70 | - const type_sub_line_item = 'sub-item'; |
|
71 | - |
|
72 | - /** |
|
73 | - * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal). |
|
74 | - * Direct children should be event subtotals. |
|
75 | - * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals. |
|
76 | - * |
|
77 | - */ |
|
78 | - const type_sub_total = 'sub-total'; |
|
79 | - |
|
80 | - /** |
|
81 | - * Line item for the grand total of an order. Its direct children |
|
82 | - * should be tax subtotals and (pre-tax) subtotals, and possibly a regular line item |
|
83 | - * indicating a transaction-wide discount/surcharge. Should have a quantity of 1, a LIN_total and LIN_unit_price of |
|
84 | - * the entire order's mount. |
|
85 | - */ |
|
86 | - const type_total = 'total'; |
|
87 | - |
|
88 | - /** |
|
89 | - * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
90 | - * should be created, indicating the quantity that were cancelled |
|
91 | - * (because a line item could have a quantity of 1, and its cancellation item |
|
92 | - * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
93 | - * cancelled, and only one remains). |
|
94 | - * When items are refunded, a cancellation line item should be made, which points |
|
95 | - * to teh payment model object which actually refunded the payment. |
|
96 | - * Cancellations should NOT have any children line items; the should NOT affect |
|
97 | - * any calculations, and are only meant as a record that cancellations have occurred. |
|
98 | - * Their LIN_percent should be 0. |
|
99 | - */ |
|
100 | - const type_cancellation = 'cancellation'; |
|
101 | - |
|
102 | - // private instance of the EEM_Line_Item object |
|
103 | - protected static $_instance = null; |
|
104 | - |
|
105 | - |
|
106 | - /** |
|
107 | - * private constructor to prevent direct creation |
|
108 | - * @Constructor |
|
109 | - * @access protected |
|
110 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved). Note this just sends the timezone info to the date time model field objects. Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
111 | - * @return \EEM_Line_Item |
|
112 | - */ |
|
113 | - protected function __construct($timezone) |
|
114 | - { |
|
115 | - $this->singular_item = __('Line Item', 'event_espresso'); |
|
116 | - $this->plural_item = __('Line Items', 'event_espresso'); |
|
117 | - |
|
118 | - $this->_tables = array( |
|
119 | - 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID') |
|
120 | - ); |
|
121 | - $line_items_can_be_for = apply_filters('FHEE__EEM_Line_Item__line_items_can_be_for', array('Ticket', 'Price', 'Event')); |
|
122 | - $this->_fields = array( |
|
123 | - 'Line_Item' => array( |
|
124 | - 'LIN_ID' => new EE_Primary_Key_Int_Field('LIN_ID', __("ID", "event_espresso")), |
|
125 | - 'LIN_code' => new EE_Slug_Field('LIN_code', __("Code for index into Cart", "event_espresso"), true), |
|
126 | - 'TXN_ID' => new EE_Foreign_Key_Int_Field('TXN_ID', __("Transaction ID", "event_espresso"), true, null, 'Transaction'), |
|
127 | - 'LIN_name' => new EE_Full_HTML_Field('LIN_name', __("Line Item Name", "event_espresso"), false, ''), |
|
128 | - 'LIN_desc' => new EE_Full_HTML_Field('LIN_desc', __("Line Item Description", "event_espresso"), true), |
|
129 | - 'LIN_unit_price' => new EE_Money_Field('LIN_unit_price', __("Unit Price", "event_espresso"), false, 0), |
|
130 | - 'LIN_percent' => new EE_Float_Field('LIN_percent', __("Percent", "event_espresso"), false, 0), |
|
131 | - 'LIN_is_taxable' => new EE_Boolean_Field('LIN_is_taxable', __("Taxable", "event_espresso"), false, false), |
|
132 | - 'LIN_order' => new EE_Integer_Field('LIN_order', __("Order of Application towards total of parent", "event_espresso"), false, 1), |
|
133 | - 'LIN_total' => new EE_Money_Field('LIN_total', __("Total (unit price x quantity)", "event_espresso"), false, 0), |
|
134 | - 'LIN_quantity' => new EE_Integer_Field('LIN_quantity', __("Quantity", "event_espresso"), true, 1), |
|
135 | - 'LIN_parent' => new EE_Integer_Field('LIN_parent', __("Parent ID (this item goes towards that Line Item's total)", "event_espresso"), true, null), |
|
136 | - 'LIN_type' => new EE_Enum_Text_Field('LIN_type', __("Type", "event_espresso"), false, 'line-item', array( |
|
137 | - self::type_line_item => __("Line Item", "event_espresso"), |
|
138 | - self::type_sub_line_item => __("Sub-Item", "event_espresso"), |
|
139 | - self::type_sub_total => __("Subtotal", "event_espresso"), |
|
140 | - self::type_tax_sub_total => __("Tax Subtotal", "event_espresso"), |
|
141 | - self::type_tax => __("Tax", "event_espresso"), |
|
142 | - self::type_total => __("Total", "event_espresso"), |
|
143 | - self::type_cancellation => __('Cancellation', 'event_espresso') |
|
144 | - )), |
|
145 | - 'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __('ID of Item purchased.', 'event_espresso'), true, null, $line_items_can_be_for), |
|
146 | - 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field('OBJ_type', __("Model Name this Line Item is for", "event_espresso"), true, null, $line_items_can_be_for), |
|
147 | - 'LIN_timestamp' => new EE_Datetime_Field('LIN_timestamp', __('When the line item was created', 'event_espresso'), false, EE_Datetime_Field::now, $timezone), |
|
148 | - ) |
|
149 | - ); |
|
150 | - $this->_model_relations = array( |
|
151 | - 'Transaction' => new EE_Belongs_To_Relation(), |
|
152 | - 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
153 | - 'Price' => new EE_Belongs_To_Any_Relation(), |
|
154 | - 'Event' => new EE_Belongs_To_Any_Relation() |
|
155 | - ); |
|
156 | - $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
157 | - $this->_caps_slug = 'transactions'; |
|
158 | - parent::__construct($timezone); |
|
159 | - } |
|
160 | - |
|
161 | - |
|
162 | - /** |
|
163 | - * Gets all the line items for this transaction of the given type |
|
164 | - * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
165 | - * @param EE_Transaction|int $transaction |
|
166 | - * @return EE_Line_Item[] |
|
167 | - */ |
|
168 | - public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
169 | - { |
|
170 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
171 | - return $this->get_all(array(array( |
|
172 | - 'LIN_type' => $line_item_type, |
|
173 | - 'TXN_ID' => $transaction |
|
174 | - ))); |
|
175 | - } |
|
176 | - |
|
177 | - |
|
178 | - /** |
|
179 | - * Gets all line items unrelated to tickets that are normal line items |
|
180 | - * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
181 | - * @param EE_Transaction|int $transaction |
|
182 | - * @return EE_Line_Item[] |
|
183 | - */ |
|
184 | - public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
185 | - { |
|
186 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
187 | - return $this->get_all(array(array( |
|
188 | - 'LIN_type' => self::type_line_item, |
|
189 | - 'TXN_ID' => $transaction, |
|
190 | - 'OR' => array( |
|
191 | - 'OBJ_type*notticket' => array('!=', 'Ticket'), |
|
192 | - 'OBJ_type*null' => array('IS_NULL')) |
|
193 | - ))); |
|
194 | - } |
|
195 | - |
|
196 | - /** |
|
197 | - * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
198 | - * This needs to be very efficient |
|
199 | - * because if there are spam bots afoot there will be LOTS of line items |
|
200 | - * @return int count of how many deleted |
|
201 | - */ |
|
202 | - public function delete_line_items_with_no_transaction() |
|
203 | - { |
|
204 | - /** @type WPDB $wpdb */ |
|
205 | - global $wpdb; |
|
206 | - $time_to_leave_alone = apply_filters( |
|
207 | - 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', |
|
208 | - WEEK_IN_SECONDS |
|
209 | - ); |
|
210 | - $query = $wpdb->prepare( |
|
211 | - 'DELETE li |
|
35 | + /** |
|
36 | + * Tax sub-total is just the total of all the taxes, which should be children |
|
37 | + * of this line item. There should only ever be one tax sub-total, and it should |
|
38 | + * be a direct child of. Its quantity and LIN_unit_price = 1. |
|
39 | + */ |
|
40 | + const type_tax_sub_total = 'tax-sub-total'; |
|
41 | + |
|
42 | + /** |
|
43 | + * Tax line items indicate a tax applied to all the taxable line items. |
|
44 | + * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal |
|
45 | + * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1. |
|
46 | + */ |
|
47 | + const type_tax = 'tax'; |
|
48 | + |
|
49 | + /** |
|
50 | + * Indicating individual items purchased, or discounts or surcharges. |
|
51 | + * The sum of all the regular line items plus the tax items should equal |
|
52 | + * the grand total. |
|
53 | + * Possible children are sub-line-items and cancellations. |
|
54 | + * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children |
|
55 | + * LIN_totals. Its LIN_percent = 0. |
|
56 | + * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1). |
|
57 | + * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1. |
|
58 | + */ |
|
59 | + const type_line_item = 'line-item'; |
|
60 | + |
|
61 | + /** |
|
62 | + * Line item indicating all the factors that make a single line item. |
|
63 | + * Sub-line items should have NO children line items. |
|
64 | + * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's |
|
65 | + * contribution towards the price of ONE of their parent items, and its LIN_total should be |
|
66 | + * = LIN_quantity * LIN_unit_price. Its LIN_percent = 0. |
|
67 | + * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should |
|
68 | + * = LIN_percent / 100 * sum of lower-priority sibling line items.. |
|
69 | + */ |
|
70 | + const type_sub_line_item = 'sub-item'; |
|
71 | + |
|
72 | + /** |
|
73 | + * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal). |
|
74 | + * Direct children should be event subtotals. |
|
75 | + * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals. |
|
76 | + * |
|
77 | + */ |
|
78 | + const type_sub_total = 'sub-total'; |
|
79 | + |
|
80 | + /** |
|
81 | + * Line item for the grand total of an order. Its direct children |
|
82 | + * should be tax subtotals and (pre-tax) subtotals, and possibly a regular line item |
|
83 | + * indicating a transaction-wide discount/surcharge. Should have a quantity of 1, a LIN_total and LIN_unit_price of |
|
84 | + * the entire order's mount. |
|
85 | + */ |
|
86 | + const type_total = 'total'; |
|
87 | + |
|
88 | + /** |
|
89 | + * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
90 | + * should be created, indicating the quantity that were cancelled |
|
91 | + * (because a line item could have a quantity of 1, and its cancellation item |
|
92 | + * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
93 | + * cancelled, and only one remains). |
|
94 | + * When items are refunded, a cancellation line item should be made, which points |
|
95 | + * to teh payment model object which actually refunded the payment. |
|
96 | + * Cancellations should NOT have any children line items; the should NOT affect |
|
97 | + * any calculations, and are only meant as a record that cancellations have occurred. |
|
98 | + * Their LIN_percent should be 0. |
|
99 | + */ |
|
100 | + const type_cancellation = 'cancellation'; |
|
101 | + |
|
102 | + // private instance of the EEM_Line_Item object |
|
103 | + protected static $_instance = null; |
|
104 | + |
|
105 | + |
|
106 | + /** |
|
107 | + * private constructor to prevent direct creation |
|
108 | + * @Constructor |
|
109 | + * @access protected |
|
110 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved). Note this just sends the timezone info to the date time model field objects. Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
111 | + * @return \EEM_Line_Item |
|
112 | + */ |
|
113 | + protected function __construct($timezone) |
|
114 | + { |
|
115 | + $this->singular_item = __('Line Item', 'event_espresso'); |
|
116 | + $this->plural_item = __('Line Items', 'event_espresso'); |
|
117 | + |
|
118 | + $this->_tables = array( |
|
119 | + 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID') |
|
120 | + ); |
|
121 | + $line_items_can_be_for = apply_filters('FHEE__EEM_Line_Item__line_items_can_be_for', array('Ticket', 'Price', 'Event')); |
|
122 | + $this->_fields = array( |
|
123 | + 'Line_Item' => array( |
|
124 | + 'LIN_ID' => new EE_Primary_Key_Int_Field('LIN_ID', __("ID", "event_espresso")), |
|
125 | + 'LIN_code' => new EE_Slug_Field('LIN_code', __("Code for index into Cart", "event_espresso"), true), |
|
126 | + 'TXN_ID' => new EE_Foreign_Key_Int_Field('TXN_ID', __("Transaction ID", "event_espresso"), true, null, 'Transaction'), |
|
127 | + 'LIN_name' => new EE_Full_HTML_Field('LIN_name', __("Line Item Name", "event_espresso"), false, ''), |
|
128 | + 'LIN_desc' => new EE_Full_HTML_Field('LIN_desc', __("Line Item Description", "event_espresso"), true), |
|
129 | + 'LIN_unit_price' => new EE_Money_Field('LIN_unit_price', __("Unit Price", "event_espresso"), false, 0), |
|
130 | + 'LIN_percent' => new EE_Float_Field('LIN_percent', __("Percent", "event_espresso"), false, 0), |
|
131 | + 'LIN_is_taxable' => new EE_Boolean_Field('LIN_is_taxable', __("Taxable", "event_espresso"), false, false), |
|
132 | + 'LIN_order' => new EE_Integer_Field('LIN_order', __("Order of Application towards total of parent", "event_espresso"), false, 1), |
|
133 | + 'LIN_total' => new EE_Money_Field('LIN_total', __("Total (unit price x quantity)", "event_espresso"), false, 0), |
|
134 | + 'LIN_quantity' => new EE_Integer_Field('LIN_quantity', __("Quantity", "event_espresso"), true, 1), |
|
135 | + 'LIN_parent' => new EE_Integer_Field('LIN_parent', __("Parent ID (this item goes towards that Line Item's total)", "event_espresso"), true, null), |
|
136 | + 'LIN_type' => new EE_Enum_Text_Field('LIN_type', __("Type", "event_espresso"), false, 'line-item', array( |
|
137 | + self::type_line_item => __("Line Item", "event_espresso"), |
|
138 | + self::type_sub_line_item => __("Sub-Item", "event_espresso"), |
|
139 | + self::type_sub_total => __("Subtotal", "event_espresso"), |
|
140 | + self::type_tax_sub_total => __("Tax Subtotal", "event_espresso"), |
|
141 | + self::type_tax => __("Tax", "event_espresso"), |
|
142 | + self::type_total => __("Total", "event_espresso"), |
|
143 | + self::type_cancellation => __('Cancellation', 'event_espresso') |
|
144 | + )), |
|
145 | + 'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __('ID of Item purchased.', 'event_espresso'), true, null, $line_items_can_be_for), |
|
146 | + 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field('OBJ_type', __("Model Name this Line Item is for", "event_espresso"), true, null, $line_items_can_be_for), |
|
147 | + 'LIN_timestamp' => new EE_Datetime_Field('LIN_timestamp', __('When the line item was created', 'event_espresso'), false, EE_Datetime_Field::now, $timezone), |
|
148 | + ) |
|
149 | + ); |
|
150 | + $this->_model_relations = array( |
|
151 | + 'Transaction' => new EE_Belongs_To_Relation(), |
|
152 | + 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
153 | + 'Price' => new EE_Belongs_To_Any_Relation(), |
|
154 | + 'Event' => new EE_Belongs_To_Any_Relation() |
|
155 | + ); |
|
156 | + $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
157 | + $this->_caps_slug = 'transactions'; |
|
158 | + parent::__construct($timezone); |
|
159 | + } |
|
160 | + |
|
161 | + |
|
162 | + /** |
|
163 | + * Gets all the line items for this transaction of the given type |
|
164 | + * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
165 | + * @param EE_Transaction|int $transaction |
|
166 | + * @return EE_Line_Item[] |
|
167 | + */ |
|
168 | + public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
169 | + { |
|
170 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
171 | + return $this->get_all(array(array( |
|
172 | + 'LIN_type' => $line_item_type, |
|
173 | + 'TXN_ID' => $transaction |
|
174 | + ))); |
|
175 | + } |
|
176 | + |
|
177 | + |
|
178 | + /** |
|
179 | + * Gets all line items unrelated to tickets that are normal line items |
|
180 | + * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
181 | + * @param EE_Transaction|int $transaction |
|
182 | + * @return EE_Line_Item[] |
|
183 | + */ |
|
184 | + public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
185 | + { |
|
186 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
187 | + return $this->get_all(array(array( |
|
188 | + 'LIN_type' => self::type_line_item, |
|
189 | + 'TXN_ID' => $transaction, |
|
190 | + 'OR' => array( |
|
191 | + 'OBJ_type*notticket' => array('!=', 'Ticket'), |
|
192 | + 'OBJ_type*null' => array('IS_NULL')) |
|
193 | + ))); |
|
194 | + } |
|
195 | + |
|
196 | + /** |
|
197 | + * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
198 | + * This needs to be very efficient |
|
199 | + * because if there are spam bots afoot there will be LOTS of line items |
|
200 | + * @return int count of how many deleted |
|
201 | + */ |
|
202 | + public function delete_line_items_with_no_transaction() |
|
203 | + { |
|
204 | + /** @type WPDB $wpdb */ |
|
205 | + global $wpdb; |
|
206 | + $time_to_leave_alone = apply_filters( |
|
207 | + 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', |
|
208 | + WEEK_IN_SECONDS |
|
209 | + ); |
|
210 | + $query = $wpdb->prepare( |
|
211 | + 'DELETE li |
|
212 | 212 | FROM ' . $this->table() . ' li |
213 | 213 | LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID |
214 | 214 | WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s', |
215 | - // use GMT time because that's what TXN_timestamps are in |
|
216 | - date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
217 | - ); |
|
218 | - return $wpdb->query($query); |
|
219 | - } |
|
220 | - |
|
221 | - |
|
222 | - /** |
|
223 | - * get_line_item_for_transaction_object |
|
224 | - * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
225 | - * |
|
226 | - * @param int $TXN_ID |
|
227 | - * @param \EE_Base_Class $object |
|
228 | - * @return EE_Line_Item[] |
|
229 | - */ |
|
230 | - public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
231 | - { |
|
232 | - return $this->get_all(array(array( |
|
233 | - 'TXN_ID' => $TXN_ID, |
|
234 | - 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
235 | - 'OBJ_ID' => $object->ID() |
|
236 | - ))); |
|
237 | - } |
|
238 | - |
|
239 | - |
|
240 | - /** |
|
241 | - * get_object_line_items_for_transaction |
|
242 | - * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
243 | - * |
|
244 | - * @param int $TXN_ID |
|
245 | - * @param string $OBJ_type |
|
246 | - * @param array $OBJ_IDs |
|
247 | - * @return EE_Line_Item[] |
|
248 | - */ |
|
249 | - public function get_object_line_items_for_transaction($TXN_ID, $OBJ_type = 'Event', $OBJ_IDs = array()) |
|
250 | - { |
|
251 | - $query_params = array( |
|
252 | - 'OBJ_type' => $OBJ_type, |
|
253 | - // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
254 | - 'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs |
|
255 | - ); |
|
256 | - if ($TXN_ID) { |
|
257 | - $query_params['TXN_ID'] = $TXN_ID; |
|
258 | - } |
|
259 | - return $this->get_all(array($query_params)); |
|
260 | - } |
|
261 | - |
|
262 | - |
|
263 | - /** |
|
264 | - * get_all_ticket_line_items_for_transaction |
|
265 | - * |
|
266 | - * @param EE_Transaction $transaction |
|
267 | - * @return EE_Line_Item[] |
|
268 | - */ |
|
269 | - public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
270 | - { |
|
271 | - return $this->get_all(array( |
|
272 | - array( |
|
273 | - 'TXN_ID' => $transaction->ID(), |
|
274 | - 'OBJ_type' => 'Ticket', |
|
275 | - ) |
|
276 | - )); |
|
277 | - } |
|
278 | - |
|
279 | - |
|
280 | - /** |
|
281 | - * get_ticket_line_item_for_transaction |
|
282 | - * |
|
283 | - * @param int $TXN_ID |
|
284 | - * @param int $TKT_ID |
|
285 | - * @return \EE_Line_Item |
|
286 | - */ |
|
287 | - public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
288 | - { |
|
289 | - return $this->get_one(array( |
|
290 | - array( |
|
291 | - 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
292 | - 'OBJ_ID' => $TKT_ID, |
|
293 | - 'OBJ_type' => 'Ticket', |
|
294 | - ) |
|
295 | - )); |
|
296 | - } |
|
297 | - |
|
298 | - |
|
299 | - /** |
|
300 | - * get_existing_promotion_line_item |
|
301 | - * searches the cart for existing line items for the specified promotion |
|
302 | - * |
|
303 | - * @since 1.0.0 |
|
304 | - * |
|
305 | - * @param EE_Line_Item $parent_line_item |
|
306 | - * @param EE_Promotion $promotion |
|
307 | - * @return EE_Line_Item |
|
308 | - */ |
|
309 | - public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
310 | - { |
|
311 | - return $this->get_one(array( |
|
312 | - array( |
|
313 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
314 | - 'LIN_parent' => $parent_line_item->ID(), |
|
315 | - 'OBJ_type' => 'Promotion', |
|
316 | - 'OBJ_ID' => $promotion->ID() |
|
317 | - ) |
|
318 | - )); |
|
319 | - } |
|
320 | - |
|
321 | - |
|
322 | - /** |
|
323 | - * get_all_promotion_line_items |
|
324 | - * searches the cart for any and all existing promotion line items |
|
325 | - * |
|
326 | - * @since 1.0.0 |
|
327 | - * |
|
328 | - * @param EE_Line_Item $parent_line_item |
|
329 | - * @return EE_Line_Item[] |
|
330 | - */ |
|
331 | - public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
332 | - { |
|
333 | - return $this->get_all(array( |
|
334 | - array( |
|
335 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
336 | - 'LIN_parent' => $parent_line_item->ID(), |
|
337 | - 'OBJ_type' => 'Promotion' |
|
338 | - ) |
|
339 | - )); |
|
340 | - } |
|
341 | - |
|
342 | - /** |
|
343 | - * Gets the registration's corresponding line item. |
|
344 | - * Note: basically does NOT support having multiple line items for a single ticket, |
|
345 | - * which would happen if some of the registrations had a price modifier while others didn't. |
|
346 | - * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
347 | - * @param EE_Registration $registration |
|
348 | - * @return EE_Line_ITem |
|
349 | - */ |
|
350 | - public function get_line_item_for_registration(EE_Registration $registration) |
|
351 | - { |
|
352 | - return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
353 | - } |
|
354 | - |
|
355 | - /** |
|
356 | - * Gets the query params used to retrieve a specific line item for the given registration |
|
357 | - * @param EE_Registration $registration |
|
358 | - * @param array $original_query_params any extra query params you'd like to be merged with |
|
359 | - * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
360 | - */ |
|
361 | - public function line_item_for_registration_query_params(EE_Registration $registration, $original_query_params = array()) |
|
362 | - { |
|
363 | - return array_replace_recursive($original_query_params, array( |
|
364 | - array( |
|
365 | - 'OBJ_ID' => $registration->ticket_ID(), |
|
366 | - 'OBJ_type' => 'Ticket', |
|
367 | - 'TXN_ID' => $registration->transaction_ID() |
|
368 | - ) |
|
369 | - )); |
|
370 | - } |
|
371 | - |
|
372 | - |
|
373 | - /** |
|
374 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
375 | - * @throws InvalidInterfaceException |
|
376 | - * @throws InvalidDataTypeException |
|
377 | - * @throws EE_Error |
|
378 | - * @throws InvalidArgumentException |
|
379 | - */ |
|
380 | - public function get_total_line_items_with_no_transaction() |
|
381 | - { |
|
382 | - return $this->get_total_line_items_for_carts(); |
|
383 | - } |
|
384 | - |
|
385 | - |
|
386 | - /** |
|
387 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
388 | - * @throws InvalidInterfaceException |
|
389 | - * @throws InvalidDataTypeException |
|
390 | - * @throws EE_Error |
|
391 | - * @throws InvalidArgumentException |
|
392 | - */ |
|
393 | - public function get_total_line_items_for_active_carts() |
|
394 | - { |
|
395 | - return $this->get_total_line_items_for_carts(false); |
|
396 | - } |
|
397 | - |
|
398 | - |
|
399 | - /** |
|
400 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
401 | - * @throws InvalidInterfaceException |
|
402 | - * @throws InvalidDataTypeException |
|
403 | - * @throws EE_Error |
|
404 | - * @throws InvalidArgumentException |
|
405 | - */ |
|
406 | - public function get_total_line_items_for_expired_carts() |
|
407 | - { |
|
408 | - return $this->get_total_line_items_for_carts(true); |
|
409 | - } |
|
410 | - |
|
411 | - |
|
412 | - /** |
|
413 | - * Returns an array of grand total line items where the TXN_ID is 0. |
|
414 | - * If $expired is set to true, then only line items for expired sessions will be returned. |
|
415 | - * If $expired is set to false, then only line items for active sessions will be returned. |
|
416 | - * |
|
417 | - * @param null $expired |
|
418 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
419 | - * @throws EE_Error |
|
420 | - * @throws InvalidArgumentException |
|
421 | - * @throws InvalidDataTypeException |
|
422 | - * @throws InvalidInterfaceException |
|
423 | - */ |
|
424 | - private function get_total_line_items_for_carts($expired = null) |
|
425 | - { |
|
426 | - $where_params = array( |
|
427 | - 'TXN_ID' => 0, |
|
428 | - 'LIN_type' => 'total', |
|
429 | - ); |
|
430 | - if ($expired !== null) { |
|
431 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
432 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
433 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
434 | - ); |
|
435 | - $where_params['LIN_timestamp'] = array( |
|
436 | - $expired ? '<=' : '>', |
|
437 | - $session_lifespan->expiration(), |
|
438 | - ); |
|
439 | - } |
|
440 | - return $this->get_all(array($where_params)); |
|
441 | - } |
|
442 | - |
|
443 | - |
|
444 | - /** |
|
445 | - * Returns an array of ticket total line items where the TXN_ID is 0 |
|
446 | - * AND the timestamp is older than the session lifespan. |
|
447 | - * |
|
448 | - * @param int $timestamp |
|
449 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
450 | - * @throws EE_Error |
|
451 | - * @throws InvalidArgumentException |
|
452 | - * @throws InvalidDataTypeException |
|
453 | - * @throws InvalidInterfaceException |
|
454 | - */ |
|
455 | - public function getTicketLineItemsForExpiredCarts($timestamp = 0) |
|
456 | - { |
|
457 | - if (! absint($timestamp)) { |
|
458 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
459 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
460 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
461 | - ); |
|
462 | - $timestamp = $session_lifespan->expiration(); |
|
463 | - } |
|
464 | - return $this->get_all( |
|
465 | - array( |
|
466 | - array( |
|
467 | - 'TXN_ID' => 0, |
|
468 | - 'OBJ_type' => 'Ticket', |
|
469 | - 'LIN_timestamp' => array('<=', $timestamp), |
|
470 | - ) |
|
471 | - ) |
|
472 | - ); |
|
473 | - } |
|
215 | + // use GMT time because that's what TXN_timestamps are in |
|
216 | + date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
217 | + ); |
|
218 | + return $wpdb->query($query); |
|
219 | + } |
|
220 | + |
|
221 | + |
|
222 | + /** |
|
223 | + * get_line_item_for_transaction_object |
|
224 | + * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
225 | + * |
|
226 | + * @param int $TXN_ID |
|
227 | + * @param \EE_Base_Class $object |
|
228 | + * @return EE_Line_Item[] |
|
229 | + */ |
|
230 | + public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
231 | + { |
|
232 | + return $this->get_all(array(array( |
|
233 | + 'TXN_ID' => $TXN_ID, |
|
234 | + 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
235 | + 'OBJ_ID' => $object->ID() |
|
236 | + ))); |
|
237 | + } |
|
238 | + |
|
239 | + |
|
240 | + /** |
|
241 | + * get_object_line_items_for_transaction |
|
242 | + * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
243 | + * |
|
244 | + * @param int $TXN_ID |
|
245 | + * @param string $OBJ_type |
|
246 | + * @param array $OBJ_IDs |
|
247 | + * @return EE_Line_Item[] |
|
248 | + */ |
|
249 | + public function get_object_line_items_for_transaction($TXN_ID, $OBJ_type = 'Event', $OBJ_IDs = array()) |
|
250 | + { |
|
251 | + $query_params = array( |
|
252 | + 'OBJ_type' => $OBJ_type, |
|
253 | + // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
254 | + 'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs |
|
255 | + ); |
|
256 | + if ($TXN_ID) { |
|
257 | + $query_params['TXN_ID'] = $TXN_ID; |
|
258 | + } |
|
259 | + return $this->get_all(array($query_params)); |
|
260 | + } |
|
261 | + |
|
262 | + |
|
263 | + /** |
|
264 | + * get_all_ticket_line_items_for_transaction |
|
265 | + * |
|
266 | + * @param EE_Transaction $transaction |
|
267 | + * @return EE_Line_Item[] |
|
268 | + */ |
|
269 | + public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
270 | + { |
|
271 | + return $this->get_all(array( |
|
272 | + array( |
|
273 | + 'TXN_ID' => $transaction->ID(), |
|
274 | + 'OBJ_type' => 'Ticket', |
|
275 | + ) |
|
276 | + )); |
|
277 | + } |
|
278 | + |
|
279 | + |
|
280 | + /** |
|
281 | + * get_ticket_line_item_for_transaction |
|
282 | + * |
|
283 | + * @param int $TXN_ID |
|
284 | + * @param int $TKT_ID |
|
285 | + * @return \EE_Line_Item |
|
286 | + */ |
|
287 | + public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
288 | + { |
|
289 | + return $this->get_one(array( |
|
290 | + array( |
|
291 | + 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
292 | + 'OBJ_ID' => $TKT_ID, |
|
293 | + 'OBJ_type' => 'Ticket', |
|
294 | + ) |
|
295 | + )); |
|
296 | + } |
|
297 | + |
|
298 | + |
|
299 | + /** |
|
300 | + * get_existing_promotion_line_item |
|
301 | + * searches the cart for existing line items for the specified promotion |
|
302 | + * |
|
303 | + * @since 1.0.0 |
|
304 | + * |
|
305 | + * @param EE_Line_Item $parent_line_item |
|
306 | + * @param EE_Promotion $promotion |
|
307 | + * @return EE_Line_Item |
|
308 | + */ |
|
309 | + public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
310 | + { |
|
311 | + return $this->get_one(array( |
|
312 | + array( |
|
313 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
314 | + 'LIN_parent' => $parent_line_item->ID(), |
|
315 | + 'OBJ_type' => 'Promotion', |
|
316 | + 'OBJ_ID' => $promotion->ID() |
|
317 | + ) |
|
318 | + )); |
|
319 | + } |
|
320 | + |
|
321 | + |
|
322 | + /** |
|
323 | + * get_all_promotion_line_items |
|
324 | + * searches the cart for any and all existing promotion line items |
|
325 | + * |
|
326 | + * @since 1.0.0 |
|
327 | + * |
|
328 | + * @param EE_Line_Item $parent_line_item |
|
329 | + * @return EE_Line_Item[] |
|
330 | + */ |
|
331 | + public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
332 | + { |
|
333 | + return $this->get_all(array( |
|
334 | + array( |
|
335 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
336 | + 'LIN_parent' => $parent_line_item->ID(), |
|
337 | + 'OBJ_type' => 'Promotion' |
|
338 | + ) |
|
339 | + )); |
|
340 | + } |
|
341 | + |
|
342 | + /** |
|
343 | + * Gets the registration's corresponding line item. |
|
344 | + * Note: basically does NOT support having multiple line items for a single ticket, |
|
345 | + * which would happen if some of the registrations had a price modifier while others didn't. |
|
346 | + * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
347 | + * @param EE_Registration $registration |
|
348 | + * @return EE_Line_ITem |
|
349 | + */ |
|
350 | + public function get_line_item_for_registration(EE_Registration $registration) |
|
351 | + { |
|
352 | + return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
353 | + } |
|
354 | + |
|
355 | + /** |
|
356 | + * Gets the query params used to retrieve a specific line item for the given registration |
|
357 | + * @param EE_Registration $registration |
|
358 | + * @param array $original_query_params any extra query params you'd like to be merged with |
|
359 | + * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
360 | + */ |
|
361 | + public function line_item_for_registration_query_params(EE_Registration $registration, $original_query_params = array()) |
|
362 | + { |
|
363 | + return array_replace_recursive($original_query_params, array( |
|
364 | + array( |
|
365 | + 'OBJ_ID' => $registration->ticket_ID(), |
|
366 | + 'OBJ_type' => 'Ticket', |
|
367 | + 'TXN_ID' => $registration->transaction_ID() |
|
368 | + ) |
|
369 | + )); |
|
370 | + } |
|
371 | + |
|
372 | + |
|
373 | + /** |
|
374 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
375 | + * @throws InvalidInterfaceException |
|
376 | + * @throws InvalidDataTypeException |
|
377 | + * @throws EE_Error |
|
378 | + * @throws InvalidArgumentException |
|
379 | + */ |
|
380 | + public function get_total_line_items_with_no_transaction() |
|
381 | + { |
|
382 | + return $this->get_total_line_items_for_carts(); |
|
383 | + } |
|
384 | + |
|
385 | + |
|
386 | + /** |
|
387 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
388 | + * @throws InvalidInterfaceException |
|
389 | + * @throws InvalidDataTypeException |
|
390 | + * @throws EE_Error |
|
391 | + * @throws InvalidArgumentException |
|
392 | + */ |
|
393 | + public function get_total_line_items_for_active_carts() |
|
394 | + { |
|
395 | + return $this->get_total_line_items_for_carts(false); |
|
396 | + } |
|
397 | + |
|
398 | + |
|
399 | + /** |
|
400 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
401 | + * @throws InvalidInterfaceException |
|
402 | + * @throws InvalidDataTypeException |
|
403 | + * @throws EE_Error |
|
404 | + * @throws InvalidArgumentException |
|
405 | + */ |
|
406 | + public function get_total_line_items_for_expired_carts() |
|
407 | + { |
|
408 | + return $this->get_total_line_items_for_carts(true); |
|
409 | + } |
|
410 | + |
|
411 | + |
|
412 | + /** |
|
413 | + * Returns an array of grand total line items where the TXN_ID is 0. |
|
414 | + * If $expired is set to true, then only line items for expired sessions will be returned. |
|
415 | + * If $expired is set to false, then only line items for active sessions will be returned. |
|
416 | + * |
|
417 | + * @param null $expired |
|
418 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
419 | + * @throws EE_Error |
|
420 | + * @throws InvalidArgumentException |
|
421 | + * @throws InvalidDataTypeException |
|
422 | + * @throws InvalidInterfaceException |
|
423 | + */ |
|
424 | + private function get_total_line_items_for_carts($expired = null) |
|
425 | + { |
|
426 | + $where_params = array( |
|
427 | + 'TXN_ID' => 0, |
|
428 | + 'LIN_type' => 'total', |
|
429 | + ); |
|
430 | + if ($expired !== null) { |
|
431 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
432 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
433 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
434 | + ); |
|
435 | + $where_params['LIN_timestamp'] = array( |
|
436 | + $expired ? '<=' : '>', |
|
437 | + $session_lifespan->expiration(), |
|
438 | + ); |
|
439 | + } |
|
440 | + return $this->get_all(array($where_params)); |
|
441 | + } |
|
442 | + |
|
443 | + |
|
444 | + /** |
|
445 | + * Returns an array of ticket total line items where the TXN_ID is 0 |
|
446 | + * AND the timestamp is older than the session lifespan. |
|
447 | + * |
|
448 | + * @param int $timestamp |
|
449 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
450 | + * @throws EE_Error |
|
451 | + * @throws InvalidArgumentException |
|
452 | + * @throws InvalidDataTypeException |
|
453 | + * @throws InvalidInterfaceException |
|
454 | + */ |
|
455 | + public function getTicketLineItemsForExpiredCarts($timestamp = 0) |
|
456 | + { |
|
457 | + if (! absint($timestamp)) { |
|
458 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
459 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
460 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
461 | + ); |
|
462 | + $timestamp = $session_lifespan->expiration(); |
|
463 | + } |
|
464 | + return $this->get_all( |
|
465 | + array( |
|
466 | + array( |
|
467 | + 'TXN_ID' => 0, |
|
468 | + 'OBJ_type' => 'Ticket', |
|
469 | + 'LIN_timestamp' => array('<=', $timestamp), |
|
470 | + ) |
|
471 | + ) |
|
472 | + ); |
|
473 | + } |
|
474 | 474 | } |
@@ -12,137 +12,137 @@ |
||
12 | 12 | class EE_Belongs_To_Relation extends EE_Model_Relation_Base |
13 | 13 | { |
14 | 14 | |
15 | - /** |
|
16 | - * Object representing the relationship between two models. Belongs_To means that THIS model has the foreign key |
|
17 | - * to the other model. This knows how to join the models, |
|
18 | - * get related models across the relation, and add-and-remove the relationships. |
|
19 | - * |
|
20 | - * @param boolean $block_deletes For Belongs_To relations, this is set to FALSE by |
|
21 | - * default. if there are related models across this |
|
22 | - * relation, block (prevent and add an error) the |
|
23 | - * deletion of this model |
|
24 | - * @param string $related_model_objects_deletion_error_message a customized error message on blocking deletes |
|
25 | - * instead of the default |
|
26 | - */ |
|
27 | - public function __construct($block_deletes = false, $related_model_objects_deletion_error_message = null) |
|
28 | - { |
|
29 | - parent::__construct($block_deletes, $related_model_objects_deletion_error_message); |
|
30 | - } |
|
15 | + /** |
|
16 | + * Object representing the relationship between two models. Belongs_To means that THIS model has the foreign key |
|
17 | + * to the other model. This knows how to join the models, |
|
18 | + * get related models across the relation, and add-and-remove the relationships. |
|
19 | + * |
|
20 | + * @param boolean $block_deletes For Belongs_To relations, this is set to FALSE by |
|
21 | + * default. if there are related models across this |
|
22 | + * relation, block (prevent and add an error) the |
|
23 | + * deletion of this model |
|
24 | + * @param string $related_model_objects_deletion_error_message a customized error message on blocking deletes |
|
25 | + * instead of the default |
|
26 | + */ |
|
27 | + public function __construct($block_deletes = false, $related_model_objects_deletion_error_message = null) |
|
28 | + { |
|
29 | + parent::__construct($block_deletes, $related_model_objects_deletion_error_message); |
|
30 | + } |
|
31 | 31 | |
32 | 32 | |
33 | - /** |
|
34 | - * get_join_statement |
|
35 | - * |
|
36 | - * @param string $model_relation_chain |
|
37 | - * @return string |
|
38 | - * @throws \EE_Error |
|
39 | - */ |
|
40 | - public function get_join_statement($model_relation_chain) |
|
41 | - { |
|
42 | - // create the sql string like |
|
43 | - $this_table_fk_field = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
44 | - $other_table_pk_field = $this->get_other_model()->get_primary_key_field(); |
|
45 | - $this_table_alias = EE_Model_Parser::extract_table_alias_model_relation_chain_prefix( |
|
46 | - $model_relation_chain, |
|
47 | - $this->get_this_model()->get_this_model_name() |
|
48 | - ) . $this_table_fk_field->get_table_alias(); |
|
49 | - $other_table_alias = EE_Model_Parser::extract_table_alias_model_relation_chain_prefix( |
|
50 | - $model_relation_chain, |
|
51 | - $this->get_other_model()->get_this_model_name() |
|
52 | - ) . $other_table_pk_field->get_table_alias(); |
|
53 | - $other_table = $this->get_other_model()->get_table_for_alias($other_table_alias); |
|
54 | - return $this->_left_join( |
|
55 | - $other_table, |
|
56 | - $other_table_alias, |
|
57 | - $other_table_pk_field->get_table_column(), |
|
58 | - $this_table_alias, |
|
59 | - $this_table_fk_field->get_table_column() |
|
60 | - ) . $this->get_other_model()->_construct_internal_join_to_table_with_alias($other_table_alias); |
|
61 | - } |
|
33 | + /** |
|
34 | + * get_join_statement |
|
35 | + * |
|
36 | + * @param string $model_relation_chain |
|
37 | + * @return string |
|
38 | + * @throws \EE_Error |
|
39 | + */ |
|
40 | + public function get_join_statement($model_relation_chain) |
|
41 | + { |
|
42 | + // create the sql string like |
|
43 | + $this_table_fk_field = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
44 | + $other_table_pk_field = $this->get_other_model()->get_primary_key_field(); |
|
45 | + $this_table_alias = EE_Model_Parser::extract_table_alias_model_relation_chain_prefix( |
|
46 | + $model_relation_chain, |
|
47 | + $this->get_this_model()->get_this_model_name() |
|
48 | + ) . $this_table_fk_field->get_table_alias(); |
|
49 | + $other_table_alias = EE_Model_Parser::extract_table_alias_model_relation_chain_prefix( |
|
50 | + $model_relation_chain, |
|
51 | + $this->get_other_model()->get_this_model_name() |
|
52 | + ) . $other_table_pk_field->get_table_alias(); |
|
53 | + $other_table = $this->get_other_model()->get_table_for_alias($other_table_alias); |
|
54 | + return $this->_left_join( |
|
55 | + $other_table, |
|
56 | + $other_table_alias, |
|
57 | + $other_table_pk_field->get_table_column(), |
|
58 | + $this_table_alias, |
|
59 | + $this_table_fk_field->get_table_column() |
|
60 | + ) . $this->get_other_model()->_construct_internal_join_to_table_with_alias($other_table_alias); |
|
61 | + } |
|
62 | 62 | |
63 | 63 | |
64 | - /** |
|
65 | - * Sets this model object's foreign key to the other model object's primary key. Feel free to do this manually if |
|
66 | - * you like. |
|
67 | - * |
|
68 | - * @param EE_Base_Class|int $this_obj_or_id |
|
69 | - * @param EE_Base_Class|int $other_obj_or_id |
|
70 | - * @param array $extra_join_model_fields_n_values |
|
71 | - * @return \EE_Base_Class |
|
72 | - * @throws \EE_Error |
|
73 | - */ |
|
74 | - public function add_relation_to($this_obj_or_id, $other_obj_or_id, $extra_join_model_fields_n_values = array()) |
|
75 | - { |
|
76 | - $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id, true); |
|
77 | - $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id, true); |
|
78 | - // find the field on the other model which is a foreign key to this model |
|
79 | - $fk_on_this_model = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
80 | - if ($this_model_obj->get($fk_on_this_model->get_name()) != $other_model_obj->ID()) { |
|
81 | - // set that field on the other model to this model's ID |
|
82 | - $this_model_obj->set($fk_on_this_model->get_name(), $other_model_obj->ID()); |
|
83 | - $this_model_obj->save(); |
|
84 | - } |
|
85 | - return $other_model_obj; |
|
86 | - } |
|
64 | + /** |
|
65 | + * Sets this model object's foreign key to the other model object's primary key. Feel free to do this manually if |
|
66 | + * you like. |
|
67 | + * |
|
68 | + * @param EE_Base_Class|int $this_obj_or_id |
|
69 | + * @param EE_Base_Class|int $other_obj_or_id |
|
70 | + * @param array $extra_join_model_fields_n_values |
|
71 | + * @return \EE_Base_Class |
|
72 | + * @throws \EE_Error |
|
73 | + */ |
|
74 | + public function add_relation_to($this_obj_or_id, $other_obj_or_id, $extra_join_model_fields_n_values = array()) |
|
75 | + { |
|
76 | + $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id, true); |
|
77 | + $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id, true); |
|
78 | + // find the field on the other model which is a foreign key to this model |
|
79 | + $fk_on_this_model = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
80 | + if ($this_model_obj->get($fk_on_this_model->get_name()) != $other_model_obj->ID()) { |
|
81 | + // set that field on the other model to this model's ID |
|
82 | + $this_model_obj->set($fk_on_this_model->get_name(), $other_model_obj->ID()); |
|
83 | + $this_model_obj->save(); |
|
84 | + } |
|
85 | + return $other_model_obj; |
|
86 | + } |
|
87 | 87 | |
88 | 88 | |
89 | - /** |
|
90 | - * Sets the this model object's foreign key to its default, instead of pointing to the other model object |
|
91 | - * |
|
92 | - * @param EE_Base_Class|int $this_obj_or_id |
|
93 | - * @param EE_Base_Class|int $other_obj_or_id |
|
94 | - * @param array $where_query |
|
95 | - * @return \EE_Base_Class |
|
96 | - * @throws \EE_Error |
|
97 | - */ |
|
98 | - public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array()) |
|
99 | - { |
|
100 | - $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id, true); |
|
101 | - $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id); |
|
102 | - // find the field on the other model which is a foreign key to this model |
|
103 | - $fk_on_this_model = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
104 | - // set that field on the other model to this model's ID |
|
105 | - $this_model_obj->set($fk_on_this_model->get_name(), null, true); |
|
106 | - $this_model_obj->save(); |
|
107 | - return $other_model_obj; |
|
108 | - } |
|
89 | + /** |
|
90 | + * Sets the this model object's foreign key to its default, instead of pointing to the other model object |
|
91 | + * |
|
92 | + * @param EE_Base_Class|int $this_obj_or_id |
|
93 | + * @param EE_Base_Class|int $other_obj_or_id |
|
94 | + * @param array $where_query |
|
95 | + * @return \EE_Base_Class |
|
96 | + * @throws \EE_Error |
|
97 | + */ |
|
98 | + public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array()) |
|
99 | + { |
|
100 | + $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id, true); |
|
101 | + $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id); |
|
102 | + // find the field on the other model which is a foreign key to this model |
|
103 | + $fk_on_this_model = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
104 | + // set that field on the other model to this model's ID |
|
105 | + $this_model_obj->set($fk_on_this_model->get_name(), null, true); |
|
106 | + $this_model_obj->save(); |
|
107 | + return $other_model_obj; |
|
108 | + } |
|
109 | 109 | |
110 | 110 | |
111 | - /** |
|
112 | - * Overrides parent so that we don't NEED to save the $model_object before getting the related objects. |
|
113 | - * |
|
114 | - * @param EE_Base_Class $model_obj_or_id |
|
115 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
116 | - * @param boolean $values_already_prepared_by_model_object @deprecated since 4.8.1 |
|
117 | - * @return EE_Base_Class[] |
|
118 | - * @throws \EE_Error |
|
119 | - */ |
|
120 | - public function get_all_related( |
|
121 | - $model_obj_or_id, |
|
122 | - $query_params = array(), |
|
123 | - $values_already_prepared_by_model_object = false |
|
124 | - ) { |
|
125 | - if ($values_already_prepared_by_model_object !== false) { |
|
126 | - EE_Error::doing_it_wrong( |
|
127 | - 'EE_Model_Relation_Base::get_all_related', |
|
128 | - __('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'), |
|
129 | - '4.8.1' |
|
130 | - ); |
|
131 | - } |
|
132 | - // get column on this model object which is a foreign key to the other model |
|
133 | - $fk_field_obj = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
134 | - // get its value |
|
135 | - if ($model_obj_or_id instanceof EE_Base_Class) { |
|
136 | - $model_obj = $model_obj_or_id; |
|
137 | - } else { |
|
138 | - $model_obj = $this->get_this_model()->ensure_is_obj($model_obj_or_id); |
|
139 | - } |
|
140 | - $ID_value_on_other_model = $model_obj->get($fk_field_obj->get_name()); |
|
141 | - // get all where their PK matches that value |
|
142 | - $query_params[0][ $this->get_other_model()->get_primary_key_field()->get_name() ] = $ID_value_on_other_model; |
|
143 | - $query_params = $this->_disable_default_where_conditions_on_query_param($query_params); |
|
111 | + /** |
|
112 | + * Overrides parent so that we don't NEED to save the $model_object before getting the related objects. |
|
113 | + * |
|
114 | + * @param EE_Base_Class $model_obj_or_id |
|
115 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
116 | + * @param boolean $values_already_prepared_by_model_object @deprecated since 4.8.1 |
|
117 | + * @return EE_Base_Class[] |
|
118 | + * @throws \EE_Error |
|
119 | + */ |
|
120 | + public function get_all_related( |
|
121 | + $model_obj_or_id, |
|
122 | + $query_params = array(), |
|
123 | + $values_already_prepared_by_model_object = false |
|
124 | + ) { |
|
125 | + if ($values_already_prepared_by_model_object !== false) { |
|
126 | + EE_Error::doing_it_wrong( |
|
127 | + 'EE_Model_Relation_Base::get_all_related', |
|
128 | + __('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'), |
|
129 | + '4.8.1' |
|
130 | + ); |
|
131 | + } |
|
132 | + // get column on this model object which is a foreign key to the other model |
|
133 | + $fk_field_obj = $this->get_this_model()->get_foreign_key_to($this->get_other_model()->get_this_model_name()); |
|
134 | + // get its value |
|
135 | + if ($model_obj_or_id instanceof EE_Base_Class) { |
|
136 | + $model_obj = $model_obj_or_id; |
|
137 | + } else { |
|
138 | + $model_obj = $this->get_this_model()->ensure_is_obj($model_obj_or_id); |
|
139 | + } |
|
140 | + $ID_value_on_other_model = $model_obj->get($fk_field_obj->get_name()); |
|
141 | + // get all where their PK matches that value |
|
142 | + $query_params[0][ $this->get_other_model()->get_primary_key_field()->get_name() ] = $ID_value_on_other_model; |
|
143 | + $query_params = $this->_disable_default_where_conditions_on_query_param($query_params); |
|
144 | 144 | // echo '$query_params'; |
145 | 145 | // var_dump($query_params); |
146 | - return $this->get_other_model()->get_all($query_params); |
|
147 | - } |
|
146 | + return $this->get_other_model()->get_all($query_params); |
|
147 | + } |
|
148 | 148 | } |
@@ -12,303 +12,303 @@ |
||
12 | 12 | { |
13 | 13 | |
14 | 14 | |
15 | - /** |
|
16 | - * The Foreign key on the model that acts as the PRIMARY KEY used in special autosave handling where we query for |
|
17 | - * autosaves (or the Foreign key on other models in relations pointing to this models primary key which is this |
|
18 | - * value). The _primary_cpt_field is what is equivalent to the post_id field on a cpt join. |
|
19 | - * |
|
20 | - * @var string |
|
21 | - */ |
|
22 | - private $_primary_cpt_field; |
|
23 | - |
|
24 | - |
|
25 | - /** |
|
26 | - * This is what field serves as the "parent" column that is linked with whatever the main model's calling this |
|
27 | - * relation has as a primary key. In other words EEM_Event has 'Datetime' => new |
|
28 | - * EE_Has_Many_Revision_Relation('EVT_ID', 'DTT_parent'). That means that in the EEM_Datetime model the |
|
29 | - * 'DTT_Parent' field is related to the 'DTT_ID' primary key field (in the same model) because 'DTT_ID' is the |
|
30 | - * primary key in the other model (EEM_Datetime). |
|
31 | - * |
|
32 | - * @var string |
|
33 | - */ |
|
34 | - private $_parent_pk_relation_field; |
|
35 | - |
|
36 | - |
|
37 | - /** |
|
38 | - * Object representing the relationship between two models. Has_Many_Relations are where the OTHER model has the |
|
39 | - * foreign key this model. IE, there can be many other model objects related to one of this model's objects (but |
|
40 | - * NOT through a JOIN table, which is the case for EE_HABTM_Relations). This knows how to join the models, get |
|
41 | - * related models across the relation, and add-and-remove the relationships. |
|
42 | - * |
|
43 | - * @param string $primary_cpt_field See property description for details |
|
44 | - * @param string $parent_pk_relation_field This is the field that is "connected" to the $primary_cpt_field. |
|
45 | - * See property desc for details. |
|
46 | - * @param boolean $block_deletes For this type of relation, we block by default. If there are |
|
47 | - * related models across this relation, block (prevent and add an |
|
48 | - * error) the deletion of this model |
|
49 | - * @param string $blocking_delete_error_message a customized error message on blocking deletes instead of the |
|
50 | - * default |
|
51 | - */ |
|
52 | - public function __construct( |
|
53 | - $primary_cpt_field, |
|
54 | - $parent_pk_relation_field, |
|
55 | - $block_deletes = true, |
|
56 | - $blocking_delete_error_message = null |
|
57 | - ) { |
|
58 | - $this->_primary_cpt_field = $primary_cpt_field; |
|
59 | - $this->_parent_pk_relation_field = $parent_pk_relation_field; |
|
60 | - parent::__construct($block_deletes, $blocking_delete_error_message); |
|
61 | - } |
|
62 | - |
|
63 | - |
|
64 | - /** |
|
65 | - * Sets the other model object's foreign key to this model object's primary key. Feel free to do this manually if |
|
66 | - * you like. |
|
67 | - * |
|
68 | - * @param EE_Base_Class|int $this_obj_or_id |
|
69 | - * @param EE_Base_Class|int $other_obj_or_id |
|
70 | - * @param array $extra_join_model_fields_n_values |
|
71 | - * @return \EE_Base_Class |
|
72 | - * @throws \EE_Error |
|
73 | - */ |
|
74 | - public function add_relation_to($this_obj_or_id, $other_obj_or_id, $extra_join_model_fields_n_values = array()) |
|
75 | - { |
|
76 | - $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id, true); |
|
77 | - $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id); |
|
78 | - |
|
79 | - // handle possible revisions |
|
80 | - $other_model_obj = $this->_check_for_revision($this_model_obj, $other_model_obj); |
|
81 | - |
|
82 | - // if is array, then we've already done the add_relation so let's get out |
|
83 | - if (is_array($other_model_obj)) { |
|
84 | - return $other_model_obj[0]; |
|
85 | - } |
|
86 | - // find the field on the other model which is a foreign key to this model |
|
87 | - $fk_field_on_other_model = $this->get_other_model()->get_foreign_key_to($this->get_this_model()->get_this_model_name()); |
|
88 | - // set that field on the other model to this model's ID |
|
89 | - $other_model_obj->set($fk_field_on_other_model->get_name(), $this_model_obj->ID()); |
|
90 | - $other_model_obj->save(); |
|
91 | - return $other_model_obj; |
|
92 | - } |
|
93 | - |
|
94 | - |
|
95 | - /** |
|
96 | - * Sets the other model object's foreign key to its default, instead of pointing to this model object |
|
97 | - * |
|
98 | - * @param EE_Base_Class|int $this_obj_or_id |
|
99 | - * @param EE_Base_Class|int $other_obj_or_id |
|
100 | - * @param array $where_query |
|
101 | - * @return \EE_Base_Class |
|
102 | - * @throws \EE_Error |
|
103 | - */ |
|
104 | - public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array()) |
|
105 | - { |
|
106 | - $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id); |
|
107 | - $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id); |
|
108 | - // handle possible revisions |
|
109 | - $other_model_obj = $this->_check_for_revision($this_model_obj, $other_model_obj, true); |
|
110 | - |
|
111 | - |
|
112 | - // if is array, then we've already done the add_relation so let's get out |
|
113 | - if (is_array($other_model_obj)) { |
|
114 | - return $other_model_obj[0]; |
|
115 | - } |
|
116 | - |
|
117 | - // find the field on the other model which is a foreign key to this model |
|
118 | - $fk_field_on_other_model = $this->get_other_model()->get_foreign_key_to($this->get_this_model()->get_this_model_name()); |
|
119 | - |
|
120 | - |
|
121 | - // set that field on the other model to this model's ID |
|
122 | - if ($this->_blocking_delete) { |
|
123 | - $other_model_obj->set($fk_field_on_other_model->get_name(), null, true); |
|
124 | - $other_model_obj->save(); |
|
125 | - } else { |
|
126 | - $other_model_obj->delete(); |
|
127 | - $other_model_obj->set($fk_field_on_other_model->get_name(), null, true); |
|
128 | - return $other_model_obj; |
|
129 | - } |
|
130 | - return $other_model_obj; |
|
131 | - } |
|
132 | - |
|
133 | - |
|
134 | - /** |
|
135 | - * This is identical to EE_Model_Relation->get_all_related() except we're going handle special autosave conditions |
|
136 | - * in here. |
|
137 | - * |
|
138 | - * @param EE_Base_Class|int $model_object_or_id |
|
139 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
140 | - * @param boolean $values_already_prepared_by_model_object @deprecated since 4.8.1 |
|
141 | - * @return EE_Base_Class[] |
|
142 | - * @throws \EE_Error |
|
143 | - */ |
|
144 | - public function get_all_related( |
|
145 | - $model_object_or_id, |
|
146 | - $query_params = array(), |
|
147 | - $values_already_prepared_by_model_object = false |
|
148 | - ) { |
|
149 | - if ($values_already_prepared_by_model_object !== false) { |
|
150 | - EE_Error::doing_it_wrong( |
|
151 | - 'EE_Model_Relation_Base::get_all_related', |
|
152 | - __('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'), |
|
153 | - '4.8.1' |
|
154 | - ); |
|
155 | - } |
|
156 | - |
|
157 | - // if this is an autosave then we're going to get things differently |
|
158 | - if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { |
|
159 | - return $this->_do_autosave_get_all($model_object_or_id, $query_params); |
|
160 | - } |
|
161 | - |
|
162 | - return parent::get_all_related($model_object_or_id, $query_params); |
|
163 | - } |
|
164 | - |
|
165 | - |
|
166 | - /** |
|
167 | - * If we're in the midst of an autosave then we're going to do things a bit differently than the usual |
|
168 | - * get_all_related (commenting within). For description of params see the get_all_related() comments |
|
169 | - * |
|
170 | - * @access protected |
|
171 | - * @param $model_object_or_id |
|
172 | - * @param $query_params |
|
173 | - * @param bool $deprecated |
|
174 | - * @return \EE_Base_Class[] |
|
175 | - * @throws \EE_Error |
|
176 | - */ |
|
177 | - protected function _do_autosave_get_all($model_object_or_id, $query_params, $deprecated = false) |
|
178 | - { |
|
179 | - |
|
180 | - // first we check if the post_id for the incoming query is for an autosave. If it isn't that's what we want! |
|
181 | - $model_object_id = $this->_get_model_object_id($model_object_or_id); |
|
182 | - |
|
183 | - $autosave = wp_get_post_autosave($model_object_id); |
|
184 | - $id_to_use = $autosave ? $autosave->ID : $model_object_id; |
|
185 | - |
|
186 | - $autosave_relations = parent::get_all_related($id_to_use, $query_params); |
|
187 | - $parent_ids = $parents = array(); |
|
188 | - $return_objs = array(); |
|
189 | - |
|
190 | - // k this is where things differ because NOW what we're going to do is get the PARENTS for the get all related (and we'll also start setting up the return_objs array containing related that DON'T have parent ids, for those that DON'T have parents to merge with our returned objects); |
|
191 | - foreach ($autosave_relations as $a_r) { |
|
192 | - $pid = $a_r->parent(); |
|
193 | - if (! empty($pid)) { |
|
194 | - $parent_ids[] = $pid; |
|
195 | - } else { |
|
196 | - $return_objs[] = $a_r; |
|
197 | - } |
|
198 | - } |
|
199 | - |
|
200 | - // we have to make sure we also include the ORIGINAL values |
|
201 | - $originals = parent::get_all_related($model_object_or_id, $query_params); |
|
202 | - |
|
203 | - // merge $originals with $return_objs |
|
204 | - if ($originals) { |
|
205 | - $return_objs = array_merge($originals, $return_objs); |
|
206 | - } |
|
207 | - |
|
208 | - // now we setup the query to get all the parents |
|
209 | - if (! empty($parent_ids)) { |
|
210 | - $query_param_where_this_model_pk = $this->get_this_model()->get_this_model_name() . "." . $this->get_this_model()->get_primary_key_field()->get_name(); |
|
211 | - $query_param[0][ $query_param_where_this_model_pk ] = array('IN', $parent_ids); |
|
212 | - $parents = $this->get_other_model()->get_all($query_params); |
|
213 | - } |
|
214 | - |
|
215 | - // var_dump($parents); |
|
216 | - |
|
217 | - |
|
218 | - // now merge parents with our current $return_objs and send back |
|
219 | - return array_merge($parents, $return_objs); |
|
220 | - } |
|
221 | - |
|
222 | - |
|
223 | - /** |
|
224 | - * Basically this method gets called to verify if the incoming object needs to be manipulated somewhat because it |
|
225 | - * is a revision save. If so, then we change things before sending back. We also do verifications when this IS |
|
226 | - * NOT an revision because we always need to make sure that the autosave/revision has parent recorded (which is |
|
227 | - * sometime delayed if the object is created/saved first by the autosave) |
|
228 | - * |
|
229 | - * @param EE_Base_Class $this_obj |
|
230 | - * @param EE_Base_Class $other_obj |
|
231 | - * @param boolean $remove_relation Indicates whether we're doing a remove_relation or add_relation. |
|
232 | - * @return EE_Base_Class. ($other_obj); |
|
233 | - * @throws \EE_Error |
|
234 | - */ |
|
235 | - protected function _check_for_revision($this_obj, $other_obj, $remove_relation = false) |
|
236 | - { |
|
237 | - $pk_on_related_model = $this->get_other_model()->get_primary_key_field()->get_name(); |
|
238 | - // now we need to determine if we're in a WP revision save cause if we are we need to do some special handling |
|
239 | - if ($this_obj->post_type() === 'revision') { |
|
240 | - // first if $other_obj fk = this_obj pk then we know that this is a pk object, let's make sure there is a matching set for the autosave if there is then we save over it, if there isn't then we need to create a new one. |
|
241 | - $parent_evt_id = $this_obj->parent(); |
|
242 | - /*var_dump($parent_evt_id); |
|
15 | + /** |
|
16 | + * The Foreign key on the model that acts as the PRIMARY KEY used in special autosave handling where we query for |
|
17 | + * autosaves (or the Foreign key on other models in relations pointing to this models primary key which is this |
|
18 | + * value). The _primary_cpt_field is what is equivalent to the post_id field on a cpt join. |
|
19 | + * |
|
20 | + * @var string |
|
21 | + */ |
|
22 | + private $_primary_cpt_field; |
|
23 | + |
|
24 | + |
|
25 | + /** |
|
26 | + * This is what field serves as the "parent" column that is linked with whatever the main model's calling this |
|
27 | + * relation has as a primary key. In other words EEM_Event has 'Datetime' => new |
|
28 | + * EE_Has_Many_Revision_Relation('EVT_ID', 'DTT_parent'). That means that in the EEM_Datetime model the |
|
29 | + * 'DTT_Parent' field is related to the 'DTT_ID' primary key field (in the same model) because 'DTT_ID' is the |
|
30 | + * primary key in the other model (EEM_Datetime). |
|
31 | + * |
|
32 | + * @var string |
|
33 | + */ |
|
34 | + private $_parent_pk_relation_field; |
|
35 | + |
|
36 | + |
|
37 | + /** |
|
38 | + * Object representing the relationship between two models. Has_Many_Relations are where the OTHER model has the |
|
39 | + * foreign key this model. IE, there can be many other model objects related to one of this model's objects (but |
|
40 | + * NOT through a JOIN table, which is the case for EE_HABTM_Relations). This knows how to join the models, get |
|
41 | + * related models across the relation, and add-and-remove the relationships. |
|
42 | + * |
|
43 | + * @param string $primary_cpt_field See property description for details |
|
44 | + * @param string $parent_pk_relation_field This is the field that is "connected" to the $primary_cpt_field. |
|
45 | + * See property desc for details. |
|
46 | + * @param boolean $block_deletes For this type of relation, we block by default. If there are |
|
47 | + * related models across this relation, block (prevent and add an |
|
48 | + * error) the deletion of this model |
|
49 | + * @param string $blocking_delete_error_message a customized error message on blocking deletes instead of the |
|
50 | + * default |
|
51 | + */ |
|
52 | + public function __construct( |
|
53 | + $primary_cpt_field, |
|
54 | + $parent_pk_relation_field, |
|
55 | + $block_deletes = true, |
|
56 | + $blocking_delete_error_message = null |
|
57 | + ) { |
|
58 | + $this->_primary_cpt_field = $primary_cpt_field; |
|
59 | + $this->_parent_pk_relation_field = $parent_pk_relation_field; |
|
60 | + parent::__construct($block_deletes, $blocking_delete_error_message); |
|
61 | + } |
|
62 | + |
|
63 | + |
|
64 | + /** |
|
65 | + * Sets the other model object's foreign key to this model object's primary key. Feel free to do this manually if |
|
66 | + * you like. |
|
67 | + * |
|
68 | + * @param EE_Base_Class|int $this_obj_or_id |
|
69 | + * @param EE_Base_Class|int $other_obj_or_id |
|
70 | + * @param array $extra_join_model_fields_n_values |
|
71 | + * @return \EE_Base_Class |
|
72 | + * @throws \EE_Error |
|
73 | + */ |
|
74 | + public function add_relation_to($this_obj_or_id, $other_obj_or_id, $extra_join_model_fields_n_values = array()) |
|
75 | + { |
|
76 | + $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id, true); |
|
77 | + $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id); |
|
78 | + |
|
79 | + // handle possible revisions |
|
80 | + $other_model_obj = $this->_check_for_revision($this_model_obj, $other_model_obj); |
|
81 | + |
|
82 | + // if is array, then we've already done the add_relation so let's get out |
|
83 | + if (is_array($other_model_obj)) { |
|
84 | + return $other_model_obj[0]; |
|
85 | + } |
|
86 | + // find the field on the other model which is a foreign key to this model |
|
87 | + $fk_field_on_other_model = $this->get_other_model()->get_foreign_key_to($this->get_this_model()->get_this_model_name()); |
|
88 | + // set that field on the other model to this model's ID |
|
89 | + $other_model_obj->set($fk_field_on_other_model->get_name(), $this_model_obj->ID()); |
|
90 | + $other_model_obj->save(); |
|
91 | + return $other_model_obj; |
|
92 | + } |
|
93 | + |
|
94 | + |
|
95 | + /** |
|
96 | + * Sets the other model object's foreign key to its default, instead of pointing to this model object |
|
97 | + * |
|
98 | + * @param EE_Base_Class|int $this_obj_or_id |
|
99 | + * @param EE_Base_Class|int $other_obj_or_id |
|
100 | + * @param array $where_query |
|
101 | + * @return \EE_Base_Class |
|
102 | + * @throws \EE_Error |
|
103 | + */ |
|
104 | + public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array()) |
|
105 | + { |
|
106 | + $this_model_obj = $this->get_this_model()->ensure_is_obj($this_obj_or_id); |
|
107 | + $other_model_obj = $this->get_other_model()->ensure_is_obj($other_obj_or_id); |
|
108 | + // handle possible revisions |
|
109 | + $other_model_obj = $this->_check_for_revision($this_model_obj, $other_model_obj, true); |
|
110 | + |
|
111 | + |
|
112 | + // if is array, then we've already done the add_relation so let's get out |
|
113 | + if (is_array($other_model_obj)) { |
|
114 | + return $other_model_obj[0]; |
|
115 | + } |
|
116 | + |
|
117 | + // find the field on the other model which is a foreign key to this model |
|
118 | + $fk_field_on_other_model = $this->get_other_model()->get_foreign_key_to($this->get_this_model()->get_this_model_name()); |
|
119 | + |
|
120 | + |
|
121 | + // set that field on the other model to this model's ID |
|
122 | + if ($this->_blocking_delete) { |
|
123 | + $other_model_obj->set($fk_field_on_other_model->get_name(), null, true); |
|
124 | + $other_model_obj->save(); |
|
125 | + } else { |
|
126 | + $other_model_obj->delete(); |
|
127 | + $other_model_obj->set($fk_field_on_other_model->get_name(), null, true); |
|
128 | + return $other_model_obj; |
|
129 | + } |
|
130 | + return $other_model_obj; |
|
131 | + } |
|
132 | + |
|
133 | + |
|
134 | + /** |
|
135 | + * This is identical to EE_Model_Relation->get_all_related() except we're going handle special autosave conditions |
|
136 | + * in here. |
|
137 | + * |
|
138 | + * @param EE_Base_Class|int $model_object_or_id |
|
139 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
140 | + * @param boolean $values_already_prepared_by_model_object @deprecated since 4.8.1 |
|
141 | + * @return EE_Base_Class[] |
|
142 | + * @throws \EE_Error |
|
143 | + */ |
|
144 | + public function get_all_related( |
|
145 | + $model_object_or_id, |
|
146 | + $query_params = array(), |
|
147 | + $values_already_prepared_by_model_object = false |
|
148 | + ) { |
|
149 | + if ($values_already_prepared_by_model_object !== false) { |
|
150 | + EE_Error::doing_it_wrong( |
|
151 | + 'EE_Model_Relation_Base::get_all_related', |
|
152 | + __('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'), |
|
153 | + '4.8.1' |
|
154 | + ); |
|
155 | + } |
|
156 | + |
|
157 | + // if this is an autosave then we're going to get things differently |
|
158 | + if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { |
|
159 | + return $this->_do_autosave_get_all($model_object_or_id, $query_params); |
|
160 | + } |
|
161 | + |
|
162 | + return parent::get_all_related($model_object_or_id, $query_params); |
|
163 | + } |
|
164 | + |
|
165 | + |
|
166 | + /** |
|
167 | + * If we're in the midst of an autosave then we're going to do things a bit differently than the usual |
|
168 | + * get_all_related (commenting within). For description of params see the get_all_related() comments |
|
169 | + * |
|
170 | + * @access protected |
|
171 | + * @param $model_object_or_id |
|
172 | + * @param $query_params |
|
173 | + * @param bool $deprecated |
|
174 | + * @return \EE_Base_Class[] |
|
175 | + * @throws \EE_Error |
|
176 | + */ |
|
177 | + protected function _do_autosave_get_all($model_object_or_id, $query_params, $deprecated = false) |
|
178 | + { |
|
179 | + |
|
180 | + // first we check if the post_id for the incoming query is for an autosave. If it isn't that's what we want! |
|
181 | + $model_object_id = $this->_get_model_object_id($model_object_or_id); |
|
182 | + |
|
183 | + $autosave = wp_get_post_autosave($model_object_id); |
|
184 | + $id_to_use = $autosave ? $autosave->ID : $model_object_id; |
|
185 | + |
|
186 | + $autosave_relations = parent::get_all_related($id_to_use, $query_params); |
|
187 | + $parent_ids = $parents = array(); |
|
188 | + $return_objs = array(); |
|
189 | + |
|
190 | + // k this is where things differ because NOW what we're going to do is get the PARENTS for the get all related (and we'll also start setting up the return_objs array containing related that DON'T have parent ids, for those that DON'T have parents to merge with our returned objects); |
|
191 | + foreach ($autosave_relations as $a_r) { |
|
192 | + $pid = $a_r->parent(); |
|
193 | + if (! empty($pid)) { |
|
194 | + $parent_ids[] = $pid; |
|
195 | + } else { |
|
196 | + $return_objs[] = $a_r; |
|
197 | + } |
|
198 | + } |
|
199 | + |
|
200 | + // we have to make sure we also include the ORIGINAL values |
|
201 | + $originals = parent::get_all_related($model_object_or_id, $query_params); |
|
202 | + |
|
203 | + // merge $originals with $return_objs |
|
204 | + if ($originals) { |
|
205 | + $return_objs = array_merge($originals, $return_objs); |
|
206 | + } |
|
207 | + |
|
208 | + // now we setup the query to get all the parents |
|
209 | + if (! empty($parent_ids)) { |
|
210 | + $query_param_where_this_model_pk = $this->get_this_model()->get_this_model_name() . "." . $this->get_this_model()->get_primary_key_field()->get_name(); |
|
211 | + $query_param[0][ $query_param_where_this_model_pk ] = array('IN', $parent_ids); |
|
212 | + $parents = $this->get_other_model()->get_all($query_params); |
|
213 | + } |
|
214 | + |
|
215 | + // var_dump($parents); |
|
216 | + |
|
217 | + |
|
218 | + // now merge parents with our current $return_objs and send back |
|
219 | + return array_merge($parents, $return_objs); |
|
220 | + } |
|
221 | + |
|
222 | + |
|
223 | + /** |
|
224 | + * Basically this method gets called to verify if the incoming object needs to be manipulated somewhat because it |
|
225 | + * is a revision save. If so, then we change things before sending back. We also do verifications when this IS |
|
226 | + * NOT an revision because we always need to make sure that the autosave/revision has parent recorded (which is |
|
227 | + * sometime delayed if the object is created/saved first by the autosave) |
|
228 | + * |
|
229 | + * @param EE_Base_Class $this_obj |
|
230 | + * @param EE_Base_Class $other_obj |
|
231 | + * @param boolean $remove_relation Indicates whether we're doing a remove_relation or add_relation. |
|
232 | + * @return EE_Base_Class. ($other_obj); |
|
233 | + * @throws \EE_Error |
|
234 | + */ |
|
235 | + protected function _check_for_revision($this_obj, $other_obj, $remove_relation = false) |
|
236 | + { |
|
237 | + $pk_on_related_model = $this->get_other_model()->get_primary_key_field()->get_name(); |
|
238 | + // now we need to determine if we're in a WP revision save cause if we are we need to do some special handling |
|
239 | + if ($this_obj->post_type() === 'revision') { |
|
240 | + // first if $other_obj fk = this_obj pk then we know that this is a pk object, let's make sure there is a matching set for the autosave if there is then we save over it, if there isn't then we need to create a new one. |
|
241 | + $parent_evt_id = $this_obj->parent(); |
|
242 | + /*var_dump($parent_evt_id); |
|
243 | 243 | var_dump($this_obj); |
244 | 244 | var_dump($other_obj);/**/ |
245 | 245 | |
246 | - if (! empty($parent_evt_id) && $parent_evt_id == $other_obj->get($this->_primary_cpt_field)) { |
|
247 | - // let's do query on this objects model to see if the incoming pk value on the obj matches any parents in this objects table. |
|
248 | - $has_parent_obj = $this->get_other_model()->get_one(array( |
|
249 | - array( |
|
250 | - $this->_parent_pk_relation_field => $other_obj->ID(), |
|
251 | - $this->_primary_cpt_field => $this_obj->ID(), |
|
252 | - ), |
|
253 | - )); |
|
254 | - |
|
255 | - if ($has_parent_obj) { |
|
256 | - // this makes sure the update on the current obj happens to the revision's row NOT the parent row. |
|
257 | - |
|
258 | - $other_obj->set($this->_parent_pk_relation_field, $other_obj->ID()); |
|
259 | - $other_obj->set($pk_on_related_model, $has_parent_obj->ID()); |
|
260 | - $other_obj->set($this->_primary_cpt_field, $this_obj->ID()); |
|
261 | - |
|
262 | - if (! $remove_relation) { |
|
263 | - $other_obj->save(); |
|
264 | - return array($other_obj); |
|
265 | - } elseif ($remove_relation && ! $this->_blocking_delete) { |
|
266 | - $other_obj->delete(); |
|
267 | - $other_obj->set($this->_parent_pk_relation_field, null, true); |
|
268 | - return array($other_obj); |
|
269 | - } |
|
270 | - } else { |
|
271 | - $other_obj->set($this->_parent_pk_relation_field, $other_obj->ID()); |
|
272 | - $other_obj->set($this->_primary_cpt_field, $this_obj->ID()); |
|
273 | - $other_obj->set( |
|
274 | - $pk_on_related_model, |
|
275 | - null, |
|
276 | - true |
|
277 | - ); // ensure we create a new row for the autosave with parent id the same as the incoming ID. |
|
278 | - $other_obj->save(); // make sure we insert. |
|
279 | - return array($other_obj); |
|
280 | - } |
|
281 | - } |
|
282 | - |
|
283 | - // var_dump('what makes it here'); |
|
284 | - // var_dump($other_obj); |
|
285 | - // the next possible condition is that the incoming other_model obj has a NULL pk which means it just gets saved (which in turn creates it) |
|
286 | - |
|
287 | - // the last possible condition on a revision is that the incoming other_model object has a fk that == $this_obj pk which means we just return the $other obj and let it save as normal so we see the return at the bottom of this method. |
|
288 | - } else { |
|
289 | - // we only need to do the below IF this is not a remove relation |
|
290 | - if (! $remove_relation) { |
|
291 | - // okay this is is a normal update/save/remove so, let's make sure the other object is not a revision of the current object. |
|
292 | - // the other object will likely NOT have the correct fk on it (which is the primary_cpt_field_mame) so we must retrieve from the db to get that first. |
|
293 | - $existing_other_obj = $this->get_other_model()->get_one_by_ID($other_obj->ID()); |
|
294 | - $potential_revision_id = is_object($existing_other_obj) ? $existing_other_obj->get($this->_primary_cpt_field) : null; |
|
295 | - |
|
296 | - if ($parent_this_obj_id = wp_is_post_revision($potential_revision_id)) { |
|
297 | - // yes the OTHER object is linked to the revision of the parent, not the parent itself. That means we need to make the other_object an attachment of this_obj and then duplicate other_obj for the revision. |
|
298 | - $other_obj->set($this->_primary_cpt_field, $this_obj->ID()); |
|
299 | - $other_obj->save(); |
|
300 | - |
|
301 | - // now create a new other_obj and fill with details from existing object |
|
302 | - $new_obj = $other_obj; |
|
303 | - $new_obj->set($this->_primary_cpt_field, $potential_revision_id); |
|
304 | - $new_obj->set($this->_parent_pk_relation_field, $other_obj->ID()); |
|
305 | - $new_obj->set($pk_on_related_model, null); |
|
306 | - $new_obj->save(); |
|
307 | - return array($new_obj); |
|
308 | - } |
|
309 | - } |
|
310 | - } |
|
311 | - |
|
312 | - return $other_obj; |
|
313 | - } |
|
246 | + if (! empty($parent_evt_id) && $parent_evt_id == $other_obj->get($this->_primary_cpt_field)) { |
|
247 | + // let's do query on this objects model to see if the incoming pk value on the obj matches any parents in this objects table. |
|
248 | + $has_parent_obj = $this->get_other_model()->get_one(array( |
|
249 | + array( |
|
250 | + $this->_parent_pk_relation_field => $other_obj->ID(), |
|
251 | + $this->_primary_cpt_field => $this_obj->ID(), |
|
252 | + ), |
|
253 | + )); |
|
254 | + |
|
255 | + if ($has_parent_obj) { |
|
256 | + // this makes sure the update on the current obj happens to the revision's row NOT the parent row. |
|
257 | + |
|
258 | + $other_obj->set($this->_parent_pk_relation_field, $other_obj->ID()); |
|
259 | + $other_obj->set($pk_on_related_model, $has_parent_obj->ID()); |
|
260 | + $other_obj->set($this->_primary_cpt_field, $this_obj->ID()); |
|
261 | + |
|
262 | + if (! $remove_relation) { |
|
263 | + $other_obj->save(); |
|
264 | + return array($other_obj); |
|
265 | + } elseif ($remove_relation && ! $this->_blocking_delete) { |
|
266 | + $other_obj->delete(); |
|
267 | + $other_obj->set($this->_parent_pk_relation_field, null, true); |
|
268 | + return array($other_obj); |
|
269 | + } |
|
270 | + } else { |
|
271 | + $other_obj->set($this->_parent_pk_relation_field, $other_obj->ID()); |
|
272 | + $other_obj->set($this->_primary_cpt_field, $this_obj->ID()); |
|
273 | + $other_obj->set( |
|
274 | + $pk_on_related_model, |
|
275 | + null, |
|
276 | + true |
|
277 | + ); // ensure we create a new row for the autosave with parent id the same as the incoming ID. |
|
278 | + $other_obj->save(); // make sure we insert. |
|
279 | + return array($other_obj); |
|
280 | + } |
|
281 | + } |
|
282 | + |
|
283 | + // var_dump('what makes it here'); |
|
284 | + // var_dump($other_obj); |
|
285 | + // the next possible condition is that the incoming other_model obj has a NULL pk which means it just gets saved (which in turn creates it) |
|
286 | + |
|
287 | + // the last possible condition on a revision is that the incoming other_model object has a fk that == $this_obj pk which means we just return the $other obj and let it save as normal so we see the return at the bottom of this method. |
|
288 | + } else { |
|
289 | + // we only need to do the below IF this is not a remove relation |
|
290 | + if (! $remove_relation) { |
|
291 | + // okay this is is a normal update/save/remove so, let's make sure the other object is not a revision of the current object. |
|
292 | + // the other object will likely NOT have the correct fk on it (which is the primary_cpt_field_mame) so we must retrieve from the db to get that first. |
|
293 | + $existing_other_obj = $this->get_other_model()->get_one_by_ID($other_obj->ID()); |
|
294 | + $potential_revision_id = is_object($existing_other_obj) ? $existing_other_obj->get($this->_primary_cpt_field) : null; |
|
295 | + |
|
296 | + if ($parent_this_obj_id = wp_is_post_revision($potential_revision_id)) { |
|
297 | + // yes the OTHER object is linked to the revision of the parent, not the parent itself. That means we need to make the other_object an attachment of this_obj and then duplicate other_obj for the revision. |
|
298 | + $other_obj->set($this->_primary_cpt_field, $this_obj->ID()); |
|
299 | + $other_obj->save(); |
|
300 | + |
|
301 | + // now create a new other_obj and fill with details from existing object |
|
302 | + $new_obj = $other_obj; |
|
303 | + $new_obj->set($this->_primary_cpt_field, $potential_revision_id); |
|
304 | + $new_obj->set($this->_parent_pk_relation_field, $other_obj->ID()); |
|
305 | + $new_obj->set($pk_on_related_model, null); |
|
306 | + $new_obj->save(); |
|
307 | + return array($new_obj); |
|
308 | + } |
|
309 | + } |
|
310 | + } |
|
311 | + |
|
312 | + return $other_obj; |
|
313 | + } |
|
314 | 314 | } |
@@ -15,502 +15,502 @@ |
||
15 | 15 | */ |
16 | 16 | abstract class EE_Model_Relation_Base implements HasSchemaInterface |
17 | 17 | { |
18 | - /** |
|
19 | - * The model name of which this relation is a component (ie, the model that called new EE_Model_Relation_Base) |
|
20 | - * |
|
21 | - * @var string eg Event, Question_Group, Registration |
|
22 | - */ |
|
23 | - private $_this_model_name; |
|
24 | - /** |
|
25 | - * The model name pointed to by this relation (ie, the model we want to establish a relationship to) |
|
26 | - * |
|
27 | - * @var string eg Event, Question_Group, Registration |
|
28 | - */ |
|
29 | - private $_other_model_name; |
|
30 | - |
|
31 | - /** |
|
32 | - * this is typically used when calling the relation models to make sure they inherit any set timezone from the |
|
33 | - * initiating model. |
|
34 | - * |
|
35 | - * @var string |
|
36 | - */ |
|
37 | - protected $_timezone; |
|
38 | - |
|
39 | - /** |
|
40 | - * If you try to delete "this_model", and there are related "other_models", |
|
41 | - * and this isn't null, then abandon the deletion and add this warning. |
|
42 | - * This effectively makes it impossible to delete "this_model" while there are |
|
43 | - * related "other_models" along this relation. |
|
44 | - * |
|
45 | - * @var string (internationalized) |
|
46 | - */ |
|
47 | - protected $_blocking_delete_error_message; |
|
48 | - |
|
49 | - protected $_blocking_delete = false; |
|
50 | - |
|
51 | - /** |
|
52 | - * Object representing the relationship between two models. This knows how to join the models, |
|
53 | - * get related models across the relation, and add-and-remove the relationships. |
|
54 | - * |
|
55 | - * @param boolean $block_deletes if there are related models across this relation, block (prevent |
|
56 | - * and add an error) the deletion of this model |
|
57 | - * @param string $blocking_delete_error_message a customized error message on blocking deletes instead of the |
|
58 | - * default |
|
59 | - */ |
|
60 | - public function __construct($block_deletes, $blocking_delete_error_message) |
|
61 | - { |
|
62 | - $this->_blocking_delete = $block_deletes; |
|
63 | - $this->_blocking_delete_error_message = $blocking_delete_error_message; |
|
64 | - } |
|
65 | - |
|
66 | - |
|
67 | - /** |
|
68 | - * @param $this_model_name |
|
69 | - * @param $other_model_name |
|
70 | - * @throws EE_Error |
|
71 | - */ |
|
72 | - public function _construct_finalize_set_models($this_model_name, $other_model_name) |
|
73 | - { |
|
74 | - $this->_this_model_name = $this_model_name; |
|
75 | - $this->_other_model_name = $other_model_name; |
|
76 | - if (is_string($this->_blocking_delete)) { |
|
77 | - throw new EE_Error(sprintf( |
|
78 | - __( |
|
79 | - "When instantiating the relation of type %s from %s to %s, the \$block_deletes argument should be a boolean, not a string (%s)", |
|
80 | - "event_espresso" |
|
81 | - ), |
|
82 | - get_class($this), |
|
83 | - $this_model_name, |
|
84 | - $other_model_name, |
|
85 | - $this->_blocking_delete |
|
86 | - )); |
|
87 | - } |
|
88 | - } |
|
89 | - |
|
90 | - |
|
91 | - /** |
|
92 | - * Gets the model where this relation is defined. |
|
93 | - * |
|
94 | - * @return EEM_Base |
|
95 | - */ |
|
96 | - public function get_this_model() |
|
97 | - { |
|
98 | - return $this->_get_model($this->_this_model_name); |
|
99 | - } |
|
100 | - |
|
101 | - |
|
102 | - /** |
|
103 | - * Gets the model which this relation establishes the relation TO (ie, |
|
104 | - * this relation object was defined on get_this_model(), get_other_model() is the other one) |
|
105 | - * |
|
106 | - * @return EEM_Base |
|
107 | - */ |
|
108 | - public function get_other_model() |
|
109 | - { |
|
110 | - return $this->_get_model($this->_other_model_name); |
|
111 | - } |
|
112 | - |
|
113 | - |
|
114 | - /** |
|
115 | - * Internally used by get_this_model() and get_other_model() |
|
116 | - * |
|
117 | - * @param string $model_name like Event, Question_Group, etc. omit the EEM_ |
|
118 | - * @return EEM_Base |
|
119 | - */ |
|
120 | - protected function _get_model($model_name) |
|
121 | - { |
|
122 | - $modelInstance = EE_Registry::instance()->load_model($model_name); |
|
123 | - $modelInstance->set_timezone($this->_timezone); |
|
124 | - return $modelInstance; |
|
125 | - } |
|
126 | - |
|
127 | - |
|
128 | - /** |
|
129 | - * entirely possible that relations may be called from a model and we need to make sure those relations have their |
|
130 | - * timezone set correctly. |
|
131 | - * |
|
132 | - * @param string $timezone timezone to set. |
|
133 | - */ |
|
134 | - public function set_timezone($timezone) |
|
135 | - { |
|
136 | - if ($timezone !== null) { |
|
137 | - $this->_timezone = $timezone; |
|
138 | - } |
|
139 | - } |
|
140 | - |
|
141 | - |
|
142 | - /** |
|
143 | - * @param $other_table |
|
144 | - * @param $other_table_alias |
|
145 | - * @param $other_table_column |
|
146 | - * @param $this_table_alias |
|
147 | - * @param $this_table_join_column |
|
148 | - * @param string $extra_join_sql |
|
149 | - * @return string |
|
150 | - */ |
|
151 | - protected function _left_join( |
|
152 | - $other_table, |
|
153 | - $other_table_alias, |
|
154 | - $other_table_column, |
|
155 | - $this_table_alias, |
|
156 | - $this_table_join_column, |
|
157 | - $extra_join_sql = '' |
|
158 | - ) { |
|
159 | - return " LEFT JOIN " . $other_table . " AS " . $other_table_alias . " ON " . $other_table_alias . "." . $other_table_column . "=" . $this_table_alias . "." . $this_table_join_column . ($extra_join_sql ? " AND $extra_join_sql" : ''); |
|
160 | - } |
|
161 | - |
|
162 | - |
|
163 | - /** |
|
164 | - * Gets all the model objects of type of other model related to $model_object, |
|
165 | - * according to this relation. This is the same code for EE_HABTM_Relation and EE_Has_Many_Relation. |
|
166 | - * For both of those child classes, $model_object must be saved so that it has an ID before querying, |
|
167 | - * otherwise an error will be thrown. Note: by default we disable default_where_conditions |
|
168 | - * EE_Belongs_To_Relation doesn't need to be saved before querying. |
|
169 | - * |
|
170 | - * @param EE_Base_Class|int $model_object_or_id or the primary key of this model |
|
171 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
172 | - * @param boolean $values_already_prepared_by_model_object @deprecated since 4.8.1 |
|
173 | - * @return EE_Base_Class[] |
|
174 | - * @throws \EE_Error |
|
175 | - */ |
|
176 | - public function get_all_related( |
|
177 | - $model_object_or_id, |
|
178 | - $query_params = array(), |
|
179 | - $values_already_prepared_by_model_object = false |
|
180 | - ) { |
|
181 | - if ($values_already_prepared_by_model_object !== false) { |
|
182 | - EE_Error::doing_it_wrong( |
|
183 | - 'EE_Model_Relation_Base::get_all_related', |
|
184 | - __('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'), |
|
185 | - '4.8.1' |
|
186 | - ); |
|
187 | - } |
|
188 | - $query_params = $this->_disable_default_where_conditions_on_query_param($query_params); |
|
189 | - $query_param_where_this_model_pk = $this->get_this_model()->get_this_model_name() |
|
190 | - . "." |
|
191 | - . $this->get_this_model()->get_primary_key_field()->get_name(); |
|
192 | - $model_object_id = $this->_get_model_object_id($model_object_or_id); |
|
193 | - $query_params[0][ $query_param_where_this_model_pk ] = $model_object_id; |
|
194 | - return $this->get_other_model()->get_all($query_params); |
|
195 | - } |
|
196 | - |
|
197 | - |
|
198 | - /** |
|
199 | - * Alters the $query_params to disable default where conditions, unless otherwise specified |
|
200 | - * |
|
201 | - * @param string $query_params |
|
202 | - * @return array |
|
203 | - */ |
|
204 | - protected function _disable_default_where_conditions_on_query_param($query_params) |
|
205 | - { |
|
206 | - if (! isset($query_params['default_where_conditions'])) { |
|
207 | - $query_params['default_where_conditions'] = 'none'; |
|
208 | - } |
|
209 | - return $query_params; |
|
210 | - } |
|
211 | - |
|
212 | - |
|
213 | - /** |
|
214 | - * Deletes the related model objects which meet the query parameters. If no |
|
215 | - * parameters are specified, then all related model objects will be deleted. |
|
216 | - * Note: If the related model is extends EEM_Soft_Delete_Base, then the related |
|
217 | - * model objects will only be soft-deleted. |
|
218 | - * |
|
219 | - * @param EE_Base_Class|int|string $model_object_or_id |
|
220 | - * @param array $query_params |
|
221 | - * @return int of how many related models got deleted |
|
222 | - * @throws \EE_Error |
|
223 | - */ |
|
224 | - public function delete_all_related($model_object_or_id, $query_params = array()) |
|
225 | - { |
|
226 | - // for each thing we would delete, |
|
227 | - $related_model_objects = $this->get_all_related($model_object_or_id, $query_params); |
|
228 | - // determine if it's blocked by anything else before it can be deleted |
|
229 | - $deleted_count = 0; |
|
230 | - foreach ($related_model_objects as $related_model_object) { |
|
231 | - $delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models( |
|
232 | - $related_model_object, |
|
233 | - $model_object_or_id |
|
234 | - ); |
|
235 | - /* @var $model_object_or_id EE_Base_Class */ |
|
236 | - if (! $delete_is_blocked) { |
|
237 | - $this->remove_relation_to($model_object_or_id, $related_model_object); |
|
238 | - $related_model_object->delete(); |
|
239 | - $deleted_count++; |
|
240 | - } |
|
241 | - } |
|
242 | - return $deleted_count; |
|
243 | - } |
|
244 | - |
|
245 | - |
|
246 | - /** |
|
247 | - * Deletes the related model objects which meet the query parameters. If no |
|
248 | - * parameters are specified, then all related model objects will be deleted. |
|
249 | - * Note: If the related model is extends EEM_Soft_Delete_Base, then the related |
|
250 | - * model objects will only be soft-deleted. |
|
251 | - * |
|
252 | - * @param EE_Base_Class|int|string $model_object_or_id |
|
253 | - * @param array $query_params |
|
254 | - * @return int of how many related models got deleted |
|
255 | - * @throws \EE_Error |
|
256 | - */ |
|
257 | - public function delete_related_permanently($model_object_or_id, $query_params = array()) |
|
258 | - { |
|
259 | - // for each thing we would delete, |
|
260 | - $related_model_objects = $this->get_all_related($model_object_or_id, $query_params); |
|
261 | - // determine if it's blocked by anything else before it can be deleted |
|
262 | - $deleted_count = 0; |
|
263 | - foreach ($related_model_objects as $related_model_object) { |
|
264 | - $delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models( |
|
265 | - $related_model_object, |
|
266 | - $model_object_or_id |
|
267 | - ); |
|
268 | - /* @var $model_object_or_id EE_Base_Class */ |
|
269 | - if ($related_model_object instanceof EE_Soft_Delete_Base_Class) { |
|
270 | - $this->remove_relation_to($model_object_or_id, $related_model_object); |
|
271 | - $deleted_count++; |
|
272 | - if (! $delete_is_blocked) { |
|
273 | - $related_model_object->delete_permanently(); |
|
274 | - } else { |
|
275 | - // delete is blocked |
|
276 | - // brent and darren, in this case, wanted to just soft delete it then |
|
277 | - $related_model_object->delete(); |
|
278 | - } |
|
279 | - } else { |
|
280 | - // its not a soft-deletable thing anyways. do the normal logic. |
|
281 | - if (! $delete_is_blocked) { |
|
282 | - $this->remove_relation_to($model_object_or_id, $related_model_object); |
|
283 | - $related_model_object->delete(); |
|
284 | - $deleted_count++; |
|
285 | - } |
|
286 | - } |
|
287 | - } |
|
288 | - return $deleted_count; |
|
289 | - } |
|
290 | - |
|
291 | - |
|
292 | - /** |
|
293 | - * this just returns a model_object_id for incoming item that could be an object or id. |
|
294 | - * |
|
295 | - * @param EE_Base_Class|int $model_object_or_id model object or the primary key of this model |
|
296 | - * @throws EE_Error |
|
297 | - * @return int |
|
298 | - */ |
|
299 | - protected function _get_model_object_id($model_object_or_id) |
|
300 | - { |
|
301 | - $model_object_id = $model_object_or_id; |
|
302 | - if ($model_object_or_id instanceof EE_Base_Class) { |
|
303 | - $model_object_id = $model_object_or_id->ID(); |
|
304 | - } |
|
305 | - if (! $model_object_id) { |
|
306 | - throw new EE_Error(sprintf( |
|
307 | - __( |
|
308 | - "Sorry, we cant get the related %s model objects to %s model object before it has an ID. You can solve that by just saving it before trying to get its related model objects", |
|
309 | - "event_espresso" |
|
310 | - ), |
|
311 | - $this->get_other_model()->get_this_model_name(), |
|
312 | - $this->get_this_model()->get_this_model_name() |
|
313 | - )); |
|
314 | - } |
|
315 | - return $model_object_id; |
|
316 | - } |
|
317 | - |
|
318 | - |
|
319 | - /** |
|
320 | - * Gets the SQL string for performing the join between this model and the other model. |
|
321 | - * |
|
322 | - * @param string $model_relation_chain like 'Event.Event_Venue.Venue' |
|
323 | - * @return string of SQL, eg "LEFT JOIN table_name AS table_alias ON this_model_primary_table.pk = |
|
324 | - * other_model_primary_table.fk" etc |
|
325 | - */ |
|
326 | - abstract public function get_join_statement($model_relation_chain); |
|
327 | - |
|
328 | - |
|
329 | - /** |
|
330 | - * Adds a relationships between the two model objects provided. Each type of relationship handles this differently |
|
331 | - * (EE_Belongs_To is a slight exception, it should more accurately be called set_relation_to(...), as this |
|
332 | - * relationship only allows this model to be related to a single other model of this type) |
|
333 | - * |
|
334 | - * @param $this_obj_or_id |
|
335 | - * @param $other_obj_or_id |
|
336 | - * @param array $extra_join_model_fields_n_values |
|
337 | - * @return \EE_Base_Class the EE_Base_Class which was added as a relation. (Convenient if you only pass an ID for |
|
338 | - * $other_obj_or_id) |
|
339 | - */ |
|
340 | - abstract public function add_relation_to( |
|
341 | - $this_obj_or_id, |
|
342 | - $other_obj_or_id, |
|
343 | - $extra_join_model_fields_n_values = array() |
|
344 | - ); |
|
345 | - |
|
346 | - |
|
347 | - /** |
|
348 | - * Similar to 'add_relation_to(...)', performs the opposite action of removing the relationship between the two |
|
349 | - * model objects |
|
350 | - * |
|
351 | - * @param $this_obj_or_id |
|
352 | - * @param $other_obj_or_id |
|
353 | - * @param array $where_query |
|
354 | - * @return bool |
|
355 | - */ |
|
356 | - abstract public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array()); |
|
357 | - |
|
358 | - |
|
359 | - /** |
|
360 | - * Removes ALL relation instances for this relation obj |
|
361 | - * |
|
362 | - * @param EE_Base_Class|int $this_obj_or_id |
|
363 | - * @param array $where_query_param @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
364 | - * @return EE_Base_Class[] |
|
365 | - * @throws \EE_Error |
|
366 | - */ |
|
367 | - public function remove_relations($this_obj_or_id, $where_query_param = array()) |
|
368 | - { |
|
369 | - $related_things = $this->get_all_related($this_obj_or_id, array($where_query_param)); |
|
370 | - $objs_removed = array(); |
|
371 | - foreach ($related_things as $related_thing) { |
|
372 | - $objs_removed[] = $this->remove_relation_to($this_obj_or_id, $related_thing); |
|
373 | - } |
|
374 | - return $objs_removed; |
|
375 | - } |
|
376 | - |
|
377 | - |
|
378 | - /** |
|
379 | - * If you aren't allowed to delete this model when there are related models across this |
|
380 | - * relation object, return true. Otherwise, if you can delete this model even though |
|
381 | - * related objects exist, returns false. |
|
382 | - * |
|
383 | - * @return boolean |
|
384 | - */ |
|
385 | - public function block_delete_if_related_models_exist() |
|
386 | - { |
|
387 | - return $this->_blocking_delete; |
|
388 | - } |
|
389 | - |
|
390 | - |
|
391 | - /** |
|
392 | - * Gets the error message to show |
|
393 | - * |
|
394 | - * @return string |
|
395 | - */ |
|
396 | - public function get_deletion_error_message() |
|
397 | - { |
|
398 | - if ($this->_blocking_delete_error_message) { |
|
399 | - return $this->_blocking_delete_error_message; |
|
400 | - } else { |
|
18 | + /** |
|
19 | + * The model name of which this relation is a component (ie, the model that called new EE_Model_Relation_Base) |
|
20 | + * |
|
21 | + * @var string eg Event, Question_Group, Registration |
|
22 | + */ |
|
23 | + private $_this_model_name; |
|
24 | + /** |
|
25 | + * The model name pointed to by this relation (ie, the model we want to establish a relationship to) |
|
26 | + * |
|
27 | + * @var string eg Event, Question_Group, Registration |
|
28 | + */ |
|
29 | + private $_other_model_name; |
|
30 | + |
|
31 | + /** |
|
32 | + * this is typically used when calling the relation models to make sure they inherit any set timezone from the |
|
33 | + * initiating model. |
|
34 | + * |
|
35 | + * @var string |
|
36 | + */ |
|
37 | + protected $_timezone; |
|
38 | + |
|
39 | + /** |
|
40 | + * If you try to delete "this_model", and there are related "other_models", |
|
41 | + * and this isn't null, then abandon the deletion and add this warning. |
|
42 | + * This effectively makes it impossible to delete "this_model" while there are |
|
43 | + * related "other_models" along this relation. |
|
44 | + * |
|
45 | + * @var string (internationalized) |
|
46 | + */ |
|
47 | + protected $_blocking_delete_error_message; |
|
48 | + |
|
49 | + protected $_blocking_delete = false; |
|
50 | + |
|
51 | + /** |
|
52 | + * Object representing the relationship between two models. This knows how to join the models, |
|
53 | + * get related models across the relation, and add-and-remove the relationships. |
|
54 | + * |
|
55 | + * @param boolean $block_deletes if there are related models across this relation, block (prevent |
|
56 | + * and add an error) the deletion of this model |
|
57 | + * @param string $blocking_delete_error_message a customized error message on blocking deletes instead of the |
|
58 | + * default |
|
59 | + */ |
|
60 | + public function __construct($block_deletes, $blocking_delete_error_message) |
|
61 | + { |
|
62 | + $this->_blocking_delete = $block_deletes; |
|
63 | + $this->_blocking_delete_error_message = $blocking_delete_error_message; |
|
64 | + } |
|
65 | + |
|
66 | + |
|
67 | + /** |
|
68 | + * @param $this_model_name |
|
69 | + * @param $other_model_name |
|
70 | + * @throws EE_Error |
|
71 | + */ |
|
72 | + public function _construct_finalize_set_models($this_model_name, $other_model_name) |
|
73 | + { |
|
74 | + $this->_this_model_name = $this_model_name; |
|
75 | + $this->_other_model_name = $other_model_name; |
|
76 | + if (is_string($this->_blocking_delete)) { |
|
77 | + throw new EE_Error(sprintf( |
|
78 | + __( |
|
79 | + "When instantiating the relation of type %s from %s to %s, the \$block_deletes argument should be a boolean, not a string (%s)", |
|
80 | + "event_espresso" |
|
81 | + ), |
|
82 | + get_class($this), |
|
83 | + $this_model_name, |
|
84 | + $other_model_name, |
|
85 | + $this->_blocking_delete |
|
86 | + )); |
|
87 | + } |
|
88 | + } |
|
89 | + |
|
90 | + |
|
91 | + /** |
|
92 | + * Gets the model where this relation is defined. |
|
93 | + * |
|
94 | + * @return EEM_Base |
|
95 | + */ |
|
96 | + public function get_this_model() |
|
97 | + { |
|
98 | + return $this->_get_model($this->_this_model_name); |
|
99 | + } |
|
100 | + |
|
101 | + |
|
102 | + /** |
|
103 | + * Gets the model which this relation establishes the relation TO (ie, |
|
104 | + * this relation object was defined on get_this_model(), get_other_model() is the other one) |
|
105 | + * |
|
106 | + * @return EEM_Base |
|
107 | + */ |
|
108 | + public function get_other_model() |
|
109 | + { |
|
110 | + return $this->_get_model($this->_other_model_name); |
|
111 | + } |
|
112 | + |
|
113 | + |
|
114 | + /** |
|
115 | + * Internally used by get_this_model() and get_other_model() |
|
116 | + * |
|
117 | + * @param string $model_name like Event, Question_Group, etc. omit the EEM_ |
|
118 | + * @return EEM_Base |
|
119 | + */ |
|
120 | + protected function _get_model($model_name) |
|
121 | + { |
|
122 | + $modelInstance = EE_Registry::instance()->load_model($model_name); |
|
123 | + $modelInstance->set_timezone($this->_timezone); |
|
124 | + return $modelInstance; |
|
125 | + } |
|
126 | + |
|
127 | + |
|
128 | + /** |
|
129 | + * entirely possible that relations may be called from a model and we need to make sure those relations have their |
|
130 | + * timezone set correctly. |
|
131 | + * |
|
132 | + * @param string $timezone timezone to set. |
|
133 | + */ |
|
134 | + public function set_timezone($timezone) |
|
135 | + { |
|
136 | + if ($timezone !== null) { |
|
137 | + $this->_timezone = $timezone; |
|
138 | + } |
|
139 | + } |
|
140 | + |
|
141 | + |
|
142 | + /** |
|
143 | + * @param $other_table |
|
144 | + * @param $other_table_alias |
|
145 | + * @param $other_table_column |
|
146 | + * @param $this_table_alias |
|
147 | + * @param $this_table_join_column |
|
148 | + * @param string $extra_join_sql |
|
149 | + * @return string |
|
150 | + */ |
|
151 | + protected function _left_join( |
|
152 | + $other_table, |
|
153 | + $other_table_alias, |
|
154 | + $other_table_column, |
|
155 | + $this_table_alias, |
|
156 | + $this_table_join_column, |
|
157 | + $extra_join_sql = '' |
|
158 | + ) { |
|
159 | + return " LEFT JOIN " . $other_table . " AS " . $other_table_alias . " ON " . $other_table_alias . "." . $other_table_column . "=" . $this_table_alias . "." . $this_table_join_column . ($extra_join_sql ? " AND $extra_join_sql" : ''); |
|
160 | + } |
|
161 | + |
|
162 | + |
|
163 | + /** |
|
164 | + * Gets all the model objects of type of other model related to $model_object, |
|
165 | + * according to this relation. This is the same code for EE_HABTM_Relation and EE_Has_Many_Relation. |
|
166 | + * For both of those child classes, $model_object must be saved so that it has an ID before querying, |
|
167 | + * otherwise an error will be thrown. Note: by default we disable default_where_conditions |
|
168 | + * EE_Belongs_To_Relation doesn't need to be saved before querying. |
|
169 | + * |
|
170 | + * @param EE_Base_Class|int $model_object_or_id or the primary key of this model |
|
171 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
172 | + * @param boolean $values_already_prepared_by_model_object @deprecated since 4.8.1 |
|
173 | + * @return EE_Base_Class[] |
|
174 | + * @throws \EE_Error |
|
175 | + */ |
|
176 | + public function get_all_related( |
|
177 | + $model_object_or_id, |
|
178 | + $query_params = array(), |
|
179 | + $values_already_prepared_by_model_object = false |
|
180 | + ) { |
|
181 | + if ($values_already_prepared_by_model_object !== false) { |
|
182 | + EE_Error::doing_it_wrong( |
|
183 | + 'EE_Model_Relation_Base::get_all_related', |
|
184 | + __('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'), |
|
185 | + '4.8.1' |
|
186 | + ); |
|
187 | + } |
|
188 | + $query_params = $this->_disable_default_where_conditions_on_query_param($query_params); |
|
189 | + $query_param_where_this_model_pk = $this->get_this_model()->get_this_model_name() |
|
190 | + . "." |
|
191 | + . $this->get_this_model()->get_primary_key_field()->get_name(); |
|
192 | + $model_object_id = $this->_get_model_object_id($model_object_or_id); |
|
193 | + $query_params[0][ $query_param_where_this_model_pk ] = $model_object_id; |
|
194 | + return $this->get_other_model()->get_all($query_params); |
|
195 | + } |
|
196 | + |
|
197 | + |
|
198 | + /** |
|
199 | + * Alters the $query_params to disable default where conditions, unless otherwise specified |
|
200 | + * |
|
201 | + * @param string $query_params |
|
202 | + * @return array |
|
203 | + */ |
|
204 | + protected function _disable_default_where_conditions_on_query_param($query_params) |
|
205 | + { |
|
206 | + if (! isset($query_params['default_where_conditions'])) { |
|
207 | + $query_params['default_where_conditions'] = 'none'; |
|
208 | + } |
|
209 | + return $query_params; |
|
210 | + } |
|
211 | + |
|
212 | + |
|
213 | + /** |
|
214 | + * Deletes the related model objects which meet the query parameters. If no |
|
215 | + * parameters are specified, then all related model objects will be deleted. |
|
216 | + * Note: If the related model is extends EEM_Soft_Delete_Base, then the related |
|
217 | + * model objects will only be soft-deleted. |
|
218 | + * |
|
219 | + * @param EE_Base_Class|int|string $model_object_or_id |
|
220 | + * @param array $query_params |
|
221 | + * @return int of how many related models got deleted |
|
222 | + * @throws \EE_Error |
|
223 | + */ |
|
224 | + public function delete_all_related($model_object_or_id, $query_params = array()) |
|
225 | + { |
|
226 | + // for each thing we would delete, |
|
227 | + $related_model_objects = $this->get_all_related($model_object_or_id, $query_params); |
|
228 | + // determine if it's blocked by anything else before it can be deleted |
|
229 | + $deleted_count = 0; |
|
230 | + foreach ($related_model_objects as $related_model_object) { |
|
231 | + $delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models( |
|
232 | + $related_model_object, |
|
233 | + $model_object_or_id |
|
234 | + ); |
|
235 | + /* @var $model_object_or_id EE_Base_Class */ |
|
236 | + if (! $delete_is_blocked) { |
|
237 | + $this->remove_relation_to($model_object_or_id, $related_model_object); |
|
238 | + $related_model_object->delete(); |
|
239 | + $deleted_count++; |
|
240 | + } |
|
241 | + } |
|
242 | + return $deleted_count; |
|
243 | + } |
|
244 | + |
|
245 | + |
|
246 | + /** |
|
247 | + * Deletes the related model objects which meet the query parameters. If no |
|
248 | + * parameters are specified, then all related model objects will be deleted. |
|
249 | + * Note: If the related model is extends EEM_Soft_Delete_Base, then the related |
|
250 | + * model objects will only be soft-deleted. |
|
251 | + * |
|
252 | + * @param EE_Base_Class|int|string $model_object_or_id |
|
253 | + * @param array $query_params |
|
254 | + * @return int of how many related models got deleted |
|
255 | + * @throws \EE_Error |
|
256 | + */ |
|
257 | + public function delete_related_permanently($model_object_or_id, $query_params = array()) |
|
258 | + { |
|
259 | + // for each thing we would delete, |
|
260 | + $related_model_objects = $this->get_all_related($model_object_or_id, $query_params); |
|
261 | + // determine if it's blocked by anything else before it can be deleted |
|
262 | + $deleted_count = 0; |
|
263 | + foreach ($related_model_objects as $related_model_object) { |
|
264 | + $delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models( |
|
265 | + $related_model_object, |
|
266 | + $model_object_or_id |
|
267 | + ); |
|
268 | + /* @var $model_object_or_id EE_Base_Class */ |
|
269 | + if ($related_model_object instanceof EE_Soft_Delete_Base_Class) { |
|
270 | + $this->remove_relation_to($model_object_or_id, $related_model_object); |
|
271 | + $deleted_count++; |
|
272 | + if (! $delete_is_blocked) { |
|
273 | + $related_model_object->delete_permanently(); |
|
274 | + } else { |
|
275 | + // delete is blocked |
|
276 | + // brent and darren, in this case, wanted to just soft delete it then |
|
277 | + $related_model_object->delete(); |
|
278 | + } |
|
279 | + } else { |
|
280 | + // its not a soft-deletable thing anyways. do the normal logic. |
|
281 | + if (! $delete_is_blocked) { |
|
282 | + $this->remove_relation_to($model_object_or_id, $related_model_object); |
|
283 | + $related_model_object->delete(); |
|
284 | + $deleted_count++; |
|
285 | + } |
|
286 | + } |
|
287 | + } |
|
288 | + return $deleted_count; |
|
289 | + } |
|
290 | + |
|
291 | + |
|
292 | + /** |
|
293 | + * this just returns a model_object_id for incoming item that could be an object or id. |
|
294 | + * |
|
295 | + * @param EE_Base_Class|int $model_object_or_id model object or the primary key of this model |
|
296 | + * @throws EE_Error |
|
297 | + * @return int |
|
298 | + */ |
|
299 | + protected function _get_model_object_id($model_object_or_id) |
|
300 | + { |
|
301 | + $model_object_id = $model_object_or_id; |
|
302 | + if ($model_object_or_id instanceof EE_Base_Class) { |
|
303 | + $model_object_id = $model_object_or_id->ID(); |
|
304 | + } |
|
305 | + if (! $model_object_id) { |
|
306 | + throw new EE_Error(sprintf( |
|
307 | + __( |
|
308 | + "Sorry, we cant get the related %s model objects to %s model object before it has an ID. You can solve that by just saving it before trying to get its related model objects", |
|
309 | + "event_espresso" |
|
310 | + ), |
|
311 | + $this->get_other_model()->get_this_model_name(), |
|
312 | + $this->get_this_model()->get_this_model_name() |
|
313 | + )); |
|
314 | + } |
|
315 | + return $model_object_id; |
|
316 | + } |
|
317 | + |
|
318 | + |
|
319 | + /** |
|
320 | + * Gets the SQL string for performing the join between this model and the other model. |
|
321 | + * |
|
322 | + * @param string $model_relation_chain like 'Event.Event_Venue.Venue' |
|
323 | + * @return string of SQL, eg "LEFT JOIN table_name AS table_alias ON this_model_primary_table.pk = |
|
324 | + * other_model_primary_table.fk" etc |
|
325 | + */ |
|
326 | + abstract public function get_join_statement($model_relation_chain); |
|
327 | + |
|
328 | + |
|
329 | + /** |
|
330 | + * Adds a relationships between the two model objects provided. Each type of relationship handles this differently |
|
331 | + * (EE_Belongs_To is a slight exception, it should more accurately be called set_relation_to(...), as this |
|
332 | + * relationship only allows this model to be related to a single other model of this type) |
|
333 | + * |
|
334 | + * @param $this_obj_or_id |
|
335 | + * @param $other_obj_or_id |
|
336 | + * @param array $extra_join_model_fields_n_values |
|
337 | + * @return \EE_Base_Class the EE_Base_Class which was added as a relation. (Convenient if you only pass an ID for |
|
338 | + * $other_obj_or_id) |
|
339 | + */ |
|
340 | + abstract public function add_relation_to( |
|
341 | + $this_obj_or_id, |
|
342 | + $other_obj_or_id, |
|
343 | + $extra_join_model_fields_n_values = array() |
|
344 | + ); |
|
345 | + |
|
346 | + |
|
347 | + /** |
|
348 | + * Similar to 'add_relation_to(...)', performs the opposite action of removing the relationship between the two |
|
349 | + * model objects |
|
350 | + * |
|
351 | + * @param $this_obj_or_id |
|
352 | + * @param $other_obj_or_id |
|
353 | + * @param array $where_query |
|
354 | + * @return bool |
|
355 | + */ |
|
356 | + abstract public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array()); |
|
357 | + |
|
358 | + |
|
359 | + /** |
|
360 | + * Removes ALL relation instances for this relation obj |
|
361 | + * |
|
362 | + * @param EE_Base_Class|int $this_obj_or_id |
|
363 | + * @param array $where_query_param @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
364 | + * @return EE_Base_Class[] |
|
365 | + * @throws \EE_Error |
|
366 | + */ |
|
367 | + public function remove_relations($this_obj_or_id, $where_query_param = array()) |
|
368 | + { |
|
369 | + $related_things = $this->get_all_related($this_obj_or_id, array($where_query_param)); |
|
370 | + $objs_removed = array(); |
|
371 | + foreach ($related_things as $related_thing) { |
|
372 | + $objs_removed[] = $this->remove_relation_to($this_obj_or_id, $related_thing); |
|
373 | + } |
|
374 | + return $objs_removed; |
|
375 | + } |
|
376 | + |
|
377 | + |
|
378 | + /** |
|
379 | + * If you aren't allowed to delete this model when there are related models across this |
|
380 | + * relation object, return true. Otherwise, if you can delete this model even though |
|
381 | + * related objects exist, returns false. |
|
382 | + * |
|
383 | + * @return boolean |
|
384 | + */ |
|
385 | + public function block_delete_if_related_models_exist() |
|
386 | + { |
|
387 | + return $this->_blocking_delete; |
|
388 | + } |
|
389 | + |
|
390 | + |
|
391 | + /** |
|
392 | + * Gets the error message to show |
|
393 | + * |
|
394 | + * @return string |
|
395 | + */ |
|
396 | + public function get_deletion_error_message() |
|
397 | + { |
|
398 | + if ($this->_blocking_delete_error_message) { |
|
399 | + return $this->_blocking_delete_error_message; |
|
400 | + } else { |
|
401 | 401 | // return sprintf(__('Cannot delete %1$s when there are related %2$s', "event_espresso"),$this->get_this_model()->item_name(2),$this->get_other_model()->item_name(2)); |
402 | - return sprintf( |
|
403 | - __( |
|
404 | - 'This %1$s is currently linked to one or more %2$s records. If this %1$s is incorrect, then please remove it from all %3$s before attempting to delete it.', |
|
405 | - "event_espresso" |
|
406 | - ), |
|
407 | - $this->get_this_model()->item_name(1), |
|
408 | - $this->get_other_model()->item_name(1), |
|
409 | - $this->get_other_model()->item_name(2) |
|
410 | - ); |
|
411 | - } |
|
412 | - } |
|
413 | - |
|
414 | - /** |
|
415 | - * Returns whatever is set as the nicename for the object. |
|
416 | - * |
|
417 | - * @return string |
|
418 | - */ |
|
419 | - public function getSchemaDescription() |
|
420 | - { |
|
421 | - $description = $this instanceof EE_Belongs_To_Relation |
|
422 | - ? esc_html__('The related %1$s entity to the %2$s.', 'event_espresso') |
|
423 | - : esc_html__('The related %1$s entities to the %2$s.', 'event_espresso'); |
|
424 | - return sprintf( |
|
425 | - $description, |
|
426 | - $this->get_other_model()->get_this_model_name(), |
|
427 | - $this->get_this_model()->get_this_model_name() |
|
428 | - ); |
|
429 | - } |
|
430 | - |
|
431 | - /** |
|
432 | - * Returns whatever is set as the $_schema_type property for the object. |
|
433 | - * Note: this will automatically add 'null' to the schema if the object is_nullable() |
|
434 | - * |
|
435 | - * @return string|array |
|
436 | - */ |
|
437 | - public function getSchemaType() |
|
438 | - { |
|
439 | - return $this instanceof EE_Belongs_To_Relation ? 'object' : 'array'; |
|
440 | - } |
|
441 | - |
|
442 | - /** |
|
443 | - * This is usually present when the $_schema_type property is 'object'. Any child classes will need to override |
|
444 | - * this method and return the properties for the schema. |
|
445 | - * The reason this is not a property on the class is because there may be filters set on the values for the property |
|
446 | - * that won't be exposed on construct. For example enum type schemas may have the enum values filtered. |
|
447 | - * |
|
448 | - * @return array |
|
449 | - */ |
|
450 | - public function getSchemaProperties() |
|
451 | - { |
|
452 | - return array(); |
|
453 | - } |
|
454 | - |
|
455 | - /** |
|
456 | - * If a child class has enum values, they should override this method and provide a simple array |
|
457 | - * of the enum values. |
|
458 | - * The reason this is not a property on the class is because there may be filterable enum values that |
|
459 | - * are set on the instantiated object that could be filtered after construct. |
|
460 | - * |
|
461 | - * @return array |
|
462 | - */ |
|
463 | - public function getSchemaEnum() |
|
464 | - { |
|
465 | - return array(); |
|
466 | - } |
|
467 | - |
|
468 | - /** |
|
469 | - * This returns the value of the $_schema_format property on the object. |
|
470 | - * |
|
471 | - * @return string |
|
472 | - */ |
|
473 | - public function getSchemaFormat() |
|
474 | - { |
|
475 | - return array(); |
|
476 | - } |
|
477 | - |
|
478 | - /** |
|
479 | - * This returns the value of the $_schema_readonly property on the object. |
|
480 | - * |
|
481 | - * @return bool |
|
482 | - */ |
|
483 | - public function getSchemaReadonly() |
|
484 | - { |
|
485 | - return true; |
|
486 | - } |
|
487 | - |
|
488 | - /** |
|
489 | - * This returns elements used to represent this field in the json schema. |
|
490 | - * |
|
491 | - * @link http://json-schema.org/ |
|
492 | - * @return array |
|
493 | - */ |
|
494 | - public function getSchema() |
|
495 | - { |
|
496 | - $schema = array( |
|
497 | - 'description' => $this->getSchemaDescription(), |
|
498 | - 'type' => $this->getSchemaType(), |
|
499 | - 'relation' => true, |
|
500 | - 'relation_type' => get_class($this), |
|
501 | - 'readonly' => $this->getSchemaReadonly() |
|
502 | - ); |
|
503 | - |
|
504 | - if ($this instanceof EE_HABTM_Relation) { |
|
505 | - $schema['joining_model_name'] = $this->get_join_model()->get_this_model_name(); |
|
506 | - } |
|
507 | - |
|
508 | - if ($this->getSchemaType() === 'array') { |
|
509 | - $schema['items'] = array( |
|
510 | - 'type' => 'object' |
|
511 | - ); |
|
512 | - } |
|
513 | - |
|
514 | - return $schema; |
|
515 | - } |
|
402 | + return sprintf( |
|
403 | + __( |
|
404 | + 'This %1$s is currently linked to one or more %2$s records. If this %1$s is incorrect, then please remove it from all %3$s before attempting to delete it.', |
|
405 | + "event_espresso" |
|
406 | + ), |
|
407 | + $this->get_this_model()->item_name(1), |
|
408 | + $this->get_other_model()->item_name(1), |
|
409 | + $this->get_other_model()->item_name(2) |
|
410 | + ); |
|
411 | + } |
|
412 | + } |
|
413 | + |
|
414 | + /** |
|
415 | + * Returns whatever is set as the nicename for the object. |
|
416 | + * |
|
417 | + * @return string |
|
418 | + */ |
|
419 | + public function getSchemaDescription() |
|
420 | + { |
|
421 | + $description = $this instanceof EE_Belongs_To_Relation |
|
422 | + ? esc_html__('The related %1$s entity to the %2$s.', 'event_espresso') |
|
423 | + : esc_html__('The related %1$s entities to the %2$s.', 'event_espresso'); |
|
424 | + return sprintf( |
|
425 | + $description, |
|
426 | + $this->get_other_model()->get_this_model_name(), |
|
427 | + $this->get_this_model()->get_this_model_name() |
|
428 | + ); |
|
429 | + } |
|
430 | + |
|
431 | + /** |
|
432 | + * Returns whatever is set as the $_schema_type property for the object. |
|
433 | + * Note: this will automatically add 'null' to the schema if the object is_nullable() |
|
434 | + * |
|
435 | + * @return string|array |
|
436 | + */ |
|
437 | + public function getSchemaType() |
|
438 | + { |
|
439 | + return $this instanceof EE_Belongs_To_Relation ? 'object' : 'array'; |
|
440 | + } |
|
441 | + |
|
442 | + /** |
|
443 | + * This is usually present when the $_schema_type property is 'object'. Any child classes will need to override |
|
444 | + * this method and return the properties for the schema. |
|
445 | + * The reason this is not a property on the class is because there may be filters set on the values for the property |
|
446 | + * that won't be exposed on construct. For example enum type schemas may have the enum values filtered. |
|
447 | + * |
|
448 | + * @return array |
|
449 | + */ |
|
450 | + public function getSchemaProperties() |
|
451 | + { |
|
452 | + return array(); |
|
453 | + } |
|
454 | + |
|
455 | + /** |
|
456 | + * If a child class has enum values, they should override this method and provide a simple array |
|
457 | + * of the enum values. |
|
458 | + * The reason this is not a property on the class is because there may be filterable enum values that |
|
459 | + * are set on the instantiated object that could be filtered after construct. |
|
460 | + * |
|
461 | + * @return array |
|
462 | + */ |
|
463 | + public function getSchemaEnum() |
|
464 | + { |
|
465 | + return array(); |
|
466 | + } |
|
467 | + |
|
468 | + /** |
|
469 | + * This returns the value of the $_schema_format property on the object. |
|
470 | + * |
|
471 | + * @return string |
|
472 | + */ |
|
473 | + public function getSchemaFormat() |
|
474 | + { |
|
475 | + return array(); |
|
476 | + } |
|
477 | + |
|
478 | + /** |
|
479 | + * This returns the value of the $_schema_readonly property on the object. |
|
480 | + * |
|
481 | + * @return bool |
|
482 | + */ |
|
483 | + public function getSchemaReadonly() |
|
484 | + { |
|
485 | + return true; |
|
486 | + } |
|
487 | + |
|
488 | + /** |
|
489 | + * This returns elements used to represent this field in the json schema. |
|
490 | + * |
|
491 | + * @link http://json-schema.org/ |
|
492 | + * @return array |
|
493 | + */ |
|
494 | + public function getSchema() |
|
495 | + { |
|
496 | + $schema = array( |
|
497 | + 'description' => $this->getSchemaDescription(), |
|
498 | + 'type' => $this->getSchemaType(), |
|
499 | + 'relation' => true, |
|
500 | + 'relation_type' => get_class($this), |
|
501 | + 'readonly' => $this->getSchemaReadonly() |
|
502 | + ); |
|
503 | + |
|
504 | + if ($this instanceof EE_HABTM_Relation) { |
|
505 | + $schema['joining_model_name'] = $this->get_join_model()->get_this_model_name(); |
|
506 | + } |
|
507 | + |
|
508 | + if ($this->getSchemaType() === 'array') { |
|
509 | + $schema['items'] = array( |
|
510 | + 'type' => 'object' |
|
511 | + ); |
|
512 | + } |
|
513 | + |
|
514 | + return $schema; |
|
515 | + } |
|
516 | 516 | } |