@@ -51,7 +51,7 @@ discard block |
||
51 | 51 | { |
52 | 52 | $has_object = parent::_check_for_object($props_n_values, __CLASS__); |
53 | 53 | // if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db. |
54 | - if (! $has_object) { |
|
54 | + if ( ! $has_object) { |
|
55 | 55 | EE_Registry::instance()->load_helper('URL'); |
56 | 56 | $props_n_values['MSG_token'] = EEH_URL::generate_unique_token(); |
57 | 57 | } |
@@ -219,7 +219,7 @@ discard block |
||
219 | 219 | { |
220 | 220 | $label_type = $plural ? 'plural' : 'singular'; |
221 | 221 | $messenger = $this->messenger_object(); |
222 | - return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger(); |
|
222 | + return $messenger instanceof EE_messenger ? $messenger->label[$label_type] : $this->messenger(); |
|
223 | 223 | } |
224 | 224 | |
225 | 225 | |
@@ -336,7 +336,7 @@ discard block |
||
336 | 336 | $this->messenger(), |
337 | 337 | $this->message_type() |
338 | 338 | ); |
339 | - if (! $valid && $throw_exceptions) { |
|
339 | + if ( ! $valid && $throw_exceptions) { |
|
340 | 340 | throw new EE_Error( |
341 | 341 | sprintf( |
342 | 342 | esc_html__( |
@@ -366,7 +366,7 @@ discard block |
||
366 | 366 | $label_type = $plural ? 'plural' : 'singular'; |
367 | 367 | $message_type = $this->message_type_object(); |
368 | 368 | return $message_type instanceof EE_message_type |
369 | - ? $message_type->label[ $label_type ] |
|
369 | + ? $message_type->label[$label_type] |
|
370 | 370 | : str_replace( |
371 | 371 | '_', |
372 | 372 | ' ', |
@@ -397,7 +397,7 @@ discard block |
||
397 | 397 | /** @type EE_Message_Resource_Manager $message_resource_manager */ |
398 | 398 | $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
399 | 399 | $contexts = $message_resource_manager->get_all_contexts(); |
400 | - return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context(); |
|
400 | + return isset($contexts[$this->context()]) ? $contexts[$this->context()] : $this->context(); |
|
401 | 401 | } |
402 | 402 | |
403 | 403 | |
@@ -452,7 +452,7 @@ discard block |
||
452 | 452 | */ |
453 | 453 | public function recipient_object() |
454 | 454 | { |
455 | - if (! $this->recipient_type() || ! $this->recipient_ID()) { |
|
455 | + if ( ! $this->recipient_type() || ! $this->recipient_ID()) { |
|
456 | 456 | return null; |
457 | 457 | } |
458 | 458 | |
@@ -736,13 +736,13 @@ discard block |
||
736 | 736 | /** |
737 | 737 | * This is deprecated functionality that will be removed eventually but included here now for backward compat. |
738 | 738 | */ |
739 | - if (! empty($this->template_pack)) { |
|
739 | + if ( ! empty($this->template_pack)) { |
|
740 | 740 | return $this->template_pack; |
741 | 741 | } |
742 | 742 | /** @type EE_Message_Template_Group $grp */ |
743 | 743 | $grp = $this->get_first_related('Message_Template_Group'); |
744 | 744 | // if no group then let's try to get the first related group by internal messenger and message type (will use global grp). |
745 | - if (! $grp instanceof EE_Message_Template_Group) { |
|
745 | + if ( ! $grp instanceof EE_Message_Template_Group) { |
|
746 | 746 | $grp = EEM_Message_Template_Group::instance()->get_one( |
747 | 747 | array( |
748 | 748 | array( |
@@ -768,7 +768,7 @@ discard block |
||
768 | 768 | /** |
769 | 769 | * This is deprecated functionality that will be removed eventually but included here now for backward compat. |
770 | 770 | */ |
771 | - if (! empty($this->template_variation)) { |
|
771 | + if ( ! empty($this->template_variation)) { |
|
772 | 772 | return $this->template_variation; |
773 | 773 | } |
774 | 774 | |
@@ -776,7 +776,7 @@ discard block |
||
776 | 776 | $grp = $this->get_first_related('Message_Template_Group'); |
777 | 777 | |
778 | 778 | // if no group then let's try to get the first related group by internal messenger and message type (will use global grp). |
779 | - if (! $grp instanceof EE_Message_Template_Group) { |
|
779 | + if ( ! $grp instanceof EE_Message_Template_Group) { |
|
780 | 780 | $grp = EEM_Message_Template_Group::instance()->get_one( |
781 | 781 | array( |
782 | 782 | array( |
@@ -9,875 +9,875 @@ |
||
9 | 9 | */ |
10 | 10 | class EE_Message extends EE_Base_Class implements EEI_Admin_Links |
11 | 11 | { |
12 | - /** |
|
13 | - * @deprecated 4.9.0 Added for backward compat with add-on's |
|
14 | - * @type null |
|
15 | - */ |
|
16 | - public $template_pack; |
|
17 | - |
|
18 | - /** |
|
19 | - * @deprecated 4.9.0 Added for backward compat with add-on's |
|
20 | - * @type null |
|
21 | - */ |
|
22 | - public $template_variation; |
|
23 | - |
|
24 | - /** |
|
25 | - * @deprecated 4.9.0 Added for backward compat with add-on's |
|
26 | - * @type string |
|
27 | - */ |
|
28 | - public $content = ''; |
|
29 | - |
|
30 | - |
|
31 | - /** |
|
32 | - * @type EE_messenger $_messenger |
|
33 | - */ |
|
34 | - protected $_messenger = null; |
|
35 | - |
|
36 | - /** |
|
37 | - * @type EE_message_type $_message_type |
|
38 | - */ |
|
39 | - protected $_message_type = null; |
|
40 | - |
|
41 | - |
|
42 | - /** |
|
43 | - * @param array $props_n_values |
|
44 | - * @param string $timezone |
|
45 | - * @param array $date_formats incoming date formats in an array. First value is the date_format, second is time |
|
46 | - * format. |
|
47 | - * @return EE_Message |
|
48 | - */ |
|
49 | - public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
50 | - { |
|
51 | - $has_object = parent::_check_for_object($props_n_values, __CLASS__); |
|
52 | - // if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db. |
|
53 | - if (! $has_object) { |
|
54 | - EE_Registry::instance()->load_helper('URL'); |
|
55 | - $props_n_values['MSG_token'] = EEH_URL::generate_unique_token(); |
|
56 | - } |
|
57 | - return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats); |
|
58 | - } |
|
59 | - |
|
60 | - |
|
61 | - /** |
|
62 | - * @param array $props_n_values |
|
63 | - * @param string $timezone |
|
64 | - * @return EE_Message |
|
65 | - */ |
|
66 | - public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
67 | - { |
|
68 | - return new self($props_n_values, true, $timezone); |
|
69 | - } |
|
70 | - |
|
71 | - |
|
72 | - /** |
|
73 | - * Gets MSG_token |
|
74 | - * |
|
75 | - * @return int |
|
76 | - */ |
|
77 | - public function MSG_token() |
|
78 | - { |
|
79 | - return $this->get('MSG_token'); |
|
80 | - } |
|
81 | - |
|
82 | - |
|
83 | - /** |
|
84 | - * Sets MSG_token |
|
85 | - * |
|
86 | - * @param int $MSG_token |
|
87 | - */ |
|
88 | - public function set_MSG_token($MSG_token) |
|
89 | - { |
|
90 | - $this->set('MSG_token', $MSG_token); |
|
91 | - } |
|
92 | - |
|
93 | - |
|
94 | - /** |
|
95 | - * Gets GRP_ID |
|
96 | - * |
|
97 | - * @return int |
|
98 | - */ |
|
99 | - public function GRP_ID() |
|
100 | - { |
|
101 | - return $this->get('GRP_ID'); |
|
102 | - } |
|
103 | - |
|
104 | - |
|
105 | - /** |
|
106 | - * Sets GRP_ID |
|
107 | - * |
|
108 | - * @param int $GRP_ID |
|
109 | - */ |
|
110 | - public function set_GRP_ID($GRP_ID) |
|
111 | - { |
|
112 | - $this->set('GRP_ID', $GRP_ID); |
|
113 | - } |
|
114 | - |
|
115 | - |
|
116 | - /** |
|
117 | - * Gets TXN_ID |
|
118 | - * |
|
119 | - * @return int |
|
120 | - */ |
|
121 | - public function TXN_ID() |
|
122 | - { |
|
123 | - return $this->get('TXN_ID'); |
|
124 | - } |
|
125 | - |
|
126 | - |
|
127 | - /** |
|
128 | - * Sets TXN_ID |
|
129 | - * |
|
130 | - * @param int $TXN_ID |
|
131 | - */ |
|
132 | - public function set_TXN_ID($TXN_ID) |
|
133 | - { |
|
134 | - $this->set('TXN_ID', $TXN_ID); |
|
135 | - } |
|
136 | - |
|
137 | - |
|
138 | - /** |
|
139 | - * Gets messenger |
|
140 | - * |
|
141 | - * @return string |
|
142 | - */ |
|
143 | - public function messenger() |
|
144 | - { |
|
145 | - return $this->get('MSG_messenger'); |
|
146 | - } |
|
147 | - |
|
148 | - |
|
149 | - /** |
|
150 | - * Sets messenger |
|
151 | - * |
|
152 | - * @param string $messenger |
|
153 | - */ |
|
154 | - public function set_messenger($messenger) |
|
155 | - { |
|
156 | - $this->set('MSG_messenger', $messenger); |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - /** |
|
161 | - * Returns corresponding messenger object for the set messenger on this message |
|
162 | - * |
|
163 | - * @return EE_messenger | null |
|
164 | - */ |
|
165 | - public function messenger_object() |
|
166 | - { |
|
167 | - return $this->_messenger; |
|
168 | - } |
|
169 | - |
|
170 | - |
|
171 | - /** |
|
172 | - * Sets messenger |
|
173 | - * |
|
174 | - * @param EE_messenger $messenger |
|
175 | - */ |
|
176 | - public function set_messenger_object(EE_messenger $messenger) |
|
177 | - { |
|
178 | - $this->_messenger = $messenger; |
|
179 | - } |
|
180 | - |
|
181 | - |
|
182 | - /** |
|
183 | - * validates messenger |
|
184 | - * |
|
185 | - * @param bool $throw_exceptions |
|
186 | - * @return bool |
|
187 | - * @throws \EE_Error |
|
188 | - */ |
|
189 | - public function valid_messenger($throw_exceptions = false) |
|
190 | - { |
|
191 | - if ($this->_messenger instanceof EE_messenger) { |
|
192 | - return true; |
|
193 | - } |
|
194 | - if ($throw_exceptions) { |
|
195 | - throw new EE_Error( |
|
196 | - sprintf( |
|
197 | - esc_html__( |
|
198 | - 'The "%1$s" messenger set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.', |
|
199 | - 'event_espresso' |
|
200 | - ), |
|
201 | - $this->messenger() |
|
202 | - ) |
|
203 | - ); |
|
204 | - } |
|
205 | - return false; |
|
206 | - } |
|
207 | - |
|
208 | - |
|
209 | - /** |
|
210 | - * This returns the set localized label for the messenger on this message. |
|
211 | - * Note, if unable to retrieve the EE_messenger object then will just return the messenger slug saved |
|
212 | - * with this message. |
|
213 | - * |
|
214 | - * @param bool $plural whether to return the plural label or not. |
|
215 | - * @return string |
|
216 | - */ |
|
217 | - public function messenger_label($plural = false) |
|
218 | - { |
|
219 | - $label_type = $plural ? 'plural' : 'singular'; |
|
220 | - $messenger = $this->messenger_object(); |
|
221 | - return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger(); |
|
222 | - } |
|
223 | - |
|
224 | - |
|
225 | - /** |
|
226 | - * Gets message_type |
|
227 | - * |
|
228 | - * @return string |
|
229 | - */ |
|
230 | - public function message_type() |
|
231 | - { |
|
232 | - return $this->get('MSG_message_type'); |
|
233 | - } |
|
234 | - |
|
235 | - |
|
236 | - /** |
|
237 | - * Sets message_type |
|
238 | - * |
|
239 | - * @param string $message_type |
|
240 | - */ |
|
241 | - public function set_message_type($message_type) |
|
242 | - { |
|
243 | - $this->set('MSG_message_type', $message_type); |
|
244 | - } |
|
245 | - |
|
246 | - |
|
247 | - /** |
|
248 | - * Returns the message type object for the set message type on this message |
|
249 | - * |
|
250 | - * @return EE_message_type | null |
|
251 | - */ |
|
252 | - public function message_type_object() |
|
253 | - { |
|
254 | - return $this->_message_type; |
|
255 | - } |
|
256 | - |
|
257 | - |
|
258 | - /** |
|
259 | - * Sets message_type |
|
260 | - * |
|
261 | - * @param EE_message_type $message_type |
|
262 | - * @param bool $set_priority This indicates whether to set the priority to whatever the priority is on |
|
263 | - * the message type or not. |
|
264 | - */ |
|
265 | - public function set_message_type_object(EE_message_type $message_type, $set_priority = false) |
|
266 | - { |
|
267 | - $this->_message_type = $message_type; |
|
268 | - if ($set_priority) { |
|
269 | - $this->set_priority($this->_message_type->get_priority()); |
|
270 | - } |
|
271 | - } |
|
272 | - |
|
273 | - |
|
274 | - /** |
|
275 | - * validates message_type |
|
276 | - * |
|
277 | - * @param bool $throw_exceptions |
|
278 | - * @return bool |
|
279 | - * @throws \EE_Error |
|
280 | - */ |
|
281 | - public function valid_message_type($throw_exceptions = false) |
|
282 | - { |
|
283 | - if ($this->_message_type instanceof EE_message_type) { |
|
284 | - return true; |
|
285 | - } |
|
286 | - if ($throw_exceptions) { |
|
287 | - throw new EE_Error( |
|
288 | - sprintf( |
|
289 | - esc_html__( |
|
290 | - 'The %1$s message type set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.', |
|
291 | - 'event_espresso' |
|
292 | - ), |
|
293 | - $this->message_type() |
|
294 | - ) |
|
295 | - ); |
|
296 | - } |
|
297 | - return false; |
|
298 | - } |
|
299 | - |
|
300 | - |
|
301 | - /** |
|
302 | - * validates messenger and message_type (that they are valid EE_messenger and EE_message_type objects). |
|
303 | - * |
|
304 | - * @param bool $throw_exceptions |
|
305 | - * @return bool |
|
306 | - * @throws \EE_Error |
|
307 | - */ |
|
308 | - public function is_valid($throw_exceptions = false) |
|
309 | - { |
|
310 | - if ($this->valid_messenger($throw_exceptions) && $this->valid_message_type($throw_exceptions)) { |
|
311 | - return true; |
|
312 | - } |
|
313 | - return false; |
|
314 | - } |
|
315 | - |
|
316 | - |
|
317 | - /** |
|
318 | - * This validates whether the internal messenger and message type objects are valid for sending. |
|
319 | - * Three checks are done: |
|
320 | - * 1. There is a valid messenger object. |
|
321 | - * 2. There is a valid message type object. |
|
322 | - * 3. The message type object is active for the messenger. |
|
323 | - * |
|
324 | - * @throws EE_Error But only if $throw_exceptions is set to true. |
|
325 | - * @param bool $throw_exceptions |
|
326 | - * @return bool |
|
327 | - */ |
|
328 | - public function is_valid_for_sending_or_generation($throw_exceptions = false) |
|
329 | - { |
|
330 | - $valid = false; |
|
331 | - if ($this->is_valid($throw_exceptions)) { |
|
332 | - /** @var EE_Message_Resource_Manager $message_resource_manager */ |
|
333 | - $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
334 | - $valid = $message_resource_manager->is_message_type_active_for_messenger( |
|
335 | - $this->messenger(), |
|
336 | - $this->message_type() |
|
337 | - ); |
|
338 | - if (! $valid && $throw_exceptions) { |
|
339 | - throw new EE_Error( |
|
340 | - sprintf( |
|
341 | - esc_html__( |
|
342 | - 'The %1$s message type is not a valid message type for the %2$s messenger so it will not be sent.', |
|
343 | - 'event_espresso' |
|
344 | - ), |
|
345 | - $this->message_type(), |
|
346 | - $this->messenger() |
|
347 | - ) |
|
348 | - ); |
|
349 | - } |
|
350 | - } |
|
351 | - return $valid; |
|
352 | - } |
|
353 | - |
|
354 | - |
|
355 | - /** |
|
356 | - * This returns the set localized label for the message type on this message. |
|
357 | - * Note, if unable to retrieve the EE_message_type object then will just return the message type slug saved |
|
358 | - * with this message. |
|
359 | - * |
|
360 | - * @param bool $plural whether to return the plural label or not. |
|
361 | - * @return string |
|
362 | - */ |
|
363 | - public function message_type_label($plural = false) |
|
364 | - { |
|
365 | - $label_type = $plural ? 'plural' : 'singular'; |
|
366 | - $message_type = $this->message_type_object(); |
|
367 | - return $message_type instanceof EE_message_type |
|
368 | - ? $message_type->label[ $label_type ] |
|
369 | - : str_replace( |
|
370 | - '_', |
|
371 | - ' ', |
|
372 | - $this->message_type() |
|
373 | - ); |
|
374 | - } |
|
375 | - |
|
376 | - |
|
377 | - /** |
|
378 | - * Gets context |
|
379 | - * |
|
380 | - * @return string |
|
381 | - */ |
|
382 | - public function context() |
|
383 | - { |
|
384 | - return $this->get('MSG_context'); |
|
385 | - } |
|
386 | - |
|
387 | - |
|
388 | - /** |
|
389 | - * This returns the corresponding localized label for the given context slug, if possible from installed message |
|
390 | - * types. Otherwise, this will just return the set context slug on this object. |
|
391 | - * |
|
392 | - * @return string |
|
393 | - */ |
|
394 | - public function context_label() |
|
395 | - { |
|
396 | - /** @type EE_Message_Resource_Manager $message_resource_manager */ |
|
397 | - $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
398 | - $contexts = $message_resource_manager->get_all_contexts(); |
|
399 | - return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context(); |
|
400 | - } |
|
401 | - |
|
402 | - |
|
403 | - /** |
|
404 | - * Sets context |
|
405 | - * |
|
406 | - * @param string $context |
|
407 | - */ |
|
408 | - public function set_context($context) |
|
409 | - { |
|
410 | - $this->set('MSG_context', $context); |
|
411 | - } |
|
412 | - |
|
413 | - |
|
414 | - /** |
|
415 | - * Gets recipient_ID |
|
416 | - * |
|
417 | - * @return int |
|
418 | - */ |
|
419 | - public function recipient_ID() |
|
420 | - { |
|
421 | - return $this->get('MSG_recipient_ID'); |
|
422 | - } |
|
423 | - |
|
424 | - |
|
425 | - /** |
|
426 | - * Sets recipient_ID |
|
427 | - * |
|
428 | - * @param string $recipient_ID |
|
429 | - */ |
|
430 | - public function set_recipient_ID($recipient_ID) |
|
431 | - { |
|
432 | - $this->set('MSG_recipient_ID', $recipient_ID); |
|
433 | - } |
|
434 | - |
|
435 | - |
|
436 | - /** |
|
437 | - * Gets recipient_type |
|
438 | - * |
|
439 | - * @return string |
|
440 | - */ |
|
441 | - public function recipient_type() |
|
442 | - { |
|
443 | - return $this->get('MSG_recipient_type'); |
|
444 | - } |
|
445 | - |
|
446 | - |
|
447 | - /** |
|
448 | - * Return the related object matching the recipient type and ID. |
|
449 | - * |
|
450 | - * @return EE_Base_Class | null |
|
451 | - */ |
|
452 | - public function recipient_object() |
|
453 | - { |
|
454 | - if (! $this->recipient_type() || ! $this->recipient_ID()) { |
|
455 | - return null; |
|
456 | - } |
|
457 | - |
|
458 | - return $this->get_first_related($this->recipient_type()); |
|
459 | - } |
|
460 | - |
|
461 | - |
|
462 | - /** |
|
463 | - * Sets recipient_type |
|
464 | - * |
|
465 | - * @param string $recipient_type |
|
466 | - */ |
|
467 | - public function set_recipient_type($recipient_type) |
|
468 | - { |
|
469 | - $this->set('MSG_recipient_type', $recipient_type); |
|
470 | - } |
|
471 | - |
|
472 | - |
|
473 | - /** |
|
474 | - * Gets content |
|
475 | - * |
|
476 | - * @return string |
|
477 | - */ |
|
478 | - public function content() |
|
479 | - { |
|
480 | - return $this->get('MSG_content'); |
|
481 | - } |
|
482 | - |
|
483 | - |
|
484 | - /** |
|
485 | - * Sets content |
|
486 | - * |
|
487 | - * @param string $content |
|
488 | - */ |
|
489 | - public function set_content($content) |
|
490 | - { |
|
491 | - $this->set('MSG_content', $content); |
|
492 | - } |
|
493 | - |
|
494 | - |
|
495 | - /** |
|
496 | - * Gets subject |
|
497 | - * |
|
498 | - * @return string |
|
499 | - */ |
|
500 | - public function subject() |
|
501 | - { |
|
502 | - return $this->get('MSG_subject'); |
|
503 | - } |
|
504 | - |
|
505 | - |
|
506 | - /** |
|
507 | - * Sets subject |
|
508 | - * |
|
509 | - * @param string $subject |
|
510 | - */ |
|
511 | - public function set_subject($subject) |
|
512 | - { |
|
513 | - $this->set('MSG_subject', $subject); |
|
514 | - } |
|
515 | - |
|
516 | - |
|
517 | - /** |
|
518 | - * Gets to |
|
519 | - * |
|
520 | - * @return string |
|
521 | - */ |
|
522 | - public function to() |
|
523 | - { |
|
524 | - $to = $this->get('MSG_to'); |
|
525 | - return empty($to) ? esc_html__('No recipient', 'event_espresso') : $to; |
|
526 | - } |
|
527 | - |
|
528 | - |
|
529 | - /** |
|
530 | - * Sets to |
|
531 | - * |
|
532 | - * @param string $to |
|
533 | - */ |
|
534 | - public function set_to($to) |
|
535 | - { |
|
536 | - $this->set('MSG_to', $to); |
|
537 | - } |
|
538 | - |
|
539 | - |
|
540 | - /** |
|
541 | - * Gets from |
|
542 | - * |
|
543 | - * @return string |
|
544 | - */ |
|
545 | - public function from() |
|
546 | - { |
|
547 | - return $this->get('MSG_from'); |
|
548 | - } |
|
549 | - |
|
550 | - |
|
551 | - /** |
|
552 | - * Sets from |
|
553 | - * |
|
554 | - * @param string $from |
|
555 | - */ |
|
556 | - public function set_from($from) |
|
557 | - { |
|
558 | - $this->set('MSG_from', $from); |
|
559 | - } |
|
560 | - |
|
561 | - |
|
562 | - /** |
|
563 | - * Gets priority |
|
564 | - * |
|
565 | - * @return int |
|
566 | - */ |
|
567 | - public function priority() |
|
568 | - { |
|
569 | - return $this->get('MSG_priority'); |
|
570 | - } |
|
571 | - |
|
572 | - |
|
573 | - /** |
|
574 | - * Sets priority |
|
575 | - * Note. Send Now Messengers always override any priority that may be set on a Message. So |
|
576 | - * this method calls the send_now method to verify that. |
|
577 | - * |
|
578 | - * @param int $priority |
|
579 | - */ |
|
580 | - public function set_priority($priority) |
|
581 | - { |
|
582 | - $priority = $this->send_now() ? EEM_Message::priority_high : $priority; |
|
583 | - parent::set('MSG_priority', $priority); |
|
584 | - } |
|
585 | - |
|
586 | - |
|
587 | - /** |
|
588 | - * Overrides parent::set method so we can capture any sets for priority. |
|
589 | - * |
|
590 | - * @see parent::set() for phpdocs |
|
591 | - * @param string $field_name |
|
592 | - * @param mixed $field_value |
|
593 | - * @param bool $use_default |
|
594 | - * @throws EE_Error |
|
595 | - */ |
|
596 | - public function set($field_name, $field_value, $use_default = false) |
|
597 | - { |
|
598 | - if ($field_name === 'MSG_priority') { |
|
599 | - $this->set_priority($field_value); |
|
600 | - } |
|
601 | - parent::set($field_name, $field_value, $use_default); |
|
602 | - } |
|
603 | - |
|
604 | - |
|
605 | - /** |
|
606 | - * @return bool |
|
607 | - * @throws \EE_Error |
|
608 | - */ |
|
609 | - public function send_now() |
|
610 | - { |
|
611 | - $send_now = $this->valid_messenger() && $this->messenger_object()->send_now() ? EEM_Message::priority_high |
|
612 | - : $this->priority(); |
|
613 | - return $send_now === EEM_Message::priority_high ? true : false; |
|
614 | - } |
|
615 | - |
|
616 | - |
|
617 | - /** |
|
618 | - * Gets STS_ID |
|
619 | - * |
|
620 | - * @return string |
|
621 | - */ |
|
622 | - public function STS_ID() |
|
623 | - { |
|
624 | - return $this->get('STS_ID'); |
|
625 | - } |
|
626 | - |
|
627 | - |
|
628 | - /** |
|
629 | - * Sets STS_ID |
|
630 | - * |
|
631 | - * @param string $STS_ID |
|
632 | - */ |
|
633 | - public function set_STS_ID($STS_ID) |
|
634 | - { |
|
635 | - $this->set('STS_ID', $STS_ID); |
|
636 | - } |
|
637 | - |
|
638 | - |
|
639 | - /** |
|
640 | - * Gets created |
|
641 | - * |
|
642 | - * @return string |
|
643 | - */ |
|
644 | - public function created() |
|
645 | - { |
|
646 | - return $this->get('MSG_created'); |
|
647 | - } |
|
648 | - |
|
649 | - |
|
650 | - /** |
|
651 | - * Sets created |
|
652 | - * |
|
653 | - * @param string $created |
|
654 | - */ |
|
655 | - public function set_created($created) |
|
656 | - { |
|
657 | - $this->set('MSG_created', $created); |
|
658 | - } |
|
659 | - |
|
660 | - |
|
661 | - /** |
|
662 | - * Gets modified |
|
663 | - * |
|
664 | - * @return string |
|
665 | - */ |
|
666 | - public function modified() |
|
667 | - { |
|
668 | - return $this->get('MSG_modified'); |
|
669 | - } |
|
670 | - |
|
671 | - |
|
672 | - /** |
|
673 | - * Sets modified |
|
674 | - * |
|
675 | - * @param string $modified |
|
676 | - */ |
|
677 | - public function set_modified($modified) |
|
678 | - { |
|
679 | - $this->set('MSG_modified', $modified); |
|
680 | - } |
|
681 | - |
|
682 | - |
|
683 | - /** |
|
684 | - * Sets generation data for this message. |
|
685 | - * |
|
686 | - * @param mixed $data |
|
687 | - */ |
|
688 | - public function set_generation_data($data) |
|
689 | - { |
|
690 | - $this->set_field_or_extra_meta('MSG_generation_data', $data); |
|
691 | - } |
|
692 | - |
|
693 | - |
|
694 | - /** |
|
695 | - * Returns any set generation data for this message. |
|
696 | - * |
|
697 | - * @return mixed|null |
|
698 | - */ |
|
699 | - public function get_generation_data() |
|
700 | - { |
|
701 | - return $this->get_field_or_extra_meta('MSG_generation_data'); |
|
702 | - } |
|
703 | - |
|
704 | - |
|
705 | - /** |
|
706 | - * Gets any error message. |
|
707 | - * |
|
708 | - * @return mixed|null |
|
709 | - */ |
|
710 | - public function error_message() |
|
711 | - { |
|
712 | - return $this->get_field_or_extra_meta('MSG_error'); |
|
713 | - } |
|
714 | - |
|
715 | - |
|
716 | - /** |
|
717 | - * Sets an error message. |
|
718 | - * |
|
719 | - * @param $message |
|
720 | - * @return bool|int |
|
721 | - */ |
|
722 | - public function set_error_message($message) |
|
723 | - { |
|
724 | - return $this->set_field_or_extra_meta('MSG_error', $message); |
|
725 | - } |
|
726 | - |
|
727 | - |
|
728 | - /** |
|
729 | - * This retrieves the associated template pack with this message. |
|
730 | - * |
|
731 | - * @return EE_Messages_Template_Pack | null |
|
732 | - */ |
|
733 | - public function get_template_pack() |
|
734 | - { |
|
735 | - /** |
|
736 | - * This is deprecated functionality that will be removed eventually but included here now for backward compat. |
|
737 | - */ |
|
738 | - if (! empty($this->template_pack)) { |
|
739 | - return $this->template_pack; |
|
740 | - } |
|
741 | - /** @type EE_Message_Template_Group $grp */ |
|
742 | - $grp = $this->get_first_related('Message_Template_Group'); |
|
743 | - // if no group then let's try to get the first related group by internal messenger and message type (will use global grp). |
|
744 | - if (! $grp instanceof EE_Message_Template_Group) { |
|
745 | - $grp = EEM_Message_Template_Group::instance()->get_one( |
|
746 | - array( |
|
747 | - array( |
|
748 | - 'MTP_messenger' => $this->messenger(), |
|
749 | - 'MTP_message_type' => $this->message_type(), |
|
750 | - 'MTP_is_global' => true, |
|
751 | - ), |
|
752 | - ) |
|
753 | - ); |
|
754 | - } |
|
755 | - |
|
756 | - return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack() : null; |
|
757 | - } |
|
758 | - |
|
759 | - |
|
760 | - /** |
|
761 | - * Retrieves the variation used for generating this message. |
|
762 | - * |
|
763 | - * @return string |
|
764 | - */ |
|
765 | - public function get_template_pack_variation() |
|
766 | - { |
|
767 | - /** |
|
768 | - * This is deprecated functionality that will be removed eventually but included here now for backward compat. |
|
769 | - */ |
|
770 | - if (! empty($this->template_variation)) { |
|
771 | - return $this->template_variation; |
|
772 | - } |
|
773 | - |
|
774 | - /** @type EE_Message_Template_Group $grp */ |
|
775 | - $grp = $this->get_first_related('Message_Template_Group'); |
|
776 | - |
|
777 | - // if no group then let's try to get the first related group by internal messenger and message type (will use global grp). |
|
778 | - if (! $grp instanceof EE_Message_Template_Group) { |
|
779 | - $grp = EEM_Message_Template_Group::instance()->get_one( |
|
780 | - array( |
|
781 | - array( |
|
782 | - 'MTP_messenger' => $this->messenger(), |
|
783 | - 'MTP_message_type' => $this->message_type(), |
|
784 | - 'MTP_is_global' => true, |
|
785 | - ), |
|
786 | - ) |
|
787 | - ); |
|
788 | - } |
|
789 | - |
|
790 | - return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack_variation() : ''; |
|
791 | - } |
|
792 | - |
|
793 | - /** |
|
794 | - * Return the link to the admin details for the object. |
|
795 | - * |
|
796 | - * @return string |
|
797 | - */ |
|
798 | - public function get_admin_details_link() |
|
799 | - { |
|
800 | - EE_Registry::instance()->load_helper('URL'); |
|
801 | - EE_Registry::instance()->load_helper('MSG_Template'); |
|
802 | - switch ($this->STS_ID()) { |
|
803 | - case EEM_Message::status_failed: |
|
804 | - case EEM_Message::status_debug_only: |
|
805 | - return EEH_MSG_Template::generate_error_display_trigger($this); |
|
806 | - break; |
|
807 | - |
|
808 | - case EEM_Message::status_sent: |
|
809 | - return EEH_MSG_Template::generate_browser_trigger($this); |
|
810 | - break; |
|
811 | - |
|
812 | - default: |
|
813 | - return ''; |
|
814 | - } |
|
815 | - } |
|
816 | - |
|
817 | - /** |
|
818 | - * Returns the link to the editor for the object. Sometimes this is the same as the details. |
|
819 | - * |
|
820 | - * @return string |
|
821 | - */ |
|
822 | - public function get_admin_edit_link() |
|
823 | - { |
|
824 | - return $this->get_admin_details_link(); |
|
825 | - } |
|
826 | - |
|
827 | - /** |
|
828 | - * Returns the link to a settings page for the object. |
|
829 | - * |
|
830 | - * @return string |
|
831 | - */ |
|
832 | - public function get_admin_settings_link() |
|
833 | - { |
|
834 | - EE_Registry::instance()->load_helper('URL'); |
|
835 | - return EEH_URL::add_query_args_and_nonce( |
|
836 | - array( |
|
837 | - 'page' => 'espresso_messages', |
|
838 | - 'action' => 'settings', |
|
839 | - ), |
|
840 | - admin_url('admin.php') |
|
841 | - ); |
|
842 | - } |
|
843 | - |
|
844 | - /** |
|
845 | - * Returns the link to the "overview" for the object (typically the "list table" view). |
|
846 | - * |
|
847 | - * @return string |
|
848 | - */ |
|
849 | - public function get_admin_overview_link() |
|
850 | - { |
|
851 | - EE_Registry::instance()->load_helper('URL'); |
|
852 | - return EEH_URL::add_query_args_and_nonce( |
|
853 | - array( |
|
854 | - 'page' => 'espresso_messages', |
|
855 | - 'action' => 'default', |
|
856 | - ), |
|
857 | - admin_url('admin.php') |
|
858 | - ); |
|
859 | - } |
|
860 | - |
|
861 | - |
|
862 | - /** |
|
863 | - * This sets the EEM_Message::status_messenger_executing class on the message and the appropriate error message for |
|
864 | - * it. |
|
865 | - * Note this also SAVES the current message object to the db because it adds an error message to accompany the |
|
866 | - * status. |
|
867 | - * |
|
868 | - */ |
|
869 | - public function set_messenger_is_executing() |
|
870 | - { |
|
871 | - $this->set_STS_ID(EEM_Message::status_messenger_executing); |
|
872 | - $this->set_error_message( |
|
873 | - esc_html__( |
|
874 | - 'A message with this status indicates that there was a problem that occurred while the message was being |
|
12 | + /** |
|
13 | + * @deprecated 4.9.0 Added for backward compat with add-on's |
|
14 | + * @type null |
|
15 | + */ |
|
16 | + public $template_pack; |
|
17 | + |
|
18 | + /** |
|
19 | + * @deprecated 4.9.0 Added for backward compat with add-on's |
|
20 | + * @type null |
|
21 | + */ |
|
22 | + public $template_variation; |
|
23 | + |
|
24 | + /** |
|
25 | + * @deprecated 4.9.0 Added for backward compat with add-on's |
|
26 | + * @type string |
|
27 | + */ |
|
28 | + public $content = ''; |
|
29 | + |
|
30 | + |
|
31 | + /** |
|
32 | + * @type EE_messenger $_messenger |
|
33 | + */ |
|
34 | + protected $_messenger = null; |
|
35 | + |
|
36 | + /** |
|
37 | + * @type EE_message_type $_message_type |
|
38 | + */ |
|
39 | + protected $_message_type = null; |
|
40 | + |
|
41 | + |
|
42 | + /** |
|
43 | + * @param array $props_n_values |
|
44 | + * @param string $timezone |
|
45 | + * @param array $date_formats incoming date formats in an array. First value is the date_format, second is time |
|
46 | + * format. |
|
47 | + * @return EE_Message |
|
48 | + */ |
|
49 | + public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
50 | + { |
|
51 | + $has_object = parent::_check_for_object($props_n_values, __CLASS__); |
|
52 | + // if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db. |
|
53 | + if (! $has_object) { |
|
54 | + EE_Registry::instance()->load_helper('URL'); |
|
55 | + $props_n_values['MSG_token'] = EEH_URL::generate_unique_token(); |
|
56 | + } |
|
57 | + return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats); |
|
58 | + } |
|
59 | + |
|
60 | + |
|
61 | + /** |
|
62 | + * @param array $props_n_values |
|
63 | + * @param string $timezone |
|
64 | + * @return EE_Message |
|
65 | + */ |
|
66 | + public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
67 | + { |
|
68 | + return new self($props_n_values, true, $timezone); |
|
69 | + } |
|
70 | + |
|
71 | + |
|
72 | + /** |
|
73 | + * Gets MSG_token |
|
74 | + * |
|
75 | + * @return int |
|
76 | + */ |
|
77 | + public function MSG_token() |
|
78 | + { |
|
79 | + return $this->get('MSG_token'); |
|
80 | + } |
|
81 | + |
|
82 | + |
|
83 | + /** |
|
84 | + * Sets MSG_token |
|
85 | + * |
|
86 | + * @param int $MSG_token |
|
87 | + */ |
|
88 | + public function set_MSG_token($MSG_token) |
|
89 | + { |
|
90 | + $this->set('MSG_token', $MSG_token); |
|
91 | + } |
|
92 | + |
|
93 | + |
|
94 | + /** |
|
95 | + * Gets GRP_ID |
|
96 | + * |
|
97 | + * @return int |
|
98 | + */ |
|
99 | + public function GRP_ID() |
|
100 | + { |
|
101 | + return $this->get('GRP_ID'); |
|
102 | + } |
|
103 | + |
|
104 | + |
|
105 | + /** |
|
106 | + * Sets GRP_ID |
|
107 | + * |
|
108 | + * @param int $GRP_ID |
|
109 | + */ |
|
110 | + public function set_GRP_ID($GRP_ID) |
|
111 | + { |
|
112 | + $this->set('GRP_ID', $GRP_ID); |
|
113 | + } |
|
114 | + |
|
115 | + |
|
116 | + /** |
|
117 | + * Gets TXN_ID |
|
118 | + * |
|
119 | + * @return int |
|
120 | + */ |
|
121 | + public function TXN_ID() |
|
122 | + { |
|
123 | + return $this->get('TXN_ID'); |
|
124 | + } |
|
125 | + |
|
126 | + |
|
127 | + /** |
|
128 | + * Sets TXN_ID |
|
129 | + * |
|
130 | + * @param int $TXN_ID |
|
131 | + */ |
|
132 | + public function set_TXN_ID($TXN_ID) |
|
133 | + { |
|
134 | + $this->set('TXN_ID', $TXN_ID); |
|
135 | + } |
|
136 | + |
|
137 | + |
|
138 | + /** |
|
139 | + * Gets messenger |
|
140 | + * |
|
141 | + * @return string |
|
142 | + */ |
|
143 | + public function messenger() |
|
144 | + { |
|
145 | + return $this->get('MSG_messenger'); |
|
146 | + } |
|
147 | + |
|
148 | + |
|
149 | + /** |
|
150 | + * Sets messenger |
|
151 | + * |
|
152 | + * @param string $messenger |
|
153 | + */ |
|
154 | + public function set_messenger($messenger) |
|
155 | + { |
|
156 | + $this->set('MSG_messenger', $messenger); |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + /** |
|
161 | + * Returns corresponding messenger object for the set messenger on this message |
|
162 | + * |
|
163 | + * @return EE_messenger | null |
|
164 | + */ |
|
165 | + public function messenger_object() |
|
166 | + { |
|
167 | + return $this->_messenger; |
|
168 | + } |
|
169 | + |
|
170 | + |
|
171 | + /** |
|
172 | + * Sets messenger |
|
173 | + * |
|
174 | + * @param EE_messenger $messenger |
|
175 | + */ |
|
176 | + public function set_messenger_object(EE_messenger $messenger) |
|
177 | + { |
|
178 | + $this->_messenger = $messenger; |
|
179 | + } |
|
180 | + |
|
181 | + |
|
182 | + /** |
|
183 | + * validates messenger |
|
184 | + * |
|
185 | + * @param bool $throw_exceptions |
|
186 | + * @return bool |
|
187 | + * @throws \EE_Error |
|
188 | + */ |
|
189 | + public function valid_messenger($throw_exceptions = false) |
|
190 | + { |
|
191 | + if ($this->_messenger instanceof EE_messenger) { |
|
192 | + return true; |
|
193 | + } |
|
194 | + if ($throw_exceptions) { |
|
195 | + throw new EE_Error( |
|
196 | + sprintf( |
|
197 | + esc_html__( |
|
198 | + 'The "%1$s" messenger set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.', |
|
199 | + 'event_espresso' |
|
200 | + ), |
|
201 | + $this->messenger() |
|
202 | + ) |
|
203 | + ); |
|
204 | + } |
|
205 | + return false; |
|
206 | + } |
|
207 | + |
|
208 | + |
|
209 | + /** |
|
210 | + * This returns the set localized label for the messenger on this message. |
|
211 | + * Note, if unable to retrieve the EE_messenger object then will just return the messenger slug saved |
|
212 | + * with this message. |
|
213 | + * |
|
214 | + * @param bool $plural whether to return the plural label or not. |
|
215 | + * @return string |
|
216 | + */ |
|
217 | + public function messenger_label($plural = false) |
|
218 | + { |
|
219 | + $label_type = $plural ? 'plural' : 'singular'; |
|
220 | + $messenger = $this->messenger_object(); |
|
221 | + return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger(); |
|
222 | + } |
|
223 | + |
|
224 | + |
|
225 | + /** |
|
226 | + * Gets message_type |
|
227 | + * |
|
228 | + * @return string |
|
229 | + */ |
|
230 | + public function message_type() |
|
231 | + { |
|
232 | + return $this->get('MSG_message_type'); |
|
233 | + } |
|
234 | + |
|
235 | + |
|
236 | + /** |
|
237 | + * Sets message_type |
|
238 | + * |
|
239 | + * @param string $message_type |
|
240 | + */ |
|
241 | + public function set_message_type($message_type) |
|
242 | + { |
|
243 | + $this->set('MSG_message_type', $message_type); |
|
244 | + } |
|
245 | + |
|
246 | + |
|
247 | + /** |
|
248 | + * Returns the message type object for the set message type on this message |
|
249 | + * |
|
250 | + * @return EE_message_type | null |
|
251 | + */ |
|
252 | + public function message_type_object() |
|
253 | + { |
|
254 | + return $this->_message_type; |
|
255 | + } |
|
256 | + |
|
257 | + |
|
258 | + /** |
|
259 | + * Sets message_type |
|
260 | + * |
|
261 | + * @param EE_message_type $message_type |
|
262 | + * @param bool $set_priority This indicates whether to set the priority to whatever the priority is on |
|
263 | + * the message type or not. |
|
264 | + */ |
|
265 | + public function set_message_type_object(EE_message_type $message_type, $set_priority = false) |
|
266 | + { |
|
267 | + $this->_message_type = $message_type; |
|
268 | + if ($set_priority) { |
|
269 | + $this->set_priority($this->_message_type->get_priority()); |
|
270 | + } |
|
271 | + } |
|
272 | + |
|
273 | + |
|
274 | + /** |
|
275 | + * validates message_type |
|
276 | + * |
|
277 | + * @param bool $throw_exceptions |
|
278 | + * @return bool |
|
279 | + * @throws \EE_Error |
|
280 | + */ |
|
281 | + public function valid_message_type($throw_exceptions = false) |
|
282 | + { |
|
283 | + if ($this->_message_type instanceof EE_message_type) { |
|
284 | + return true; |
|
285 | + } |
|
286 | + if ($throw_exceptions) { |
|
287 | + throw new EE_Error( |
|
288 | + sprintf( |
|
289 | + esc_html__( |
|
290 | + 'The %1$s message type set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.', |
|
291 | + 'event_espresso' |
|
292 | + ), |
|
293 | + $this->message_type() |
|
294 | + ) |
|
295 | + ); |
|
296 | + } |
|
297 | + return false; |
|
298 | + } |
|
299 | + |
|
300 | + |
|
301 | + /** |
|
302 | + * validates messenger and message_type (that they are valid EE_messenger and EE_message_type objects). |
|
303 | + * |
|
304 | + * @param bool $throw_exceptions |
|
305 | + * @return bool |
|
306 | + * @throws \EE_Error |
|
307 | + */ |
|
308 | + public function is_valid($throw_exceptions = false) |
|
309 | + { |
|
310 | + if ($this->valid_messenger($throw_exceptions) && $this->valid_message_type($throw_exceptions)) { |
|
311 | + return true; |
|
312 | + } |
|
313 | + return false; |
|
314 | + } |
|
315 | + |
|
316 | + |
|
317 | + /** |
|
318 | + * This validates whether the internal messenger and message type objects are valid for sending. |
|
319 | + * Three checks are done: |
|
320 | + * 1. There is a valid messenger object. |
|
321 | + * 2. There is a valid message type object. |
|
322 | + * 3. The message type object is active for the messenger. |
|
323 | + * |
|
324 | + * @throws EE_Error But only if $throw_exceptions is set to true. |
|
325 | + * @param bool $throw_exceptions |
|
326 | + * @return bool |
|
327 | + */ |
|
328 | + public function is_valid_for_sending_or_generation($throw_exceptions = false) |
|
329 | + { |
|
330 | + $valid = false; |
|
331 | + if ($this->is_valid($throw_exceptions)) { |
|
332 | + /** @var EE_Message_Resource_Manager $message_resource_manager */ |
|
333 | + $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
334 | + $valid = $message_resource_manager->is_message_type_active_for_messenger( |
|
335 | + $this->messenger(), |
|
336 | + $this->message_type() |
|
337 | + ); |
|
338 | + if (! $valid && $throw_exceptions) { |
|
339 | + throw new EE_Error( |
|
340 | + sprintf( |
|
341 | + esc_html__( |
|
342 | + 'The %1$s message type is not a valid message type for the %2$s messenger so it will not be sent.', |
|
343 | + 'event_espresso' |
|
344 | + ), |
|
345 | + $this->message_type(), |
|
346 | + $this->messenger() |
|
347 | + ) |
|
348 | + ); |
|
349 | + } |
|
350 | + } |
|
351 | + return $valid; |
|
352 | + } |
|
353 | + |
|
354 | + |
|
355 | + /** |
|
356 | + * This returns the set localized label for the message type on this message. |
|
357 | + * Note, if unable to retrieve the EE_message_type object then will just return the message type slug saved |
|
358 | + * with this message. |
|
359 | + * |
|
360 | + * @param bool $plural whether to return the plural label or not. |
|
361 | + * @return string |
|
362 | + */ |
|
363 | + public function message_type_label($plural = false) |
|
364 | + { |
|
365 | + $label_type = $plural ? 'plural' : 'singular'; |
|
366 | + $message_type = $this->message_type_object(); |
|
367 | + return $message_type instanceof EE_message_type |
|
368 | + ? $message_type->label[ $label_type ] |
|
369 | + : str_replace( |
|
370 | + '_', |
|
371 | + ' ', |
|
372 | + $this->message_type() |
|
373 | + ); |
|
374 | + } |
|
375 | + |
|
376 | + |
|
377 | + /** |
|
378 | + * Gets context |
|
379 | + * |
|
380 | + * @return string |
|
381 | + */ |
|
382 | + public function context() |
|
383 | + { |
|
384 | + return $this->get('MSG_context'); |
|
385 | + } |
|
386 | + |
|
387 | + |
|
388 | + /** |
|
389 | + * This returns the corresponding localized label for the given context slug, if possible from installed message |
|
390 | + * types. Otherwise, this will just return the set context slug on this object. |
|
391 | + * |
|
392 | + * @return string |
|
393 | + */ |
|
394 | + public function context_label() |
|
395 | + { |
|
396 | + /** @type EE_Message_Resource_Manager $message_resource_manager */ |
|
397 | + $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
398 | + $contexts = $message_resource_manager->get_all_contexts(); |
|
399 | + return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context(); |
|
400 | + } |
|
401 | + |
|
402 | + |
|
403 | + /** |
|
404 | + * Sets context |
|
405 | + * |
|
406 | + * @param string $context |
|
407 | + */ |
|
408 | + public function set_context($context) |
|
409 | + { |
|
410 | + $this->set('MSG_context', $context); |
|
411 | + } |
|
412 | + |
|
413 | + |
|
414 | + /** |
|
415 | + * Gets recipient_ID |
|
416 | + * |
|
417 | + * @return int |
|
418 | + */ |
|
419 | + public function recipient_ID() |
|
420 | + { |
|
421 | + return $this->get('MSG_recipient_ID'); |
|
422 | + } |
|
423 | + |
|
424 | + |
|
425 | + /** |
|
426 | + * Sets recipient_ID |
|
427 | + * |
|
428 | + * @param string $recipient_ID |
|
429 | + */ |
|
430 | + public function set_recipient_ID($recipient_ID) |
|
431 | + { |
|
432 | + $this->set('MSG_recipient_ID', $recipient_ID); |
|
433 | + } |
|
434 | + |
|
435 | + |
|
436 | + /** |
|
437 | + * Gets recipient_type |
|
438 | + * |
|
439 | + * @return string |
|
440 | + */ |
|
441 | + public function recipient_type() |
|
442 | + { |
|
443 | + return $this->get('MSG_recipient_type'); |
|
444 | + } |
|
445 | + |
|
446 | + |
|
447 | + /** |
|
448 | + * Return the related object matching the recipient type and ID. |
|
449 | + * |
|
450 | + * @return EE_Base_Class | null |
|
451 | + */ |
|
452 | + public function recipient_object() |
|
453 | + { |
|
454 | + if (! $this->recipient_type() || ! $this->recipient_ID()) { |
|
455 | + return null; |
|
456 | + } |
|
457 | + |
|
458 | + return $this->get_first_related($this->recipient_type()); |
|
459 | + } |
|
460 | + |
|
461 | + |
|
462 | + /** |
|
463 | + * Sets recipient_type |
|
464 | + * |
|
465 | + * @param string $recipient_type |
|
466 | + */ |
|
467 | + public function set_recipient_type($recipient_type) |
|
468 | + { |
|
469 | + $this->set('MSG_recipient_type', $recipient_type); |
|
470 | + } |
|
471 | + |
|
472 | + |
|
473 | + /** |
|
474 | + * Gets content |
|
475 | + * |
|
476 | + * @return string |
|
477 | + */ |
|
478 | + public function content() |
|
479 | + { |
|
480 | + return $this->get('MSG_content'); |
|
481 | + } |
|
482 | + |
|
483 | + |
|
484 | + /** |
|
485 | + * Sets content |
|
486 | + * |
|
487 | + * @param string $content |
|
488 | + */ |
|
489 | + public function set_content($content) |
|
490 | + { |
|
491 | + $this->set('MSG_content', $content); |
|
492 | + } |
|
493 | + |
|
494 | + |
|
495 | + /** |
|
496 | + * Gets subject |
|
497 | + * |
|
498 | + * @return string |
|
499 | + */ |
|
500 | + public function subject() |
|
501 | + { |
|
502 | + return $this->get('MSG_subject'); |
|
503 | + } |
|
504 | + |
|
505 | + |
|
506 | + /** |
|
507 | + * Sets subject |
|
508 | + * |
|
509 | + * @param string $subject |
|
510 | + */ |
|
511 | + public function set_subject($subject) |
|
512 | + { |
|
513 | + $this->set('MSG_subject', $subject); |
|
514 | + } |
|
515 | + |
|
516 | + |
|
517 | + /** |
|
518 | + * Gets to |
|
519 | + * |
|
520 | + * @return string |
|
521 | + */ |
|
522 | + public function to() |
|
523 | + { |
|
524 | + $to = $this->get('MSG_to'); |
|
525 | + return empty($to) ? esc_html__('No recipient', 'event_espresso') : $to; |
|
526 | + } |
|
527 | + |
|
528 | + |
|
529 | + /** |
|
530 | + * Sets to |
|
531 | + * |
|
532 | + * @param string $to |
|
533 | + */ |
|
534 | + public function set_to($to) |
|
535 | + { |
|
536 | + $this->set('MSG_to', $to); |
|
537 | + } |
|
538 | + |
|
539 | + |
|
540 | + /** |
|
541 | + * Gets from |
|
542 | + * |
|
543 | + * @return string |
|
544 | + */ |
|
545 | + public function from() |
|
546 | + { |
|
547 | + return $this->get('MSG_from'); |
|
548 | + } |
|
549 | + |
|
550 | + |
|
551 | + /** |
|
552 | + * Sets from |
|
553 | + * |
|
554 | + * @param string $from |
|
555 | + */ |
|
556 | + public function set_from($from) |
|
557 | + { |
|
558 | + $this->set('MSG_from', $from); |
|
559 | + } |
|
560 | + |
|
561 | + |
|
562 | + /** |
|
563 | + * Gets priority |
|
564 | + * |
|
565 | + * @return int |
|
566 | + */ |
|
567 | + public function priority() |
|
568 | + { |
|
569 | + return $this->get('MSG_priority'); |
|
570 | + } |
|
571 | + |
|
572 | + |
|
573 | + /** |
|
574 | + * Sets priority |
|
575 | + * Note. Send Now Messengers always override any priority that may be set on a Message. So |
|
576 | + * this method calls the send_now method to verify that. |
|
577 | + * |
|
578 | + * @param int $priority |
|
579 | + */ |
|
580 | + public function set_priority($priority) |
|
581 | + { |
|
582 | + $priority = $this->send_now() ? EEM_Message::priority_high : $priority; |
|
583 | + parent::set('MSG_priority', $priority); |
|
584 | + } |
|
585 | + |
|
586 | + |
|
587 | + /** |
|
588 | + * Overrides parent::set method so we can capture any sets for priority. |
|
589 | + * |
|
590 | + * @see parent::set() for phpdocs |
|
591 | + * @param string $field_name |
|
592 | + * @param mixed $field_value |
|
593 | + * @param bool $use_default |
|
594 | + * @throws EE_Error |
|
595 | + */ |
|
596 | + public function set($field_name, $field_value, $use_default = false) |
|
597 | + { |
|
598 | + if ($field_name === 'MSG_priority') { |
|
599 | + $this->set_priority($field_value); |
|
600 | + } |
|
601 | + parent::set($field_name, $field_value, $use_default); |
|
602 | + } |
|
603 | + |
|
604 | + |
|
605 | + /** |
|
606 | + * @return bool |
|
607 | + * @throws \EE_Error |
|
608 | + */ |
|
609 | + public function send_now() |
|
610 | + { |
|
611 | + $send_now = $this->valid_messenger() && $this->messenger_object()->send_now() ? EEM_Message::priority_high |
|
612 | + : $this->priority(); |
|
613 | + return $send_now === EEM_Message::priority_high ? true : false; |
|
614 | + } |
|
615 | + |
|
616 | + |
|
617 | + /** |
|
618 | + * Gets STS_ID |
|
619 | + * |
|
620 | + * @return string |
|
621 | + */ |
|
622 | + public function STS_ID() |
|
623 | + { |
|
624 | + return $this->get('STS_ID'); |
|
625 | + } |
|
626 | + |
|
627 | + |
|
628 | + /** |
|
629 | + * Sets STS_ID |
|
630 | + * |
|
631 | + * @param string $STS_ID |
|
632 | + */ |
|
633 | + public function set_STS_ID($STS_ID) |
|
634 | + { |
|
635 | + $this->set('STS_ID', $STS_ID); |
|
636 | + } |
|
637 | + |
|
638 | + |
|
639 | + /** |
|
640 | + * Gets created |
|
641 | + * |
|
642 | + * @return string |
|
643 | + */ |
|
644 | + public function created() |
|
645 | + { |
|
646 | + return $this->get('MSG_created'); |
|
647 | + } |
|
648 | + |
|
649 | + |
|
650 | + /** |
|
651 | + * Sets created |
|
652 | + * |
|
653 | + * @param string $created |
|
654 | + */ |
|
655 | + public function set_created($created) |
|
656 | + { |
|
657 | + $this->set('MSG_created', $created); |
|
658 | + } |
|
659 | + |
|
660 | + |
|
661 | + /** |
|
662 | + * Gets modified |
|
663 | + * |
|
664 | + * @return string |
|
665 | + */ |
|
666 | + public function modified() |
|
667 | + { |
|
668 | + return $this->get('MSG_modified'); |
|
669 | + } |
|
670 | + |
|
671 | + |
|
672 | + /** |
|
673 | + * Sets modified |
|
674 | + * |
|
675 | + * @param string $modified |
|
676 | + */ |
|
677 | + public function set_modified($modified) |
|
678 | + { |
|
679 | + $this->set('MSG_modified', $modified); |
|
680 | + } |
|
681 | + |
|
682 | + |
|
683 | + /** |
|
684 | + * Sets generation data for this message. |
|
685 | + * |
|
686 | + * @param mixed $data |
|
687 | + */ |
|
688 | + public function set_generation_data($data) |
|
689 | + { |
|
690 | + $this->set_field_or_extra_meta('MSG_generation_data', $data); |
|
691 | + } |
|
692 | + |
|
693 | + |
|
694 | + /** |
|
695 | + * Returns any set generation data for this message. |
|
696 | + * |
|
697 | + * @return mixed|null |
|
698 | + */ |
|
699 | + public function get_generation_data() |
|
700 | + { |
|
701 | + return $this->get_field_or_extra_meta('MSG_generation_data'); |
|
702 | + } |
|
703 | + |
|
704 | + |
|
705 | + /** |
|
706 | + * Gets any error message. |
|
707 | + * |
|
708 | + * @return mixed|null |
|
709 | + */ |
|
710 | + public function error_message() |
|
711 | + { |
|
712 | + return $this->get_field_or_extra_meta('MSG_error'); |
|
713 | + } |
|
714 | + |
|
715 | + |
|
716 | + /** |
|
717 | + * Sets an error message. |
|
718 | + * |
|
719 | + * @param $message |
|
720 | + * @return bool|int |
|
721 | + */ |
|
722 | + public function set_error_message($message) |
|
723 | + { |
|
724 | + return $this->set_field_or_extra_meta('MSG_error', $message); |
|
725 | + } |
|
726 | + |
|
727 | + |
|
728 | + /** |
|
729 | + * This retrieves the associated template pack with this message. |
|
730 | + * |
|
731 | + * @return EE_Messages_Template_Pack | null |
|
732 | + */ |
|
733 | + public function get_template_pack() |
|
734 | + { |
|
735 | + /** |
|
736 | + * This is deprecated functionality that will be removed eventually but included here now for backward compat. |
|
737 | + */ |
|
738 | + if (! empty($this->template_pack)) { |
|
739 | + return $this->template_pack; |
|
740 | + } |
|
741 | + /** @type EE_Message_Template_Group $grp */ |
|
742 | + $grp = $this->get_first_related('Message_Template_Group'); |
|
743 | + // if no group then let's try to get the first related group by internal messenger and message type (will use global grp). |
|
744 | + if (! $grp instanceof EE_Message_Template_Group) { |
|
745 | + $grp = EEM_Message_Template_Group::instance()->get_one( |
|
746 | + array( |
|
747 | + array( |
|
748 | + 'MTP_messenger' => $this->messenger(), |
|
749 | + 'MTP_message_type' => $this->message_type(), |
|
750 | + 'MTP_is_global' => true, |
|
751 | + ), |
|
752 | + ) |
|
753 | + ); |
|
754 | + } |
|
755 | + |
|
756 | + return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack() : null; |
|
757 | + } |
|
758 | + |
|
759 | + |
|
760 | + /** |
|
761 | + * Retrieves the variation used for generating this message. |
|
762 | + * |
|
763 | + * @return string |
|
764 | + */ |
|
765 | + public function get_template_pack_variation() |
|
766 | + { |
|
767 | + /** |
|
768 | + * This is deprecated functionality that will be removed eventually but included here now for backward compat. |
|
769 | + */ |
|
770 | + if (! empty($this->template_variation)) { |
|
771 | + return $this->template_variation; |
|
772 | + } |
|
773 | + |
|
774 | + /** @type EE_Message_Template_Group $grp */ |
|
775 | + $grp = $this->get_first_related('Message_Template_Group'); |
|
776 | + |
|
777 | + // if no group then let's try to get the first related group by internal messenger and message type (will use global grp). |
|
778 | + if (! $grp instanceof EE_Message_Template_Group) { |
|
779 | + $grp = EEM_Message_Template_Group::instance()->get_one( |
|
780 | + array( |
|
781 | + array( |
|
782 | + 'MTP_messenger' => $this->messenger(), |
|
783 | + 'MTP_message_type' => $this->message_type(), |
|
784 | + 'MTP_is_global' => true, |
|
785 | + ), |
|
786 | + ) |
|
787 | + ); |
|
788 | + } |
|
789 | + |
|
790 | + return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack_variation() : ''; |
|
791 | + } |
|
792 | + |
|
793 | + /** |
|
794 | + * Return the link to the admin details for the object. |
|
795 | + * |
|
796 | + * @return string |
|
797 | + */ |
|
798 | + public function get_admin_details_link() |
|
799 | + { |
|
800 | + EE_Registry::instance()->load_helper('URL'); |
|
801 | + EE_Registry::instance()->load_helper('MSG_Template'); |
|
802 | + switch ($this->STS_ID()) { |
|
803 | + case EEM_Message::status_failed: |
|
804 | + case EEM_Message::status_debug_only: |
|
805 | + return EEH_MSG_Template::generate_error_display_trigger($this); |
|
806 | + break; |
|
807 | + |
|
808 | + case EEM_Message::status_sent: |
|
809 | + return EEH_MSG_Template::generate_browser_trigger($this); |
|
810 | + break; |
|
811 | + |
|
812 | + default: |
|
813 | + return ''; |
|
814 | + } |
|
815 | + } |
|
816 | + |
|
817 | + /** |
|
818 | + * Returns the link to the editor for the object. Sometimes this is the same as the details. |
|
819 | + * |
|
820 | + * @return string |
|
821 | + */ |
|
822 | + public function get_admin_edit_link() |
|
823 | + { |
|
824 | + return $this->get_admin_details_link(); |
|
825 | + } |
|
826 | + |
|
827 | + /** |
|
828 | + * Returns the link to a settings page for the object. |
|
829 | + * |
|
830 | + * @return string |
|
831 | + */ |
|
832 | + public function get_admin_settings_link() |
|
833 | + { |
|
834 | + EE_Registry::instance()->load_helper('URL'); |
|
835 | + return EEH_URL::add_query_args_and_nonce( |
|
836 | + array( |
|
837 | + 'page' => 'espresso_messages', |
|
838 | + 'action' => 'settings', |
|
839 | + ), |
|
840 | + admin_url('admin.php') |
|
841 | + ); |
|
842 | + } |
|
843 | + |
|
844 | + /** |
|
845 | + * Returns the link to the "overview" for the object (typically the "list table" view). |
|
846 | + * |
|
847 | + * @return string |
|
848 | + */ |
|
849 | + public function get_admin_overview_link() |
|
850 | + { |
|
851 | + EE_Registry::instance()->load_helper('URL'); |
|
852 | + return EEH_URL::add_query_args_and_nonce( |
|
853 | + array( |
|
854 | + 'page' => 'espresso_messages', |
|
855 | + 'action' => 'default', |
|
856 | + ), |
|
857 | + admin_url('admin.php') |
|
858 | + ); |
|
859 | + } |
|
860 | + |
|
861 | + |
|
862 | + /** |
|
863 | + * This sets the EEM_Message::status_messenger_executing class on the message and the appropriate error message for |
|
864 | + * it. |
|
865 | + * Note this also SAVES the current message object to the db because it adds an error message to accompany the |
|
866 | + * status. |
|
867 | + * |
|
868 | + */ |
|
869 | + public function set_messenger_is_executing() |
|
870 | + { |
|
871 | + $this->set_STS_ID(EEM_Message::status_messenger_executing); |
|
872 | + $this->set_error_message( |
|
873 | + esc_html__( |
|
874 | + 'A message with this status indicates that there was a problem that occurred while the message was being |
|
875 | 875 | processed by the messenger. It is still possible that the message was sent successfully, but at some |
876 | 876 | point during the processing there was a failure. This usually is indicative of a timeout issue with PHP |
877 | 877 | or memory limits being reached. If you see this repeatedly you may want to consider upgrading the memory |
878 | 878 | available to PHP on your server.', |
879 | - 'event_espresso' |
|
880 | - ) |
|
881 | - ); |
|
882 | - } |
|
879 | + 'event_espresso' |
|
880 | + ) |
|
881 | + ); |
|
882 | + } |
|
883 | 883 | } |
@@ -42,7 +42,7 @@ |
||
42 | 42 | */ |
43 | 43 | public function set_group_template_id($GRP_ID = false) |
44 | 44 | { |
45 | - if (! $GRP_ID) { |
|
45 | + if ( ! $GRP_ID) { |
|
46 | 46 | throw new EE_Error(esc_html__('Missing required value for the message template group id', 'event_espresso')); |
47 | 47 | } |
48 | 48 | $this->set('GRP_ID', $GRP_ID); |
@@ -12,173 +12,173 @@ |
||
12 | 12 | */ |
13 | 13 | class EE_Message_Template extends EE_Base_Class |
14 | 14 | { |
15 | - /** |
|
16 | - * @param array $props_n_values |
|
17 | - * @param string $timezone |
|
18 | - * @return EE_Message_Template|mixed |
|
19 | - */ |
|
20 | - public static function new_instance($props_n_values = array(), $timezone = '') |
|
21 | - { |
|
22 | - $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone); |
|
23 | - return $has_object ? $has_object : new self($props_n_values, false, $timezone); |
|
24 | - } |
|
25 | - |
|
26 | - |
|
27 | - /** |
|
28 | - * @param array $props_n_values |
|
29 | - * @param string $timezone |
|
30 | - * @return EE_Message_Template |
|
31 | - */ |
|
32 | - public static function new_instance_from_db($props_n_values = array(), $timezone = '') |
|
33 | - { |
|
34 | - return new self($props_n_values, true, $timezone); |
|
35 | - } |
|
36 | - |
|
37 | - |
|
38 | - /** |
|
39 | - * @param bool $GRP_ID |
|
40 | - * @throws EE_Error |
|
41 | - */ |
|
42 | - public function set_group_template_id($GRP_ID = false) |
|
43 | - { |
|
44 | - if (! $GRP_ID) { |
|
45 | - throw new EE_Error(esc_html__('Missing required value for the message template group id', 'event_espresso')); |
|
46 | - } |
|
47 | - $this->set('GRP_ID', $GRP_ID); |
|
48 | - } |
|
49 | - |
|
50 | - |
|
51 | - /** |
|
52 | - * get Group ID |
|
53 | - * |
|
54 | - * @access public |
|
55 | - * @return int |
|
56 | - */ |
|
57 | - public function GRP_ID() |
|
58 | - { |
|
59 | - return $this->get('GRP_ID'); |
|
60 | - } |
|
61 | - |
|
62 | - |
|
63 | - /** |
|
64 | - * get User ID |
|
65 | - * |
|
66 | - * @access public |
|
67 | - * @return int |
|
68 | - */ |
|
69 | - public function user() |
|
70 | - { |
|
71 | - return $this->get_first_related('Message_Template_Group')->get('MTP_user_id'); |
|
72 | - } |
|
73 | - |
|
74 | - |
|
75 | - /** |
|
76 | - * get Message Messenger |
|
77 | - * |
|
78 | - * @access public |
|
79 | - * @return string |
|
80 | - */ |
|
81 | - public function messenger() |
|
82 | - { |
|
83 | - return $this->get_first_related('Message_Template_Group')->messenger(); |
|
84 | - } |
|
85 | - |
|
86 | - |
|
87 | - /** |
|
88 | - * get Message Messenger OBJECT |
|
89 | - * |
|
90 | - * @access public |
|
91 | - * @return object Messenger Object for the given messenger |
|
92 | - */ |
|
93 | - public function messenger_obj() |
|
94 | - { |
|
95 | - return $this->get_first_related('Message_Template_Group')->messenger_obj(); |
|
96 | - } |
|
97 | - |
|
98 | - |
|
99 | - /** |
|
100 | - * get Message Type |
|
101 | - * |
|
102 | - * @access public |
|
103 | - * @return string |
|
104 | - */ |
|
105 | - public function message_type() |
|
106 | - { |
|
107 | - return $this->get_first_related('Message_Template_Group')->message_type(); |
|
108 | - } |
|
109 | - |
|
110 | - |
|
111 | - /** |
|
112 | - * get Message type OBJECT |
|
113 | - * |
|
114 | - * @access public |
|
115 | - * @return object Message Type object for the given message type |
|
116 | - */ |
|
117 | - public function message_type_obj() |
|
118 | - { |
|
119 | - return $this->get_first_related('Message_Template_Group')->message_type_obj(); |
|
120 | - } |
|
121 | - |
|
122 | - |
|
123 | - /** |
|
124 | - * This returns the set context array configured in the message type object |
|
125 | - * |
|
126 | - * @access public |
|
127 | - * @return array array of contexts and their configuration. |
|
128 | - */ |
|
129 | - public function contexts_config() |
|
130 | - { |
|
131 | - return $this->get_first_related('Message_Template_Group')->contexts_config(); |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - /** |
|
136 | - * This returns the context_label for contexts as set in the message type object |
|
137 | - * |
|
138 | - * @access public |
|
139 | - * @return string label for "context" |
|
140 | - */ |
|
141 | - public function context_label() |
|
142 | - { |
|
143 | - return $this->get_first_related('Message_Template_Group')->context_label(); |
|
144 | - } |
|
145 | - |
|
146 | - |
|
147 | - /** |
|
148 | - * this returns if the template group this template belongs to is global |
|
149 | - * |
|
150 | - * @return boolean true if it is, false if it isn't |
|
151 | - */ |
|
152 | - public function is_global() |
|
153 | - { |
|
154 | - return $this->get_first_related('Message_Template_Group')->is_global(); |
|
155 | - } |
|
156 | - |
|
157 | - |
|
158 | - /** |
|
159 | - * this returns if the template group this template belongs to is active (i.e. turned "on" or not) |
|
160 | - * |
|
161 | - * @return boolean true if it is, false if it isn't |
|
162 | - */ |
|
163 | - public function is_active() |
|
164 | - { |
|
165 | - return $this->get_first_related('Message_Template_Group')->is_active(); |
|
166 | - } |
|
167 | - |
|
168 | - |
|
169 | - /** |
|
170 | - * This will return an array of shortcodes => labels from the messenger and message_type objects associated with |
|
171 | - * this template. |
|
172 | - * |
|
173 | - * @access public |
|
174 | - * @param string $context what context we're going to return shortcodes for |
|
175 | - * @param array $fields what fields we're returning valid shortcodes for. If empty then we assume all fields are |
|
176 | - * to be merged and returned. |
|
177 | - * @return mixed (array|bool) an array of shortcodes in the format array( '[shortcode] => 'label') OR FALSE if no |
|
178 | - * shortcodes found. |
|
179 | - */ |
|
180 | - public function get_shortcodes($context, $fields = array()) |
|
181 | - { |
|
182 | - return $this->get_first_related('Message_Template_Group')->get_shortcodes($context, $fields); |
|
183 | - } |
|
15 | + /** |
|
16 | + * @param array $props_n_values |
|
17 | + * @param string $timezone |
|
18 | + * @return EE_Message_Template|mixed |
|
19 | + */ |
|
20 | + public static function new_instance($props_n_values = array(), $timezone = '') |
|
21 | + { |
|
22 | + $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone); |
|
23 | + return $has_object ? $has_object : new self($props_n_values, false, $timezone); |
|
24 | + } |
|
25 | + |
|
26 | + |
|
27 | + /** |
|
28 | + * @param array $props_n_values |
|
29 | + * @param string $timezone |
|
30 | + * @return EE_Message_Template |
|
31 | + */ |
|
32 | + public static function new_instance_from_db($props_n_values = array(), $timezone = '') |
|
33 | + { |
|
34 | + return new self($props_n_values, true, $timezone); |
|
35 | + } |
|
36 | + |
|
37 | + |
|
38 | + /** |
|
39 | + * @param bool $GRP_ID |
|
40 | + * @throws EE_Error |
|
41 | + */ |
|
42 | + public function set_group_template_id($GRP_ID = false) |
|
43 | + { |
|
44 | + if (! $GRP_ID) { |
|
45 | + throw new EE_Error(esc_html__('Missing required value for the message template group id', 'event_espresso')); |
|
46 | + } |
|
47 | + $this->set('GRP_ID', $GRP_ID); |
|
48 | + } |
|
49 | + |
|
50 | + |
|
51 | + /** |
|
52 | + * get Group ID |
|
53 | + * |
|
54 | + * @access public |
|
55 | + * @return int |
|
56 | + */ |
|
57 | + public function GRP_ID() |
|
58 | + { |
|
59 | + return $this->get('GRP_ID'); |
|
60 | + } |
|
61 | + |
|
62 | + |
|
63 | + /** |
|
64 | + * get User ID |
|
65 | + * |
|
66 | + * @access public |
|
67 | + * @return int |
|
68 | + */ |
|
69 | + public function user() |
|
70 | + { |
|
71 | + return $this->get_first_related('Message_Template_Group')->get('MTP_user_id'); |
|
72 | + } |
|
73 | + |
|
74 | + |
|
75 | + /** |
|
76 | + * get Message Messenger |
|
77 | + * |
|
78 | + * @access public |
|
79 | + * @return string |
|
80 | + */ |
|
81 | + public function messenger() |
|
82 | + { |
|
83 | + return $this->get_first_related('Message_Template_Group')->messenger(); |
|
84 | + } |
|
85 | + |
|
86 | + |
|
87 | + /** |
|
88 | + * get Message Messenger OBJECT |
|
89 | + * |
|
90 | + * @access public |
|
91 | + * @return object Messenger Object for the given messenger |
|
92 | + */ |
|
93 | + public function messenger_obj() |
|
94 | + { |
|
95 | + return $this->get_first_related('Message_Template_Group')->messenger_obj(); |
|
96 | + } |
|
97 | + |
|
98 | + |
|
99 | + /** |
|
100 | + * get Message Type |
|
101 | + * |
|
102 | + * @access public |
|
103 | + * @return string |
|
104 | + */ |
|
105 | + public function message_type() |
|
106 | + { |
|
107 | + return $this->get_first_related('Message_Template_Group')->message_type(); |
|
108 | + } |
|
109 | + |
|
110 | + |
|
111 | + /** |
|
112 | + * get Message type OBJECT |
|
113 | + * |
|
114 | + * @access public |
|
115 | + * @return object Message Type object for the given message type |
|
116 | + */ |
|
117 | + public function message_type_obj() |
|
118 | + { |
|
119 | + return $this->get_first_related('Message_Template_Group')->message_type_obj(); |
|
120 | + } |
|
121 | + |
|
122 | + |
|
123 | + /** |
|
124 | + * This returns the set context array configured in the message type object |
|
125 | + * |
|
126 | + * @access public |
|
127 | + * @return array array of contexts and their configuration. |
|
128 | + */ |
|
129 | + public function contexts_config() |
|
130 | + { |
|
131 | + return $this->get_first_related('Message_Template_Group')->contexts_config(); |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + /** |
|
136 | + * This returns the context_label for contexts as set in the message type object |
|
137 | + * |
|
138 | + * @access public |
|
139 | + * @return string label for "context" |
|
140 | + */ |
|
141 | + public function context_label() |
|
142 | + { |
|
143 | + return $this->get_first_related('Message_Template_Group')->context_label(); |
|
144 | + } |
|
145 | + |
|
146 | + |
|
147 | + /** |
|
148 | + * this returns if the template group this template belongs to is global |
|
149 | + * |
|
150 | + * @return boolean true if it is, false if it isn't |
|
151 | + */ |
|
152 | + public function is_global() |
|
153 | + { |
|
154 | + return $this->get_first_related('Message_Template_Group')->is_global(); |
|
155 | + } |
|
156 | + |
|
157 | + |
|
158 | + /** |
|
159 | + * this returns if the template group this template belongs to is active (i.e. turned "on" or not) |
|
160 | + * |
|
161 | + * @return boolean true if it is, false if it isn't |
|
162 | + */ |
|
163 | + public function is_active() |
|
164 | + { |
|
165 | + return $this->get_first_related('Message_Template_Group')->is_active(); |
|
166 | + } |
|
167 | + |
|
168 | + |
|
169 | + /** |
|
170 | + * This will return an array of shortcodes => labels from the messenger and message_type objects associated with |
|
171 | + * this template. |
|
172 | + * |
|
173 | + * @access public |
|
174 | + * @param string $context what context we're going to return shortcodes for |
|
175 | + * @param array $fields what fields we're returning valid shortcodes for. If empty then we assume all fields are |
|
176 | + * to be merged and returned. |
|
177 | + * @return mixed (array|bool) an array of shortcodes in the format array( '[shortcode] => 'label') OR FALSE if no |
|
178 | + * shortcodes found. |
|
179 | + */ |
|
180 | + public function get_shortcodes($context, $fields = array()) |
|
181 | + { |
|
182 | + return $this->get_first_related('Message_Template_Group')->get_shortcodes($context, $fields); |
|
183 | + } |
|
184 | 184 | } |
@@ -36,16 +36,16 @@ discard block |
||
36 | 36 | */ |
37 | 37 | protected function __construct($fieldValues = null, $bydb = false, $timezone = null, $date_formats = array()) |
38 | 38 | { |
39 | - if (! isset($fieldValues['ATT_full_name'])) { |
|
40 | - $fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'] . ' ' : ''; |
|
39 | + if ( ! isset($fieldValues['ATT_full_name'])) { |
|
40 | + $fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'].' ' : ''; |
|
41 | 41 | $lname = isset($fieldValues['ATT_lname']) ? $fieldValues['ATT_lname'] : ''; |
42 | - $fieldValues['ATT_full_name'] = $fname . $lname; |
|
42 | + $fieldValues['ATT_full_name'] = $fname.$lname; |
|
43 | 43 | } |
44 | - if (! isset($fieldValues['ATT_slug'])) { |
|
44 | + if ( ! isset($fieldValues['ATT_slug'])) { |
|
45 | 45 | // $fieldValues['ATT_slug'] = sanitize_key(wp_generate_password(20)); |
46 | 46 | $fieldValues['ATT_slug'] = sanitize_title($fieldValues['ATT_full_name']); |
47 | 47 | } |
48 | - if (! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) { |
|
48 | + if ( ! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) { |
|
49 | 49 | $fieldValues['ATT_short_bio'] = substr($fieldValues['ATT_bio'], 0, 50); |
50 | 50 | } |
51 | 51 | parent::__construct($fieldValues, $bydb, $timezone, $date_formats); |
@@ -325,7 +325,7 @@ discard block |
||
325 | 325 | $initial_address_fields = array('ATT_address', 'ATT_address2', 'ATT_city',); |
326 | 326 | foreach ($initial_address_fields as $address_field_name) { |
327 | 327 | $address_fields_value = $this->get($address_field_name); |
328 | - if (! empty($address_fields_value)) { |
|
328 | + if ( ! empty($address_fields_value)) { |
|
329 | 329 | $full_address_array[] = $address_fields_value; |
330 | 330 | } |
331 | 331 | } |
@@ -340,7 +340,7 @@ discard block |
||
340 | 340 | } |
341 | 341 | // lastly get the xip |
342 | 342 | $zip_value = $this->zip(); |
343 | - if (! empty($zip_value)) { |
|
343 | + if ( ! empty($zip_value)) { |
|
344 | 344 | $full_address_array[] = $zip_value; |
345 | 345 | } |
346 | 346 | return $full_address_array; |
@@ -622,18 +622,18 @@ discard block |
||
622 | 622 | public function billing_info_for_payment_method($payment_method) |
623 | 623 | { |
624 | 624 | $pm_type = $payment_method->type_obj(); |
625 | - if (! $pm_type instanceof EE_PMT_Base) { |
|
625 | + if ( ! $pm_type instanceof EE_PMT_Base) { |
|
626 | 626 | return null; |
627 | 627 | } |
628 | 628 | $billing_info = $this->get_post_meta($this->get_billing_info_postmeta_name($payment_method), true); |
629 | - if (! $billing_info) { |
|
629 | + if ( ! $billing_info) { |
|
630 | 630 | return null; |
631 | 631 | } |
632 | 632 | $billing_form = $pm_type->billing_form(); |
633 | 633 | // double-check the form isn't totally hidden, in which case pretend there is no form |
634 | 634 | $form_totally_hidden = true; |
635 | 635 | foreach ($billing_form->inputs_in_subsections() as $input) { |
636 | - if (! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) { |
|
636 | + if ( ! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) { |
|
637 | 637 | $form_totally_hidden = false; |
638 | 638 | break; |
639 | 639 | } |
@@ -660,7 +660,7 @@ discard block |
||
660 | 660 | public function get_billing_info_postmeta_name($payment_method) |
661 | 661 | { |
662 | 662 | if ($payment_method->type_obj() instanceof EE_PMT_Base) { |
663 | - return 'billing_info_' . $payment_method->type_obj()->system_name(); |
|
663 | + return 'billing_info_'.$payment_method->type_obj()->system_name(); |
|
664 | 664 | } |
665 | 665 | return null; |
666 | 666 | } |
@@ -677,7 +677,7 @@ discard block |
||
677 | 677 | */ |
678 | 678 | public function save_and_clean_billing_info_for_payment_method($billing_form, $payment_method) |
679 | 679 | { |
680 | - if (! $billing_form instanceof EE_Billing_Attendee_Info_Form) { |
|
680 | + if ( ! $billing_form instanceof EE_Billing_Attendee_Info_Form) { |
|
681 | 681 | EE_Error::add_error(esc_html__('Cannot save billing info because there is none.', 'event_espresso')); |
682 | 682 | return false; |
683 | 683 | } |
@@ -24,772 +24,772 @@ |
||
24 | 24 | */ |
25 | 25 | class EE_Attendee extends EE_CPT_Base implements EEI_Contact, EEI_Address, EEI_Admin_Links, EEI_Attendee |
26 | 26 | { |
27 | - /** |
|
28 | - * Sets some dynamic defaults |
|
29 | - * |
|
30 | - * @param array $fieldValues |
|
31 | - * @param bool $bydb |
|
32 | - * @param string $timezone |
|
33 | - * @param array $date_formats |
|
34 | - * @throws EE_Error |
|
35 | - */ |
|
36 | - protected function __construct($fieldValues = null, $bydb = false, $timezone = null, $date_formats = array()) |
|
37 | - { |
|
38 | - if (! isset($fieldValues['ATT_full_name'])) { |
|
39 | - $fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'] . ' ' : ''; |
|
40 | - $lname = isset($fieldValues['ATT_lname']) ? $fieldValues['ATT_lname'] : ''; |
|
41 | - $fieldValues['ATT_full_name'] = $fname . $lname; |
|
42 | - } |
|
43 | - if (! isset($fieldValues['ATT_slug'])) { |
|
44 | - // $fieldValues['ATT_slug'] = sanitize_key(wp_generate_password(20)); |
|
45 | - $fieldValues['ATT_slug'] = sanitize_title($fieldValues['ATT_full_name']); |
|
46 | - } |
|
47 | - if (! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) { |
|
48 | - $fieldValues['ATT_short_bio'] = substr($fieldValues['ATT_bio'], 0, 50); |
|
49 | - } |
|
50 | - parent::__construct($fieldValues, $bydb, $timezone, $date_formats); |
|
51 | - } |
|
52 | - |
|
53 | - |
|
54 | - /** |
|
55 | - * @param array $props_n_values incoming values |
|
56 | - * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
57 | - * used.) |
|
58 | - * @param array $date_formats incoming date_formats in an array where the first value is the |
|
59 | - * date_format and the second value is the time format |
|
60 | - * @return EE_Attendee |
|
61 | - * @throws EE_Error |
|
62 | - */ |
|
63 | - public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
64 | - { |
|
65 | - $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
66 | - return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats); |
|
67 | - } |
|
68 | - |
|
69 | - |
|
70 | - /** |
|
71 | - * @param array $props_n_values incoming values from the database |
|
72 | - * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
73 | - * the website will be used. |
|
74 | - * @return EE_Attendee |
|
75 | - */ |
|
76 | - public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
77 | - { |
|
78 | - return new self($props_n_values, true, $timezone); |
|
79 | - } |
|
80 | - |
|
81 | - |
|
82 | - /** |
|
83 | - * Set Attendee First Name |
|
84 | - * |
|
85 | - * @access public |
|
86 | - * @param string $fname |
|
87 | - * @throws EE_Error |
|
88 | - */ |
|
89 | - public function set_fname($fname = '') |
|
90 | - { |
|
91 | - $this->set('ATT_fname', $fname); |
|
92 | - } |
|
93 | - |
|
94 | - |
|
95 | - /** |
|
96 | - * Set Attendee Last Name |
|
97 | - * |
|
98 | - * @access public |
|
99 | - * @param string $lname |
|
100 | - * @throws EE_Error |
|
101 | - */ |
|
102 | - public function set_lname($lname = '') |
|
103 | - { |
|
104 | - $this->set('ATT_lname', $lname); |
|
105 | - } |
|
106 | - |
|
107 | - |
|
108 | - /** |
|
109 | - * Set Attendee Address |
|
110 | - * |
|
111 | - * @access public |
|
112 | - * @param string $address |
|
113 | - * @throws EE_Error |
|
114 | - */ |
|
115 | - public function set_address($address = '') |
|
116 | - { |
|
117 | - $this->set('ATT_address', $address); |
|
118 | - } |
|
119 | - |
|
120 | - |
|
121 | - /** |
|
122 | - * Set Attendee Address2 |
|
123 | - * |
|
124 | - * @access public |
|
125 | - * @param string $address2 |
|
126 | - * @throws EE_Error |
|
127 | - */ |
|
128 | - public function set_address2($address2 = '') |
|
129 | - { |
|
130 | - $this->set('ATT_address2', $address2); |
|
131 | - } |
|
132 | - |
|
133 | - |
|
134 | - /** |
|
135 | - * Set Attendee City |
|
136 | - * |
|
137 | - * @access public |
|
138 | - * @param string $city |
|
139 | - * @throws EE_Error |
|
140 | - */ |
|
141 | - public function set_city($city = '') |
|
142 | - { |
|
143 | - $this->set('ATT_city', $city); |
|
144 | - } |
|
145 | - |
|
146 | - |
|
147 | - /** |
|
148 | - * Set Attendee State ID |
|
149 | - * |
|
150 | - * @access public |
|
151 | - * @param int $STA_ID |
|
152 | - * @throws EE_Error |
|
153 | - */ |
|
154 | - public function set_state($STA_ID = 0) |
|
155 | - { |
|
156 | - $this->set('STA_ID', $STA_ID); |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - /** |
|
161 | - * Set Attendee Country ISO Code |
|
162 | - * |
|
163 | - * @access public |
|
164 | - * @param string $CNT_ISO |
|
165 | - * @throws EE_Error |
|
166 | - */ |
|
167 | - public function set_country($CNT_ISO = '') |
|
168 | - { |
|
169 | - $this->set('CNT_ISO', $CNT_ISO); |
|
170 | - } |
|
171 | - |
|
172 | - |
|
173 | - /** |
|
174 | - * Set Attendee Zip/Postal Code |
|
175 | - * |
|
176 | - * @access public |
|
177 | - * @param string $zip |
|
178 | - * @throws EE_Error |
|
179 | - */ |
|
180 | - public function set_zip($zip = '') |
|
181 | - { |
|
182 | - $this->set('ATT_zip', $zip); |
|
183 | - } |
|
184 | - |
|
185 | - |
|
186 | - /** |
|
187 | - * Set Attendee Email Address |
|
188 | - * |
|
189 | - * @access public |
|
190 | - * @param string $email |
|
191 | - * @throws EE_Error |
|
192 | - */ |
|
193 | - public function set_email($email = '') |
|
194 | - { |
|
195 | - $this->set('ATT_email', $email); |
|
196 | - } |
|
197 | - |
|
198 | - |
|
199 | - /** |
|
200 | - * Set Attendee Phone |
|
201 | - * |
|
202 | - * @access public |
|
203 | - * @param string $phone |
|
204 | - * @throws EE_Error |
|
205 | - */ |
|
206 | - public function set_phone($phone = '') |
|
207 | - { |
|
208 | - $this->set('ATT_phone', $phone); |
|
209 | - } |
|
210 | - |
|
211 | - |
|
212 | - /** |
|
213 | - * set deleted |
|
214 | - * |
|
215 | - * @access public |
|
216 | - * @param bool $ATT_deleted |
|
217 | - * @throws EE_Error |
|
218 | - */ |
|
219 | - public function set_deleted($ATT_deleted = false) |
|
220 | - { |
|
221 | - $this->set('ATT_deleted', $ATT_deleted); |
|
222 | - } |
|
223 | - |
|
224 | - |
|
225 | - /** |
|
226 | - * Returns the value for the post_author id saved with the cpt |
|
227 | - * |
|
228 | - * @since 4.5.0 |
|
229 | - * @return int |
|
230 | - * @throws EE_Error |
|
231 | - */ |
|
232 | - public function wp_user() |
|
233 | - { |
|
234 | - return $this->get('ATT_author'); |
|
235 | - } |
|
236 | - |
|
237 | - |
|
238 | - /** |
|
239 | - * get Attendee First Name |
|
240 | - * |
|
241 | - * @access public |
|
242 | - * @return string |
|
243 | - * @throws EE_Error |
|
244 | - */ |
|
245 | - public function fname() |
|
246 | - { |
|
247 | - return $this->get('ATT_fname'); |
|
248 | - } |
|
249 | - |
|
250 | - |
|
251 | - /** |
|
252 | - * echoes out the attendee's first name |
|
253 | - * |
|
254 | - * @return void |
|
255 | - * @throws EE_Error |
|
256 | - */ |
|
257 | - public function e_full_name() |
|
258 | - { |
|
259 | - echo esc_html($this->full_name()); |
|
260 | - } |
|
261 | - |
|
262 | - |
|
263 | - /** |
|
264 | - * Returns the first and last name concatenated together with a space. |
|
265 | - * |
|
266 | - * @param bool $apply_html_entities |
|
267 | - * @return string |
|
268 | - * @throws EE_Error |
|
269 | - */ |
|
270 | - public function full_name($apply_html_entities = false) |
|
271 | - { |
|
272 | - $full_name = array( |
|
273 | - $this->fname(), |
|
274 | - $this->lname(), |
|
275 | - ); |
|
276 | - $full_name = array_filter($full_name); |
|
277 | - $full_name = implode(' ', $full_name); |
|
278 | - return $apply_html_entities ? htmlentities($full_name, ENT_QUOTES, 'UTF-8') : $full_name; |
|
279 | - } |
|
280 | - |
|
281 | - |
|
282 | - /** |
|
283 | - * This returns the value of the `ATT_full_name` field which is usually equivalent to calling `full_name()` unless |
|
284 | - * the post_title field has been directly modified in the db for the post (espresso_attendees post type) for this |
|
285 | - * attendee. |
|
286 | - * |
|
287 | - * @param bool $apply_html_entities |
|
288 | - * @return string |
|
289 | - * @throws EE_Error |
|
290 | - */ |
|
291 | - public function ATT_full_name($apply_html_entities = false) |
|
292 | - { |
|
293 | - return $apply_html_entities |
|
294 | - ? htmlentities($this->get('ATT_full_name'), ENT_QUOTES, 'UTF-8') |
|
295 | - : $this->get('ATT_full_name'); |
|
296 | - } |
|
297 | - |
|
298 | - |
|
299 | - /** |
|
300 | - * get Attendee Last Name |
|
301 | - * |
|
302 | - * @access public |
|
303 | - * @return string |
|
304 | - * @throws EE_Error |
|
305 | - */ |
|
306 | - public function lname() |
|
307 | - { |
|
308 | - return $this->get('ATT_lname'); |
|
309 | - } |
|
310 | - |
|
311 | - |
|
312 | - /** |
|
313 | - * get Attendee bio |
|
314 | - * |
|
315 | - * @access public |
|
316 | - * @return string |
|
317 | - * @throws EE_Error |
|
318 | - */ |
|
319 | - public function bio() |
|
320 | - { |
|
321 | - return $this->get('ATT_bio'); |
|
322 | - } |
|
323 | - |
|
324 | - |
|
325 | - /** |
|
326 | - * get Attendee short bio |
|
327 | - * |
|
328 | - * @access public |
|
329 | - * @return string |
|
330 | - * @throws EE_Error |
|
331 | - */ |
|
332 | - public function short_bio() |
|
333 | - { |
|
334 | - return $this->get('ATT_short_bio'); |
|
335 | - } |
|
336 | - |
|
337 | - |
|
338 | - /** |
|
339 | - * Gets the attendee's full address as an array so client code can decide hwo to display it |
|
340 | - * |
|
341 | - * @return array numerically indexed, with each part of the address that is known. |
|
342 | - * Eg, if the user only responded to state and country, |
|
343 | - * it would be array(0=>'Alabama',1=>'USA') |
|
344 | - * @return array |
|
345 | - * @throws EE_Error |
|
346 | - */ |
|
347 | - public function full_address_as_array() |
|
348 | - { |
|
349 | - $full_address_array = array(); |
|
350 | - $initial_address_fields = array('ATT_address', 'ATT_address2', 'ATT_city',); |
|
351 | - foreach ($initial_address_fields as $address_field_name) { |
|
352 | - $address_fields_value = $this->get($address_field_name); |
|
353 | - if (! empty($address_fields_value)) { |
|
354 | - $full_address_array[] = $address_fields_value; |
|
355 | - } |
|
356 | - } |
|
357 | - // now handle state and country |
|
358 | - $state_obj = $this->state_obj(); |
|
359 | - if ($state_obj instanceof EE_State) { |
|
360 | - $full_address_array[] = $state_obj->name(); |
|
361 | - } |
|
362 | - $country_obj = $this->country_obj(); |
|
363 | - if ($country_obj instanceof EE_Country) { |
|
364 | - $full_address_array[] = $country_obj->name(); |
|
365 | - } |
|
366 | - // lastly get the xip |
|
367 | - $zip_value = $this->zip(); |
|
368 | - if (! empty($zip_value)) { |
|
369 | - $full_address_array[] = $zip_value; |
|
370 | - } |
|
371 | - return $full_address_array; |
|
372 | - } |
|
373 | - |
|
374 | - |
|
375 | - /** |
|
376 | - * get Attendee Address |
|
377 | - * |
|
378 | - * @return string |
|
379 | - * @throws EE_Error |
|
380 | - */ |
|
381 | - public function address() |
|
382 | - { |
|
383 | - return $this->get('ATT_address'); |
|
384 | - } |
|
385 | - |
|
386 | - |
|
387 | - /** |
|
388 | - * get Attendee Address2 |
|
389 | - * |
|
390 | - * @return string |
|
391 | - * @throws EE_Error |
|
392 | - */ |
|
393 | - public function address2() |
|
394 | - { |
|
395 | - return $this->get('ATT_address2'); |
|
396 | - } |
|
397 | - |
|
398 | - |
|
399 | - /** |
|
400 | - * get Attendee City |
|
401 | - * |
|
402 | - * @return string |
|
403 | - * @throws EE_Error |
|
404 | - */ |
|
405 | - public function city() |
|
406 | - { |
|
407 | - return $this->get('ATT_city'); |
|
408 | - } |
|
409 | - |
|
410 | - |
|
411 | - /** |
|
412 | - * get Attendee State ID |
|
413 | - * |
|
414 | - * @return string |
|
415 | - * @throws EE_Error |
|
416 | - */ |
|
417 | - public function state_ID() |
|
418 | - { |
|
419 | - return $this->get('STA_ID'); |
|
420 | - } |
|
421 | - |
|
422 | - |
|
423 | - /** |
|
424 | - * @return string |
|
425 | - * @throws EE_Error |
|
426 | - */ |
|
427 | - public function state_abbrev() |
|
428 | - { |
|
429 | - return $this->state_obj() instanceof EE_State ? $this->state_obj()->abbrev() : ''; |
|
430 | - } |
|
431 | - |
|
432 | - |
|
433 | - /** |
|
434 | - * Gets the state set to this attendee |
|
435 | - * |
|
436 | - * @return EE_State |
|
437 | - * @throws EE_Error |
|
438 | - */ |
|
439 | - public function state_obj() |
|
440 | - { |
|
441 | - return $this->get_first_related('State'); |
|
442 | - } |
|
443 | - |
|
444 | - |
|
445 | - /** |
|
446 | - * Returns the state's name, otherwise 'Unknown' |
|
447 | - * |
|
448 | - * @return string |
|
449 | - * @throws EE_Error |
|
450 | - */ |
|
451 | - public function state_name() |
|
452 | - { |
|
453 | - if ($this->state_obj()) { |
|
454 | - return $this->state_obj()->name(); |
|
455 | - } else { |
|
456 | - return ''; |
|
457 | - } |
|
458 | - } |
|
459 | - |
|
460 | - |
|
461 | - /** |
|
462 | - * either displays the state abbreviation or the state name, as determined |
|
463 | - * by the "FHEE__EEI_Address__state__use_abbreviation" filter. |
|
464 | - * defaults to abbreviation |
|
465 | - * |
|
466 | - * @return string |
|
467 | - * @throws EE_Error |
|
468 | - */ |
|
469 | - public function state() |
|
470 | - { |
|
471 | - if (apply_filters('FHEE__EEI_Address__state__use_abbreviation', true, $this->state_obj())) { |
|
472 | - return $this->state_abbrev(); |
|
473 | - } |
|
474 | - return $this->state_name(); |
|
475 | - } |
|
476 | - |
|
477 | - |
|
478 | - /** |
|
479 | - * get Attendee Country ISO Code |
|
480 | - * |
|
481 | - * @return string |
|
482 | - * @throws EE_Error |
|
483 | - */ |
|
484 | - public function country_ID() |
|
485 | - { |
|
486 | - return $this->get('CNT_ISO'); |
|
487 | - } |
|
488 | - |
|
489 | - |
|
490 | - /** |
|
491 | - * Gets country set for this attendee |
|
492 | - * |
|
493 | - * @return EE_Country |
|
494 | - * @throws EE_Error |
|
495 | - */ |
|
496 | - public function country_obj() |
|
497 | - { |
|
498 | - return $this->get_first_related('Country'); |
|
499 | - } |
|
500 | - |
|
501 | - |
|
502 | - /** |
|
503 | - * Returns the country's name if known, otherwise 'Unknown' |
|
504 | - * |
|
505 | - * @return string |
|
506 | - * @throws EE_Error |
|
507 | - */ |
|
508 | - public function country_name() |
|
509 | - { |
|
510 | - if ($this->country_obj()) { |
|
511 | - return $this->country_obj()->name(); |
|
512 | - } |
|
513 | - return ''; |
|
514 | - } |
|
515 | - |
|
516 | - |
|
517 | - /** |
|
518 | - * either displays the country ISO2 code or the country name, as determined |
|
519 | - * by the "FHEE__EEI_Address__country__use_abbreviation" filter. |
|
520 | - * defaults to abbreviation |
|
521 | - * |
|
522 | - * @return string |
|
523 | - * @throws EE_Error |
|
524 | - */ |
|
525 | - public function country() |
|
526 | - { |
|
527 | - if (apply_filters('FHEE__EEI_Address__country__use_abbreviation', true, $this->country_obj())) { |
|
528 | - return $this->country_ID(); |
|
529 | - } |
|
530 | - return $this->country_name(); |
|
531 | - } |
|
532 | - |
|
533 | - |
|
534 | - /** |
|
535 | - * get Attendee Zip/Postal Code |
|
536 | - * |
|
537 | - * @return string |
|
538 | - * @throws EE_Error |
|
539 | - */ |
|
540 | - public function zip() |
|
541 | - { |
|
542 | - return $this->get('ATT_zip'); |
|
543 | - } |
|
544 | - |
|
545 | - |
|
546 | - /** |
|
547 | - * get Attendee Email Address |
|
548 | - * |
|
549 | - * @return string |
|
550 | - * @throws EE_Error |
|
551 | - */ |
|
552 | - public function email() |
|
553 | - { |
|
554 | - return $this->get('ATT_email'); |
|
555 | - } |
|
556 | - |
|
557 | - |
|
558 | - /** |
|
559 | - * get Attendee Phone # |
|
560 | - * |
|
561 | - * @return string |
|
562 | - * @throws EE_Error |
|
563 | - */ |
|
564 | - public function phone() |
|
565 | - { |
|
566 | - return $this->get('ATT_phone'); |
|
567 | - } |
|
568 | - |
|
569 | - |
|
570 | - /** |
|
571 | - * get deleted |
|
572 | - * |
|
573 | - * @return bool |
|
574 | - * @throws EE_Error |
|
575 | - */ |
|
576 | - public function deleted() |
|
577 | - { |
|
578 | - return $this->get('ATT_deleted'); |
|
579 | - } |
|
580 | - |
|
581 | - |
|
582 | - /** |
|
583 | - * Gets registrations of this attendee |
|
584 | - * |
|
585 | - * @param array $query_params |
|
586 | - * @return EE_Registration[] |
|
587 | - * @throws EE_Error |
|
588 | - */ |
|
589 | - public function get_registrations($query_params = array()) |
|
590 | - { |
|
591 | - return $this->get_many_related('Registration', $query_params); |
|
592 | - } |
|
593 | - |
|
594 | - |
|
595 | - /** |
|
596 | - * Gets the most recent registration of this attendee |
|
597 | - * |
|
598 | - * @return EE_Registration |
|
599 | - * @throws EE_Error |
|
600 | - */ |
|
601 | - public function get_most_recent_registration() |
|
602 | - { |
|
603 | - return $this->get_first_related( |
|
604 | - 'Registration', |
|
605 | - array('order_by' => array('REG_date' => 'DESC')) |
|
606 | - ); // null, 'REG_date', 'DESC', '=', 'OBJECT_K'); |
|
607 | - } |
|
608 | - |
|
609 | - |
|
610 | - /** |
|
611 | - * Gets the most recent registration for this attend at this event |
|
612 | - * |
|
613 | - * @param int $event_id |
|
614 | - * @return EE_Registration |
|
615 | - * @throws EE_Error |
|
616 | - */ |
|
617 | - public function get_most_recent_registration_for_event($event_id) |
|
618 | - { |
|
619 | - return $this->get_first_related( |
|
620 | - 'Registration', |
|
621 | - array(array('EVT_ID' => $event_id), 'order_by' => array('REG_date' => 'DESC')) |
|
622 | - ); |
|
623 | - } |
|
624 | - |
|
625 | - |
|
626 | - /** |
|
627 | - * returns any events attached to this attendee ($_Event property); |
|
628 | - * |
|
629 | - * @return array |
|
630 | - * @throws EE_Error |
|
631 | - */ |
|
632 | - public function events() |
|
633 | - { |
|
634 | - return $this->get_many_related('Event'); |
|
635 | - } |
|
636 | - |
|
637 | - |
|
638 | - /** |
|
639 | - * Gets the billing info array where keys match espresso_reg_page_billing_inputs(), |
|
640 | - * and keys are their cleaned values. @see EE_Attendee::save_and_clean_billing_info_for_payment_method() which was |
|
641 | - * used to save the billing info |
|
642 | - * |
|
643 | - * @param EE_Payment_Method $payment_method the _gateway_name property on the gateway class |
|
644 | - * @return EE_Form_Section_Proper|null |
|
645 | - * @throws EE_Error |
|
646 | - */ |
|
647 | - public function billing_info_for_payment_method($payment_method) |
|
648 | - { |
|
649 | - $pm_type = $payment_method->type_obj(); |
|
650 | - if (! $pm_type instanceof EE_PMT_Base) { |
|
651 | - return null; |
|
652 | - } |
|
653 | - $billing_info = $this->get_post_meta($this->get_billing_info_postmeta_name($payment_method), true); |
|
654 | - if (! $billing_info) { |
|
655 | - return null; |
|
656 | - } |
|
657 | - $billing_form = $pm_type->billing_form(); |
|
658 | - // double-check the form isn't totally hidden, in which case pretend there is no form |
|
659 | - $form_totally_hidden = true; |
|
660 | - foreach ($billing_form->inputs_in_subsections() as $input) { |
|
661 | - if (! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) { |
|
662 | - $form_totally_hidden = false; |
|
663 | - break; |
|
664 | - } |
|
665 | - } |
|
666 | - if ($form_totally_hidden) { |
|
667 | - return null; |
|
668 | - } |
|
669 | - if ($billing_form instanceof EE_Form_Section_Proper) { |
|
670 | - $billing_form->receive_form_submission(array($billing_form->name() => $billing_info), false); |
|
671 | - } |
|
672 | - |
|
673 | - return $billing_form; |
|
674 | - } |
|
675 | - |
|
676 | - |
|
677 | - /** |
|
678 | - * Gets the postmeta key that holds this attendee's billing info for the |
|
679 | - * specified payment method |
|
680 | - * |
|
681 | - * @param EE_Payment_Method $payment_method |
|
682 | - * @return string |
|
683 | - * @throws EE_Error |
|
684 | - */ |
|
685 | - public function get_billing_info_postmeta_name($payment_method) |
|
686 | - { |
|
687 | - if ($payment_method->type_obj() instanceof EE_PMT_Base) { |
|
688 | - return 'billing_info_' . $payment_method->type_obj()->system_name(); |
|
689 | - } |
|
690 | - return null; |
|
691 | - } |
|
692 | - |
|
693 | - |
|
694 | - /** |
|
695 | - * Saves the billing info to the attendee. @see EE_Attendee::billing_info_for_payment_method() which is used to |
|
696 | - * retrieve it |
|
697 | - * |
|
698 | - * @param EE_Billing_Attendee_Info_Form $billing_form |
|
699 | - * @param EE_Payment_Method $payment_method |
|
700 | - * @return boolean |
|
701 | - * @throws EE_Error |
|
702 | - */ |
|
703 | - public function save_and_clean_billing_info_for_payment_method($billing_form, $payment_method) |
|
704 | - { |
|
705 | - if (! $billing_form instanceof EE_Billing_Attendee_Info_Form) { |
|
706 | - EE_Error::add_error(esc_html__('Cannot save billing info because there is none.', 'event_espresso')); |
|
707 | - return false; |
|
708 | - } |
|
709 | - $billing_form->clean_sensitive_data(); |
|
710 | - return update_post_meta( |
|
711 | - $this->ID(), |
|
712 | - $this->get_billing_info_postmeta_name($payment_method), |
|
713 | - $billing_form->input_values(true) |
|
714 | - ); |
|
715 | - } |
|
716 | - |
|
717 | - |
|
718 | - /** |
|
719 | - * Return the link to the admin details for the object. |
|
720 | - * |
|
721 | - * @return string |
|
722 | - * @throws EE_Error |
|
723 | - * @throws InvalidArgumentException |
|
724 | - * @throws InvalidDataTypeException |
|
725 | - * @throws InvalidInterfaceException |
|
726 | - * @throws ReflectionException |
|
727 | - */ |
|
728 | - public function get_admin_details_link() |
|
729 | - { |
|
730 | - return $this->get_admin_edit_link(); |
|
731 | - } |
|
732 | - |
|
733 | - |
|
734 | - /** |
|
735 | - * Returns the link to the editor for the object. Sometimes this is the same as the details. |
|
736 | - * |
|
737 | - * @return string |
|
738 | - * @throws EE_Error |
|
739 | - * @throws InvalidArgumentException |
|
740 | - * @throws ReflectionException |
|
741 | - * @throws InvalidDataTypeException |
|
742 | - * @throws InvalidInterfaceException |
|
743 | - */ |
|
744 | - public function get_admin_edit_link() |
|
745 | - { |
|
746 | - EE_Registry::instance()->load_helper('URL'); |
|
747 | - return EEH_URL::add_query_args_and_nonce( |
|
748 | - array( |
|
749 | - 'page' => 'espresso_registrations', |
|
750 | - 'action' => 'edit_attendee', |
|
751 | - 'post' => $this->ID(), |
|
752 | - ), |
|
753 | - admin_url('admin.php') |
|
754 | - ); |
|
755 | - } |
|
756 | - |
|
757 | - |
|
758 | - /** |
|
759 | - * Returns the link to a settings page for the object. |
|
760 | - * |
|
761 | - * @return string |
|
762 | - * @throws EE_Error |
|
763 | - * @throws InvalidArgumentException |
|
764 | - * @throws InvalidDataTypeException |
|
765 | - * @throws InvalidInterfaceException |
|
766 | - * @throws ReflectionException |
|
767 | - */ |
|
768 | - public function get_admin_settings_link() |
|
769 | - { |
|
770 | - return $this->get_admin_edit_link(); |
|
771 | - } |
|
772 | - |
|
773 | - |
|
774 | - /** |
|
775 | - * Returns the link to the "overview" for the object (typically the "list table" view). |
|
776 | - * |
|
777 | - * @return string |
|
778 | - * @throws EE_Error |
|
779 | - * @throws InvalidArgumentException |
|
780 | - * @throws ReflectionException |
|
781 | - * @throws InvalidDataTypeException |
|
782 | - * @throws InvalidInterfaceException |
|
783 | - */ |
|
784 | - public function get_admin_overview_link() |
|
785 | - { |
|
786 | - EE_Registry::instance()->load_helper('URL'); |
|
787 | - return EEH_URL::add_query_args_and_nonce( |
|
788 | - array( |
|
789 | - 'page' => 'espresso_registrations', |
|
790 | - 'action' => 'contact_list', |
|
791 | - ), |
|
792 | - admin_url('admin.php') |
|
793 | - ); |
|
794 | - } |
|
27 | + /** |
|
28 | + * Sets some dynamic defaults |
|
29 | + * |
|
30 | + * @param array $fieldValues |
|
31 | + * @param bool $bydb |
|
32 | + * @param string $timezone |
|
33 | + * @param array $date_formats |
|
34 | + * @throws EE_Error |
|
35 | + */ |
|
36 | + protected function __construct($fieldValues = null, $bydb = false, $timezone = null, $date_formats = array()) |
|
37 | + { |
|
38 | + if (! isset($fieldValues['ATT_full_name'])) { |
|
39 | + $fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'] . ' ' : ''; |
|
40 | + $lname = isset($fieldValues['ATT_lname']) ? $fieldValues['ATT_lname'] : ''; |
|
41 | + $fieldValues['ATT_full_name'] = $fname . $lname; |
|
42 | + } |
|
43 | + if (! isset($fieldValues['ATT_slug'])) { |
|
44 | + // $fieldValues['ATT_slug'] = sanitize_key(wp_generate_password(20)); |
|
45 | + $fieldValues['ATT_slug'] = sanitize_title($fieldValues['ATT_full_name']); |
|
46 | + } |
|
47 | + if (! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) { |
|
48 | + $fieldValues['ATT_short_bio'] = substr($fieldValues['ATT_bio'], 0, 50); |
|
49 | + } |
|
50 | + parent::__construct($fieldValues, $bydb, $timezone, $date_formats); |
|
51 | + } |
|
52 | + |
|
53 | + |
|
54 | + /** |
|
55 | + * @param array $props_n_values incoming values |
|
56 | + * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
57 | + * used.) |
|
58 | + * @param array $date_formats incoming date_formats in an array where the first value is the |
|
59 | + * date_format and the second value is the time format |
|
60 | + * @return EE_Attendee |
|
61 | + * @throws EE_Error |
|
62 | + */ |
|
63 | + public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
64 | + { |
|
65 | + $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
66 | + return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats); |
|
67 | + } |
|
68 | + |
|
69 | + |
|
70 | + /** |
|
71 | + * @param array $props_n_values incoming values from the database |
|
72 | + * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
73 | + * the website will be used. |
|
74 | + * @return EE_Attendee |
|
75 | + */ |
|
76 | + public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
77 | + { |
|
78 | + return new self($props_n_values, true, $timezone); |
|
79 | + } |
|
80 | + |
|
81 | + |
|
82 | + /** |
|
83 | + * Set Attendee First Name |
|
84 | + * |
|
85 | + * @access public |
|
86 | + * @param string $fname |
|
87 | + * @throws EE_Error |
|
88 | + */ |
|
89 | + public function set_fname($fname = '') |
|
90 | + { |
|
91 | + $this->set('ATT_fname', $fname); |
|
92 | + } |
|
93 | + |
|
94 | + |
|
95 | + /** |
|
96 | + * Set Attendee Last Name |
|
97 | + * |
|
98 | + * @access public |
|
99 | + * @param string $lname |
|
100 | + * @throws EE_Error |
|
101 | + */ |
|
102 | + public function set_lname($lname = '') |
|
103 | + { |
|
104 | + $this->set('ATT_lname', $lname); |
|
105 | + } |
|
106 | + |
|
107 | + |
|
108 | + /** |
|
109 | + * Set Attendee Address |
|
110 | + * |
|
111 | + * @access public |
|
112 | + * @param string $address |
|
113 | + * @throws EE_Error |
|
114 | + */ |
|
115 | + public function set_address($address = '') |
|
116 | + { |
|
117 | + $this->set('ATT_address', $address); |
|
118 | + } |
|
119 | + |
|
120 | + |
|
121 | + /** |
|
122 | + * Set Attendee Address2 |
|
123 | + * |
|
124 | + * @access public |
|
125 | + * @param string $address2 |
|
126 | + * @throws EE_Error |
|
127 | + */ |
|
128 | + public function set_address2($address2 = '') |
|
129 | + { |
|
130 | + $this->set('ATT_address2', $address2); |
|
131 | + } |
|
132 | + |
|
133 | + |
|
134 | + /** |
|
135 | + * Set Attendee City |
|
136 | + * |
|
137 | + * @access public |
|
138 | + * @param string $city |
|
139 | + * @throws EE_Error |
|
140 | + */ |
|
141 | + public function set_city($city = '') |
|
142 | + { |
|
143 | + $this->set('ATT_city', $city); |
|
144 | + } |
|
145 | + |
|
146 | + |
|
147 | + /** |
|
148 | + * Set Attendee State ID |
|
149 | + * |
|
150 | + * @access public |
|
151 | + * @param int $STA_ID |
|
152 | + * @throws EE_Error |
|
153 | + */ |
|
154 | + public function set_state($STA_ID = 0) |
|
155 | + { |
|
156 | + $this->set('STA_ID', $STA_ID); |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + /** |
|
161 | + * Set Attendee Country ISO Code |
|
162 | + * |
|
163 | + * @access public |
|
164 | + * @param string $CNT_ISO |
|
165 | + * @throws EE_Error |
|
166 | + */ |
|
167 | + public function set_country($CNT_ISO = '') |
|
168 | + { |
|
169 | + $this->set('CNT_ISO', $CNT_ISO); |
|
170 | + } |
|
171 | + |
|
172 | + |
|
173 | + /** |
|
174 | + * Set Attendee Zip/Postal Code |
|
175 | + * |
|
176 | + * @access public |
|
177 | + * @param string $zip |
|
178 | + * @throws EE_Error |
|
179 | + */ |
|
180 | + public function set_zip($zip = '') |
|
181 | + { |
|
182 | + $this->set('ATT_zip', $zip); |
|
183 | + } |
|
184 | + |
|
185 | + |
|
186 | + /** |
|
187 | + * Set Attendee Email Address |
|
188 | + * |
|
189 | + * @access public |
|
190 | + * @param string $email |
|
191 | + * @throws EE_Error |
|
192 | + */ |
|
193 | + public function set_email($email = '') |
|
194 | + { |
|
195 | + $this->set('ATT_email', $email); |
|
196 | + } |
|
197 | + |
|
198 | + |
|
199 | + /** |
|
200 | + * Set Attendee Phone |
|
201 | + * |
|
202 | + * @access public |
|
203 | + * @param string $phone |
|
204 | + * @throws EE_Error |
|
205 | + */ |
|
206 | + public function set_phone($phone = '') |
|
207 | + { |
|
208 | + $this->set('ATT_phone', $phone); |
|
209 | + } |
|
210 | + |
|
211 | + |
|
212 | + /** |
|
213 | + * set deleted |
|
214 | + * |
|
215 | + * @access public |
|
216 | + * @param bool $ATT_deleted |
|
217 | + * @throws EE_Error |
|
218 | + */ |
|
219 | + public function set_deleted($ATT_deleted = false) |
|
220 | + { |
|
221 | + $this->set('ATT_deleted', $ATT_deleted); |
|
222 | + } |
|
223 | + |
|
224 | + |
|
225 | + /** |
|
226 | + * Returns the value for the post_author id saved with the cpt |
|
227 | + * |
|
228 | + * @since 4.5.0 |
|
229 | + * @return int |
|
230 | + * @throws EE_Error |
|
231 | + */ |
|
232 | + public function wp_user() |
|
233 | + { |
|
234 | + return $this->get('ATT_author'); |
|
235 | + } |
|
236 | + |
|
237 | + |
|
238 | + /** |
|
239 | + * get Attendee First Name |
|
240 | + * |
|
241 | + * @access public |
|
242 | + * @return string |
|
243 | + * @throws EE_Error |
|
244 | + */ |
|
245 | + public function fname() |
|
246 | + { |
|
247 | + return $this->get('ATT_fname'); |
|
248 | + } |
|
249 | + |
|
250 | + |
|
251 | + /** |
|
252 | + * echoes out the attendee's first name |
|
253 | + * |
|
254 | + * @return void |
|
255 | + * @throws EE_Error |
|
256 | + */ |
|
257 | + public function e_full_name() |
|
258 | + { |
|
259 | + echo esc_html($this->full_name()); |
|
260 | + } |
|
261 | + |
|
262 | + |
|
263 | + /** |
|
264 | + * Returns the first and last name concatenated together with a space. |
|
265 | + * |
|
266 | + * @param bool $apply_html_entities |
|
267 | + * @return string |
|
268 | + * @throws EE_Error |
|
269 | + */ |
|
270 | + public function full_name($apply_html_entities = false) |
|
271 | + { |
|
272 | + $full_name = array( |
|
273 | + $this->fname(), |
|
274 | + $this->lname(), |
|
275 | + ); |
|
276 | + $full_name = array_filter($full_name); |
|
277 | + $full_name = implode(' ', $full_name); |
|
278 | + return $apply_html_entities ? htmlentities($full_name, ENT_QUOTES, 'UTF-8') : $full_name; |
|
279 | + } |
|
280 | + |
|
281 | + |
|
282 | + /** |
|
283 | + * This returns the value of the `ATT_full_name` field which is usually equivalent to calling `full_name()` unless |
|
284 | + * the post_title field has been directly modified in the db for the post (espresso_attendees post type) for this |
|
285 | + * attendee. |
|
286 | + * |
|
287 | + * @param bool $apply_html_entities |
|
288 | + * @return string |
|
289 | + * @throws EE_Error |
|
290 | + */ |
|
291 | + public function ATT_full_name($apply_html_entities = false) |
|
292 | + { |
|
293 | + return $apply_html_entities |
|
294 | + ? htmlentities($this->get('ATT_full_name'), ENT_QUOTES, 'UTF-8') |
|
295 | + : $this->get('ATT_full_name'); |
|
296 | + } |
|
297 | + |
|
298 | + |
|
299 | + /** |
|
300 | + * get Attendee Last Name |
|
301 | + * |
|
302 | + * @access public |
|
303 | + * @return string |
|
304 | + * @throws EE_Error |
|
305 | + */ |
|
306 | + public function lname() |
|
307 | + { |
|
308 | + return $this->get('ATT_lname'); |
|
309 | + } |
|
310 | + |
|
311 | + |
|
312 | + /** |
|
313 | + * get Attendee bio |
|
314 | + * |
|
315 | + * @access public |
|
316 | + * @return string |
|
317 | + * @throws EE_Error |
|
318 | + */ |
|
319 | + public function bio() |
|
320 | + { |
|
321 | + return $this->get('ATT_bio'); |
|
322 | + } |
|
323 | + |
|
324 | + |
|
325 | + /** |
|
326 | + * get Attendee short bio |
|
327 | + * |
|
328 | + * @access public |
|
329 | + * @return string |
|
330 | + * @throws EE_Error |
|
331 | + */ |
|
332 | + public function short_bio() |
|
333 | + { |
|
334 | + return $this->get('ATT_short_bio'); |
|
335 | + } |
|
336 | + |
|
337 | + |
|
338 | + /** |
|
339 | + * Gets the attendee's full address as an array so client code can decide hwo to display it |
|
340 | + * |
|
341 | + * @return array numerically indexed, with each part of the address that is known. |
|
342 | + * Eg, if the user only responded to state and country, |
|
343 | + * it would be array(0=>'Alabama',1=>'USA') |
|
344 | + * @return array |
|
345 | + * @throws EE_Error |
|
346 | + */ |
|
347 | + public function full_address_as_array() |
|
348 | + { |
|
349 | + $full_address_array = array(); |
|
350 | + $initial_address_fields = array('ATT_address', 'ATT_address2', 'ATT_city',); |
|
351 | + foreach ($initial_address_fields as $address_field_name) { |
|
352 | + $address_fields_value = $this->get($address_field_name); |
|
353 | + if (! empty($address_fields_value)) { |
|
354 | + $full_address_array[] = $address_fields_value; |
|
355 | + } |
|
356 | + } |
|
357 | + // now handle state and country |
|
358 | + $state_obj = $this->state_obj(); |
|
359 | + if ($state_obj instanceof EE_State) { |
|
360 | + $full_address_array[] = $state_obj->name(); |
|
361 | + } |
|
362 | + $country_obj = $this->country_obj(); |
|
363 | + if ($country_obj instanceof EE_Country) { |
|
364 | + $full_address_array[] = $country_obj->name(); |
|
365 | + } |
|
366 | + // lastly get the xip |
|
367 | + $zip_value = $this->zip(); |
|
368 | + if (! empty($zip_value)) { |
|
369 | + $full_address_array[] = $zip_value; |
|
370 | + } |
|
371 | + return $full_address_array; |
|
372 | + } |
|
373 | + |
|
374 | + |
|
375 | + /** |
|
376 | + * get Attendee Address |
|
377 | + * |
|
378 | + * @return string |
|
379 | + * @throws EE_Error |
|
380 | + */ |
|
381 | + public function address() |
|
382 | + { |
|
383 | + return $this->get('ATT_address'); |
|
384 | + } |
|
385 | + |
|
386 | + |
|
387 | + /** |
|
388 | + * get Attendee Address2 |
|
389 | + * |
|
390 | + * @return string |
|
391 | + * @throws EE_Error |
|
392 | + */ |
|
393 | + public function address2() |
|
394 | + { |
|
395 | + return $this->get('ATT_address2'); |
|
396 | + } |
|
397 | + |
|
398 | + |
|
399 | + /** |
|
400 | + * get Attendee City |
|
401 | + * |
|
402 | + * @return string |
|
403 | + * @throws EE_Error |
|
404 | + */ |
|
405 | + public function city() |
|
406 | + { |
|
407 | + return $this->get('ATT_city'); |
|
408 | + } |
|
409 | + |
|
410 | + |
|
411 | + /** |
|
412 | + * get Attendee State ID |
|
413 | + * |
|
414 | + * @return string |
|
415 | + * @throws EE_Error |
|
416 | + */ |
|
417 | + public function state_ID() |
|
418 | + { |
|
419 | + return $this->get('STA_ID'); |
|
420 | + } |
|
421 | + |
|
422 | + |
|
423 | + /** |
|
424 | + * @return string |
|
425 | + * @throws EE_Error |
|
426 | + */ |
|
427 | + public function state_abbrev() |
|
428 | + { |
|
429 | + return $this->state_obj() instanceof EE_State ? $this->state_obj()->abbrev() : ''; |
|
430 | + } |
|
431 | + |
|
432 | + |
|
433 | + /** |
|
434 | + * Gets the state set to this attendee |
|
435 | + * |
|
436 | + * @return EE_State |
|
437 | + * @throws EE_Error |
|
438 | + */ |
|
439 | + public function state_obj() |
|
440 | + { |
|
441 | + return $this->get_first_related('State'); |
|
442 | + } |
|
443 | + |
|
444 | + |
|
445 | + /** |
|
446 | + * Returns the state's name, otherwise 'Unknown' |
|
447 | + * |
|
448 | + * @return string |
|
449 | + * @throws EE_Error |
|
450 | + */ |
|
451 | + public function state_name() |
|
452 | + { |
|
453 | + if ($this->state_obj()) { |
|
454 | + return $this->state_obj()->name(); |
|
455 | + } else { |
|
456 | + return ''; |
|
457 | + } |
|
458 | + } |
|
459 | + |
|
460 | + |
|
461 | + /** |
|
462 | + * either displays the state abbreviation or the state name, as determined |
|
463 | + * by the "FHEE__EEI_Address__state__use_abbreviation" filter. |
|
464 | + * defaults to abbreviation |
|
465 | + * |
|
466 | + * @return string |
|
467 | + * @throws EE_Error |
|
468 | + */ |
|
469 | + public function state() |
|
470 | + { |
|
471 | + if (apply_filters('FHEE__EEI_Address__state__use_abbreviation', true, $this->state_obj())) { |
|
472 | + return $this->state_abbrev(); |
|
473 | + } |
|
474 | + return $this->state_name(); |
|
475 | + } |
|
476 | + |
|
477 | + |
|
478 | + /** |
|
479 | + * get Attendee Country ISO Code |
|
480 | + * |
|
481 | + * @return string |
|
482 | + * @throws EE_Error |
|
483 | + */ |
|
484 | + public function country_ID() |
|
485 | + { |
|
486 | + return $this->get('CNT_ISO'); |
|
487 | + } |
|
488 | + |
|
489 | + |
|
490 | + /** |
|
491 | + * Gets country set for this attendee |
|
492 | + * |
|
493 | + * @return EE_Country |
|
494 | + * @throws EE_Error |
|
495 | + */ |
|
496 | + public function country_obj() |
|
497 | + { |
|
498 | + return $this->get_first_related('Country'); |
|
499 | + } |
|
500 | + |
|
501 | + |
|
502 | + /** |
|
503 | + * Returns the country's name if known, otherwise 'Unknown' |
|
504 | + * |
|
505 | + * @return string |
|
506 | + * @throws EE_Error |
|
507 | + */ |
|
508 | + public function country_name() |
|
509 | + { |
|
510 | + if ($this->country_obj()) { |
|
511 | + return $this->country_obj()->name(); |
|
512 | + } |
|
513 | + return ''; |
|
514 | + } |
|
515 | + |
|
516 | + |
|
517 | + /** |
|
518 | + * either displays the country ISO2 code or the country name, as determined |
|
519 | + * by the "FHEE__EEI_Address__country__use_abbreviation" filter. |
|
520 | + * defaults to abbreviation |
|
521 | + * |
|
522 | + * @return string |
|
523 | + * @throws EE_Error |
|
524 | + */ |
|
525 | + public function country() |
|
526 | + { |
|
527 | + if (apply_filters('FHEE__EEI_Address__country__use_abbreviation', true, $this->country_obj())) { |
|
528 | + return $this->country_ID(); |
|
529 | + } |
|
530 | + return $this->country_name(); |
|
531 | + } |
|
532 | + |
|
533 | + |
|
534 | + /** |
|
535 | + * get Attendee Zip/Postal Code |
|
536 | + * |
|
537 | + * @return string |
|
538 | + * @throws EE_Error |
|
539 | + */ |
|
540 | + public function zip() |
|
541 | + { |
|
542 | + return $this->get('ATT_zip'); |
|
543 | + } |
|
544 | + |
|
545 | + |
|
546 | + /** |
|
547 | + * get Attendee Email Address |
|
548 | + * |
|
549 | + * @return string |
|
550 | + * @throws EE_Error |
|
551 | + */ |
|
552 | + public function email() |
|
553 | + { |
|
554 | + return $this->get('ATT_email'); |
|
555 | + } |
|
556 | + |
|
557 | + |
|
558 | + /** |
|
559 | + * get Attendee Phone # |
|
560 | + * |
|
561 | + * @return string |
|
562 | + * @throws EE_Error |
|
563 | + */ |
|
564 | + public function phone() |
|
565 | + { |
|
566 | + return $this->get('ATT_phone'); |
|
567 | + } |
|
568 | + |
|
569 | + |
|
570 | + /** |
|
571 | + * get deleted |
|
572 | + * |
|
573 | + * @return bool |
|
574 | + * @throws EE_Error |
|
575 | + */ |
|
576 | + public function deleted() |
|
577 | + { |
|
578 | + return $this->get('ATT_deleted'); |
|
579 | + } |
|
580 | + |
|
581 | + |
|
582 | + /** |
|
583 | + * Gets registrations of this attendee |
|
584 | + * |
|
585 | + * @param array $query_params |
|
586 | + * @return EE_Registration[] |
|
587 | + * @throws EE_Error |
|
588 | + */ |
|
589 | + public function get_registrations($query_params = array()) |
|
590 | + { |
|
591 | + return $this->get_many_related('Registration', $query_params); |
|
592 | + } |
|
593 | + |
|
594 | + |
|
595 | + /** |
|
596 | + * Gets the most recent registration of this attendee |
|
597 | + * |
|
598 | + * @return EE_Registration |
|
599 | + * @throws EE_Error |
|
600 | + */ |
|
601 | + public function get_most_recent_registration() |
|
602 | + { |
|
603 | + return $this->get_first_related( |
|
604 | + 'Registration', |
|
605 | + array('order_by' => array('REG_date' => 'DESC')) |
|
606 | + ); // null, 'REG_date', 'DESC', '=', 'OBJECT_K'); |
|
607 | + } |
|
608 | + |
|
609 | + |
|
610 | + /** |
|
611 | + * Gets the most recent registration for this attend at this event |
|
612 | + * |
|
613 | + * @param int $event_id |
|
614 | + * @return EE_Registration |
|
615 | + * @throws EE_Error |
|
616 | + */ |
|
617 | + public function get_most_recent_registration_for_event($event_id) |
|
618 | + { |
|
619 | + return $this->get_first_related( |
|
620 | + 'Registration', |
|
621 | + array(array('EVT_ID' => $event_id), 'order_by' => array('REG_date' => 'DESC')) |
|
622 | + ); |
|
623 | + } |
|
624 | + |
|
625 | + |
|
626 | + /** |
|
627 | + * returns any events attached to this attendee ($_Event property); |
|
628 | + * |
|
629 | + * @return array |
|
630 | + * @throws EE_Error |
|
631 | + */ |
|
632 | + public function events() |
|
633 | + { |
|
634 | + return $this->get_many_related('Event'); |
|
635 | + } |
|
636 | + |
|
637 | + |
|
638 | + /** |
|
639 | + * Gets the billing info array where keys match espresso_reg_page_billing_inputs(), |
|
640 | + * and keys are their cleaned values. @see EE_Attendee::save_and_clean_billing_info_for_payment_method() which was |
|
641 | + * used to save the billing info |
|
642 | + * |
|
643 | + * @param EE_Payment_Method $payment_method the _gateway_name property on the gateway class |
|
644 | + * @return EE_Form_Section_Proper|null |
|
645 | + * @throws EE_Error |
|
646 | + */ |
|
647 | + public function billing_info_for_payment_method($payment_method) |
|
648 | + { |
|
649 | + $pm_type = $payment_method->type_obj(); |
|
650 | + if (! $pm_type instanceof EE_PMT_Base) { |
|
651 | + return null; |
|
652 | + } |
|
653 | + $billing_info = $this->get_post_meta($this->get_billing_info_postmeta_name($payment_method), true); |
|
654 | + if (! $billing_info) { |
|
655 | + return null; |
|
656 | + } |
|
657 | + $billing_form = $pm_type->billing_form(); |
|
658 | + // double-check the form isn't totally hidden, in which case pretend there is no form |
|
659 | + $form_totally_hidden = true; |
|
660 | + foreach ($billing_form->inputs_in_subsections() as $input) { |
|
661 | + if (! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) { |
|
662 | + $form_totally_hidden = false; |
|
663 | + break; |
|
664 | + } |
|
665 | + } |
|
666 | + if ($form_totally_hidden) { |
|
667 | + return null; |
|
668 | + } |
|
669 | + if ($billing_form instanceof EE_Form_Section_Proper) { |
|
670 | + $billing_form->receive_form_submission(array($billing_form->name() => $billing_info), false); |
|
671 | + } |
|
672 | + |
|
673 | + return $billing_form; |
|
674 | + } |
|
675 | + |
|
676 | + |
|
677 | + /** |
|
678 | + * Gets the postmeta key that holds this attendee's billing info for the |
|
679 | + * specified payment method |
|
680 | + * |
|
681 | + * @param EE_Payment_Method $payment_method |
|
682 | + * @return string |
|
683 | + * @throws EE_Error |
|
684 | + */ |
|
685 | + public function get_billing_info_postmeta_name($payment_method) |
|
686 | + { |
|
687 | + if ($payment_method->type_obj() instanceof EE_PMT_Base) { |
|
688 | + return 'billing_info_' . $payment_method->type_obj()->system_name(); |
|
689 | + } |
|
690 | + return null; |
|
691 | + } |
|
692 | + |
|
693 | + |
|
694 | + /** |
|
695 | + * Saves the billing info to the attendee. @see EE_Attendee::billing_info_for_payment_method() which is used to |
|
696 | + * retrieve it |
|
697 | + * |
|
698 | + * @param EE_Billing_Attendee_Info_Form $billing_form |
|
699 | + * @param EE_Payment_Method $payment_method |
|
700 | + * @return boolean |
|
701 | + * @throws EE_Error |
|
702 | + */ |
|
703 | + public function save_and_clean_billing_info_for_payment_method($billing_form, $payment_method) |
|
704 | + { |
|
705 | + if (! $billing_form instanceof EE_Billing_Attendee_Info_Form) { |
|
706 | + EE_Error::add_error(esc_html__('Cannot save billing info because there is none.', 'event_espresso')); |
|
707 | + return false; |
|
708 | + } |
|
709 | + $billing_form->clean_sensitive_data(); |
|
710 | + return update_post_meta( |
|
711 | + $this->ID(), |
|
712 | + $this->get_billing_info_postmeta_name($payment_method), |
|
713 | + $billing_form->input_values(true) |
|
714 | + ); |
|
715 | + } |
|
716 | + |
|
717 | + |
|
718 | + /** |
|
719 | + * Return the link to the admin details for the object. |
|
720 | + * |
|
721 | + * @return string |
|
722 | + * @throws EE_Error |
|
723 | + * @throws InvalidArgumentException |
|
724 | + * @throws InvalidDataTypeException |
|
725 | + * @throws InvalidInterfaceException |
|
726 | + * @throws ReflectionException |
|
727 | + */ |
|
728 | + public function get_admin_details_link() |
|
729 | + { |
|
730 | + return $this->get_admin_edit_link(); |
|
731 | + } |
|
732 | + |
|
733 | + |
|
734 | + /** |
|
735 | + * Returns the link to the editor for the object. Sometimes this is the same as the details. |
|
736 | + * |
|
737 | + * @return string |
|
738 | + * @throws EE_Error |
|
739 | + * @throws InvalidArgumentException |
|
740 | + * @throws ReflectionException |
|
741 | + * @throws InvalidDataTypeException |
|
742 | + * @throws InvalidInterfaceException |
|
743 | + */ |
|
744 | + public function get_admin_edit_link() |
|
745 | + { |
|
746 | + EE_Registry::instance()->load_helper('URL'); |
|
747 | + return EEH_URL::add_query_args_and_nonce( |
|
748 | + array( |
|
749 | + 'page' => 'espresso_registrations', |
|
750 | + 'action' => 'edit_attendee', |
|
751 | + 'post' => $this->ID(), |
|
752 | + ), |
|
753 | + admin_url('admin.php') |
|
754 | + ); |
|
755 | + } |
|
756 | + |
|
757 | + |
|
758 | + /** |
|
759 | + * Returns the link to a settings page for the object. |
|
760 | + * |
|
761 | + * @return string |
|
762 | + * @throws EE_Error |
|
763 | + * @throws InvalidArgumentException |
|
764 | + * @throws InvalidDataTypeException |
|
765 | + * @throws InvalidInterfaceException |
|
766 | + * @throws ReflectionException |
|
767 | + */ |
|
768 | + public function get_admin_settings_link() |
|
769 | + { |
|
770 | + return $this->get_admin_edit_link(); |
|
771 | + } |
|
772 | + |
|
773 | + |
|
774 | + /** |
|
775 | + * Returns the link to the "overview" for the object (typically the "list table" view). |
|
776 | + * |
|
777 | + * @return string |
|
778 | + * @throws EE_Error |
|
779 | + * @throws InvalidArgumentException |
|
780 | + * @throws ReflectionException |
|
781 | + * @throws InvalidDataTypeException |
|
782 | + * @throws InvalidInterfaceException |
|
783 | + */ |
|
784 | + public function get_admin_overview_link() |
|
785 | + { |
|
786 | + EE_Registry::instance()->load_helper('URL'); |
|
787 | + return EEH_URL::add_query_args_and_nonce( |
|
788 | + array( |
|
789 | + 'page' => 'espresso_registrations', |
|
790 | + 'action' => 'contact_list', |
|
791 | + ), |
|
792 | + admin_url('admin.php') |
|
793 | + ); |
|
794 | + } |
|
795 | 795 | } |
@@ -33,7 +33,7 @@ discard block |
||
33 | 33 | public static function instance() |
34 | 34 | { |
35 | 35 | // check if class object is instantiated |
36 | - if (! self::$_instance instanceof EE_Payment_Processor) { |
|
36 | + if ( ! self::$_instance instanceof EE_Payment_Processor) { |
|
37 | 37 | self::$_instance = new self(); |
38 | 38 | } |
39 | 39 | return self::$_instance; |
@@ -170,7 +170,7 @@ discard block |
||
170 | 170 | /** @type \EE_Transaction $transaction */ |
171 | 171 | $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
172 | 172 | $primary_reg = $transaction->primary_registration(); |
173 | - if (! $primary_reg instanceof EE_Registration) { |
|
173 | + if ( ! $primary_reg instanceof EE_Registration) { |
|
174 | 174 | throw new EE_Error( |
175 | 175 | sprintf( |
176 | 176 | esc_html__( |
@@ -265,7 +265,7 @@ discard block |
||
265 | 265 | EEM_Change_Log::instance()->log( |
266 | 266 | EEM_Change_Log::type_gateway, |
267 | 267 | array( |
268 | - 'message' => 'IPN Exception: ' . $e->getMessage(), |
|
268 | + 'message' => 'IPN Exception: '.$e->getMessage(), |
|
269 | 269 | 'current_url' => EEH_URL::current_url(), |
270 | 270 | 'payment' => $e->getPaymentProperties(), |
271 | 271 | 'IPN_data' => $e->getIpnData(), |
@@ -309,7 +309,7 @@ discard block |
||
309 | 309 | EEM_Change_Log::instance()->log( |
310 | 310 | EEM_Change_Log::type_gateway, |
311 | 311 | array( |
312 | - 'message' => 'IPN Exception: ' . $e->getMessage(), |
|
312 | + 'message' => 'IPN Exception: '.$e->getMessage(), |
|
313 | 313 | 'current_url' => EEH_URL::current_url(), |
314 | 314 | 'payment' => $e->getPaymentProperties(), |
315 | 315 | 'IPN_data' => $e->getIpnData(), |
@@ -380,7 +380,7 @@ discard block |
||
380 | 380 | { |
381 | 381 | $return_data = array(); |
382 | 382 | foreach ($request_data as $key => $value) { |
383 | - $return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters( |
|
383 | + $return_data[$this->_remove_unusable_characters($key)] = $this->_remove_unusable_characters( |
|
384 | 384 | $value |
385 | 385 | ); |
386 | 386 | } |
@@ -17,846 +17,846 @@ |
||
17 | 17 | */ |
18 | 18 | class EE_Payment_Processor extends EE_Processor_Base implements ResettableInterface |
19 | 19 | { |
20 | - /** |
|
21 | - * @var EE_Payment_Processor $_instance |
|
22 | - * @access private |
|
23 | - */ |
|
24 | - private static $_instance; |
|
25 | - |
|
26 | - |
|
27 | - /** |
|
28 | - * @singleton method used to instantiate class object |
|
29 | - * @access public |
|
30 | - * @return EE_Payment_Processor instance |
|
31 | - */ |
|
32 | - public static function instance() |
|
33 | - { |
|
34 | - // check if class object is instantiated |
|
35 | - if (! self::$_instance instanceof EE_Payment_Processor) { |
|
36 | - self::$_instance = new self(); |
|
37 | - } |
|
38 | - return self::$_instance; |
|
39 | - } |
|
40 | - |
|
41 | - |
|
42 | - /** |
|
43 | - * @return EE_Payment_Processor |
|
44 | - */ |
|
45 | - public static function reset() |
|
46 | - { |
|
47 | - self::$_instance = null; |
|
48 | - return self::instance(); |
|
49 | - } |
|
50 | - |
|
51 | - |
|
52 | - /** |
|
53 | - *private constructor to prevent direct creation |
|
54 | - * |
|
55 | - * @Constructor |
|
56 | - * @access private |
|
57 | - */ |
|
58 | - private function __construct() |
|
59 | - { |
|
60 | - do_action('AHEE__EE_Payment_Processor__construct'); |
|
61 | - add_action('http_api_curl', array($this, '_curl_requests_to_paypal_use_tls'), 10, 3); |
|
62 | - } |
|
63 | - |
|
64 | - |
|
65 | - /** |
|
66 | - * Using the selected gateway, processes the payment for that transaction, and updates the transaction |
|
67 | - * appropriately. Saves the payment that is generated |
|
68 | - * |
|
69 | - * @param EE_Payment_Method $payment_method |
|
70 | - * @param EE_Transaction $transaction |
|
71 | - * @param float|null $amount if only part of the transaction is to be paid for, how much. |
|
72 | - * Leave null if payment is for the full amount owing |
|
73 | - * @param EE_Billing_Info_Form|null $billing_form (or probably null, if it's an offline or offsite payment method). |
|
74 | - * Receive_form_submission() should have |
|
75 | - * already been called on the billing form |
|
76 | - * (ie, its inputs should have their normalized values set). |
|
77 | - * @param string|null $return_url string used mostly by offsite gateways to specify |
|
78 | - * where to go AFTER the offsite gateway |
|
79 | - * @param string $method like 'CART', indicates who the client who called this was |
|
80 | - * @param bool $by_admin TRUE if payment is being attempted from the admin |
|
81 | - * @param bool $update_txn whether or not to call |
|
82 | - * EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() |
|
83 | - * @param string $cancel_url URL to return to if off-site payments are cancelled |
|
84 | - * @return EE_Payment |
|
85 | - * @throws EE_Error |
|
86 | - * @throws InvalidArgumentException |
|
87 | - * @throws ReflectionException |
|
88 | - * @throws RuntimeException |
|
89 | - * @throws InvalidDataTypeException |
|
90 | - * @throws InvalidInterfaceException |
|
91 | - */ |
|
92 | - public function process_payment( |
|
93 | - EE_Payment_Method $payment_method, |
|
94 | - EE_Transaction $transaction, |
|
95 | - ?float $amount = null, |
|
96 | - ?EE_Billing_Info_Form $billing_form = null, |
|
97 | - ?string $return_url = null, |
|
98 | - string $method = 'CART', |
|
99 | - bool $by_admin = false, |
|
100 | - bool $update_txn = true, |
|
101 | - string $cancel_url = '' |
|
102 | - ): ?EE_Payment { |
|
103 | - if ((float) $amount < 0) { |
|
104 | - throw new EE_Error( |
|
105 | - sprintf( |
|
106 | - esc_html__( |
|
107 | - 'Attempting to make a payment for a negative amount of %1$d for transaction %2$d. That should be a refund', |
|
108 | - 'event_espresso' |
|
109 | - ), |
|
110 | - $amount, |
|
111 | - $transaction->ID() |
|
112 | - ) |
|
113 | - ); |
|
114 | - } |
|
115 | - // verify payment method |
|
116 | - $payment_method = EEM_Payment_Method::instance()->ensure_is_obj( |
|
117 | - $payment_method, |
|
118 | - true |
|
119 | - ); |
|
120 | - // verify transaction |
|
121 | - EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
122 | - $transaction->set_payment_method_ID($payment_method->ID()); |
|
123 | - // verify payment method type |
|
124 | - if ($payment_method->type_obj() instanceof EE_PMT_Base) { |
|
125 | - $payment = $payment_method->type_obj()->process_payment( |
|
126 | - $transaction, |
|
127 | - min($amount, $transaction->remaining()), // make sure we don't overcharge |
|
128 | - $billing_form, |
|
129 | - $return_url, |
|
130 | - add_query_arg(array('ee_cancel_payment' => true), $cancel_url), |
|
131 | - $method, |
|
132 | - $by_admin |
|
133 | - ); |
|
134 | - // check if payment method uses an off-site gateway |
|
135 | - if ($payment_method->type_obj()->payment_occurs() !== EE_PMT_Base::offsite) { |
|
136 | - // don't process payments for off-site gateways yet because no payment has occurred yet |
|
137 | - $this->update_txn_based_on_payment($transaction, $payment, $update_txn); |
|
138 | - } |
|
139 | - return $payment; |
|
140 | - } |
|
141 | - EE_Error::add_error( |
|
142 | - sprintf( |
|
143 | - esc_html__( |
|
144 | - 'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.', |
|
145 | - 'event_espresso' |
|
146 | - ), |
|
147 | - '<br/>', |
|
148 | - EE_Registry::instance()->CFG->organization->get_pretty('email') |
|
149 | - ), |
|
150 | - __FILE__, |
|
151 | - __FUNCTION__, |
|
152 | - __LINE__ |
|
153 | - ); |
|
154 | - return null; |
|
155 | - } |
|
156 | - |
|
157 | - |
|
158 | - /** |
|
159 | - * @param EE_Transaction|int $transaction |
|
160 | - * @param EE_Payment_Method $payment_method |
|
161 | - * @return string |
|
162 | - * @throws EE_Error |
|
163 | - * @throws InvalidArgumentException |
|
164 | - * @throws InvalidDataTypeException |
|
165 | - * @throws InvalidInterfaceException |
|
166 | - */ |
|
167 | - public function get_ipn_url_for_payment_method($transaction, $payment_method) |
|
168 | - { |
|
169 | - /** @type \EE_Transaction $transaction */ |
|
170 | - $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
171 | - $primary_reg = $transaction->primary_registration(); |
|
172 | - if (! $primary_reg instanceof EE_Registration) { |
|
173 | - throw new EE_Error( |
|
174 | - sprintf( |
|
175 | - esc_html__( |
|
176 | - 'Cannot get IPN URL for transaction with ID %d because it has no primary registration', |
|
177 | - 'event_espresso' |
|
178 | - ), |
|
179 | - $transaction->ID() |
|
180 | - ) |
|
181 | - ); |
|
182 | - } |
|
183 | - $payment_method = EEM_Payment_Method::instance()->ensure_is_obj( |
|
184 | - $payment_method, |
|
185 | - true |
|
186 | - ); |
|
187 | - $url = add_query_arg( |
|
188 | - array( |
|
189 | - 'e_reg_url_link' => $primary_reg->reg_url_link(), |
|
190 | - 'ee_payment_method' => $payment_method->slug(), |
|
191 | - ), |
|
192 | - EE_Registry::instance()->CFG->core->txn_page_url() |
|
193 | - ); |
|
194 | - return $url; |
|
195 | - } |
|
196 | - |
|
197 | - |
|
198 | - /** |
|
199 | - * Process the IPN. Firstly, we'll hope we put the standard args into the IPN URL so |
|
200 | - * we can easily find what registration the IPN is for and what payment method. |
|
201 | - * However, if not, we'll give all payment methods a chance to claim it and process it. |
|
202 | - * If a payment is found for the IPN info, it is saved. |
|
203 | - * |
|
204 | - * @param array $_req_data form post data |
|
205 | - * @param EE_Transaction|int $transaction optional (or a transactions id) |
|
206 | - * @param EE_Payment_Method $payment_method (or a slug or id of one) |
|
207 | - * @param boolean $update_txn whether or not to call |
|
208 | - * EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() |
|
209 | - * @param bool $separate_IPN_request whether the IPN uses a separate request (true, like PayPal) |
|
210 | - * or is processed manually (false, like Authorize.net) |
|
211 | - * @throws EE_Error |
|
212 | - * @throws Exception |
|
213 | - * @return EE_Payment |
|
214 | - * @throws \RuntimeException |
|
215 | - * @throws \ReflectionException |
|
216 | - * @throws \InvalidArgumentException |
|
217 | - * @throws InvalidInterfaceException |
|
218 | - * @throws InvalidDataTypeException |
|
219 | - */ |
|
220 | - public function process_ipn( |
|
221 | - $_req_data, |
|
222 | - $transaction = null, |
|
223 | - $payment_method = null, |
|
224 | - $update_txn = true, |
|
225 | - $separate_IPN_request = true |
|
226 | - ) { |
|
227 | - EE_Registry::instance()->load_model('Change_Log'); |
|
228 | - $_req_data = $this->_remove_unusable_characters_from_array((array) $_req_data); |
|
229 | - EE_Processor_Base::set_IPN($separate_IPN_request); |
|
230 | - $obj_for_log = null; |
|
231 | - if ($transaction instanceof EE_Transaction) { |
|
232 | - $obj_for_log = $transaction; |
|
233 | - if ($payment_method instanceof EE_Payment_Method) { |
|
234 | - $obj_for_log = EEM_Payment::instance()->get_one( |
|
235 | - array( |
|
236 | - array('TXN_ID' => $transaction->ID(), 'PMD_ID' => $payment_method->ID()), |
|
237 | - 'order_by' => array('PAY_timestamp' => 'desc'), |
|
238 | - ) |
|
239 | - ); |
|
240 | - } |
|
241 | - } elseif ($payment_method instanceof EE_Payment) { |
|
242 | - $obj_for_log = $payment_method; |
|
243 | - } |
|
244 | - $log = EEM_Change_Log::instance()->log( |
|
245 | - EEM_Change_Log::type_gateway, |
|
246 | - array('IPN data received' => $_req_data), |
|
247 | - $obj_for_log |
|
248 | - ); |
|
249 | - try { |
|
250 | - /** |
|
251 | - * @var EE_Payment $payment |
|
252 | - */ |
|
253 | - $payment = null; |
|
254 | - if ($transaction && $payment_method) { |
|
255 | - /** @type EE_Transaction $transaction */ |
|
256 | - $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
257 | - /** @type EE_Payment_Method $payment_method */ |
|
258 | - $payment_method = EEM_Payment_Method::instance()->ensure_is_obj($payment_method); |
|
259 | - if ($payment_method->type_obj() instanceof EE_PMT_Base) { |
|
260 | - try { |
|
261 | - $payment = $payment_method->type_obj()->handle_ipn($_req_data, $transaction); |
|
262 | - $log->set_object($payment); |
|
263 | - } catch (EventEspresso\core\exceptions\IpnException $e) { |
|
264 | - EEM_Change_Log::instance()->log( |
|
265 | - EEM_Change_Log::type_gateway, |
|
266 | - array( |
|
267 | - 'message' => 'IPN Exception: ' . $e->getMessage(), |
|
268 | - 'current_url' => EEH_URL::current_url(), |
|
269 | - 'payment' => $e->getPaymentProperties(), |
|
270 | - 'IPN_data' => $e->getIpnData(), |
|
271 | - ), |
|
272 | - $obj_for_log |
|
273 | - ); |
|
274 | - return $e->getPayment(); |
|
275 | - } |
|
276 | - } else { |
|
277 | - // not a payment |
|
278 | - EE_Error::add_error( |
|
279 | - sprintf( |
|
280 | - esc_html__( |
|
281 | - 'A valid payment method could not be determined due to a technical issue.%sPlease refresh your browser and try again or contact %s for assistance.', |
|
282 | - 'event_espresso' |
|
283 | - ), |
|
284 | - '<br/>', |
|
285 | - EE_Registry::instance()->CFG->organization->get_pretty('email') |
|
286 | - ), |
|
287 | - __FILE__, |
|
288 | - __FUNCTION__, |
|
289 | - __LINE__ |
|
290 | - ); |
|
291 | - } |
|
292 | - } else { |
|
293 | - // that's actually pretty ok. The IPN just wasn't able |
|
294 | - // to identify which transaction or payment method this was for |
|
295 | - // give all active payment methods a chance to claim it |
|
296 | - $active_payment_methods = EEM_Payment_Method::instance()->get_all_active(); |
|
297 | - foreach ($active_payment_methods as $active_payment_method) { |
|
298 | - try { |
|
299 | - $payment = $active_payment_method->type_obj()->handle_unclaimed_ipn($_req_data); |
|
300 | - $payment_method = $active_payment_method; |
|
301 | - EEM_Change_Log::instance()->log( |
|
302 | - EEM_Change_Log::type_gateway, |
|
303 | - array('IPN data' => $_req_data), |
|
304 | - $payment |
|
305 | - ); |
|
306 | - break; |
|
307 | - } catch (EventEspresso\core\exceptions\IpnException $e) { |
|
308 | - EEM_Change_Log::instance()->log( |
|
309 | - EEM_Change_Log::type_gateway, |
|
310 | - array( |
|
311 | - 'message' => 'IPN Exception: ' . $e->getMessage(), |
|
312 | - 'current_url' => EEH_URL::current_url(), |
|
313 | - 'payment' => $e->getPaymentProperties(), |
|
314 | - 'IPN_data' => $e->getIpnData(), |
|
315 | - ), |
|
316 | - $obj_for_log |
|
317 | - ); |
|
318 | - return $e->getPayment(); |
|
319 | - } catch (EE_Error $e) { |
|
320 | - // that's fine- it apparently couldn't handle the IPN |
|
321 | - } |
|
322 | - } |
|
323 | - } |
|
324 | - // EEM_Payment_Log::instance()->log("got to 7",$transaction,$payment_method); |
|
325 | - if ($payment instanceof EE_Payment) { |
|
326 | - $payment->save(); |
|
327 | - // update the TXN |
|
328 | - $this->update_txn_based_on_payment( |
|
329 | - $transaction, |
|
330 | - $payment, |
|
331 | - $update_txn, |
|
332 | - $separate_IPN_request |
|
333 | - ); |
|
334 | - } else { |
|
335 | - // we couldn't find the payment for this IPN... let's try and log at least SOMETHING |
|
336 | - if ($payment_method) { |
|
337 | - EEM_Change_Log::instance()->log( |
|
338 | - EEM_Change_Log::type_gateway, |
|
339 | - array('IPN data' => $_req_data), |
|
340 | - $payment_method |
|
341 | - ); |
|
342 | - } elseif ($transaction) { |
|
343 | - EEM_Change_Log::instance()->log( |
|
344 | - EEM_Change_Log::type_gateway, |
|
345 | - array('IPN data' => $_req_data), |
|
346 | - $transaction |
|
347 | - ); |
|
348 | - } |
|
349 | - } |
|
350 | - return $payment; |
|
351 | - } catch (EE_Error $e) { |
|
352 | - do_action( |
|
353 | - 'AHEE__log', |
|
354 | - __FILE__, |
|
355 | - __FUNCTION__, |
|
356 | - sprintf( |
|
357 | - esc_html__( |
|
358 | - 'Error occurred while receiving IPN. Transaction: %1$s, req data: %2$s. The error was "%3$s"', |
|
359 | - 'event_espresso' |
|
360 | - ), |
|
361 | - print_r($transaction, true), |
|
362 | - print_r($_req_data, true), |
|
363 | - $e->getMessage() |
|
364 | - ) |
|
365 | - ); |
|
366 | - throw $e; |
|
367 | - } |
|
368 | - } |
|
369 | - |
|
370 | - |
|
371 | - /** |
|
372 | - * Removes any non-printable illegal characters from the input, |
|
373 | - * which might cause a raucous when trying to insert into the database |
|
374 | - * |
|
375 | - * @param array $request_data |
|
376 | - * @return array |
|
377 | - */ |
|
378 | - protected function _remove_unusable_characters_from_array(array $request_data) |
|
379 | - { |
|
380 | - $return_data = array(); |
|
381 | - foreach ($request_data as $key => $value) { |
|
382 | - $return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters( |
|
383 | - $value |
|
384 | - ); |
|
385 | - } |
|
386 | - return $return_data; |
|
387 | - } |
|
388 | - |
|
389 | - |
|
390 | - /** |
|
391 | - * Removes any non-printable illegal characters from the input, |
|
392 | - * which might cause a raucous when trying to insert into the database |
|
393 | - * |
|
394 | - * @param string $request_data |
|
395 | - * @return string |
|
396 | - */ |
|
397 | - protected function _remove_unusable_characters($request_data) |
|
398 | - { |
|
399 | - return preg_replace('/[^[:print:]]/', '', $request_data); |
|
400 | - } |
|
401 | - |
|
402 | - |
|
403 | - /** |
|
404 | - * Should be called just before displaying the payment attempt results to the user, |
|
405 | - * when the payment attempt has finished. Some payment methods may have special |
|
406 | - * logic to perform here. For example, if process_payment() happens on a special request |
|
407 | - * and then the user is redirected to a page that displays the payment's status, this |
|
408 | - * should be called while loading the page that displays the payment's status. If the user is |
|
409 | - * sent to an offsite payment provider, this should be called upon returning from that offsite payment |
|
410 | - * provider. |
|
411 | - * |
|
412 | - * @param EE_Transaction|int $transaction |
|
413 | - * @param bool $update_txn whether or not to call |
|
414 | - * EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() |
|
415 | - * @return EE_Payment |
|
416 | - * @throws EE_Error |
|
417 | - * @throws InvalidArgumentException |
|
418 | - * @throws ReflectionException |
|
419 | - * @throws RuntimeException |
|
420 | - * @throws InvalidDataTypeException |
|
421 | - * @throws InvalidInterfaceException |
|
422 | - * @deprecated 4.6.24 method is no longer used. Instead it is up to client code, like SPCO, |
|
423 | - * to call handle_ipn() for offsite gateways that don't receive separate IPNs |
|
424 | - */ |
|
425 | - public function finalize_payment_for($transaction, $update_txn = true) |
|
426 | - { |
|
427 | - /** @var $transaction EE_Transaction */ |
|
428 | - $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
429 | - $last_payment_method = $transaction->payment_method(); |
|
430 | - if ($last_payment_method instanceof EE_Payment_Method) { |
|
431 | - $payment = $last_payment_method->type_obj()->finalize_payment_for($transaction); |
|
432 | - $this->update_txn_based_on_payment($transaction, $payment, $update_txn); |
|
433 | - return $payment; |
|
434 | - } |
|
435 | - return null; |
|
436 | - } |
|
437 | - |
|
438 | - |
|
439 | - /** |
|
440 | - * Processes a direct refund request, saves the payment, and updates the transaction appropriately. |
|
441 | - * |
|
442 | - * @param EE_Payment_Method $payment_method |
|
443 | - * @param EE_Payment $payment_to_refund |
|
444 | - * @param array $refund_info |
|
445 | - * @return EE_Payment |
|
446 | - * @throws EE_Error |
|
447 | - * @throws InvalidArgumentException |
|
448 | - * @throws ReflectionException |
|
449 | - * @throws RuntimeException |
|
450 | - * @throws InvalidDataTypeException |
|
451 | - * @throws InvalidInterfaceException |
|
452 | - */ |
|
453 | - public function process_refund( |
|
454 | - EE_Payment_Method $payment_method, |
|
455 | - EE_Payment $payment_to_refund, |
|
456 | - array $refund_info = array() |
|
457 | - ) { |
|
458 | - if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj()->supports_sending_refunds()) { |
|
459 | - $payment_method->type_obj()->process_refund($payment_to_refund, $refund_info); |
|
460 | - $this->update_txn_based_on_payment($payment_to_refund->transaction(), $payment_to_refund); |
|
461 | - } |
|
462 | - return $payment_to_refund; |
|
463 | - } |
|
464 | - |
|
465 | - |
|
466 | - /** |
|
467 | - * This should be called each time there may have been an update to a |
|
468 | - * payment on a transaction (ie, we asked for a payment to process a |
|
469 | - * payment for a transaction, or we told a payment method about an IPN, or |
|
470 | - * we told a payment method to |
|
471 | - * "finalize_payment_for" (a transaction), or we told a payment method to |
|
472 | - * process a refund. This should handle firing the correct hooks to |
|
473 | - * indicate |
|
474 | - * what exactly happened and updating the transaction appropriately). This |
|
475 | - * could be integrated directly into EE_Transaction upon save, but we want |
|
476 | - * this logic to be separate from 'normal' plain-jane saving and updating |
|
477 | - * of transactions and payments, and to be tied to payment processing. |
|
478 | - * Note: this method DOES NOT save the payment passed into it. It is the responsibility |
|
479 | - * of previous code to decide whether or not to save (because the payment passed into |
|
480 | - * this method might be a temporary, never-to-be-saved payment from an offline gateway, |
|
481 | - * in which case we only want that payment object for some temporary usage during this request, |
|
482 | - * but we don't want it to be saved). |
|
483 | - * |
|
484 | - * @param EE_Transaction|int $transaction |
|
485 | - * @param EE_Payment $payment |
|
486 | - * @param boolean $update_txn |
|
487 | - * whether or not to call |
|
488 | - * EE_Transaction_Processor:: |
|
489 | - * update_transaction_and_registrations_after_checkout_or_payment() |
|
490 | - * (you can save 1 DB query if you know you're going |
|
491 | - * to save it later instead) |
|
492 | - * @param bool $IPN |
|
493 | - * if processing IPNs or other similar payment |
|
494 | - * related activities that occur in alternate |
|
495 | - * requests than the main one that is processing the |
|
496 | - * TXN, then set this to true to check whether the |
|
497 | - * TXN is locked before updating |
|
498 | - * @throws EE_Error |
|
499 | - * @throws InvalidArgumentException |
|
500 | - * @throws ReflectionException |
|
501 | - * @throws RuntimeException |
|
502 | - * @throws InvalidDataTypeException |
|
503 | - * @throws InvalidInterfaceException |
|
504 | - */ |
|
505 | - public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false) |
|
506 | - { |
|
507 | - $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful'; |
|
508 | - /** @type EE_Transaction $transaction */ |
|
509 | - $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
510 | - // can we freely update the TXN at this moment? |
|
511 | - if ($IPN && $transaction->is_locked()) { |
|
512 | - // don't update the transaction at this exact moment |
|
513 | - // because the TXN is active in another request |
|
514 | - EE_Cron_Tasks::schedule_update_transaction_with_payment( |
|
515 | - time(), |
|
516 | - $transaction->ID(), |
|
517 | - $payment->ID() |
|
518 | - ); |
|
519 | - } else { |
|
520 | - // verify payment and that it has been saved |
|
521 | - if ($payment instanceof EE_Payment && $payment->ID()) { |
|
522 | - if ( |
|
523 | - $payment->payment_method() instanceof EE_Payment_Method |
|
524 | - && $payment->payment_method()->type_obj() instanceof EE_PMT_Base |
|
525 | - ) { |
|
526 | - $payment->payment_method()->type_obj()->update_txn_based_on_payment($payment); |
|
527 | - // update TXN registrations with payment info |
|
528 | - $this->process_registration_payments($transaction, $payment); |
|
529 | - } |
|
530 | - $do_action = $payment->just_approved() |
|
531 | - ? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful' |
|
532 | - : $do_action; |
|
533 | - } else { |
|
534 | - // send out notifications |
|
535 | - add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true'); |
|
536 | - $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made'; |
|
537 | - } |
|
538 | - if ($payment instanceof EE_Payment && $payment->status() !== EEM_Payment::status_id_failed) { |
|
539 | - /** @type EE_Transaction_Payments $transaction_payments */ |
|
540 | - $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments'); |
|
541 | - // set new value for total paid |
|
542 | - $transaction_payments->calculate_total_payments_and_update_status($transaction); |
|
543 | - // call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ??? |
|
544 | - if ($update_txn) { |
|
545 | - $this->_post_payment_processing($transaction, $payment, $IPN); |
|
546 | - } |
|
547 | - } |
|
548 | - // granular hook for others to use. |
|
549 | - do_action($do_action, $transaction, $payment); |
|
550 | - do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action'); |
|
551 | - // global hook for others to use. |
|
552 | - do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment); |
|
553 | - } |
|
554 | - } |
|
555 | - |
|
556 | - |
|
557 | - /** |
|
558 | - * update registrations REG_paid field after successful payment and link registrations with payment |
|
559 | - * |
|
560 | - * @param EE_Transaction $transaction |
|
561 | - * @param EE_Payment $payment |
|
562 | - * @param EE_Registration[] $registrations |
|
563 | - * @throws EE_Error |
|
564 | - * @throws InvalidArgumentException |
|
565 | - * @throws RuntimeException |
|
566 | - * @throws InvalidDataTypeException |
|
567 | - * @throws InvalidInterfaceException |
|
568 | - */ |
|
569 | - public function process_registration_payments( |
|
570 | - EE_Transaction $transaction, |
|
571 | - EE_Payment $payment, |
|
572 | - array $registrations = array() |
|
573 | - ) { |
|
574 | - // only process if payment was successful |
|
575 | - if ($payment->status() !== EEM_Payment::status_id_approved) { |
|
576 | - return; |
|
577 | - } |
|
578 | - // EEM_Registration::instance()->show_next_x_db_queries(); |
|
579 | - if (empty($registrations)) { |
|
580 | - // find registrations with monies owing that can receive a payment |
|
581 | - $registrations = $transaction->registrations( |
|
582 | - array( |
|
583 | - array( |
|
584 | - // only these reg statuses can receive payments |
|
585 | - 'STS_ID' => array('IN', EEM_Registration::reg_statuses_that_allow_payment()), |
|
586 | - 'REG_final_price' => array('!=', 0), |
|
587 | - 'REG_final_price*' => array('!=', 'REG_paid', true), |
|
588 | - ), |
|
589 | - ) |
|
590 | - ); |
|
591 | - } |
|
592 | - // still nothing ??!?? |
|
593 | - if (empty($registrations)) { |
|
594 | - return; |
|
595 | - } |
|
596 | - // todo: break out the following logic into a separate strategy class |
|
597 | - // todo: named something like "Sequential_Reg_Payment_Strategy" |
|
598 | - // todo: which would apply payments using the capitalist "first come first paid" approach |
|
599 | - // todo: then have another strategy class like "Distributed_Reg_Payment_Strategy" |
|
600 | - // todo: which would be the socialist "everybody gets a piece of pie" approach, |
|
601 | - // todo: which would be better for deposits, where you want a bit of the payment applied to each registration |
|
602 | - $refund = $payment->is_a_refund(); |
|
603 | - // how much is available to apply to registrations? |
|
604 | - $available_payment_amount = abs($payment->amount()); |
|
605 | - foreach ($registrations as $registration) { |
|
606 | - if ($registration instanceof EE_Registration) { |
|
607 | - // nothing left? |
|
608 | - if ($available_payment_amount <= 0) { |
|
609 | - break; |
|
610 | - } |
|
611 | - if ($refund) { |
|
612 | - $available_payment_amount = $this->process_registration_refund( |
|
613 | - $registration, |
|
614 | - $payment, |
|
615 | - $available_payment_amount |
|
616 | - ); |
|
617 | - } else { |
|
618 | - $available_payment_amount = $this->process_registration_payment( |
|
619 | - $registration, |
|
620 | - $payment, |
|
621 | - $available_payment_amount |
|
622 | - ); |
|
623 | - } |
|
624 | - } |
|
625 | - } |
|
626 | - if ( |
|
627 | - $available_payment_amount > 0 |
|
628 | - && apply_filters( |
|
629 | - 'FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', |
|
630 | - false |
|
631 | - ) |
|
632 | - ) { |
|
633 | - EE_Error::add_attention( |
|
634 | - sprintf( |
|
635 | - esc_html__( |
|
636 | - 'A remainder of %1$s exists after applying this payment to Registration(s) %2$s.%3$sPlease verify that the original payment amount of %4$s is correct. If so, you should edit this payment and select at least one additional registration in the "Registrations to Apply Payment to" section, so that the remainder of this payment can be applied to the additional registration(s).', |
|
637 | - 'event_espresso' |
|
638 | - ), |
|
639 | - EEH_Template::format_currency($available_payment_amount), |
|
640 | - implode(', ', array_keys($registrations)), |
|
641 | - '<br/>', |
|
642 | - EEH_Template::format_currency($payment->amount()) |
|
643 | - ), |
|
644 | - __FILE__, |
|
645 | - __FUNCTION__, |
|
646 | - __LINE__ |
|
647 | - ); |
|
648 | - } |
|
649 | - } |
|
650 | - |
|
651 | - |
|
652 | - /** |
|
653 | - * update registration REG_paid field after successful payment and link registration with payment |
|
654 | - * |
|
655 | - * @param EE_Registration $registration |
|
656 | - * @param EE_Payment $payment |
|
657 | - * @param float $available_payment_amount |
|
658 | - * @return float |
|
659 | - * @throws EE_Error |
|
660 | - * @throws InvalidArgumentException |
|
661 | - * @throws RuntimeException |
|
662 | - * @throws InvalidDataTypeException |
|
663 | - * @throws InvalidInterfaceException |
|
664 | - */ |
|
665 | - public function process_registration_payment( |
|
666 | - EE_Registration $registration, |
|
667 | - EE_Payment $payment, |
|
668 | - $available_payment_amount = 0.00 |
|
669 | - ) { |
|
670 | - $owing = $registration->final_price() - $registration->paid(); |
|
671 | - if ($owing > 0) { |
|
672 | - // don't allow payment amount to exceed the available payment amount, OR the amount owing |
|
673 | - $payment_amount = min($available_payment_amount, $owing); |
|
674 | - // update $available_payment_amount |
|
675 | - $available_payment_amount -= $payment_amount; |
|
676 | - // calculate and set new REG_paid |
|
677 | - $registration->set_paid($registration->paid() + $payment_amount); |
|
678 | - // now save it |
|
679 | - $this->_apply_registration_payment($registration, $payment, $payment_amount); |
|
680 | - } |
|
681 | - return $available_payment_amount; |
|
682 | - } |
|
683 | - |
|
684 | - |
|
685 | - /** |
|
686 | - * update registration REG_paid field after successful payment and link registration with payment |
|
687 | - * |
|
688 | - * @param EE_Registration $registration |
|
689 | - * @param EE_Payment $payment |
|
690 | - * @param float $payment_amount |
|
691 | - * @return void |
|
692 | - * @throws EE_Error |
|
693 | - * @throws InvalidArgumentException |
|
694 | - * @throws InvalidDataTypeException |
|
695 | - * @throws InvalidInterfaceException |
|
696 | - */ |
|
697 | - protected function _apply_registration_payment( |
|
698 | - EE_Registration $registration, |
|
699 | - EE_Payment $payment, |
|
700 | - $payment_amount = 0.00 |
|
701 | - ) { |
|
702 | - // find any existing reg payment records for this registration and payment |
|
703 | - $existing_reg_payment = EEM_Registration_Payment::instance()->get_one( |
|
704 | - array(array('REG_ID' => $registration->ID(), 'PAY_ID' => $payment->ID())) |
|
705 | - ); |
|
706 | - // if existing registration payment exists |
|
707 | - if ($existing_reg_payment instanceof EE_Registration_Payment) { |
|
708 | - // then update that record |
|
709 | - $existing_reg_payment->set_amount($payment_amount); |
|
710 | - $existing_reg_payment->save(); |
|
711 | - } else { |
|
712 | - // or add new relation between registration and payment and set amount |
|
713 | - $registration->_add_relation_to( |
|
714 | - $payment, |
|
715 | - 'Payment', |
|
716 | - array('RPY_amount' => $payment_amount) |
|
717 | - ); |
|
718 | - // make it stick |
|
719 | - $registration->save(); |
|
720 | - } |
|
721 | - } |
|
722 | - |
|
723 | - |
|
724 | - /** |
|
725 | - * update registration REG_paid field after refund and link registration with payment |
|
726 | - * |
|
727 | - * @param EE_Registration $registration |
|
728 | - * @param EE_Payment $payment |
|
729 | - * @param float $available_refund_amount - IMPORTANT !!! SEND AVAILABLE REFUND AMOUNT AS A POSITIVE NUMBER |
|
730 | - * @return float |
|
731 | - * @throws EE_Error |
|
732 | - * @throws InvalidArgumentException |
|
733 | - * @throws RuntimeException |
|
734 | - * @throws InvalidDataTypeException |
|
735 | - * @throws InvalidInterfaceException |
|
736 | - */ |
|
737 | - public function process_registration_refund( |
|
738 | - EE_Registration $registration, |
|
739 | - EE_Payment $payment, |
|
740 | - $available_refund_amount = 0.00 |
|
741 | - ) { |
|
742 | - // EEH_Debug_Tools::printr( $payment->amount(), '$payment->amount()', __FILE__, __LINE__ ); |
|
743 | - if ($registration->paid() > 0) { |
|
744 | - // ensure $available_refund_amount is NOT negative |
|
745 | - $available_refund_amount = (float) abs($available_refund_amount); |
|
746 | - // don't allow refund amount to exceed the available payment amount, OR the amount paid |
|
747 | - $refund_amount = min($available_refund_amount, (float) $registration->paid()); |
|
748 | - // update $available_payment_amount |
|
749 | - $available_refund_amount -= $refund_amount; |
|
750 | - // calculate and set new REG_paid |
|
751 | - $registration->set_paid($registration->paid() - $refund_amount); |
|
752 | - // convert payment amount back to a negative value for storage in the db |
|
753 | - $refund_amount = (float) abs($refund_amount) * -1; |
|
754 | - // now save it |
|
755 | - $this->_apply_registration_payment($registration, $payment, $refund_amount); |
|
756 | - } |
|
757 | - return $available_refund_amount; |
|
758 | - } |
|
759 | - |
|
760 | - |
|
761 | - /** |
|
762 | - * Process payments and transaction after payment process completed. |
|
763 | - * ultimately this will send the TXN and payment details off so that notifications can be sent out. |
|
764 | - * if this request happens to be processing an IPN, |
|
765 | - * then we will also set the Payment Options Reg Step to completed, |
|
766 | - * and attempt to completely finalize the TXN if all of the other Reg Steps are completed as well. |
|
767 | - * |
|
768 | - * @param EE_Transaction $transaction |
|
769 | - * @param EE_Payment $payment |
|
770 | - * @param bool $IPN |
|
771 | - * @throws EE_Error |
|
772 | - * @throws InvalidArgumentException |
|
773 | - * @throws ReflectionException |
|
774 | - * @throws RuntimeException |
|
775 | - * @throws InvalidDataTypeException |
|
776 | - * @throws InvalidInterfaceException |
|
777 | - */ |
|
778 | - protected function _post_payment_processing(EE_Transaction $transaction, EE_Payment $payment, $IPN = false) |
|
779 | - { |
|
780 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
781 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
782 | - // is the Payment Options Reg Step completed ? |
|
783 | - $payment_options_step_completed = $transaction->reg_step_completed('payment_options'); |
|
784 | - // if the Payment Options Reg Step is completed... |
|
785 | - $revisit = $payment_options_step_completed === true; |
|
786 | - // then this is kinda sorta a revisit with regards to payments at least |
|
787 | - $transaction_processor->set_revisit($revisit); |
|
788 | - // if this is an IPN, let's consider the Payment Options Reg Step completed if not already |
|
789 | - if ( |
|
790 | - $IPN |
|
791 | - && $payment_options_step_completed !== true |
|
792 | - && ($payment->is_approved() || $payment->is_pending()) |
|
793 | - ) { |
|
794 | - $payment_options_step_completed = $transaction->set_reg_step_completed( |
|
795 | - 'payment_options' |
|
796 | - ); |
|
797 | - } |
|
798 | - // maybe update status, but don't save transaction just yet |
|
799 | - $transaction->update_status_based_on_total_paid(false); |
|
800 | - // check if 'finalize_registration' step has been completed... |
|
801 | - $finalized = $transaction->reg_step_completed('finalize_registration'); |
|
802 | - // if this is an IPN and the final step has not been initiated |
|
803 | - if ($IPN && $payment_options_step_completed && $finalized === false) { |
|
804 | - // and if it hasn't already been set as being started... |
|
805 | - $finalized = $transaction->set_reg_step_initiated('finalize_registration'); |
|
806 | - } |
|
807 | - $transaction->save(); |
|
808 | - // because the above will return false if the final step was not fully completed, we need to check again... |
|
809 | - if ($IPN && $finalized !== false) { |
|
810 | - // and if we are all good to go, then send out notifications |
|
811 | - add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true'); |
|
812 | - // ok, now process the transaction according to the payment |
|
813 | - $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
814 | - $transaction, |
|
815 | - $payment |
|
816 | - ); |
|
817 | - } |
|
818 | - // DEBUG LOG |
|
819 | - $payment_method = $payment->payment_method(); |
|
820 | - if ($payment_method instanceof EE_Payment_Method) { |
|
821 | - $payment_method_type_obj = $payment_method->type_obj(); |
|
822 | - if ($payment_method_type_obj instanceof EE_PMT_Base) { |
|
823 | - $gateway = $payment_method_type_obj->get_gateway(); |
|
824 | - if ($gateway instanceof EE_Gateway) { |
|
825 | - $gateway->log( |
|
826 | - array( |
|
827 | - 'message' => (string) esc_html__('Post Payment Transaction Details', 'event_espresso'), |
|
828 | - 'transaction' => $transaction->model_field_array(), |
|
829 | - 'finalized' => $finalized, |
|
830 | - 'IPN' => $IPN, |
|
831 | - 'deliver_notifications' => has_filter( |
|
832 | - 'FHEE__EED_Messages___maybe_registration__deliver_notifications' |
|
833 | - ), |
|
834 | - ), |
|
835 | - $payment |
|
836 | - ); |
|
837 | - } |
|
838 | - } |
|
839 | - } |
|
840 | - } |
|
841 | - |
|
842 | - |
|
843 | - /** |
|
844 | - * Force posts to PayPal to use TLS v1.2. See: |
|
845 | - * https://core.trac.wordpress.org/ticket/36320 |
|
846 | - * https://core.trac.wordpress.org/ticket/34924#comment:15 |
|
847 | - * https://www.paypal-knowledge.com/infocenter/index?page=content&widgetview=true&id=FAQ1914&viewlocale=en_US |
|
848 | - * This will affect PayPal standard, pro, express, and Payflow. |
|
849 | - * |
|
850 | - * @param $handle |
|
851 | - * @param $r |
|
852 | - * @param $url |
|
853 | - */ |
|
854 | - public static function _curl_requests_to_paypal_use_tls($handle, $r, $url) |
|
855 | - { |
|
856 | - if (strpos($url, 'https://') !== false && strpos($url, '.paypal.com') !== false) { |
|
857 | - // Use the value of the constant CURL_SSLVERSION_TLSv1 = 1 |
|
858 | - // instead of the constant because it might not be defined |
|
859 | - curl_setopt($handle, CURLOPT_SSLVERSION, 6); |
|
860 | - } |
|
861 | - } |
|
20 | + /** |
|
21 | + * @var EE_Payment_Processor $_instance |
|
22 | + * @access private |
|
23 | + */ |
|
24 | + private static $_instance; |
|
25 | + |
|
26 | + |
|
27 | + /** |
|
28 | + * @singleton method used to instantiate class object |
|
29 | + * @access public |
|
30 | + * @return EE_Payment_Processor instance |
|
31 | + */ |
|
32 | + public static function instance() |
|
33 | + { |
|
34 | + // check if class object is instantiated |
|
35 | + if (! self::$_instance instanceof EE_Payment_Processor) { |
|
36 | + self::$_instance = new self(); |
|
37 | + } |
|
38 | + return self::$_instance; |
|
39 | + } |
|
40 | + |
|
41 | + |
|
42 | + /** |
|
43 | + * @return EE_Payment_Processor |
|
44 | + */ |
|
45 | + public static function reset() |
|
46 | + { |
|
47 | + self::$_instance = null; |
|
48 | + return self::instance(); |
|
49 | + } |
|
50 | + |
|
51 | + |
|
52 | + /** |
|
53 | + *private constructor to prevent direct creation |
|
54 | + * |
|
55 | + * @Constructor |
|
56 | + * @access private |
|
57 | + */ |
|
58 | + private function __construct() |
|
59 | + { |
|
60 | + do_action('AHEE__EE_Payment_Processor__construct'); |
|
61 | + add_action('http_api_curl', array($this, '_curl_requests_to_paypal_use_tls'), 10, 3); |
|
62 | + } |
|
63 | + |
|
64 | + |
|
65 | + /** |
|
66 | + * Using the selected gateway, processes the payment for that transaction, and updates the transaction |
|
67 | + * appropriately. Saves the payment that is generated |
|
68 | + * |
|
69 | + * @param EE_Payment_Method $payment_method |
|
70 | + * @param EE_Transaction $transaction |
|
71 | + * @param float|null $amount if only part of the transaction is to be paid for, how much. |
|
72 | + * Leave null if payment is for the full amount owing |
|
73 | + * @param EE_Billing_Info_Form|null $billing_form (or probably null, if it's an offline or offsite payment method). |
|
74 | + * Receive_form_submission() should have |
|
75 | + * already been called on the billing form |
|
76 | + * (ie, its inputs should have their normalized values set). |
|
77 | + * @param string|null $return_url string used mostly by offsite gateways to specify |
|
78 | + * where to go AFTER the offsite gateway |
|
79 | + * @param string $method like 'CART', indicates who the client who called this was |
|
80 | + * @param bool $by_admin TRUE if payment is being attempted from the admin |
|
81 | + * @param bool $update_txn whether or not to call |
|
82 | + * EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() |
|
83 | + * @param string $cancel_url URL to return to if off-site payments are cancelled |
|
84 | + * @return EE_Payment |
|
85 | + * @throws EE_Error |
|
86 | + * @throws InvalidArgumentException |
|
87 | + * @throws ReflectionException |
|
88 | + * @throws RuntimeException |
|
89 | + * @throws InvalidDataTypeException |
|
90 | + * @throws InvalidInterfaceException |
|
91 | + */ |
|
92 | + public function process_payment( |
|
93 | + EE_Payment_Method $payment_method, |
|
94 | + EE_Transaction $transaction, |
|
95 | + ?float $amount = null, |
|
96 | + ?EE_Billing_Info_Form $billing_form = null, |
|
97 | + ?string $return_url = null, |
|
98 | + string $method = 'CART', |
|
99 | + bool $by_admin = false, |
|
100 | + bool $update_txn = true, |
|
101 | + string $cancel_url = '' |
|
102 | + ): ?EE_Payment { |
|
103 | + if ((float) $amount < 0) { |
|
104 | + throw new EE_Error( |
|
105 | + sprintf( |
|
106 | + esc_html__( |
|
107 | + 'Attempting to make a payment for a negative amount of %1$d for transaction %2$d. That should be a refund', |
|
108 | + 'event_espresso' |
|
109 | + ), |
|
110 | + $amount, |
|
111 | + $transaction->ID() |
|
112 | + ) |
|
113 | + ); |
|
114 | + } |
|
115 | + // verify payment method |
|
116 | + $payment_method = EEM_Payment_Method::instance()->ensure_is_obj( |
|
117 | + $payment_method, |
|
118 | + true |
|
119 | + ); |
|
120 | + // verify transaction |
|
121 | + EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
122 | + $transaction->set_payment_method_ID($payment_method->ID()); |
|
123 | + // verify payment method type |
|
124 | + if ($payment_method->type_obj() instanceof EE_PMT_Base) { |
|
125 | + $payment = $payment_method->type_obj()->process_payment( |
|
126 | + $transaction, |
|
127 | + min($amount, $transaction->remaining()), // make sure we don't overcharge |
|
128 | + $billing_form, |
|
129 | + $return_url, |
|
130 | + add_query_arg(array('ee_cancel_payment' => true), $cancel_url), |
|
131 | + $method, |
|
132 | + $by_admin |
|
133 | + ); |
|
134 | + // check if payment method uses an off-site gateway |
|
135 | + if ($payment_method->type_obj()->payment_occurs() !== EE_PMT_Base::offsite) { |
|
136 | + // don't process payments for off-site gateways yet because no payment has occurred yet |
|
137 | + $this->update_txn_based_on_payment($transaction, $payment, $update_txn); |
|
138 | + } |
|
139 | + return $payment; |
|
140 | + } |
|
141 | + EE_Error::add_error( |
|
142 | + sprintf( |
|
143 | + esc_html__( |
|
144 | + 'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.', |
|
145 | + 'event_espresso' |
|
146 | + ), |
|
147 | + '<br/>', |
|
148 | + EE_Registry::instance()->CFG->organization->get_pretty('email') |
|
149 | + ), |
|
150 | + __FILE__, |
|
151 | + __FUNCTION__, |
|
152 | + __LINE__ |
|
153 | + ); |
|
154 | + return null; |
|
155 | + } |
|
156 | + |
|
157 | + |
|
158 | + /** |
|
159 | + * @param EE_Transaction|int $transaction |
|
160 | + * @param EE_Payment_Method $payment_method |
|
161 | + * @return string |
|
162 | + * @throws EE_Error |
|
163 | + * @throws InvalidArgumentException |
|
164 | + * @throws InvalidDataTypeException |
|
165 | + * @throws InvalidInterfaceException |
|
166 | + */ |
|
167 | + public function get_ipn_url_for_payment_method($transaction, $payment_method) |
|
168 | + { |
|
169 | + /** @type \EE_Transaction $transaction */ |
|
170 | + $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
171 | + $primary_reg = $transaction->primary_registration(); |
|
172 | + if (! $primary_reg instanceof EE_Registration) { |
|
173 | + throw new EE_Error( |
|
174 | + sprintf( |
|
175 | + esc_html__( |
|
176 | + 'Cannot get IPN URL for transaction with ID %d because it has no primary registration', |
|
177 | + 'event_espresso' |
|
178 | + ), |
|
179 | + $transaction->ID() |
|
180 | + ) |
|
181 | + ); |
|
182 | + } |
|
183 | + $payment_method = EEM_Payment_Method::instance()->ensure_is_obj( |
|
184 | + $payment_method, |
|
185 | + true |
|
186 | + ); |
|
187 | + $url = add_query_arg( |
|
188 | + array( |
|
189 | + 'e_reg_url_link' => $primary_reg->reg_url_link(), |
|
190 | + 'ee_payment_method' => $payment_method->slug(), |
|
191 | + ), |
|
192 | + EE_Registry::instance()->CFG->core->txn_page_url() |
|
193 | + ); |
|
194 | + return $url; |
|
195 | + } |
|
196 | + |
|
197 | + |
|
198 | + /** |
|
199 | + * Process the IPN. Firstly, we'll hope we put the standard args into the IPN URL so |
|
200 | + * we can easily find what registration the IPN is for and what payment method. |
|
201 | + * However, if not, we'll give all payment methods a chance to claim it and process it. |
|
202 | + * If a payment is found for the IPN info, it is saved. |
|
203 | + * |
|
204 | + * @param array $_req_data form post data |
|
205 | + * @param EE_Transaction|int $transaction optional (or a transactions id) |
|
206 | + * @param EE_Payment_Method $payment_method (or a slug or id of one) |
|
207 | + * @param boolean $update_txn whether or not to call |
|
208 | + * EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() |
|
209 | + * @param bool $separate_IPN_request whether the IPN uses a separate request (true, like PayPal) |
|
210 | + * or is processed manually (false, like Authorize.net) |
|
211 | + * @throws EE_Error |
|
212 | + * @throws Exception |
|
213 | + * @return EE_Payment |
|
214 | + * @throws \RuntimeException |
|
215 | + * @throws \ReflectionException |
|
216 | + * @throws \InvalidArgumentException |
|
217 | + * @throws InvalidInterfaceException |
|
218 | + * @throws InvalidDataTypeException |
|
219 | + */ |
|
220 | + public function process_ipn( |
|
221 | + $_req_data, |
|
222 | + $transaction = null, |
|
223 | + $payment_method = null, |
|
224 | + $update_txn = true, |
|
225 | + $separate_IPN_request = true |
|
226 | + ) { |
|
227 | + EE_Registry::instance()->load_model('Change_Log'); |
|
228 | + $_req_data = $this->_remove_unusable_characters_from_array((array) $_req_data); |
|
229 | + EE_Processor_Base::set_IPN($separate_IPN_request); |
|
230 | + $obj_for_log = null; |
|
231 | + if ($transaction instanceof EE_Transaction) { |
|
232 | + $obj_for_log = $transaction; |
|
233 | + if ($payment_method instanceof EE_Payment_Method) { |
|
234 | + $obj_for_log = EEM_Payment::instance()->get_one( |
|
235 | + array( |
|
236 | + array('TXN_ID' => $transaction->ID(), 'PMD_ID' => $payment_method->ID()), |
|
237 | + 'order_by' => array('PAY_timestamp' => 'desc'), |
|
238 | + ) |
|
239 | + ); |
|
240 | + } |
|
241 | + } elseif ($payment_method instanceof EE_Payment) { |
|
242 | + $obj_for_log = $payment_method; |
|
243 | + } |
|
244 | + $log = EEM_Change_Log::instance()->log( |
|
245 | + EEM_Change_Log::type_gateway, |
|
246 | + array('IPN data received' => $_req_data), |
|
247 | + $obj_for_log |
|
248 | + ); |
|
249 | + try { |
|
250 | + /** |
|
251 | + * @var EE_Payment $payment |
|
252 | + */ |
|
253 | + $payment = null; |
|
254 | + if ($transaction && $payment_method) { |
|
255 | + /** @type EE_Transaction $transaction */ |
|
256 | + $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
257 | + /** @type EE_Payment_Method $payment_method */ |
|
258 | + $payment_method = EEM_Payment_Method::instance()->ensure_is_obj($payment_method); |
|
259 | + if ($payment_method->type_obj() instanceof EE_PMT_Base) { |
|
260 | + try { |
|
261 | + $payment = $payment_method->type_obj()->handle_ipn($_req_data, $transaction); |
|
262 | + $log->set_object($payment); |
|
263 | + } catch (EventEspresso\core\exceptions\IpnException $e) { |
|
264 | + EEM_Change_Log::instance()->log( |
|
265 | + EEM_Change_Log::type_gateway, |
|
266 | + array( |
|
267 | + 'message' => 'IPN Exception: ' . $e->getMessage(), |
|
268 | + 'current_url' => EEH_URL::current_url(), |
|
269 | + 'payment' => $e->getPaymentProperties(), |
|
270 | + 'IPN_data' => $e->getIpnData(), |
|
271 | + ), |
|
272 | + $obj_for_log |
|
273 | + ); |
|
274 | + return $e->getPayment(); |
|
275 | + } |
|
276 | + } else { |
|
277 | + // not a payment |
|
278 | + EE_Error::add_error( |
|
279 | + sprintf( |
|
280 | + esc_html__( |
|
281 | + 'A valid payment method could not be determined due to a technical issue.%sPlease refresh your browser and try again or contact %s for assistance.', |
|
282 | + 'event_espresso' |
|
283 | + ), |
|
284 | + '<br/>', |
|
285 | + EE_Registry::instance()->CFG->organization->get_pretty('email') |
|
286 | + ), |
|
287 | + __FILE__, |
|
288 | + __FUNCTION__, |
|
289 | + __LINE__ |
|
290 | + ); |
|
291 | + } |
|
292 | + } else { |
|
293 | + // that's actually pretty ok. The IPN just wasn't able |
|
294 | + // to identify which transaction or payment method this was for |
|
295 | + // give all active payment methods a chance to claim it |
|
296 | + $active_payment_methods = EEM_Payment_Method::instance()->get_all_active(); |
|
297 | + foreach ($active_payment_methods as $active_payment_method) { |
|
298 | + try { |
|
299 | + $payment = $active_payment_method->type_obj()->handle_unclaimed_ipn($_req_data); |
|
300 | + $payment_method = $active_payment_method; |
|
301 | + EEM_Change_Log::instance()->log( |
|
302 | + EEM_Change_Log::type_gateway, |
|
303 | + array('IPN data' => $_req_data), |
|
304 | + $payment |
|
305 | + ); |
|
306 | + break; |
|
307 | + } catch (EventEspresso\core\exceptions\IpnException $e) { |
|
308 | + EEM_Change_Log::instance()->log( |
|
309 | + EEM_Change_Log::type_gateway, |
|
310 | + array( |
|
311 | + 'message' => 'IPN Exception: ' . $e->getMessage(), |
|
312 | + 'current_url' => EEH_URL::current_url(), |
|
313 | + 'payment' => $e->getPaymentProperties(), |
|
314 | + 'IPN_data' => $e->getIpnData(), |
|
315 | + ), |
|
316 | + $obj_for_log |
|
317 | + ); |
|
318 | + return $e->getPayment(); |
|
319 | + } catch (EE_Error $e) { |
|
320 | + // that's fine- it apparently couldn't handle the IPN |
|
321 | + } |
|
322 | + } |
|
323 | + } |
|
324 | + // EEM_Payment_Log::instance()->log("got to 7",$transaction,$payment_method); |
|
325 | + if ($payment instanceof EE_Payment) { |
|
326 | + $payment->save(); |
|
327 | + // update the TXN |
|
328 | + $this->update_txn_based_on_payment( |
|
329 | + $transaction, |
|
330 | + $payment, |
|
331 | + $update_txn, |
|
332 | + $separate_IPN_request |
|
333 | + ); |
|
334 | + } else { |
|
335 | + // we couldn't find the payment for this IPN... let's try and log at least SOMETHING |
|
336 | + if ($payment_method) { |
|
337 | + EEM_Change_Log::instance()->log( |
|
338 | + EEM_Change_Log::type_gateway, |
|
339 | + array('IPN data' => $_req_data), |
|
340 | + $payment_method |
|
341 | + ); |
|
342 | + } elseif ($transaction) { |
|
343 | + EEM_Change_Log::instance()->log( |
|
344 | + EEM_Change_Log::type_gateway, |
|
345 | + array('IPN data' => $_req_data), |
|
346 | + $transaction |
|
347 | + ); |
|
348 | + } |
|
349 | + } |
|
350 | + return $payment; |
|
351 | + } catch (EE_Error $e) { |
|
352 | + do_action( |
|
353 | + 'AHEE__log', |
|
354 | + __FILE__, |
|
355 | + __FUNCTION__, |
|
356 | + sprintf( |
|
357 | + esc_html__( |
|
358 | + 'Error occurred while receiving IPN. Transaction: %1$s, req data: %2$s. The error was "%3$s"', |
|
359 | + 'event_espresso' |
|
360 | + ), |
|
361 | + print_r($transaction, true), |
|
362 | + print_r($_req_data, true), |
|
363 | + $e->getMessage() |
|
364 | + ) |
|
365 | + ); |
|
366 | + throw $e; |
|
367 | + } |
|
368 | + } |
|
369 | + |
|
370 | + |
|
371 | + /** |
|
372 | + * Removes any non-printable illegal characters from the input, |
|
373 | + * which might cause a raucous when trying to insert into the database |
|
374 | + * |
|
375 | + * @param array $request_data |
|
376 | + * @return array |
|
377 | + */ |
|
378 | + protected function _remove_unusable_characters_from_array(array $request_data) |
|
379 | + { |
|
380 | + $return_data = array(); |
|
381 | + foreach ($request_data as $key => $value) { |
|
382 | + $return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters( |
|
383 | + $value |
|
384 | + ); |
|
385 | + } |
|
386 | + return $return_data; |
|
387 | + } |
|
388 | + |
|
389 | + |
|
390 | + /** |
|
391 | + * Removes any non-printable illegal characters from the input, |
|
392 | + * which might cause a raucous when trying to insert into the database |
|
393 | + * |
|
394 | + * @param string $request_data |
|
395 | + * @return string |
|
396 | + */ |
|
397 | + protected function _remove_unusable_characters($request_data) |
|
398 | + { |
|
399 | + return preg_replace('/[^[:print:]]/', '', $request_data); |
|
400 | + } |
|
401 | + |
|
402 | + |
|
403 | + /** |
|
404 | + * Should be called just before displaying the payment attempt results to the user, |
|
405 | + * when the payment attempt has finished. Some payment methods may have special |
|
406 | + * logic to perform here. For example, if process_payment() happens on a special request |
|
407 | + * and then the user is redirected to a page that displays the payment's status, this |
|
408 | + * should be called while loading the page that displays the payment's status. If the user is |
|
409 | + * sent to an offsite payment provider, this should be called upon returning from that offsite payment |
|
410 | + * provider. |
|
411 | + * |
|
412 | + * @param EE_Transaction|int $transaction |
|
413 | + * @param bool $update_txn whether or not to call |
|
414 | + * EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() |
|
415 | + * @return EE_Payment |
|
416 | + * @throws EE_Error |
|
417 | + * @throws InvalidArgumentException |
|
418 | + * @throws ReflectionException |
|
419 | + * @throws RuntimeException |
|
420 | + * @throws InvalidDataTypeException |
|
421 | + * @throws InvalidInterfaceException |
|
422 | + * @deprecated 4.6.24 method is no longer used. Instead it is up to client code, like SPCO, |
|
423 | + * to call handle_ipn() for offsite gateways that don't receive separate IPNs |
|
424 | + */ |
|
425 | + public function finalize_payment_for($transaction, $update_txn = true) |
|
426 | + { |
|
427 | + /** @var $transaction EE_Transaction */ |
|
428 | + $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
429 | + $last_payment_method = $transaction->payment_method(); |
|
430 | + if ($last_payment_method instanceof EE_Payment_Method) { |
|
431 | + $payment = $last_payment_method->type_obj()->finalize_payment_for($transaction); |
|
432 | + $this->update_txn_based_on_payment($transaction, $payment, $update_txn); |
|
433 | + return $payment; |
|
434 | + } |
|
435 | + return null; |
|
436 | + } |
|
437 | + |
|
438 | + |
|
439 | + /** |
|
440 | + * Processes a direct refund request, saves the payment, and updates the transaction appropriately. |
|
441 | + * |
|
442 | + * @param EE_Payment_Method $payment_method |
|
443 | + * @param EE_Payment $payment_to_refund |
|
444 | + * @param array $refund_info |
|
445 | + * @return EE_Payment |
|
446 | + * @throws EE_Error |
|
447 | + * @throws InvalidArgumentException |
|
448 | + * @throws ReflectionException |
|
449 | + * @throws RuntimeException |
|
450 | + * @throws InvalidDataTypeException |
|
451 | + * @throws InvalidInterfaceException |
|
452 | + */ |
|
453 | + public function process_refund( |
|
454 | + EE_Payment_Method $payment_method, |
|
455 | + EE_Payment $payment_to_refund, |
|
456 | + array $refund_info = array() |
|
457 | + ) { |
|
458 | + if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj()->supports_sending_refunds()) { |
|
459 | + $payment_method->type_obj()->process_refund($payment_to_refund, $refund_info); |
|
460 | + $this->update_txn_based_on_payment($payment_to_refund->transaction(), $payment_to_refund); |
|
461 | + } |
|
462 | + return $payment_to_refund; |
|
463 | + } |
|
464 | + |
|
465 | + |
|
466 | + /** |
|
467 | + * This should be called each time there may have been an update to a |
|
468 | + * payment on a transaction (ie, we asked for a payment to process a |
|
469 | + * payment for a transaction, or we told a payment method about an IPN, or |
|
470 | + * we told a payment method to |
|
471 | + * "finalize_payment_for" (a transaction), or we told a payment method to |
|
472 | + * process a refund. This should handle firing the correct hooks to |
|
473 | + * indicate |
|
474 | + * what exactly happened and updating the transaction appropriately). This |
|
475 | + * could be integrated directly into EE_Transaction upon save, but we want |
|
476 | + * this logic to be separate from 'normal' plain-jane saving and updating |
|
477 | + * of transactions and payments, and to be tied to payment processing. |
|
478 | + * Note: this method DOES NOT save the payment passed into it. It is the responsibility |
|
479 | + * of previous code to decide whether or not to save (because the payment passed into |
|
480 | + * this method might be a temporary, never-to-be-saved payment from an offline gateway, |
|
481 | + * in which case we only want that payment object for some temporary usage during this request, |
|
482 | + * but we don't want it to be saved). |
|
483 | + * |
|
484 | + * @param EE_Transaction|int $transaction |
|
485 | + * @param EE_Payment $payment |
|
486 | + * @param boolean $update_txn |
|
487 | + * whether or not to call |
|
488 | + * EE_Transaction_Processor:: |
|
489 | + * update_transaction_and_registrations_after_checkout_or_payment() |
|
490 | + * (you can save 1 DB query if you know you're going |
|
491 | + * to save it later instead) |
|
492 | + * @param bool $IPN |
|
493 | + * if processing IPNs or other similar payment |
|
494 | + * related activities that occur in alternate |
|
495 | + * requests than the main one that is processing the |
|
496 | + * TXN, then set this to true to check whether the |
|
497 | + * TXN is locked before updating |
|
498 | + * @throws EE_Error |
|
499 | + * @throws InvalidArgumentException |
|
500 | + * @throws ReflectionException |
|
501 | + * @throws RuntimeException |
|
502 | + * @throws InvalidDataTypeException |
|
503 | + * @throws InvalidInterfaceException |
|
504 | + */ |
|
505 | + public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false) |
|
506 | + { |
|
507 | + $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful'; |
|
508 | + /** @type EE_Transaction $transaction */ |
|
509 | + $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
510 | + // can we freely update the TXN at this moment? |
|
511 | + if ($IPN && $transaction->is_locked()) { |
|
512 | + // don't update the transaction at this exact moment |
|
513 | + // because the TXN is active in another request |
|
514 | + EE_Cron_Tasks::schedule_update_transaction_with_payment( |
|
515 | + time(), |
|
516 | + $transaction->ID(), |
|
517 | + $payment->ID() |
|
518 | + ); |
|
519 | + } else { |
|
520 | + // verify payment and that it has been saved |
|
521 | + if ($payment instanceof EE_Payment && $payment->ID()) { |
|
522 | + if ( |
|
523 | + $payment->payment_method() instanceof EE_Payment_Method |
|
524 | + && $payment->payment_method()->type_obj() instanceof EE_PMT_Base |
|
525 | + ) { |
|
526 | + $payment->payment_method()->type_obj()->update_txn_based_on_payment($payment); |
|
527 | + // update TXN registrations with payment info |
|
528 | + $this->process_registration_payments($transaction, $payment); |
|
529 | + } |
|
530 | + $do_action = $payment->just_approved() |
|
531 | + ? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful' |
|
532 | + : $do_action; |
|
533 | + } else { |
|
534 | + // send out notifications |
|
535 | + add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true'); |
|
536 | + $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made'; |
|
537 | + } |
|
538 | + if ($payment instanceof EE_Payment && $payment->status() !== EEM_Payment::status_id_failed) { |
|
539 | + /** @type EE_Transaction_Payments $transaction_payments */ |
|
540 | + $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments'); |
|
541 | + // set new value for total paid |
|
542 | + $transaction_payments->calculate_total_payments_and_update_status($transaction); |
|
543 | + // call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ??? |
|
544 | + if ($update_txn) { |
|
545 | + $this->_post_payment_processing($transaction, $payment, $IPN); |
|
546 | + } |
|
547 | + } |
|
548 | + // granular hook for others to use. |
|
549 | + do_action($do_action, $transaction, $payment); |
|
550 | + do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action'); |
|
551 | + // global hook for others to use. |
|
552 | + do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment); |
|
553 | + } |
|
554 | + } |
|
555 | + |
|
556 | + |
|
557 | + /** |
|
558 | + * update registrations REG_paid field after successful payment and link registrations with payment |
|
559 | + * |
|
560 | + * @param EE_Transaction $transaction |
|
561 | + * @param EE_Payment $payment |
|
562 | + * @param EE_Registration[] $registrations |
|
563 | + * @throws EE_Error |
|
564 | + * @throws InvalidArgumentException |
|
565 | + * @throws RuntimeException |
|
566 | + * @throws InvalidDataTypeException |
|
567 | + * @throws InvalidInterfaceException |
|
568 | + */ |
|
569 | + public function process_registration_payments( |
|
570 | + EE_Transaction $transaction, |
|
571 | + EE_Payment $payment, |
|
572 | + array $registrations = array() |
|
573 | + ) { |
|
574 | + // only process if payment was successful |
|
575 | + if ($payment->status() !== EEM_Payment::status_id_approved) { |
|
576 | + return; |
|
577 | + } |
|
578 | + // EEM_Registration::instance()->show_next_x_db_queries(); |
|
579 | + if (empty($registrations)) { |
|
580 | + // find registrations with monies owing that can receive a payment |
|
581 | + $registrations = $transaction->registrations( |
|
582 | + array( |
|
583 | + array( |
|
584 | + // only these reg statuses can receive payments |
|
585 | + 'STS_ID' => array('IN', EEM_Registration::reg_statuses_that_allow_payment()), |
|
586 | + 'REG_final_price' => array('!=', 0), |
|
587 | + 'REG_final_price*' => array('!=', 'REG_paid', true), |
|
588 | + ), |
|
589 | + ) |
|
590 | + ); |
|
591 | + } |
|
592 | + // still nothing ??!?? |
|
593 | + if (empty($registrations)) { |
|
594 | + return; |
|
595 | + } |
|
596 | + // todo: break out the following logic into a separate strategy class |
|
597 | + // todo: named something like "Sequential_Reg_Payment_Strategy" |
|
598 | + // todo: which would apply payments using the capitalist "first come first paid" approach |
|
599 | + // todo: then have another strategy class like "Distributed_Reg_Payment_Strategy" |
|
600 | + // todo: which would be the socialist "everybody gets a piece of pie" approach, |
|
601 | + // todo: which would be better for deposits, where you want a bit of the payment applied to each registration |
|
602 | + $refund = $payment->is_a_refund(); |
|
603 | + // how much is available to apply to registrations? |
|
604 | + $available_payment_amount = abs($payment->amount()); |
|
605 | + foreach ($registrations as $registration) { |
|
606 | + if ($registration instanceof EE_Registration) { |
|
607 | + // nothing left? |
|
608 | + if ($available_payment_amount <= 0) { |
|
609 | + break; |
|
610 | + } |
|
611 | + if ($refund) { |
|
612 | + $available_payment_amount = $this->process_registration_refund( |
|
613 | + $registration, |
|
614 | + $payment, |
|
615 | + $available_payment_amount |
|
616 | + ); |
|
617 | + } else { |
|
618 | + $available_payment_amount = $this->process_registration_payment( |
|
619 | + $registration, |
|
620 | + $payment, |
|
621 | + $available_payment_amount |
|
622 | + ); |
|
623 | + } |
|
624 | + } |
|
625 | + } |
|
626 | + if ( |
|
627 | + $available_payment_amount > 0 |
|
628 | + && apply_filters( |
|
629 | + 'FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', |
|
630 | + false |
|
631 | + ) |
|
632 | + ) { |
|
633 | + EE_Error::add_attention( |
|
634 | + sprintf( |
|
635 | + esc_html__( |
|
636 | + 'A remainder of %1$s exists after applying this payment to Registration(s) %2$s.%3$sPlease verify that the original payment amount of %4$s is correct. If so, you should edit this payment and select at least one additional registration in the "Registrations to Apply Payment to" section, so that the remainder of this payment can be applied to the additional registration(s).', |
|
637 | + 'event_espresso' |
|
638 | + ), |
|
639 | + EEH_Template::format_currency($available_payment_amount), |
|
640 | + implode(', ', array_keys($registrations)), |
|
641 | + '<br/>', |
|
642 | + EEH_Template::format_currency($payment->amount()) |
|
643 | + ), |
|
644 | + __FILE__, |
|
645 | + __FUNCTION__, |
|
646 | + __LINE__ |
|
647 | + ); |
|
648 | + } |
|
649 | + } |
|
650 | + |
|
651 | + |
|
652 | + /** |
|
653 | + * update registration REG_paid field after successful payment and link registration with payment |
|
654 | + * |
|
655 | + * @param EE_Registration $registration |
|
656 | + * @param EE_Payment $payment |
|
657 | + * @param float $available_payment_amount |
|
658 | + * @return float |
|
659 | + * @throws EE_Error |
|
660 | + * @throws InvalidArgumentException |
|
661 | + * @throws RuntimeException |
|
662 | + * @throws InvalidDataTypeException |
|
663 | + * @throws InvalidInterfaceException |
|
664 | + */ |
|
665 | + public function process_registration_payment( |
|
666 | + EE_Registration $registration, |
|
667 | + EE_Payment $payment, |
|
668 | + $available_payment_amount = 0.00 |
|
669 | + ) { |
|
670 | + $owing = $registration->final_price() - $registration->paid(); |
|
671 | + if ($owing > 0) { |
|
672 | + // don't allow payment amount to exceed the available payment amount, OR the amount owing |
|
673 | + $payment_amount = min($available_payment_amount, $owing); |
|
674 | + // update $available_payment_amount |
|
675 | + $available_payment_amount -= $payment_amount; |
|
676 | + // calculate and set new REG_paid |
|
677 | + $registration->set_paid($registration->paid() + $payment_amount); |
|
678 | + // now save it |
|
679 | + $this->_apply_registration_payment($registration, $payment, $payment_amount); |
|
680 | + } |
|
681 | + return $available_payment_amount; |
|
682 | + } |
|
683 | + |
|
684 | + |
|
685 | + /** |
|
686 | + * update registration REG_paid field after successful payment and link registration with payment |
|
687 | + * |
|
688 | + * @param EE_Registration $registration |
|
689 | + * @param EE_Payment $payment |
|
690 | + * @param float $payment_amount |
|
691 | + * @return void |
|
692 | + * @throws EE_Error |
|
693 | + * @throws InvalidArgumentException |
|
694 | + * @throws InvalidDataTypeException |
|
695 | + * @throws InvalidInterfaceException |
|
696 | + */ |
|
697 | + protected function _apply_registration_payment( |
|
698 | + EE_Registration $registration, |
|
699 | + EE_Payment $payment, |
|
700 | + $payment_amount = 0.00 |
|
701 | + ) { |
|
702 | + // find any existing reg payment records for this registration and payment |
|
703 | + $existing_reg_payment = EEM_Registration_Payment::instance()->get_one( |
|
704 | + array(array('REG_ID' => $registration->ID(), 'PAY_ID' => $payment->ID())) |
|
705 | + ); |
|
706 | + // if existing registration payment exists |
|
707 | + if ($existing_reg_payment instanceof EE_Registration_Payment) { |
|
708 | + // then update that record |
|
709 | + $existing_reg_payment->set_amount($payment_amount); |
|
710 | + $existing_reg_payment->save(); |
|
711 | + } else { |
|
712 | + // or add new relation between registration and payment and set amount |
|
713 | + $registration->_add_relation_to( |
|
714 | + $payment, |
|
715 | + 'Payment', |
|
716 | + array('RPY_amount' => $payment_amount) |
|
717 | + ); |
|
718 | + // make it stick |
|
719 | + $registration->save(); |
|
720 | + } |
|
721 | + } |
|
722 | + |
|
723 | + |
|
724 | + /** |
|
725 | + * update registration REG_paid field after refund and link registration with payment |
|
726 | + * |
|
727 | + * @param EE_Registration $registration |
|
728 | + * @param EE_Payment $payment |
|
729 | + * @param float $available_refund_amount - IMPORTANT !!! SEND AVAILABLE REFUND AMOUNT AS A POSITIVE NUMBER |
|
730 | + * @return float |
|
731 | + * @throws EE_Error |
|
732 | + * @throws InvalidArgumentException |
|
733 | + * @throws RuntimeException |
|
734 | + * @throws InvalidDataTypeException |
|
735 | + * @throws InvalidInterfaceException |
|
736 | + */ |
|
737 | + public function process_registration_refund( |
|
738 | + EE_Registration $registration, |
|
739 | + EE_Payment $payment, |
|
740 | + $available_refund_amount = 0.00 |
|
741 | + ) { |
|
742 | + // EEH_Debug_Tools::printr( $payment->amount(), '$payment->amount()', __FILE__, __LINE__ ); |
|
743 | + if ($registration->paid() > 0) { |
|
744 | + // ensure $available_refund_amount is NOT negative |
|
745 | + $available_refund_amount = (float) abs($available_refund_amount); |
|
746 | + // don't allow refund amount to exceed the available payment amount, OR the amount paid |
|
747 | + $refund_amount = min($available_refund_amount, (float) $registration->paid()); |
|
748 | + // update $available_payment_amount |
|
749 | + $available_refund_amount -= $refund_amount; |
|
750 | + // calculate and set new REG_paid |
|
751 | + $registration->set_paid($registration->paid() - $refund_amount); |
|
752 | + // convert payment amount back to a negative value for storage in the db |
|
753 | + $refund_amount = (float) abs($refund_amount) * -1; |
|
754 | + // now save it |
|
755 | + $this->_apply_registration_payment($registration, $payment, $refund_amount); |
|
756 | + } |
|
757 | + return $available_refund_amount; |
|
758 | + } |
|
759 | + |
|
760 | + |
|
761 | + /** |
|
762 | + * Process payments and transaction after payment process completed. |
|
763 | + * ultimately this will send the TXN and payment details off so that notifications can be sent out. |
|
764 | + * if this request happens to be processing an IPN, |
|
765 | + * then we will also set the Payment Options Reg Step to completed, |
|
766 | + * and attempt to completely finalize the TXN if all of the other Reg Steps are completed as well. |
|
767 | + * |
|
768 | + * @param EE_Transaction $transaction |
|
769 | + * @param EE_Payment $payment |
|
770 | + * @param bool $IPN |
|
771 | + * @throws EE_Error |
|
772 | + * @throws InvalidArgumentException |
|
773 | + * @throws ReflectionException |
|
774 | + * @throws RuntimeException |
|
775 | + * @throws InvalidDataTypeException |
|
776 | + * @throws InvalidInterfaceException |
|
777 | + */ |
|
778 | + protected function _post_payment_processing(EE_Transaction $transaction, EE_Payment $payment, $IPN = false) |
|
779 | + { |
|
780 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
781 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
782 | + // is the Payment Options Reg Step completed ? |
|
783 | + $payment_options_step_completed = $transaction->reg_step_completed('payment_options'); |
|
784 | + // if the Payment Options Reg Step is completed... |
|
785 | + $revisit = $payment_options_step_completed === true; |
|
786 | + // then this is kinda sorta a revisit with regards to payments at least |
|
787 | + $transaction_processor->set_revisit($revisit); |
|
788 | + // if this is an IPN, let's consider the Payment Options Reg Step completed if not already |
|
789 | + if ( |
|
790 | + $IPN |
|
791 | + && $payment_options_step_completed !== true |
|
792 | + && ($payment->is_approved() || $payment->is_pending()) |
|
793 | + ) { |
|
794 | + $payment_options_step_completed = $transaction->set_reg_step_completed( |
|
795 | + 'payment_options' |
|
796 | + ); |
|
797 | + } |
|
798 | + // maybe update status, but don't save transaction just yet |
|
799 | + $transaction->update_status_based_on_total_paid(false); |
|
800 | + // check if 'finalize_registration' step has been completed... |
|
801 | + $finalized = $transaction->reg_step_completed('finalize_registration'); |
|
802 | + // if this is an IPN and the final step has not been initiated |
|
803 | + if ($IPN && $payment_options_step_completed && $finalized === false) { |
|
804 | + // and if it hasn't already been set as being started... |
|
805 | + $finalized = $transaction->set_reg_step_initiated('finalize_registration'); |
|
806 | + } |
|
807 | + $transaction->save(); |
|
808 | + // because the above will return false if the final step was not fully completed, we need to check again... |
|
809 | + if ($IPN && $finalized !== false) { |
|
810 | + // and if we are all good to go, then send out notifications |
|
811 | + add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true'); |
|
812 | + // ok, now process the transaction according to the payment |
|
813 | + $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
814 | + $transaction, |
|
815 | + $payment |
|
816 | + ); |
|
817 | + } |
|
818 | + // DEBUG LOG |
|
819 | + $payment_method = $payment->payment_method(); |
|
820 | + if ($payment_method instanceof EE_Payment_Method) { |
|
821 | + $payment_method_type_obj = $payment_method->type_obj(); |
|
822 | + if ($payment_method_type_obj instanceof EE_PMT_Base) { |
|
823 | + $gateway = $payment_method_type_obj->get_gateway(); |
|
824 | + if ($gateway instanceof EE_Gateway) { |
|
825 | + $gateway->log( |
|
826 | + array( |
|
827 | + 'message' => (string) esc_html__('Post Payment Transaction Details', 'event_espresso'), |
|
828 | + 'transaction' => $transaction->model_field_array(), |
|
829 | + 'finalized' => $finalized, |
|
830 | + 'IPN' => $IPN, |
|
831 | + 'deliver_notifications' => has_filter( |
|
832 | + 'FHEE__EED_Messages___maybe_registration__deliver_notifications' |
|
833 | + ), |
|
834 | + ), |
|
835 | + $payment |
|
836 | + ); |
|
837 | + } |
|
838 | + } |
|
839 | + } |
|
840 | + } |
|
841 | + |
|
842 | + |
|
843 | + /** |
|
844 | + * Force posts to PayPal to use TLS v1.2. See: |
|
845 | + * https://core.trac.wordpress.org/ticket/36320 |
|
846 | + * https://core.trac.wordpress.org/ticket/34924#comment:15 |
|
847 | + * https://www.paypal-knowledge.com/infocenter/index?page=content&widgetview=true&id=FAQ1914&viewlocale=en_US |
|
848 | + * This will affect PayPal standard, pro, express, and Payflow. |
|
849 | + * |
|
850 | + * @param $handle |
|
851 | + * @param $r |
|
852 | + * @param $url |
|
853 | + */ |
|
854 | + public static function _curl_requests_to_paypal_use_tls($handle, $r, $url) |
|
855 | + { |
|
856 | + if (strpos($url, 'https://') !== false && strpos($url, '.paypal.com') !== false) { |
|
857 | + // Use the value of the constant CURL_SSLVERSION_TLSv1 = 1 |
|
858 | + // instead of the constant because it might not be defined |
|
859 | + curl_setopt($handle, CURLOPT_SSLVERSION, 6); |
|
860 | + } |
|
861 | + } |
|
862 | 862 | } |
@@ -68,7 +68,7 @@ discard block |
||
68 | 68 | public static function validateType($type) |
69 | 69 | { |
70 | 70 | $types = CoffeeMaker::getTypes(); |
71 | - if (! in_array($type, $types, true)) { |
|
71 | + if ( ! in_array($type, $types, true)) { |
|
72 | 72 | throw new InvalidIdentifierException( |
73 | 73 | is_object($type) ? get_class($type) : gettype($type), |
74 | 74 | esc_html__( |
@@ -151,7 +151,7 @@ discard block |
||
151 | 151 | protected function resolveClassAndFilepath(RecipeInterface $recipe) |
152 | 152 | { |
153 | 153 | $paths = $recipe->paths(); |
154 | - if (! empty($paths)) { |
|
154 | + if ( ! empty($paths)) { |
|
155 | 155 | foreach ($paths as $path) { |
156 | 156 | if (strpos($path, '*') === false && is_readable($path)) { |
157 | 157 | require_once($path); |
@@ -17,156 +17,156 @@ |
||
17 | 17 | */ |
18 | 18 | abstract class CoffeeMaker implements CoffeeMakerInterface |
19 | 19 | { |
20 | - /** |
|
21 | - * Indicates that CoffeeMaker should construct a NEW entity instance from the provided arguments (if given) |
|
22 | - */ |
|
23 | - const BREW_NEW = 'new'; |
|
24 | - |
|
25 | - /** |
|
26 | - * Indicates that CoffeeMaker should always return a SHARED instance |
|
27 | - */ |
|
28 | - const BREW_SHARED = 'shared'; |
|
29 | - |
|
30 | - /** |
|
31 | - * Indicates that CoffeeMaker should only load the file/class/interface but NOT instantiate |
|
32 | - */ |
|
33 | - const BREW_LOAD_ONLY = 'load_only'; |
|
34 | - |
|
35 | - |
|
36 | - /** |
|
37 | - * @var CoffeePotInterface $coffee_pot |
|
38 | - */ |
|
39 | - private $coffee_pot; |
|
40 | - |
|
41 | - /** |
|
42 | - * @var DependencyInjector $injector |
|
43 | - */ |
|
44 | - private $injector; |
|
45 | - |
|
46 | - |
|
47 | - /** |
|
48 | - * @return array |
|
49 | - */ |
|
50 | - public static function getTypes() |
|
51 | - { |
|
52 | - return (array) apply_filters( |
|
53 | - 'FHEE__EventEspresso\core\services\container\CoffeeMaker__getTypes', |
|
54 | - array( |
|
55 | - CoffeeMaker::BREW_NEW, |
|
56 | - CoffeeMaker::BREW_SHARED, |
|
57 | - CoffeeMaker::BREW_LOAD_ONLY, |
|
58 | - ) |
|
59 | - ); |
|
60 | - } |
|
61 | - |
|
62 | - |
|
63 | - /** |
|
64 | - * @param $type |
|
65 | - * @throws \EventEspresso\core\exceptions\InvalidIdentifierException |
|
66 | - */ |
|
67 | - public static function validateType($type) |
|
68 | - { |
|
69 | - $types = CoffeeMaker::getTypes(); |
|
70 | - if (! in_array($type, $types, true)) { |
|
71 | - throw new InvalidIdentifierException( |
|
72 | - is_object($type) ? get_class($type) : gettype($type), |
|
73 | - esc_html__( |
|
74 | - 'recipe type (one of the class constants on \EventEspresso\core\services\container\CoffeeMaker)', |
|
75 | - 'event_espresso' |
|
76 | - ) |
|
77 | - ); |
|
78 | - } |
|
79 | - return $type; |
|
80 | - } |
|
81 | - |
|
82 | - |
|
83 | - /** |
|
84 | - * CoffeeMaker constructor. |
|
85 | - * |
|
86 | - * @param CoffeePotInterface $coffee_pot |
|
87 | - * @param InjectorInterface $injector |
|
88 | - */ |
|
89 | - public function __construct(CoffeePotInterface $coffee_pot, InjectorInterface $injector) |
|
90 | - { |
|
91 | - $this->coffee_pot = $coffee_pot; |
|
92 | - $this->injector = $injector; |
|
93 | - } |
|
94 | - |
|
95 | - |
|
96 | - /** |
|
97 | - * @return \EventEspresso\core\services\container\CoffeePotInterface |
|
98 | - */ |
|
99 | - protected function coffeePot() |
|
100 | - { |
|
101 | - return $this->coffee_pot; |
|
102 | - } |
|
103 | - |
|
104 | - |
|
105 | - /** |
|
106 | - * @return \EventEspresso\core\services\container\DependencyInjector |
|
107 | - */ |
|
108 | - protected function injector() |
|
109 | - { |
|
110 | - return $this->injector; |
|
111 | - } |
|
112 | - |
|
113 | - |
|
114 | - /** |
|
115 | - * Examines the constructor to determine which method should be used for instantiation |
|
116 | - * |
|
117 | - * @param \ReflectionClass $reflector |
|
118 | - * @return mixed |
|
119 | - * @throws InstantiationException |
|
120 | - */ |
|
121 | - protected function resolveInstantiationMethod(\ReflectionClass $reflector) |
|
122 | - { |
|
123 | - if ($reflector->getConstructor() === null) { |
|
124 | - return 'NewInstance'; |
|
125 | - } |
|
126 | - if ($reflector->isInstantiable()) { |
|
127 | - return 'NewInstanceArgs'; |
|
128 | - } |
|
129 | - if (method_exists($reflector->getName(), 'instance')) { |
|
130 | - return 'instance'; |
|
131 | - } |
|
132 | - if (method_exists($reflector->getName(), 'new_instance')) { |
|
133 | - return 'new_instance'; |
|
134 | - } |
|
135 | - if (method_exists($reflector->getName(), 'new_instance_from_db')) { |
|
136 | - return 'new_instance_from_db'; |
|
137 | - } |
|
138 | - throw new InstantiationException($reflector->getName()); |
|
139 | - } |
|
140 | - |
|
141 | - |
|
142 | - /** |
|
143 | - * Ensures files for classes that are not PSR-4 compatible are loaded |
|
144 | - * and then verifies that classes exist where applicable |
|
145 | - * |
|
146 | - * @param RecipeInterface $recipe |
|
147 | - * @return bool |
|
148 | - * @throws InvalidClassException |
|
149 | - */ |
|
150 | - protected function resolveClassAndFilepath(RecipeInterface $recipe) |
|
151 | - { |
|
152 | - $paths = $recipe->paths(); |
|
153 | - if (! empty($paths)) { |
|
154 | - foreach ($paths as $path) { |
|
155 | - if (strpos($path, '*') === false && is_readable($path)) { |
|
156 | - require_once($path); |
|
157 | - } |
|
158 | - } |
|
159 | - } |
|
160 | - // re: using "false" for class_exists() second param: |
|
161 | - // if a class name is not already known to PHP, then class_exists() will run through |
|
162 | - // all of the registered spl_autoload functions until it either finds the class, |
|
163 | - // or gets to the end of the registered spl_autoload functions. |
|
164 | - // When the second parameter is true, it will also attempt to load the class file, |
|
165 | - // but it will also trigger an error if the class can not be loaded. |
|
166 | - // We don't want that extra error in the mix, so we have set the second param to "false" |
|
167 | - if ($recipe->type() !== CoffeeMaker::BREW_LOAD_ONLY && ! class_exists($recipe->fqcn(), false)) { |
|
168 | - throw new InvalidClassException($recipe->identifier()); |
|
169 | - } |
|
170 | - return true; |
|
171 | - } |
|
20 | + /** |
|
21 | + * Indicates that CoffeeMaker should construct a NEW entity instance from the provided arguments (if given) |
|
22 | + */ |
|
23 | + const BREW_NEW = 'new'; |
|
24 | + |
|
25 | + /** |
|
26 | + * Indicates that CoffeeMaker should always return a SHARED instance |
|
27 | + */ |
|
28 | + const BREW_SHARED = 'shared'; |
|
29 | + |
|
30 | + /** |
|
31 | + * Indicates that CoffeeMaker should only load the file/class/interface but NOT instantiate |
|
32 | + */ |
|
33 | + const BREW_LOAD_ONLY = 'load_only'; |
|
34 | + |
|
35 | + |
|
36 | + /** |
|
37 | + * @var CoffeePotInterface $coffee_pot |
|
38 | + */ |
|
39 | + private $coffee_pot; |
|
40 | + |
|
41 | + /** |
|
42 | + * @var DependencyInjector $injector |
|
43 | + */ |
|
44 | + private $injector; |
|
45 | + |
|
46 | + |
|
47 | + /** |
|
48 | + * @return array |
|
49 | + */ |
|
50 | + public static function getTypes() |
|
51 | + { |
|
52 | + return (array) apply_filters( |
|
53 | + 'FHEE__EventEspresso\core\services\container\CoffeeMaker__getTypes', |
|
54 | + array( |
|
55 | + CoffeeMaker::BREW_NEW, |
|
56 | + CoffeeMaker::BREW_SHARED, |
|
57 | + CoffeeMaker::BREW_LOAD_ONLY, |
|
58 | + ) |
|
59 | + ); |
|
60 | + } |
|
61 | + |
|
62 | + |
|
63 | + /** |
|
64 | + * @param $type |
|
65 | + * @throws \EventEspresso\core\exceptions\InvalidIdentifierException |
|
66 | + */ |
|
67 | + public static function validateType($type) |
|
68 | + { |
|
69 | + $types = CoffeeMaker::getTypes(); |
|
70 | + if (! in_array($type, $types, true)) { |
|
71 | + throw new InvalidIdentifierException( |
|
72 | + is_object($type) ? get_class($type) : gettype($type), |
|
73 | + esc_html__( |
|
74 | + 'recipe type (one of the class constants on \EventEspresso\core\services\container\CoffeeMaker)', |
|
75 | + 'event_espresso' |
|
76 | + ) |
|
77 | + ); |
|
78 | + } |
|
79 | + return $type; |
|
80 | + } |
|
81 | + |
|
82 | + |
|
83 | + /** |
|
84 | + * CoffeeMaker constructor. |
|
85 | + * |
|
86 | + * @param CoffeePotInterface $coffee_pot |
|
87 | + * @param InjectorInterface $injector |
|
88 | + */ |
|
89 | + public function __construct(CoffeePotInterface $coffee_pot, InjectorInterface $injector) |
|
90 | + { |
|
91 | + $this->coffee_pot = $coffee_pot; |
|
92 | + $this->injector = $injector; |
|
93 | + } |
|
94 | + |
|
95 | + |
|
96 | + /** |
|
97 | + * @return \EventEspresso\core\services\container\CoffeePotInterface |
|
98 | + */ |
|
99 | + protected function coffeePot() |
|
100 | + { |
|
101 | + return $this->coffee_pot; |
|
102 | + } |
|
103 | + |
|
104 | + |
|
105 | + /** |
|
106 | + * @return \EventEspresso\core\services\container\DependencyInjector |
|
107 | + */ |
|
108 | + protected function injector() |
|
109 | + { |
|
110 | + return $this->injector; |
|
111 | + } |
|
112 | + |
|
113 | + |
|
114 | + /** |
|
115 | + * Examines the constructor to determine which method should be used for instantiation |
|
116 | + * |
|
117 | + * @param \ReflectionClass $reflector |
|
118 | + * @return mixed |
|
119 | + * @throws InstantiationException |
|
120 | + */ |
|
121 | + protected function resolveInstantiationMethod(\ReflectionClass $reflector) |
|
122 | + { |
|
123 | + if ($reflector->getConstructor() === null) { |
|
124 | + return 'NewInstance'; |
|
125 | + } |
|
126 | + if ($reflector->isInstantiable()) { |
|
127 | + return 'NewInstanceArgs'; |
|
128 | + } |
|
129 | + if (method_exists($reflector->getName(), 'instance')) { |
|
130 | + return 'instance'; |
|
131 | + } |
|
132 | + if (method_exists($reflector->getName(), 'new_instance')) { |
|
133 | + return 'new_instance'; |
|
134 | + } |
|
135 | + if (method_exists($reflector->getName(), 'new_instance_from_db')) { |
|
136 | + return 'new_instance_from_db'; |
|
137 | + } |
|
138 | + throw new InstantiationException($reflector->getName()); |
|
139 | + } |
|
140 | + |
|
141 | + |
|
142 | + /** |
|
143 | + * Ensures files for classes that are not PSR-4 compatible are loaded |
|
144 | + * and then verifies that classes exist where applicable |
|
145 | + * |
|
146 | + * @param RecipeInterface $recipe |
|
147 | + * @return bool |
|
148 | + * @throws InvalidClassException |
|
149 | + */ |
|
150 | + protected function resolveClassAndFilepath(RecipeInterface $recipe) |
|
151 | + { |
|
152 | + $paths = $recipe->paths(); |
|
153 | + if (! empty($paths)) { |
|
154 | + foreach ($paths as $path) { |
|
155 | + if (strpos($path, '*') === false && is_readable($path)) { |
|
156 | + require_once($path); |
|
157 | + } |
|
158 | + } |
|
159 | + } |
|
160 | + // re: using "false" for class_exists() second param: |
|
161 | + // if a class name is not already known to PHP, then class_exists() will run through |
|
162 | + // all of the registered spl_autoload functions until it either finds the class, |
|
163 | + // or gets to the end of the registered spl_autoload functions. |
|
164 | + // When the second parameter is true, it will also attempt to load the class file, |
|
165 | + // but it will also trigger an error if the class can not be loaded. |
|
166 | + // We don't want that extra error in the mix, so we have set the second param to "false" |
|
167 | + if ($recipe->type() !== CoffeeMaker::BREW_LOAD_ONLY && ! class_exists($recipe->fqcn(), false)) { |
|
168 | + throw new InvalidClassException($recipe->identifier()); |
|
169 | + } |
|
170 | + return true; |
|
171 | + } |
|
172 | 172 | } |
@@ -189,7 +189,7 @@ discard block |
||
189 | 189 | */ |
190 | 190 | public function setIdentifier($identifier) |
191 | 191 | { |
192 | - if (! is_string($identifier) || empty($identifier)) { |
|
192 | + if ( ! is_string($identifier) || empty($identifier)) { |
|
193 | 193 | throw new InvalidIdentifierException( |
194 | 194 | is_object($identifier) ? get_class($identifier) : gettype($identifier), |
195 | 195 | esc_html__('class identifier (typically a \Fully\Qualified\ClassName)', 'event_espresso') |
@@ -216,7 +216,7 @@ discard block |
||
216 | 216 | public function setFqcn($fqcn) |
217 | 217 | { |
218 | 218 | $fqcn = ! empty($fqcn) ? $fqcn : $this->identifier; |
219 | - if (! is_string($fqcn)) { |
|
219 | + if ( ! is_string($fqcn)) { |
|
220 | 220 | throw new InvalidDataTypeException( |
221 | 221 | '$fqcn', |
222 | 222 | is_object($fqcn) ? get_class($fqcn) : gettype($fqcn), |
@@ -247,7 +247,7 @@ discard block |
||
247 | 247 | if (empty($ingredients)) { |
248 | 248 | return; |
249 | 249 | } |
250 | - if (! is_array($ingredients)) { |
|
250 | + if ( ! is_array($ingredients)) { |
|
251 | 251 | throw new InvalidDataTypeException( |
252 | 252 | '$ingredients', |
253 | 253 | is_object($ingredients) ? get_class($ingredients) : gettype($ingredients), |
@@ -279,7 +279,7 @@ discard block |
||
279 | 279 | if (empty($filters)) { |
280 | 280 | return; |
281 | 281 | } |
282 | - if (! is_array($filters)) { |
|
282 | + if ( ! is_array($filters)) { |
|
283 | 283 | throw new InvalidDataTypeException( |
284 | 284 | '$filters', |
285 | 285 | is_object($filters) ? get_class($filters) : gettype($filters), |
@@ -306,7 +306,7 @@ discard block |
||
306 | 306 | if (empty($paths)) { |
307 | 307 | return; |
308 | 308 | } |
309 | - if (! (is_string($paths) || is_array($paths))) { |
|
309 | + if ( ! (is_string($paths) || is_array($paths))) { |
|
310 | 310 | throw new InvalidDataTypeException( |
311 | 311 | '$path', |
312 | 312 | is_object($paths) ? get_class($paths) : gettype($paths), |
@@ -18,311 +18,311 @@ |
||
18 | 18 | */ |
19 | 19 | class Recipe implements RecipeInterface |
20 | 20 | { |
21 | - /** |
|
22 | - * A default Recipe to use if none is specified for a class |
|
23 | - */ |
|
24 | - const DEFAULT_ID = '*'; |
|
25 | - |
|
26 | - /** |
|
27 | - * Identifier for the entity class to be constructed. |
|
28 | - * Typically a Fully Qualified Class Name |
|
29 | - * |
|
30 | - * @var string $identifier |
|
31 | - */ |
|
32 | - private $identifier; |
|
33 | - |
|
34 | - /** |
|
35 | - * Fully Qualified Class Name |
|
36 | - * |
|
37 | - * @var string $fqcn |
|
38 | - */ |
|
39 | - private $fqcn; |
|
40 | - |
|
41 | - /** |
|
42 | - * a dependency class map array |
|
43 | - * If a Recipe is for a single class (or group of classes that shares the EXACT SAME constructor arguments), |
|
44 | - * and that class type hints for an interface, then this property allows you to configure what dependencies |
|
45 | - * get used when instantiating the class. |
|
46 | - * For example: |
|
47 | - * There's a class called Coffee, and one of its constructor arguments is BeanInterface |
|
48 | - * There are two implementations of BeanInterface: HonduranBean, and KenyanBean |
|
49 | - * We want one Coffee object to use HonduranBean for its BeanInterface, |
|
50 | - * and the 2nd Coffee object to use KenyanBean for its BeanInterface. |
|
51 | - * To do this, we need to create two Recipes: |
|
52 | - * one with an identifier of 'HonduranCoffee' using the following ingredients : |
|
53 | - * array('BeanInterface' => 'HonduranBean') |
|
54 | - * and the other with an identifier of 'KenyanCoffee' using the following ingredients : |
|
55 | - * array('BeanInterface' => 'KenyanBean') |
|
56 | - * Then, whenever the CoffeeShop brews an instance of HonduranCoffee, |
|
57 | - * an instance of HonduranBean will get injected for the BeanInterface dependency, |
|
58 | - * and whenever the CoffeeShop brews an instance of KenyanCoffee, |
|
59 | - * an instance of KenyanBean will get injected for the BeanInterface dependency |
|
60 | - * |
|
61 | - * @var array $ingredients |
|
62 | - */ |
|
63 | - private $ingredients = array(); |
|
64 | - |
|
65 | - /** |
|
66 | - * one of the class constants from CoffeeShop: |
|
67 | - * CoffeeMaker::BREW_NEW - creates a new instance |
|
68 | - * CoffeeMaker::BREW_SHARED - creates a shared instance |
|
69 | - * CoffeeMaker::BREW_LOAD_ONLY - loads but does not instantiate |
|
70 | - * |
|
71 | - * @var string $type |
|
72 | - */ |
|
73 | - private $type; |
|
74 | - |
|
75 | - /** |
|
76 | - * class name aliases - typically a Fully Qualified Interface that the class implements |
|
77 | - * identifiers passed to the CoffeeShop will be run through the filters to find the correct class name |
|
78 | - * |
|
79 | - * @var array $filters |
|
80 | - */ |
|
81 | - private $filters = array(); |
|
82 | - |
|
83 | - /** |
|
84 | - * array of full server filepaths to files that may contain the class |
|
85 | - * |
|
86 | - * @var array $paths |
|
87 | - */ |
|
88 | - private $paths = array(); |
|
89 | - |
|
90 | - |
|
91 | - /** |
|
92 | - * Recipe constructor. |
|
93 | - * |
|
94 | - * @param string $identifier class identifier, can be an alias, or FQCN, or whatever |
|
95 | - * @param string $fqcn \Fully\Qualified\ClassName, optional if $identifier is FQCN |
|
96 | - * @param array $ingredients array of dependencies that can not be resolved automatically, |
|
97 | - * used for resolving concrete classes for type hinted interfaces |
|
98 | - * for the dependencies of THIS class |
|
99 | - * @param string $type recipe type: one of the class constants on |
|
100 | - * \EventEspresso\core\services\container\CoffeeMaker |
|
101 | - * @param array $filters array of class aliases, or class interfaces |
|
102 | - * this works somewhat opposite to the $ingredients array above, |
|
103 | - * in that this array specifies interfaces or aliases |
|
104 | - * that this Recipe can be used for when resolving OTHER class's dependencies |
|
105 | - * @param array $paths if class can not be loaded via PSR-4 autoloading, |
|
106 | - * then supply a filepath, or array of filepaths, so that it can be included |
|
107 | - * @throws InvalidIdentifierException |
|
108 | - * @throws RuntimeException |
|
109 | - * @throws InvalidInterfaceException |
|
110 | - * @throws InvalidClassException |
|
111 | - * @throws InvalidDataTypeException |
|
112 | - */ |
|
113 | - public function __construct( |
|
114 | - $identifier, |
|
115 | - $fqcn = '', |
|
116 | - array $filters = array(), |
|
117 | - array $ingredients = array(), |
|
118 | - $type = CoffeeMaker::BREW_NEW, |
|
119 | - array $paths = array() |
|
120 | - ) { |
|
121 | - $this->setIdentifier($identifier); |
|
122 | - $this->setFilters($filters); |
|
123 | - $this->setIngredients($ingredients); |
|
124 | - $this->setType($type); |
|
125 | - $this->setPaths($paths); |
|
126 | - $this->setFqcn($fqcn); |
|
127 | - } |
|
128 | - |
|
129 | - |
|
130 | - /** |
|
131 | - * @return string |
|
132 | - */ |
|
133 | - public function identifier() |
|
134 | - { |
|
135 | - return $this->identifier; |
|
136 | - } |
|
137 | - |
|
138 | - |
|
139 | - /** |
|
140 | - * @return string |
|
141 | - */ |
|
142 | - public function fqcn() |
|
143 | - { |
|
144 | - return $this->fqcn; |
|
145 | - } |
|
146 | - |
|
147 | - |
|
148 | - /** |
|
149 | - * @return array |
|
150 | - */ |
|
151 | - public function filters() |
|
152 | - { |
|
153 | - return $this->filters; |
|
154 | - } |
|
155 | - |
|
156 | - |
|
157 | - /** |
|
158 | - * @return array |
|
159 | - */ |
|
160 | - public function ingredients() |
|
161 | - { |
|
162 | - return $this->ingredients; |
|
163 | - } |
|
164 | - |
|
165 | - |
|
166 | - /** |
|
167 | - * @return string |
|
168 | - */ |
|
169 | - public function type() |
|
170 | - { |
|
171 | - return $this->type; |
|
172 | - } |
|
173 | - |
|
174 | - |
|
175 | - /** |
|
176 | - * @return array |
|
177 | - */ |
|
178 | - public function paths() |
|
179 | - { |
|
180 | - return $this->paths; |
|
181 | - } |
|
182 | - |
|
183 | - |
|
184 | - /** |
|
185 | - * @param string $identifier Identifier for the entity class that the Recipe applies to |
|
186 | - * Typically a Fully Qualified Class Name |
|
187 | - * @throws InvalidIdentifierException |
|
188 | - */ |
|
189 | - public function setIdentifier($identifier) |
|
190 | - { |
|
191 | - if (! is_string($identifier) || empty($identifier)) { |
|
192 | - throw new InvalidIdentifierException( |
|
193 | - is_object($identifier) ? get_class($identifier) : gettype($identifier), |
|
194 | - esc_html__('class identifier (typically a \Fully\Qualified\ClassName)', 'event_espresso') |
|
195 | - ); |
|
196 | - } |
|
197 | - $this->identifier = $identifier; |
|
198 | - } |
|
199 | - |
|
200 | - |
|
201 | - /** |
|
202 | - * Ensures incoming string is a valid Fully Qualified Class Name, |
|
203 | - * except if this is the default wildcard Recipe ( * ), |
|
204 | - * or it's NOT an actual FQCN because the Recipe is using filepaths |
|
205 | - * for classes that are not PSR-4 compatible |
|
206 | - * PLZ NOTE: |
|
207 | - * Recipe::setFqcn() has a check to see if Recipe::$paths is empty or not, |
|
208 | - * therefore you should always call Recipe::setPaths() before Recipe::setFqcn() |
|
209 | - * |
|
210 | - * @param string $fqcn |
|
211 | - * @throws InvalidDataTypeException |
|
212 | - * @throws InvalidClassException |
|
213 | - * @throws InvalidInterfaceException |
|
214 | - */ |
|
215 | - public function setFqcn($fqcn) |
|
216 | - { |
|
217 | - $fqcn = ! empty($fqcn) ? $fqcn : $this->identifier; |
|
218 | - if (! is_string($fqcn)) { |
|
219 | - throw new InvalidDataTypeException( |
|
220 | - '$fqcn', |
|
221 | - is_object($fqcn) ? get_class($fqcn) : gettype($fqcn), |
|
222 | - esc_html__('string (Fully\Qualified\ClassName)', 'event_espresso') |
|
223 | - ); |
|
224 | - } |
|
225 | - $fqcn = ltrim($fqcn, '\\'); |
|
226 | - if ( |
|
227 | - $fqcn !== Recipe::DEFAULT_ID |
|
228 | - && ! empty($fqcn) |
|
229 | - && empty($this->paths) |
|
230 | - && ! (class_exists($fqcn) || interface_exists($fqcn)) |
|
231 | - ) { |
|
232 | - throw new InvalidClassException($fqcn); |
|
233 | - } |
|
234 | - $this->fqcn = $fqcn; |
|
235 | - } |
|
236 | - |
|
237 | - |
|
238 | - /** |
|
239 | - * @param array $ingredients an array of dependencies where keys are the aliases and values are the FQCNs |
|
240 | - * example: |
|
241 | - * array( 'ClassInterface' => 'Fully\Qualified\ClassName' ) |
|
242 | - * @throws InvalidDataTypeException |
|
243 | - */ |
|
244 | - public function setIngredients(array $ingredients) |
|
245 | - { |
|
246 | - if (empty($ingredients)) { |
|
247 | - return; |
|
248 | - } |
|
249 | - if (! is_array($ingredients)) { |
|
250 | - throw new InvalidDataTypeException( |
|
251 | - '$ingredients', |
|
252 | - is_object($ingredients) ? get_class($ingredients) : gettype($ingredients), |
|
253 | - esc_html__('array of class dependencies', 'event_espresso') |
|
254 | - ); |
|
255 | - } |
|
256 | - $this->ingredients = array_merge($this->ingredients, $ingredients); |
|
257 | - } |
|
258 | - |
|
259 | - |
|
260 | - /** |
|
261 | - * @param string $type one of the class constants returned from CoffeeMaker::getTypes() |
|
262 | - * @throws InvalidIdentifierException |
|
263 | - */ |
|
264 | - public function setType($type = CoffeeMaker::BREW_NEW) |
|
265 | - { |
|
266 | - $this->type = CoffeeMaker::validateType($type); |
|
267 | - } |
|
268 | - |
|
269 | - |
|
270 | - /** |
|
271 | - * @param array $filters an array of filters where keys are the aliases and values are the FQCNs |
|
272 | - * example: |
|
273 | - * array( 'ClassInterface' => 'Fully\Qualified\ClassName' ) |
|
274 | - * @throws InvalidDataTypeException |
|
275 | - */ |
|
276 | - public function setFilters(array $filters) |
|
277 | - { |
|
278 | - if (empty($filters)) { |
|
279 | - return; |
|
280 | - } |
|
281 | - if (! is_array($filters)) { |
|
282 | - throw new InvalidDataTypeException( |
|
283 | - '$filters', |
|
284 | - is_object($filters) ? get_class($filters) : gettype($filters), |
|
285 | - esc_html__('array of class aliases', 'event_espresso') |
|
286 | - ); |
|
287 | - } |
|
288 | - $this->filters = array_merge($this->filters, $filters); |
|
289 | - } |
|
290 | - |
|
291 | - |
|
292 | - /** |
|
293 | - * Ensures incoming paths is a valid filepath, or array of valid filepaths, |
|
294 | - * and merges them in with any existing filepaths |
|
295 | - * PLZ NOTE: |
|
296 | - * Recipe::setFqcn() has a check to see if Recipe::$paths is empty or not, |
|
297 | - * therefore you should always call Recipe::setPaths() before Recipe::setFqcn() |
|
298 | - * |
|
299 | - * @param string|array $paths |
|
300 | - * @throws RuntimeException |
|
301 | - * @throws InvalidDataTypeException |
|
302 | - */ |
|
303 | - public function setPaths($paths = array()) |
|
304 | - { |
|
305 | - if (empty($paths)) { |
|
306 | - return; |
|
307 | - } |
|
308 | - if (! (is_string($paths) || is_array($paths))) { |
|
309 | - throw new InvalidDataTypeException( |
|
310 | - '$path', |
|
311 | - is_object($paths) ? get_class($paths) : gettype($paths), |
|
312 | - esc_html__('string or array of strings (full server filepath(s))', 'event_espresso') |
|
313 | - ); |
|
314 | - } |
|
315 | - $paths = (array) $paths; |
|
316 | - foreach ($paths as $path) { |
|
317 | - if (strpos($path, '*') === false && ! is_readable($path)) { |
|
318 | - throw new RuntimeException( |
|
319 | - sprintf( |
|
320 | - esc_html__('The following filepath is not readable: "%1$s"', 'event_espresso'), |
|
321 | - $path |
|
322 | - ) |
|
323 | - ); |
|
324 | - } |
|
325 | - } |
|
326 | - $this->paths = array_merge($this->paths, $paths); |
|
327 | - } |
|
21 | + /** |
|
22 | + * A default Recipe to use if none is specified for a class |
|
23 | + */ |
|
24 | + const DEFAULT_ID = '*'; |
|
25 | + |
|
26 | + /** |
|
27 | + * Identifier for the entity class to be constructed. |
|
28 | + * Typically a Fully Qualified Class Name |
|
29 | + * |
|
30 | + * @var string $identifier |
|
31 | + */ |
|
32 | + private $identifier; |
|
33 | + |
|
34 | + /** |
|
35 | + * Fully Qualified Class Name |
|
36 | + * |
|
37 | + * @var string $fqcn |
|
38 | + */ |
|
39 | + private $fqcn; |
|
40 | + |
|
41 | + /** |
|
42 | + * a dependency class map array |
|
43 | + * If a Recipe is for a single class (or group of classes that shares the EXACT SAME constructor arguments), |
|
44 | + * and that class type hints for an interface, then this property allows you to configure what dependencies |
|
45 | + * get used when instantiating the class. |
|
46 | + * For example: |
|
47 | + * There's a class called Coffee, and one of its constructor arguments is BeanInterface |
|
48 | + * There are two implementations of BeanInterface: HonduranBean, and KenyanBean |
|
49 | + * We want one Coffee object to use HonduranBean for its BeanInterface, |
|
50 | + * and the 2nd Coffee object to use KenyanBean for its BeanInterface. |
|
51 | + * To do this, we need to create two Recipes: |
|
52 | + * one with an identifier of 'HonduranCoffee' using the following ingredients : |
|
53 | + * array('BeanInterface' => 'HonduranBean') |
|
54 | + * and the other with an identifier of 'KenyanCoffee' using the following ingredients : |
|
55 | + * array('BeanInterface' => 'KenyanBean') |
|
56 | + * Then, whenever the CoffeeShop brews an instance of HonduranCoffee, |
|
57 | + * an instance of HonduranBean will get injected for the BeanInterface dependency, |
|
58 | + * and whenever the CoffeeShop brews an instance of KenyanCoffee, |
|
59 | + * an instance of KenyanBean will get injected for the BeanInterface dependency |
|
60 | + * |
|
61 | + * @var array $ingredients |
|
62 | + */ |
|
63 | + private $ingredients = array(); |
|
64 | + |
|
65 | + /** |
|
66 | + * one of the class constants from CoffeeShop: |
|
67 | + * CoffeeMaker::BREW_NEW - creates a new instance |
|
68 | + * CoffeeMaker::BREW_SHARED - creates a shared instance |
|
69 | + * CoffeeMaker::BREW_LOAD_ONLY - loads but does not instantiate |
|
70 | + * |
|
71 | + * @var string $type |
|
72 | + */ |
|
73 | + private $type; |
|
74 | + |
|
75 | + /** |
|
76 | + * class name aliases - typically a Fully Qualified Interface that the class implements |
|
77 | + * identifiers passed to the CoffeeShop will be run through the filters to find the correct class name |
|
78 | + * |
|
79 | + * @var array $filters |
|
80 | + */ |
|
81 | + private $filters = array(); |
|
82 | + |
|
83 | + /** |
|
84 | + * array of full server filepaths to files that may contain the class |
|
85 | + * |
|
86 | + * @var array $paths |
|
87 | + */ |
|
88 | + private $paths = array(); |
|
89 | + |
|
90 | + |
|
91 | + /** |
|
92 | + * Recipe constructor. |
|
93 | + * |
|
94 | + * @param string $identifier class identifier, can be an alias, or FQCN, or whatever |
|
95 | + * @param string $fqcn \Fully\Qualified\ClassName, optional if $identifier is FQCN |
|
96 | + * @param array $ingredients array of dependencies that can not be resolved automatically, |
|
97 | + * used for resolving concrete classes for type hinted interfaces |
|
98 | + * for the dependencies of THIS class |
|
99 | + * @param string $type recipe type: one of the class constants on |
|
100 | + * \EventEspresso\core\services\container\CoffeeMaker |
|
101 | + * @param array $filters array of class aliases, or class interfaces |
|
102 | + * this works somewhat opposite to the $ingredients array above, |
|
103 | + * in that this array specifies interfaces or aliases |
|
104 | + * that this Recipe can be used for when resolving OTHER class's dependencies |
|
105 | + * @param array $paths if class can not be loaded via PSR-4 autoloading, |
|
106 | + * then supply a filepath, or array of filepaths, so that it can be included |
|
107 | + * @throws InvalidIdentifierException |
|
108 | + * @throws RuntimeException |
|
109 | + * @throws InvalidInterfaceException |
|
110 | + * @throws InvalidClassException |
|
111 | + * @throws InvalidDataTypeException |
|
112 | + */ |
|
113 | + public function __construct( |
|
114 | + $identifier, |
|
115 | + $fqcn = '', |
|
116 | + array $filters = array(), |
|
117 | + array $ingredients = array(), |
|
118 | + $type = CoffeeMaker::BREW_NEW, |
|
119 | + array $paths = array() |
|
120 | + ) { |
|
121 | + $this->setIdentifier($identifier); |
|
122 | + $this->setFilters($filters); |
|
123 | + $this->setIngredients($ingredients); |
|
124 | + $this->setType($type); |
|
125 | + $this->setPaths($paths); |
|
126 | + $this->setFqcn($fqcn); |
|
127 | + } |
|
128 | + |
|
129 | + |
|
130 | + /** |
|
131 | + * @return string |
|
132 | + */ |
|
133 | + public function identifier() |
|
134 | + { |
|
135 | + return $this->identifier; |
|
136 | + } |
|
137 | + |
|
138 | + |
|
139 | + /** |
|
140 | + * @return string |
|
141 | + */ |
|
142 | + public function fqcn() |
|
143 | + { |
|
144 | + return $this->fqcn; |
|
145 | + } |
|
146 | + |
|
147 | + |
|
148 | + /** |
|
149 | + * @return array |
|
150 | + */ |
|
151 | + public function filters() |
|
152 | + { |
|
153 | + return $this->filters; |
|
154 | + } |
|
155 | + |
|
156 | + |
|
157 | + /** |
|
158 | + * @return array |
|
159 | + */ |
|
160 | + public function ingredients() |
|
161 | + { |
|
162 | + return $this->ingredients; |
|
163 | + } |
|
164 | + |
|
165 | + |
|
166 | + /** |
|
167 | + * @return string |
|
168 | + */ |
|
169 | + public function type() |
|
170 | + { |
|
171 | + return $this->type; |
|
172 | + } |
|
173 | + |
|
174 | + |
|
175 | + /** |
|
176 | + * @return array |
|
177 | + */ |
|
178 | + public function paths() |
|
179 | + { |
|
180 | + return $this->paths; |
|
181 | + } |
|
182 | + |
|
183 | + |
|
184 | + /** |
|
185 | + * @param string $identifier Identifier for the entity class that the Recipe applies to |
|
186 | + * Typically a Fully Qualified Class Name |
|
187 | + * @throws InvalidIdentifierException |
|
188 | + */ |
|
189 | + public function setIdentifier($identifier) |
|
190 | + { |
|
191 | + if (! is_string($identifier) || empty($identifier)) { |
|
192 | + throw new InvalidIdentifierException( |
|
193 | + is_object($identifier) ? get_class($identifier) : gettype($identifier), |
|
194 | + esc_html__('class identifier (typically a \Fully\Qualified\ClassName)', 'event_espresso') |
|
195 | + ); |
|
196 | + } |
|
197 | + $this->identifier = $identifier; |
|
198 | + } |
|
199 | + |
|
200 | + |
|
201 | + /** |
|
202 | + * Ensures incoming string is a valid Fully Qualified Class Name, |
|
203 | + * except if this is the default wildcard Recipe ( * ), |
|
204 | + * or it's NOT an actual FQCN because the Recipe is using filepaths |
|
205 | + * for classes that are not PSR-4 compatible |
|
206 | + * PLZ NOTE: |
|
207 | + * Recipe::setFqcn() has a check to see if Recipe::$paths is empty or not, |
|
208 | + * therefore you should always call Recipe::setPaths() before Recipe::setFqcn() |
|
209 | + * |
|
210 | + * @param string $fqcn |
|
211 | + * @throws InvalidDataTypeException |
|
212 | + * @throws InvalidClassException |
|
213 | + * @throws InvalidInterfaceException |
|
214 | + */ |
|
215 | + public function setFqcn($fqcn) |
|
216 | + { |
|
217 | + $fqcn = ! empty($fqcn) ? $fqcn : $this->identifier; |
|
218 | + if (! is_string($fqcn)) { |
|
219 | + throw new InvalidDataTypeException( |
|
220 | + '$fqcn', |
|
221 | + is_object($fqcn) ? get_class($fqcn) : gettype($fqcn), |
|
222 | + esc_html__('string (Fully\Qualified\ClassName)', 'event_espresso') |
|
223 | + ); |
|
224 | + } |
|
225 | + $fqcn = ltrim($fqcn, '\\'); |
|
226 | + if ( |
|
227 | + $fqcn !== Recipe::DEFAULT_ID |
|
228 | + && ! empty($fqcn) |
|
229 | + && empty($this->paths) |
|
230 | + && ! (class_exists($fqcn) || interface_exists($fqcn)) |
|
231 | + ) { |
|
232 | + throw new InvalidClassException($fqcn); |
|
233 | + } |
|
234 | + $this->fqcn = $fqcn; |
|
235 | + } |
|
236 | + |
|
237 | + |
|
238 | + /** |
|
239 | + * @param array $ingredients an array of dependencies where keys are the aliases and values are the FQCNs |
|
240 | + * example: |
|
241 | + * array( 'ClassInterface' => 'Fully\Qualified\ClassName' ) |
|
242 | + * @throws InvalidDataTypeException |
|
243 | + */ |
|
244 | + public function setIngredients(array $ingredients) |
|
245 | + { |
|
246 | + if (empty($ingredients)) { |
|
247 | + return; |
|
248 | + } |
|
249 | + if (! is_array($ingredients)) { |
|
250 | + throw new InvalidDataTypeException( |
|
251 | + '$ingredients', |
|
252 | + is_object($ingredients) ? get_class($ingredients) : gettype($ingredients), |
|
253 | + esc_html__('array of class dependencies', 'event_espresso') |
|
254 | + ); |
|
255 | + } |
|
256 | + $this->ingredients = array_merge($this->ingredients, $ingredients); |
|
257 | + } |
|
258 | + |
|
259 | + |
|
260 | + /** |
|
261 | + * @param string $type one of the class constants returned from CoffeeMaker::getTypes() |
|
262 | + * @throws InvalidIdentifierException |
|
263 | + */ |
|
264 | + public function setType($type = CoffeeMaker::BREW_NEW) |
|
265 | + { |
|
266 | + $this->type = CoffeeMaker::validateType($type); |
|
267 | + } |
|
268 | + |
|
269 | + |
|
270 | + /** |
|
271 | + * @param array $filters an array of filters where keys are the aliases and values are the FQCNs |
|
272 | + * example: |
|
273 | + * array( 'ClassInterface' => 'Fully\Qualified\ClassName' ) |
|
274 | + * @throws InvalidDataTypeException |
|
275 | + */ |
|
276 | + public function setFilters(array $filters) |
|
277 | + { |
|
278 | + if (empty($filters)) { |
|
279 | + return; |
|
280 | + } |
|
281 | + if (! is_array($filters)) { |
|
282 | + throw new InvalidDataTypeException( |
|
283 | + '$filters', |
|
284 | + is_object($filters) ? get_class($filters) : gettype($filters), |
|
285 | + esc_html__('array of class aliases', 'event_espresso') |
|
286 | + ); |
|
287 | + } |
|
288 | + $this->filters = array_merge($this->filters, $filters); |
|
289 | + } |
|
290 | + |
|
291 | + |
|
292 | + /** |
|
293 | + * Ensures incoming paths is a valid filepath, or array of valid filepaths, |
|
294 | + * and merges them in with any existing filepaths |
|
295 | + * PLZ NOTE: |
|
296 | + * Recipe::setFqcn() has a check to see if Recipe::$paths is empty or not, |
|
297 | + * therefore you should always call Recipe::setPaths() before Recipe::setFqcn() |
|
298 | + * |
|
299 | + * @param string|array $paths |
|
300 | + * @throws RuntimeException |
|
301 | + * @throws InvalidDataTypeException |
|
302 | + */ |
|
303 | + public function setPaths($paths = array()) |
|
304 | + { |
|
305 | + if (empty($paths)) { |
|
306 | + return; |
|
307 | + } |
|
308 | + if (! (is_string($paths) || is_array($paths))) { |
|
309 | + throw new InvalidDataTypeException( |
|
310 | + '$path', |
|
311 | + is_object($paths) ? get_class($paths) : gettype($paths), |
|
312 | + esc_html__('string or array of strings (full server filepath(s))', 'event_espresso') |
|
313 | + ); |
|
314 | + } |
|
315 | + $paths = (array) $paths; |
|
316 | + foreach ($paths as $path) { |
|
317 | + if (strpos($path, '*') === false && ! is_readable($path)) { |
|
318 | + throw new RuntimeException( |
|
319 | + sprintf( |
|
320 | + esc_html__('The following filepath is not readable: "%1$s"', 'event_espresso'), |
|
321 | + $path |
|
322 | + ) |
|
323 | + ); |
|
324 | + } |
|
325 | + } |
|
326 | + $this->paths = array_merge($this->paths, $paths); |
|
327 | + } |
|
328 | 328 | } |
@@ -159,7 +159,7 @@ discard block |
||
159 | 159 | } |
160 | 160 | // if the reservoir doesn't have a closure already for the requested identifier, |
161 | 161 | // then neither a shared service nor a closure for making entities has been built yet |
162 | - if (! $this->reservoir->has($identifier)) { |
|
162 | + if ( ! $this->reservoir->has($identifier)) { |
|
163 | 163 | // so let's brew something up and add it to the proper collection |
164 | 164 | $brewed = $this->makeCoffee($identifier, $arguments, $type); |
165 | 165 | } |
@@ -284,7 +284,7 @@ discard block |
||
284 | 284 | */ |
285 | 285 | public function addClosure($identifier, $closure) |
286 | 286 | { |
287 | - if (! is_callable($closure)) { |
|
287 | + if ( ! is_callable($closure)) { |
|
288 | 288 | throw new InvalidDataTypeException('$closure', $closure, 'Closure'); |
289 | 289 | } |
290 | 290 | $identifier = $this->processIdentifier($identifier); |
@@ -393,7 +393,7 @@ discard block |
||
393 | 393 | // is the wildcard recipe prefix in the identifier ? |
394 | 394 | if (strpos($identifier, $wildcard) !== false) { |
395 | 395 | // track matches and use the number of wildcard characters matched for the key |
396 | - $matches[ strlen($wildcard) ] = $default_recipe; |
|
396 | + $matches[strlen($wildcard)] = $default_recipe; |
|
397 | 397 | } |
398 | 398 | } |
399 | 399 | if (count($matches) > 0) { |
@@ -433,7 +433,7 @@ discard block |
||
433 | 433 | } |
434 | 434 | $identifier = $this->processIdentifier($identifier); |
435 | 435 | foreach ((array) $aliases as $alias) { |
436 | - $this->filters[ $this->processIdentifier($alias) ] = $identifier; |
|
436 | + $this->filters[$this->processIdentifier($alias)] = $identifier; |
|
437 | 437 | } |
438 | 438 | } |
439 | 439 | |
@@ -475,8 +475,8 @@ discard block |
||
475 | 475 | private function filterIdentifier($identifier) |
476 | 476 | { |
477 | 477 | $identifier = $this->processIdentifier($identifier); |
478 | - return isset($this->filters[ $identifier ]) && ! empty($this->filters[ $identifier ]) |
|
479 | - ? $this->filters[ $identifier ] |
|
478 | + return isset($this->filters[$identifier]) && ! empty($this->filters[$identifier]) |
|
479 | + ? $this->filters[$identifier] |
|
480 | 480 | : $identifier; |
481 | 481 | } |
482 | 482 | |
@@ -491,7 +491,7 @@ discard block |
||
491 | 491 | */ |
492 | 492 | private function processIdentifier($identifier) |
493 | 493 | { |
494 | - if (! is_string($identifier)) { |
|
494 | + if ( ! is_string($identifier)) { |
|
495 | 495 | throw new InvalidIdentifierException( |
496 | 496 | is_object($identifier) ? get_class($identifier) : gettype($identifier), |
497 | 497 | '\Fully\Qualified\ClassName' |
@@ -510,7 +510,7 @@ discard block |
||
510 | 510 | */ |
511 | 511 | private function getCoffeeMaker($type) |
512 | 512 | { |
513 | - if (! $this->coffee_makers->has($type)) { |
|
513 | + if ( ! $this->coffee_makers->has($type)) { |
|
514 | 514 | throw new OutOfBoundsException( |
515 | 515 | esc_html__('The requested coffee maker is either missing or invalid.', 'event_espresso') |
516 | 516 | ); |
@@ -537,7 +537,7 @@ discard block |
||
537 | 537 | // does this recipe use a wildcard ? (but is NOT the global default) |
538 | 538 | if ($identifier !== Recipe::DEFAULT_ID && strpos($identifier, '*') !== false) { |
539 | 539 | // strip the wildcard and use identifier as key |
540 | - $default_recipes[ str_replace('*', '', $identifier) ] = $this->recipes->current(); |
|
540 | + $default_recipes[str_replace('*', '', $identifier)] = $this->recipes->current(); |
|
541 | 541 | } |
542 | 542 | $this->recipes->next(); |
543 | 543 | } |
@@ -557,7 +557,7 @@ discard block |
||
557 | 557 | private function copyDefaultRecipe(RecipeInterface $default_recipe, $identifier, $type = '') |
558 | 558 | { |
559 | 559 | $recipe = clone $default_recipe; |
560 | - if (! empty($type)) { |
|
560 | + if ( ! empty($type)) { |
|
561 | 561 | $recipe->setType($type); |
562 | 562 | } |
563 | 563 | // is this the base default recipe ? |
@@ -587,7 +587,7 @@ discard block |
||
587 | 587 | */ |
588 | 588 | private function validateService($identifier, $service) |
589 | 589 | { |
590 | - if (! is_object($service)) { |
|
590 | + if ( ! is_object($service)) { |
|
591 | 591 | throw new InvalidServiceException( |
592 | 592 | $identifier, |
593 | 593 | $service |
@@ -28,569 +28,569 @@ |
||
28 | 28 | */ |
29 | 29 | class CoffeeShop implements CoffeePotInterface |
30 | 30 | { |
31 | - /** |
|
32 | - * This was the best coffee related name I could think of to represent class name "aliases" |
|
33 | - * So classes can be found via an alias identifier, |
|
34 | - * that is revealed when it is run through... the filters... eh? get it? |
|
35 | - * |
|
36 | - * @var array $filters |
|
37 | - */ |
|
38 | - private $filters; |
|
39 | - |
|
40 | - /** |
|
41 | - * These are the classes that will actually build the objects (to order of course) |
|
42 | - * |
|
43 | - * @var array $coffee_makers |
|
44 | - */ |
|
45 | - private $coffee_makers; |
|
46 | - |
|
47 | - /** |
|
48 | - * where the instantiated "singleton" objects are stored |
|
49 | - * |
|
50 | - * @var CollectionInterface $carafe |
|
51 | - */ |
|
52 | - private $carafe; |
|
53 | - |
|
54 | - /** |
|
55 | - * collection of Recipes that instruct us how to brew objects |
|
56 | - * |
|
57 | - * @var CollectionInterface $recipes |
|
58 | - */ |
|
59 | - private $recipes; |
|
60 | - |
|
61 | - /** |
|
62 | - * collection of closures for brewing objects |
|
63 | - * |
|
64 | - * @var CollectionInterface $reservoir |
|
65 | - */ |
|
66 | - private $reservoir; |
|
67 | - |
|
68 | - |
|
69 | - /** |
|
70 | - * CoffeeShop constructor |
|
71 | - * |
|
72 | - * @throws InvalidInterfaceException |
|
73 | - */ |
|
74 | - public function __construct() |
|
75 | - { |
|
76 | - // array for storing class aliases |
|
77 | - $this->filters = array(); |
|
78 | - // create collection for storing shared services |
|
79 | - $this->carafe = new LooseCollection(''); |
|
80 | - // create collection for storing recipes that tell us how to build services and entities |
|
81 | - $this->recipes = new Collection('EventEspresso\core\services\container\RecipeInterface'); |
|
82 | - // create collection for storing closures for constructing new entities |
|
83 | - $this->reservoir = new Collection('Closure'); |
|
84 | - // create collection for storing the generators that build our services and entity closures |
|
85 | - $this->coffee_makers = new Collection('EventEspresso\core\services\container\CoffeeMakerInterface'); |
|
86 | - } |
|
87 | - |
|
88 | - |
|
89 | - /** |
|
90 | - * Returns true if the container can return an entry for the given identifier. |
|
91 | - * Returns false otherwise. |
|
92 | - * `has($identifier)` returning true does not mean that `get($identifier)` will not throw an exception. |
|
93 | - * It does however mean that `get($identifier)` will not throw a `ServiceNotFoundException`. |
|
94 | - * |
|
95 | - * @param string $identifier Identifier of the entry to look for. |
|
96 | - * Typically a Fully Qualified Class Name |
|
97 | - * @return boolean |
|
98 | - * @throws InvalidIdentifierException |
|
99 | - */ |
|
100 | - public function has($identifier) |
|
101 | - { |
|
102 | - $identifier = $this->filterIdentifier($identifier); |
|
103 | - return $this->carafe->has($identifier); |
|
104 | - } |
|
105 | - |
|
106 | - |
|
107 | - /** |
|
108 | - * finds a previously brewed (SHARED) service and returns it |
|
109 | - * |
|
110 | - * @param string $identifier Identifier for the entity class to be constructed. |
|
111 | - * Typically a Fully Qualified Class Name |
|
112 | - * @return mixed |
|
113 | - * @throws InvalidIdentifierException |
|
114 | - * @throws ServiceNotFoundException No service was found for this identifier. |
|
115 | - */ |
|
116 | - public function get($identifier) |
|
117 | - { |
|
118 | - $identifier = $this->filterIdentifier($identifier); |
|
119 | - if ($this->carafe->has($identifier)) { |
|
120 | - return $this->carafe->get($identifier); |
|
121 | - } |
|
122 | - throw new ServiceNotFoundException($identifier); |
|
123 | - } |
|
124 | - |
|
125 | - |
|
126 | - /** |
|
127 | - * returns an instance of the requested entity type using the supplied arguments. |
|
128 | - * If a shared service is requested and an instance is already in the carafe, then it will be returned. |
|
129 | - * If it is not already in the carafe, then the service will be constructed, added to the carafe, and returned |
|
130 | - * If the request is for a new entity and a closure exists in the reservoir for creating it, |
|
131 | - * then a new entity will be instantiated from the closure and returned. |
|
132 | - * If a closure does not exist, then one will be built and added to the reservoir |
|
133 | - * before instantiating the requested entity. |
|
134 | - * |
|
135 | - * @param string $identifier Identifier for the entity class to be constructed. |
|
136 | - * Typically a Fully Qualified Class Name |
|
137 | - * @param array $arguments an array of arguments to be passed to the entity constructor |
|
138 | - * @param string $type |
|
139 | - * @return mixed |
|
140 | - * @throws OutOfBoundsException |
|
141 | - * @throws InstantiationException |
|
142 | - * @throws InvalidDataTypeException |
|
143 | - * @throws InvalidClassException |
|
144 | - * @throws InvalidIdentifierException |
|
145 | - * @throws ServiceExistsException |
|
146 | - * @throws ServiceNotFoundException No service was found for this identifier. |
|
147 | - */ |
|
148 | - public function brew($identifier, $arguments = array(), $type = '') |
|
149 | - { |
|
150 | - // resolve any class aliases that may exist |
|
151 | - $identifier = $this->filterIdentifier($identifier); |
|
152 | - // is a shared service being requested and already exists in the carafe? |
|
153 | - $brewed = $this->getShared($identifier, $type); |
|
154 | - // then return whatever was found |
|
155 | - if ($brewed !== false) { |
|
156 | - return $brewed; |
|
157 | - } |
|
158 | - // if the reservoir doesn't have a closure already for the requested identifier, |
|
159 | - // then neither a shared service nor a closure for making entities has been built yet |
|
160 | - if (! $this->reservoir->has($identifier)) { |
|
161 | - // so let's brew something up and add it to the proper collection |
|
162 | - $brewed = $this->makeCoffee($identifier, $arguments, $type); |
|
163 | - } |
|
164 | - // did the requested class only require loading, and if so, was that successful? |
|
165 | - if ($this->brewedLoadOnly($brewed, $identifier, $type) === true) { |
|
166 | - return true; |
|
167 | - } |
|
168 | - // was the brewed item a callable factory function ? |
|
169 | - if (is_callable($brewed)) { |
|
170 | - // then instantiate a new entity from the cached closure |
|
171 | - return $brewed($arguments); |
|
172 | - } |
|
173 | - if ($brewed) { |
|
174 | - // requested object was a shared entity, so attempt to get it from the carafe again |
|
175 | - // because if it wasn't there before, then it should have just been brewed and added, |
|
176 | - // but if it still isn't there, then this time the thrown ServiceNotFoundException will not be caught |
|
177 | - return $this->get($identifier); |
|
178 | - } |
|
179 | - // if identifier is for a non-shared entity, |
|
180 | - // then either a cached closure already existed, or was just brewed |
|
181 | - return $this->brewedClosure($identifier, $arguments); |
|
182 | - } |
|
183 | - |
|
184 | - |
|
185 | - /** |
|
186 | - * @param string $identifier |
|
187 | - * @param string $type |
|
188 | - * @return bool|mixed |
|
189 | - * @throws InvalidIdentifierException |
|
190 | - */ |
|
191 | - protected function getShared($identifier, $type) |
|
192 | - { |
|
193 | - try { |
|
194 | - if (empty($type) || $type === CoffeeMaker::BREW_SHARED) { |
|
195 | - // if a shared service was requested and an instance is in the carafe, then return it |
|
196 | - return $this->get($identifier); |
|
197 | - } |
|
198 | - } catch (ServiceNotFoundException $e) { |
|
199 | - // if not then we'll just catch the ServiceNotFoundException but not do anything just yet, |
|
200 | - // and instead, attempt to build whatever was requested |
|
201 | - } |
|
202 | - return false; |
|
203 | - } |
|
204 | - |
|
205 | - |
|
206 | - /** |
|
207 | - * @param mixed $brewed |
|
208 | - * @param string $identifier |
|
209 | - * @param string $type |
|
210 | - * @return bool |
|
211 | - * @throws InvalidClassException |
|
212 | - * @throws InvalidDataTypeException |
|
213 | - * @throws InvalidIdentifierException |
|
214 | - * @throws OutOfBoundsException |
|
215 | - * @throws ServiceExistsException |
|
216 | - * @throws ServiceNotFoundException |
|
217 | - */ |
|
218 | - protected function brewedLoadOnly($brewed, $identifier, $type) |
|
219 | - { |
|
220 | - if ($type === CoffeeMaker::BREW_LOAD_ONLY) { |
|
221 | - if ($brewed !== true) { |
|
222 | - throw new ServiceNotFoundException( |
|
223 | - sprintf( |
|
224 | - esc_html__( |
|
225 | - 'The "%1$s" class could not be loaded.', |
|
226 | - 'event_espresso' |
|
227 | - ), |
|
228 | - $identifier |
|
229 | - ) |
|
230 | - ); |
|
231 | - } |
|
232 | - return true; |
|
233 | - } |
|
234 | - return false; |
|
235 | - } |
|
236 | - |
|
237 | - |
|
238 | - /** |
|
239 | - * @param string $identifier |
|
240 | - * @param array $arguments |
|
241 | - * @return mixed |
|
242 | - * @throws InstantiationException |
|
243 | - */ |
|
244 | - protected function brewedClosure($identifier, array $arguments) |
|
245 | - { |
|
246 | - $closure = $this->reservoir->get($identifier); |
|
247 | - if (empty($closure)) { |
|
248 | - throw new InstantiationException( |
|
249 | - sprintf( |
|
250 | - esc_html__( |
|
251 | - 'Could not brew an instance of "%1$s".', |
|
252 | - 'event_espresso' |
|
253 | - ), |
|
254 | - $identifier |
|
255 | - ) |
|
256 | - ); |
|
257 | - } |
|
258 | - return $closure($arguments); |
|
259 | - } |
|
260 | - |
|
261 | - |
|
262 | - /** |
|
263 | - * @param CoffeeMakerInterface $coffee_maker |
|
264 | - * @param string $type |
|
265 | - * @return bool |
|
266 | - * @throws InvalidIdentifierException |
|
267 | - * @throws InvalidEntityException |
|
268 | - */ |
|
269 | - public function addCoffeeMaker(CoffeeMakerInterface $coffee_maker, $type) |
|
270 | - { |
|
271 | - $type = CoffeeMaker::validateType($type); |
|
272 | - return $this->coffee_makers->add($coffee_maker, $type); |
|
273 | - } |
|
274 | - |
|
275 | - |
|
276 | - /** |
|
277 | - * @param string $identifier |
|
278 | - * @param callable $closure |
|
279 | - * @return callable|null |
|
280 | - * @throws InvalidIdentifierException |
|
281 | - * @throws InvalidDataTypeException |
|
282 | - */ |
|
283 | - public function addClosure($identifier, $closure) |
|
284 | - { |
|
285 | - if (! is_callable($closure)) { |
|
286 | - throw new InvalidDataTypeException('$closure', $closure, 'Closure'); |
|
287 | - } |
|
288 | - $identifier = $this->processIdentifier($identifier); |
|
289 | - if ($this->reservoir->add($closure, $identifier)) { |
|
290 | - return $closure; |
|
291 | - } |
|
292 | - return null; |
|
293 | - } |
|
294 | - |
|
295 | - |
|
296 | - /** |
|
297 | - * @param string $identifier |
|
298 | - * @return boolean |
|
299 | - * @throws InvalidIdentifierException |
|
300 | - */ |
|
301 | - public function removeClosure($identifier) |
|
302 | - { |
|
303 | - $identifier = $this->processIdentifier($identifier); |
|
304 | - if ($this->reservoir->has($identifier)) { |
|
305 | - return $this->reservoir->remove($this->reservoir->get($identifier)); |
|
306 | - } |
|
307 | - return false; |
|
308 | - } |
|
309 | - |
|
310 | - |
|
311 | - /** |
|
312 | - * @param string $identifier Identifier for the entity class that the service applies to |
|
313 | - * Typically a Fully Qualified Class Name |
|
314 | - * @param mixed $service |
|
315 | - * @return bool |
|
316 | - * @throws \EventEspresso\core\services\container\exceptions\InvalidServiceException |
|
317 | - * @throws InvalidIdentifierException |
|
318 | - */ |
|
319 | - public function addService($identifier, $service) |
|
320 | - { |
|
321 | - $identifier = $this->processIdentifier($identifier); |
|
322 | - $service = $this->validateService($identifier, $service); |
|
323 | - return $this->carafe->add($service, $identifier); |
|
324 | - } |
|
325 | - |
|
326 | - |
|
327 | - /** |
|
328 | - * @param string $identifier |
|
329 | - * @return boolean |
|
330 | - * @throws InvalidIdentifierException |
|
331 | - */ |
|
332 | - public function removeService($identifier) |
|
333 | - { |
|
334 | - $identifier = $this->processIdentifier($identifier); |
|
335 | - if ($this->carafe->has($identifier)) { |
|
336 | - return $this->carafe->remove($this->carafe->get($identifier)); |
|
337 | - } |
|
338 | - return false; |
|
339 | - } |
|
340 | - |
|
341 | - |
|
342 | - /** |
|
343 | - * Adds instructions on how to brew objects |
|
344 | - * |
|
345 | - * @param RecipeInterface $recipe |
|
346 | - * @return mixed |
|
347 | - * @throws InvalidIdentifierException |
|
348 | - */ |
|
349 | - public function addRecipe(RecipeInterface $recipe) |
|
350 | - { |
|
351 | - $this->addAliases($recipe->identifier(), $recipe->filters()); |
|
352 | - $identifier = $this->processIdentifier($recipe->identifier()); |
|
353 | - return $this->recipes->add($recipe, $identifier); |
|
354 | - } |
|
355 | - |
|
356 | - |
|
357 | - /** |
|
358 | - * @param string $identifier The Recipe's identifier |
|
359 | - * @return boolean |
|
360 | - * @throws InvalidIdentifierException |
|
361 | - */ |
|
362 | - public function removeRecipe($identifier) |
|
363 | - { |
|
364 | - $identifier = $this->processIdentifier($identifier); |
|
365 | - if ($this->recipes->has($identifier)) { |
|
366 | - return $this->recipes->remove($this->recipes->get($identifier)); |
|
367 | - } |
|
368 | - return false; |
|
369 | - } |
|
370 | - |
|
371 | - |
|
372 | - /** |
|
373 | - * Get instructions on how to brew objects |
|
374 | - * |
|
375 | - * @param string $identifier Identifier for the entity class that the recipe applies to |
|
376 | - * Typically a Fully Qualified Class Name |
|
377 | - * @param string $type |
|
378 | - * @return RecipeInterface |
|
379 | - * @throws OutOfBoundsException |
|
380 | - * @throws InvalidIdentifierException |
|
381 | - */ |
|
382 | - public function getRecipe($identifier, $type = '') |
|
383 | - { |
|
384 | - $identifier = $this->processIdentifier($identifier); |
|
385 | - if ($this->recipes->has($identifier)) { |
|
386 | - return $this->recipes->get($identifier); |
|
387 | - } |
|
388 | - $default_recipes = $this->getDefaultRecipes(); |
|
389 | - $matches = array(); |
|
390 | - foreach ($default_recipes as $wildcard => $default_recipe) { |
|
391 | - // is the wildcard recipe prefix in the identifier ? |
|
392 | - if (strpos($identifier, $wildcard) !== false) { |
|
393 | - // track matches and use the number of wildcard characters matched for the key |
|
394 | - $matches[ strlen($wildcard) ] = $default_recipe; |
|
395 | - } |
|
396 | - } |
|
397 | - if (count($matches) > 0) { |
|
398 | - // sort our recipes by the number of wildcard characters matched |
|
399 | - ksort($matches); |
|
400 | - // then grab the last recipe form the list, since it had the most matching characters |
|
401 | - $match = array_pop($matches); |
|
402 | - // since we are using a default recipe, we need to set it's identifier and fqcn |
|
403 | - return $this->copyDefaultRecipe($match, $identifier, $type); |
|
404 | - } |
|
405 | - if ($this->recipes->has(Recipe::DEFAULT_ID)) { |
|
406 | - // since we are using a default recipe, we need to set it's identifier and fqcn |
|
407 | - return $this->copyDefaultRecipe($this->recipes->get(Recipe::DEFAULT_ID), $identifier, $type); |
|
408 | - } |
|
409 | - throw new OutOfBoundsException( |
|
410 | - sprintf( |
|
411 | - esc_html__('Could not brew coffee because no recipes were found for class "%1$s".', 'event_espresso'), |
|
412 | - $identifier |
|
413 | - ) |
|
414 | - ); |
|
415 | - } |
|
416 | - |
|
417 | - |
|
418 | - /** |
|
419 | - * adds class name aliases to list of filters |
|
420 | - * |
|
421 | - * @param string $identifier Identifier for the entity class that the alias applies to |
|
422 | - * Typically a Fully Qualified Class Name |
|
423 | - * @param array|string $aliases |
|
424 | - * @return void |
|
425 | - * @throws InvalidIdentifierException |
|
426 | - */ |
|
427 | - public function addAliases($identifier, $aliases) |
|
428 | - { |
|
429 | - if (empty($aliases)) { |
|
430 | - return; |
|
431 | - } |
|
432 | - $identifier = $this->processIdentifier($identifier); |
|
433 | - foreach ((array) $aliases as $alias) { |
|
434 | - $this->filters[ $this->processIdentifier($alias) ] = $identifier; |
|
435 | - } |
|
436 | - } |
|
437 | - |
|
438 | - |
|
439 | - /** |
|
440 | - * Adds a service to one of the internal collections |
|
441 | - * |
|
442 | - * @param $identifier |
|
443 | - * @param array $arguments |
|
444 | - * @param string $type |
|
445 | - * @return mixed |
|
446 | - * @throws InvalidDataTypeException |
|
447 | - * @throws InvalidClassException |
|
448 | - * @throws OutOfBoundsException |
|
449 | - * @throws InvalidIdentifierException |
|
450 | - * @throws ServiceExistsException |
|
451 | - */ |
|
452 | - private function makeCoffee($identifier, $arguments = array(), $type = '') |
|
453 | - { |
|
454 | - if ((empty($type) || $type === CoffeeMaker::BREW_SHARED) && $this->has($identifier)) { |
|
455 | - throw new ServiceExistsException($identifier); |
|
456 | - } |
|
457 | - $identifier = $this->filterIdentifier($identifier); |
|
458 | - $recipe = $this->getRecipe($identifier, $type); |
|
459 | - $type = ! empty($type) ? $type : $recipe->type(); |
|
460 | - $coffee_maker = $this->getCoffeeMaker($type); |
|
461 | - return $coffee_maker->brew($recipe, $arguments); |
|
462 | - } |
|
463 | - |
|
464 | - |
|
465 | - /** |
|
466 | - * filters alias identifiers to find the real class name |
|
467 | - * |
|
468 | - * @param string $identifier Identifier for the entity class that the filter applies to |
|
469 | - * Typically a Fully Qualified Class Name |
|
470 | - * @return string |
|
471 | - * @throws InvalidIdentifierException |
|
472 | - */ |
|
473 | - private function filterIdentifier($identifier) |
|
474 | - { |
|
475 | - $identifier = $this->processIdentifier($identifier); |
|
476 | - return isset($this->filters[ $identifier ]) && ! empty($this->filters[ $identifier ]) |
|
477 | - ? $this->filters[ $identifier ] |
|
478 | - : $identifier; |
|
479 | - } |
|
480 | - |
|
481 | - |
|
482 | - /** |
|
483 | - * verifies and standardizes identifiers |
|
484 | - * |
|
485 | - * @param string $identifier Identifier for the entity class |
|
486 | - * Typically a Fully Qualified Class Name |
|
487 | - * @return string |
|
488 | - * @throws InvalidIdentifierException |
|
489 | - */ |
|
490 | - private function processIdentifier($identifier) |
|
491 | - { |
|
492 | - if (! is_string($identifier)) { |
|
493 | - throw new InvalidIdentifierException( |
|
494 | - is_object($identifier) ? get_class($identifier) : gettype($identifier), |
|
495 | - '\Fully\Qualified\ClassName' |
|
496 | - ); |
|
497 | - } |
|
498 | - return ltrim($identifier, '\\'); |
|
499 | - } |
|
500 | - |
|
501 | - |
|
502 | - /** |
|
503 | - * @param string $type |
|
504 | - * @return CoffeeMakerInterface |
|
505 | - * @throws OutOfBoundsException |
|
506 | - * @throws InvalidDataTypeException |
|
507 | - * @throws InvalidClassException |
|
508 | - */ |
|
509 | - private function getCoffeeMaker($type) |
|
510 | - { |
|
511 | - if (! $this->coffee_makers->has($type)) { |
|
512 | - throw new OutOfBoundsException( |
|
513 | - esc_html__('The requested coffee maker is either missing or invalid.', 'event_espresso') |
|
514 | - ); |
|
515 | - } |
|
516 | - return $this->coffee_makers->get($type); |
|
517 | - } |
|
518 | - |
|
519 | - |
|
520 | - /** |
|
521 | - * Retrieves all recipes that use a wildcard "*" in their identifier |
|
522 | - * This allows recipes to be set up for handling |
|
523 | - * legacy classes that do not support PSR-4 autoloading. |
|
524 | - * for example: |
|
525 | - * using "EEM_*" for a recipe identifier would target all legacy models like EEM_Attendee |
|
526 | - * |
|
527 | - * @return array |
|
528 | - */ |
|
529 | - private function getDefaultRecipes() |
|
530 | - { |
|
531 | - $default_recipes = array(); |
|
532 | - $this->recipes->rewind(); |
|
533 | - while ($this->recipes->valid()) { |
|
534 | - $identifier = $this->recipes->getInfo(); |
|
535 | - // does this recipe use a wildcard ? (but is NOT the global default) |
|
536 | - if ($identifier !== Recipe::DEFAULT_ID && strpos($identifier, '*') !== false) { |
|
537 | - // strip the wildcard and use identifier as key |
|
538 | - $default_recipes[ str_replace('*', '', $identifier) ] = $this->recipes->current(); |
|
539 | - } |
|
540 | - $this->recipes->next(); |
|
541 | - } |
|
542 | - return $default_recipes; |
|
543 | - } |
|
544 | - |
|
545 | - |
|
546 | - /** |
|
547 | - * clones a default recipe and then copies details |
|
548 | - * from the incoming request to it so that it can be used |
|
549 | - * |
|
550 | - * @param RecipeInterface $default_recipe |
|
551 | - * @param string $identifier |
|
552 | - * @param string $type |
|
553 | - * @return RecipeInterface |
|
554 | - */ |
|
555 | - private function copyDefaultRecipe(RecipeInterface $default_recipe, $identifier, $type = '') |
|
556 | - { |
|
557 | - $recipe = clone $default_recipe; |
|
558 | - if (! empty($type)) { |
|
559 | - $recipe->setType($type); |
|
560 | - } |
|
561 | - // is this the base default recipe ? |
|
562 | - if ($default_recipe->identifier() === Recipe::DEFAULT_ID) { |
|
563 | - $recipe->setIdentifier($identifier); |
|
564 | - $recipe->setFqcn($identifier); |
|
565 | - return $recipe; |
|
566 | - } |
|
567 | - $recipe->setIdentifier($identifier); |
|
568 | - foreach ($default_recipe->paths() as $path) { |
|
569 | - $path = str_replace('*', $identifier, $path); |
|
570 | - if (is_readable($path)) { |
|
571 | - $recipe->setPaths($path); |
|
572 | - } |
|
573 | - } |
|
574 | - $recipe->setFqcn($identifier); |
|
575 | - return $recipe; |
|
576 | - } |
|
577 | - |
|
578 | - |
|
579 | - /** |
|
580 | - * @param string $identifier Identifier for the entity class that the service applies to |
|
581 | - * Typically a Fully Qualified Class Name |
|
582 | - * @param mixed $service |
|
583 | - * @return mixed |
|
584 | - * @throws InvalidServiceException |
|
585 | - */ |
|
586 | - private function validateService($identifier, $service) |
|
587 | - { |
|
588 | - if (! is_object($service)) { |
|
589 | - throw new InvalidServiceException( |
|
590 | - $identifier, |
|
591 | - $service |
|
592 | - ); |
|
593 | - } |
|
594 | - return $service; |
|
595 | - } |
|
31 | + /** |
|
32 | + * This was the best coffee related name I could think of to represent class name "aliases" |
|
33 | + * So classes can be found via an alias identifier, |
|
34 | + * that is revealed when it is run through... the filters... eh? get it? |
|
35 | + * |
|
36 | + * @var array $filters |
|
37 | + */ |
|
38 | + private $filters; |
|
39 | + |
|
40 | + /** |
|
41 | + * These are the classes that will actually build the objects (to order of course) |
|
42 | + * |
|
43 | + * @var array $coffee_makers |
|
44 | + */ |
|
45 | + private $coffee_makers; |
|
46 | + |
|
47 | + /** |
|
48 | + * where the instantiated "singleton" objects are stored |
|
49 | + * |
|
50 | + * @var CollectionInterface $carafe |
|
51 | + */ |
|
52 | + private $carafe; |
|
53 | + |
|
54 | + /** |
|
55 | + * collection of Recipes that instruct us how to brew objects |
|
56 | + * |
|
57 | + * @var CollectionInterface $recipes |
|
58 | + */ |
|
59 | + private $recipes; |
|
60 | + |
|
61 | + /** |
|
62 | + * collection of closures for brewing objects |
|
63 | + * |
|
64 | + * @var CollectionInterface $reservoir |
|
65 | + */ |
|
66 | + private $reservoir; |
|
67 | + |
|
68 | + |
|
69 | + /** |
|
70 | + * CoffeeShop constructor |
|
71 | + * |
|
72 | + * @throws InvalidInterfaceException |
|
73 | + */ |
|
74 | + public function __construct() |
|
75 | + { |
|
76 | + // array for storing class aliases |
|
77 | + $this->filters = array(); |
|
78 | + // create collection for storing shared services |
|
79 | + $this->carafe = new LooseCollection(''); |
|
80 | + // create collection for storing recipes that tell us how to build services and entities |
|
81 | + $this->recipes = new Collection('EventEspresso\core\services\container\RecipeInterface'); |
|
82 | + // create collection for storing closures for constructing new entities |
|
83 | + $this->reservoir = new Collection('Closure'); |
|
84 | + // create collection for storing the generators that build our services and entity closures |
|
85 | + $this->coffee_makers = new Collection('EventEspresso\core\services\container\CoffeeMakerInterface'); |
|
86 | + } |
|
87 | + |
|
88 | + |
|
89 | + /** |
|
90 | + * Returns true if the container can return an entry for the given identifier. |
|
91 | + * Returns false otherwise. |
|
92 | + * `has($identifier)` returning true does not mean that `get($identifier)` will not throw an exception. |
|
93 | + * It does however mean that `get($identifier)` will not throw a `ServiceNotFoundException`. |
|
94 | + * |
|
95 | + * @param string $identifier Identifier of the entry to look for. |
|
96 | + * Typically a Fully Qualified Class Name |
|
97 | + * @return boolean |
|
98 | + * @throws InvalidIdentifierException |
|
99 | + */ |
|
100 | + public function has($identifier) |
|
101 | + { |
|
102 | + $identifier = $this->filterIdentifier($identifier); |
|
103 | + return $this->carafe->has($identifier); |
|
104 | + } |
|
105 | + |
|
106 | + |
|
107 | + /** |
|
108 | + * finds a previously brewed (SHARED) service and returns it |
|
109 | + * |
|
110 | + * @param string $identifier Identifier for the entity class to be constructed. |
|
111 | + * Typically a Fully Qualified Class Name |
|
112 | + * @return mixed |
|
113 | + * @throws InvalidIdentifierException |
|
114 | + * @throws ServiceNotFoundException No service was found for this identifier. |
|
115 | + */ |
|
116 | + public function get($identifier) |
|
117 | + { |
|
118 | + $identifier = $this->filterIdentifier($identifier); |
|
119 | + if ($this->carafe->has($identifier)) { |
|
120 | + return $this->carafe->get($identifier); |
|
121 | + } |
|
122 | + throw new ServiceNotFoundException($identifier); |
|
123 | + } |
|
124 | + |
|
125 | + |
|
126 | + /** |
|
127 | + * returns an instance of the requested entity type using the supplied arguments. |
|
128 | + * If a shared service is requested and an instance is already in the carafe, then it will be returned. |
|
129 | + * If it is not already in the carafe, then the service will be constructed, added to the carafe, and returned |
|
130 | + * If the request is for a new entity and a closure exists in the reservoir for creating it, |
|
131 | + * then a new entity will be instantiated from the closure and returned. |
|
132 | + * If a closure does not exist, then one will be built and added to the reservoir |
|
133 | + * before instantiating the requested entity. |
|
134 | + * |
|
135 | + * @param string $identifier Identifier for the entity class to be constructed. |
|
136 | + * Typically a Fully Qualified Class Name |
|
137 | + * @param array $arguments an array of arguments to be passed to the entity constructor |
|
138 | + * @param string $type |
|
139 | + * @return mixed |
|
140 | + * @throws OutOfBoundsException |
|
141 | + * @throws InstantiationException |
|
142 | + * @throws InvalidDataTypeException |
|
143 | + * @throws InvalidClassException |
|
144 | + * @throws InvalidIdentifierException |
|
145 | + * @throws ServiceExistsException |
|
146 | + * @throws ServiceNotFoundException No service was found for this identifier. |
|
147 | + */ |
|
148 | + public function brew($identifier, $arguments = array(), $type = '') |
|
149 | + { |
|
150 | + // resolve any class aliases that may exist |
|
151 | + $identifier = $this->filterIdentifier($identifier); |
|
152 | + // is a shared service being requested and already exists in the carafe? |
|
153 | + $brewed = $this->getShared($identifier, $type); |
|
154 | + // then return whatever was found |
|
155 | + if ($brewed !== false) { |
|
156 | + return $brewed; |
|
157 | + } |
|
158 | + // if the reservoir doesn't have a closure already for the requested identifier, |
|
159 | + // then neither a shared service nor a closure for making entities has been built yet |
|
160 | + if (! $this->reservoir->has($identifier)) { |
|
161 | + // so let's brew something up and add it to the proper collection |
|
162 | + $brewed = $this->makeCoffee($identifier, $arguments, $type); |
|
163 | + } |
|
164 | + // did the requested class only require loading, and if so, was that successful? |
|
165 | + if ($this->brewedLoadOnly($brewed, $identifier, $type) === true) { |
|
166 | + return true; |
|
167 | + } |
|
168 | + // was the brewed item a callable factory function ? |
|
169 | + if (is_callable($brewed)) { |
|
170 | + // then instantiate a new entity from the cached closure |
|
171 | + return $brewed($arguments); |
|
172 | + } |
|
173 | + if ($brewed) { |
|
174 | + // requested object was a shared entity, so attempt to get it from the carafe again |
|
175 | + // because if it wasn't there before, then it should have just been brewed and added, |
|
176 | + // but if it still isn't there, then this time the thrown ServiceNotFoundException will not be caught |
|
177 | + return $this->get($identifier); |
|
178 | + } |
|
179 | + // if identifier is for a non-shared entity, |
|
180 | + // then either a cached closure already existed, or was just brewed |
|
181 | + return $this->brewedClosure($identifier, $arguments); |
|
182 | + } |
|
183 | + |
|
184 | + |
|
185 | + /** |
|
186 | + * @param string $identifier |
|
187 | + * @param string $type |
|
188 | + * @return bool|mixed |
|
189 | + * @throws InvalidIdentifierException |
|
190 | + */ |
|
191 | + protected function getShared($identifier, $type) |
|
192 | + { |
|
193 | + try { |
|
194 | + if (empty($type) || $type === CoffeeMaker::BREW_SHARED) { |
|
195 | + // if a shared service was requested and an instance is in the carafe, then return it |
|
196 | + return $this->get($identifier); |
|
197 | + } |
|
198 | + } catch (ServiceNotFoundException $e) { |
|
199 | + // if not then we'll just catch the ServiceNotFoundException but not do anything just yet, |
|
200 | + // and instead, attempt to build whatever was requested |
|
201 | + } |
|
202 | + return false; |
|
203 | + } |
|
204 | + |
|
205 | + |
|
206 | + /** |
|
207 | + * @param mixed $brewed |
|
208 | + * @param string $identifier |
|
209 | + * @param string $type |
|
210 | + * @return bool |
|
211 | + * @throws InvalidClassException |
|
212 | + * @throws InvalidDataTypeException |
|
213 | + * @throws InvalidIdentifierException |
|
214 | + * @throws OutOfBoundsException |
|
215 | + * @throws ServiceExistsException |
|
216 | + * @throws ServiceNotFoundException |
|
217 | + */ |
|
218 | + protected function brewedLoadOnly($brewed, $identifier, $type) |
|
219 | + { |
|
220 | + if ($type === CoffeeMaker::BREW_LOAD_ONLY) { |
|
221 | + if ($brewed !== true) { |
|
222 | + throw new ServiceNotFoundException( |
|
223 | + sprintf( |
|
224 | + esc_html__( |
|
225 | + 'The "%1$s" class could not be loaded.', |
|
226 | + 'event_espresso' |
|
227 | + ), |
|
228 | + $identifier |
|
229 | + ) |
|
230 | + ); |
|
231 | + } |
|
232 | + return true; |
|
233 | + } |
|
234 | + return false; |
|
235 | + } |
|
236 | + |
|
237 | + |
|
238 | + /** |
|
239 | + * @param string $identifier |
|
240 | + * @param array $arguments |
|
241 | + * @return mixed |
|
242 | + * @throws InstantiationException |
|
243 | + */ |
|
244 | + protected function brewedClosure($identifier, array $arguments) |
|
245 | + { |
|
246 | + $closure = $this->reservoir->get($identifier); |
|
247 | + if (empty($closure)) { |
|
248 | + throw new InstantiationException( |
|
249 | + sprintf( |
|
250 | + esc_html__( |
|
251 | + 'Could not brew an instance of "%1$s".', |
|
252 | + 'event_espresso' |
|
253 | + ), |
|
254 | + $identifier |
|
255 | + ) |
|
256 | + ); |
|
257 | + } |
|
258 | + return $closure($arguments); |
|
259 | + } |
|
260 | + |
|
261 | + |
|
262 | + /** |
|
263 | + * @param CoffeeMakerInterface $coffee_maker |
|
264 | + * @param string $type |
|
265 | + * @return bool |
|
266 | + * @throws InvalidIdentifierException |
|
267 | + * @throws InvalidEntityException |
|
268 | + */ |
|
269 | + public function addCoffeeMaker(CoffeeMakerInterface $coffee_maker, $type) |
|
270 | + { |
|
271 | + $type = CoffeeMaker::validateType($type); |
|
272 | + return $this->coffee_makers->add($coffee_maker, $type); |
|
273 | + } |
|
274 | + |
|
275 | + |
|
276 | + /** |
|
277 | + * @param string $identifier |
|
278 | + * @param callable $closure |
|
279 | + * @return callable|null |
|
280 | + * @throws InvalidIdentifierException |
|
281 | + * @throws InvalidDataTypeException |
|
282 | + */ |
|
283 | + public function addClosure($identifier, $closure) |
|
284 | + { |
|
285 | + if (! is_callable($closure)) { |
|
286 | + throw new InvalidDataTypeException('$closure', $closure, 'Closure'); |
|
287 | + } |
|
288 | + $identifier = $this->processIdentifier($identifier); |
|
289 | + if ($this->reservoir->add($closure, $identifier)) { |
|
290 | + return $closure; |
|
291 | + } |
|
292 | + return null; |
|
293 | + } |
|
294 | + |
|
295 | + |
|
296 | + /** |
|
297 | + * @param string $identifier |
|
298 | + * @return boolean |
|
299 | + * @throws InvalidIdentifierException |
|
300 | + */ |
|
301 | + public function removeClosure($identifier) |
|
302 | + { |
|
303 | + $identifier = $this->processIdentifier($identifier); |
|
304 | + if ($this->reservoir->has($identifier)) { |
|
305 | + return $this->reservoir->remove($this->reservoir->get($identifier)); |
|
306 | + } |
|
307 | + return false; |
|
308 | + } |
|
309 | + |
|
310 | + |
|
311 | + /** |
|
312 | + * @param string $identifier Identifier for the entity class that the service applies to |
|
313 | + * Typically a Fully Qualified Class Name |
|
314 | + * @param mixed $service |
|
315 | + * @return bool |
|
316 | + * @throws \EventEspresso\core\services\container\exceptions\InvalidServiceException |
|
317 | + * @throws InvalidIdentifierException |
|
318 | + */ |
|
319 | + public function addService($identifier, $service) |
|
320 | + { |
|
321 | + $identifier = $this->processIdentifier($identifier); |
|
322 | + $service = $this->validateService($identifier, $service); |
|
323 | + return $this->carafe->add($service, $identifier); |
|
324 | + } |
|
325 | + |
|
326 | + |
|
327 | + /** |
|
328 | + * @param string $identifier |
|
329 | + * @return boolean |
|
330 | + * @throws InvalidIdentifierException |
|
331 | + */ |
|
332 | + public function removeService($identifier) |
|
333 | + { |
|
334 | + $identifier = $this->processIdentifier($identifier); |
|
335 | + if ($this->carafe->has($identifier)) { |
|
336 | + return $this->carafe->remove($this->carafe->get($identifier)); |
|
337 | + } |
|
338 | + return false; |
|
339 | + } |
|
340 | + |
|
341 | + |
|
342 | + /** |
|
343 | + * Adds instructions on how to brew objects |
|
344 | + * |
|
345 | + * @param RecipeInterface $recipe |
|
346 | + * @return mixed |
|
347 | + * @throws InvalidIdentifierException |
|
348 | + */ |
|
349 | + public function addRecipe(RecipeInterface $recipe) |
|
350 | + { |
|
351 | + $this->addAliases($recipe->identifier(), $recipe->filters()); |
|
352 | + $identifier = $this->processIdentifier($recipe->identifier()); |
|
353 | + return $this->recipes->add($recipe, $identifier); |
|
354 | + } |
|
355 | + |
|
356 | + |
|
357 | + /** |
|
358 | + * @param string $identifier The Recipe's identifier |
|
359 | + * @return boolean |
|
360 | + * @throws InvalidIdentifierException |
|
361 | + */ |
|
362 | + public function removeRecipe($identifier) |
|
363 | + { |
|
364 | + $identifier = $this->processIdentifier($identifier); |
|
365 | + if ($this->recipes->has($identifier)) { |
|
366 | + return $this->recipes->remove($this->recipes->get($identifier)); |
|
367 | + } |
|
368 | + return false; |
|
369 | + } |
|
370 | + |
|
371 | + |
|
372 | + /** |
|
373 | + * Get instructions on how to brew objects |
|
374 | + * |
|
375 | + * @param string $identifier Identifier for the entity class that the recipe applies to |
|
376 | + * Typically a Fully Qualified Class Name |
|
377 | + * @param string $type |
|
378 | + * @return RecipeInterface |
|
379 | + * @throws OutOfBoundsException |
|
380 | + * @throws InvalidIdentifierException |
|
381 | + */ |
|
382 | + public function getRecipe($identifier, $type = '') |
|
383 | + { |
|
384 | + $identifier = $this->processIdentifier($identifier); |
|
385 | + if ($this->recipes->has($identifier)) { |
|
386 | + return $this->recipes->get($identifier); |
|
387 | + } |
|
388 | + $default_recipes = $this->getDefaultRecipes(); |
|
389 | + $matches = array(); |
|
390 | + foreach ($default_recipes as $wildcard => $default_recipe) { |
|
391 | + // is the wildcard recipe prefix in the identifier ? |
|
392 | + if (strpos($identifier, $wildcard) !== false) { |
|
393 | + // track matches and use the number of wildcard characters matched for the key |
|
394 | + $matches[ strlen($wildcard) ] = $default_recipe; |
|
395 | + } |
|
396 | + } |
|
397 | + if (count($matches) > 0) { |
|
398 | + // sort our recipes by the number of wildcard characters matched |
|
399 | + ksort($matches); |
|
400 | + // then grab the last recipe form the list, since it had the most matching characters |
|
401 | + $match = array_pop($matches); |
|
402 | + // since we are using a default recipe, we need to set it's identifier and fqcn |
|
403 | + return $this->copyDefaultRecipe($match, $identifier, $type); |
|
404 | + } |
|
405 | + if ($this->recipes->has(Recipe::DEFAULT_ID)) { |
|
406 | + // since we are using a default recipe, we need to set it's identifier and fqcn |
|
407 | + return $this->copyDefaultRecipe($this->recipes->get(Recipe::DEFAULT_ID), $identifier, $type); |
|
408 | + } |
|
409 | + throw new OutOfBoundsException( |
|
410 | + sprintf( |
|
411 | + esc_html__('Could not brew coffee because no recipes were found for class "%1$s".', 'event_espresso'), |
|
412 | + $identifier |
|
413 | + ) |
|
414 | + ); |
|
415 | + } |
|
416 | + |
|
417 | + |
|
418 | + /** |
|
419 | + * adds class name aliases to list of filters |
|
420 | + * |
|
421 | + * @param string $identifier Identifier for the entity class that the alias applies to |
|
422 | + * Typically a Fully Qualified Class Name |
|
423 | + * @param array|string $aliases |
|
424 | + * @return void |
|
425 | + * @throws InvalidIdentifierException |
|
426 | + */ |
|
427 | + public function addAliases($identifier, $aliases) |
|
428 | + { |
|
429 | + if (empty($aliases)) { |
|
430 | + return; |
|
431 | + } |
|
432 | + $identifier = $this->processIdentifier($identifier); |
|
433 | + foreach ((array) $aliases as $alias) { |
|
434 | + $this->filters[ $this->processIdentifier($alias) ] = $identifier; |
|
435 | + } |
|
436 | + } |
|
437 | + |
|
438 | + |
|
439 | + /** |
|
440 | + * Adds a service to one of the internal collections |
|
441 | + * |
|
442 | + * @param $identifier |
|
443 | + * @param array $arguments |
|
444 | + * @param string $type |
|
445 | + * @return mixed |
|
446 | + * @throws InvalidDataTypeException |
|
447 | + * @throws InvalidClassException |
|
448 | + * @throws OutOfBoundsException |
|
449 | + * @throws InvalidIdentifierException |
|
450 | + * @throws ServiceExistsException |
|
451 | + */ |
|
452 | + private function makeCoffee($identifier, $arguments = array(), $type = '') |
|
453 | + { |
|
454 | + if ((empty($type) || $type === CoffeeMaker::BREW_SHARED) && $this->has($identifier)) { |
|
455 | + throw new ServiceExistsException($identifier); |
|
456 | + } |
|
457 | + $identifier = $this->filterIdentifier($identifier); |
|
458 | + $recipe = $this->getRecipe($identifier, $type); |
|
459 | + $type = ! empty($type) ? $type : $recipe->type(); |
|
460 | + $coffee_maker = $this->getCoffeeMaker($type); |
|
461 | + return $coffee_maker->brew($recipe, $arguments); |
|
462 | + } |
|
463 | + |
|
464 | + |
|
465 | + /** |
|
466 | + * filters alias identifiers to find the real class name |
|
467 | + * |
|
468 | + * @param string $identifier Identifier for the entity class that the filter applies to |
|
469 | + * Typically a Fully Qualified Class Name |
|
470 | + * @return string |
|
471 | + * @throws InvalidIdentifierException |
|
472 | + */ |
|
473 | + private function filterIdentifier($identifier) |
|
474 | + { |
|
475 | + $identifier = $this->processIdentifier($identifier); |
|
476 | + return isset($this->filters[ $identifier ]) && ! empty($this->filters[ $identifier ]) |
|
477 | + ? $this->filters[ $identifier ] |
|
478 | + : $identifier; |
|
479 | + } |
|
480 | + |
|
481 | + |
|
482 | + /** |
|
483 | + * verifies and standardizes identifiers |
|
484 | + * |
|
485 | + * @param string $identifier Identifier for the entity class |
|
486 | + * Typically a Fully Qualified Class Name |
|
487 | + * @return string |
|
488 | + * @throws InvalidIdentifierException |
|
489 | + */ |
|
490 | + private function processIdentifier($identifier) |
|
491 | + { |
|
492 | + if (! is_string($identifier)) { |
|
493 | + throw new InvalidIdentifierException( |
|
494 | + is_object($identifier) ? get_class($identifier) : gettype($identifier), |
|
495 | + '\Fully\Qualified\ClassName' |
|
496 | + ); |
|
497 | + } |
|
498 | + return ltrim($identifier, '\\'); |
|
499 | + } |
|
500 | + |
|
501 | + |
|
502 | + /** |
|
503 | + * @param string $type |
|
504 | + * @return CoffeeMakerInterface |
|
505 | + * @throws OutOfBoundsException |
|
506 | + * @throws InvalidDataTypeException |
|
507 | + * @throws InvalidClassException |
|
508 | + */ |
|
509 | + private function getCoffeeMaker($type) |
|
510 | + { |
|
511 | + if (! $this->coffee_makers->has($type)) { |
|
512 | + throw new OutOfBoundsException( |
|
513 | + esc_html__('The requested coffee maker is either missing or invalid.', 'event_espresso') |
|
514 | + ); |
|
515 | + } |
|
516 | + return $this->coffee_makers->get($type); |
|
517 | + } |
|
518 | + |
|
519 | + |
|
520 | + /** |
|
521 | + * Retrieves all recipes that use a wildcard "*" in their identifier |
|
522 | + * This allows recipes to be set up for handling |
|
523 | + * legacy classes that do not support PSR-4 autoloading. |
|
524 | + * for example: |
|
525 | + * using "EEM_*" for a recipe identifier would target all legacy models like EEM_Attendee |
|
526 | + * |
|
527 | + * @return array |
|
528 | + */ |
|
529 | + private function getDefaultRecipes() |
|
530 | + { |
|
531 | + $default_recipes = array(); |
|
532 | + $this->recipes->rewind(); |
|
533 | + while ($this->recipes->valid()) { |
|
534 | + $identifier = $this->recipes->getInfo(); |
|
535 | + // does this recipe use a wildcard ? (but is NOT the global default) |
|
536 | + if ($identifier !== Recipe::DEFAULT_ID && strpos($identifier, '*') !== false) { |
|
537 | + // strip the wildcard and use identifier as key |
|
538 | + $default_recipes[ str_replace('*', '', $identifier) ] = $this->recipes->current(); |
|
539 | + } |
|
540 | + $this->recipes->next(); |
|
541 | + } |
|
542 | + return $default_recipes; |
|
543 | + } |
|
544 | + |
|
545 | + |
|
546 | + /** |
|
547 | + * clones a default recipe and then copies details |
|
548 | + * from the incoming request to it so that it can be used |
|
549 | + * |
|
550 | + * @param RecipeInterface $default_recipe |
|
551 | + * @param string $identifier |
|
552 | + * @param string $type |
|
553 | + * @return RecipeInterface |
|
554 | + */ |
|
555 | + private function copyDefaultRecipe(RecipeInterface $default_recipe, $identifier, $type = '') |
|
556 | + { |
|
557 | + $recipe = clone $default_recipe; |
|
558 | + if (! empty($type)) { |
|
559 | + $recipe->setType($type); |
|
560 | + } |
|
561 | + // is this the base default recipe ? |
|
562 | + if ($default_recipe->identifier() === Recipe::DEFAULT_ID) { |
|
563 | + $recipe->setIdentifier($identifier); |
|
564 | + $recipe->setFqcn($identifier); |
|
565 | + return $recipe; |
|
566 | + } |
|
567 | + $recipe->setIdentifier($identifier); |
|
568 | + foreach ($default_recipe->paths() as $path) { |
|
569 | + $path = str_replace('*', $identifier, $path); |
|
570 | + if (is_readable($path)) { |
|
571 | + $recipe->setPaths($path); |
|
572 | + } |
|
573 | + } |
|
574 | + $recipe->setFqcn($identifier); |
|
575 | + return $recipe; |
|
576 | + } |
|
577 | + |
|
578 | + |
|
579 | + /** |
|
580 | + * @param string $identifier Identifier for the entity class that the service applies to |
|
581 | + * Typically a Fully Qualified Class Name |
|
582 | + * @param mixed $service |
|
583 | + * @return mixed |
|
584 | + * @throws InvalidServiceException |
|
585 | + */ |
|
586 | + private function validateService($identifier, $service) |
|
587 | + { |
|
588 | + if (! is_object($service)) { |
|
589 | + throw new InvalidServiceException( |
|
590 | + $identifier, |
|
591 | + $service |
|
592 | + ); |
|
593 | + } |
|
594 | + return $service; |
|
595 | + } |
|
596 | 596 | } |
@@ -30,582 +30,582 @@ |
||
30 | 30 | */ |
31 | 31 | class CptQueryModifier |
32 | 32 | { |
33 | - /** |
|
34 | - * @var CurrentPage $current_page |
|
35 | - */ |
|
36 | - protected $current_page; |
|
37 | - |
|
38 | - /** |
|
39 | - * @var string $post_type |
|
40 | - */ |
|
41 | - protected $post_type = ''; |
|
42 | - |
|
43 | - /** |
|
44 | - * CPT details from CustomPostTypeDefinitions for specific post type |
|
45 | - * |
|
46 | - * @var array $cpt_details |
|
47 | - */ |
|
48 | - protected $cpt_details = array(); |
|
49 | - |
|
50 | - /** |
|
51 | - * @var EE_Table_Base[] $model_tables |
|
52 | - */ |
|
53 | - protected $model_tables = array(); |
|
54 | - |
|
55 | - /** |
|
56 | - * @var array $taxonomies |
|
57 | - */ |
|
58 | - protected $taxonomies = array(); |
|
59 | - |
|
60 | - /** |
|
61 | - * meta table for the related CPT |
|
62 | - * |
|
63 | - * @var EE_Secondary_Table $meta_table |
|
64 | - */ |
|
65 | - protected $meta_table; |
|
66 | - |
|
67 | - /** |
|
68 | - * EEM_CPT_Base model for the related CPT |
|
69 | - * |
|
70 | - * @var EEM_CPT_Base $model |
|
71 | - */ |
|
72 | - protected $model; |
|
73 | - |
|
74 | - /** |
|
75 | - * @var EE_Request_Handler $request_handler |
|
76 | - */ |
|
77 | - protected $request_handler; |
|
78 | - |
|
79 | - /** |
|
80 | - * @var WP_Query $wp_query |
|
81 | - */ |
|
82 | - protected $wp_query; |
|
83 | - |
|
84 | - /** |
|
85 | - * @var LoaderInterface $loader |
|
86 | - */ |
|
87 | - protected $loader; |
|
88 | - |
|
89 | - /** |
|
90 | - * @var RequestInterface $request |
|
91 | - */ |
|
92 | - protected $request; |
|
93 | - |
|
94 | - |
|
95 | - /** |
|
96 | - * CptQueryModifier constructor |
|
97 | - * |
|
98 | - * @param string $post_type |
|
99 | - * @param array $cpt_details |
|
100 | - * @param WP_Query $WP_Query |
|
101 | - * @param CurrentPage $current_page |
|
102 | - * @param RequestInterface $request |
|
103 | - * @param LoaderInterface $loader |
|
104 | - * @throws EE_Error |
|
105 | - */ |
|
106 | - public function __construct( |
|
107 | - $post_type, |
|
108 | - array $cpt_details, |
|
109 | - WP_Query $WP_Query, |
|
110 | - CurrentPage $current_page, |
|
111 | - RequestInterface $request, |
|
112 | - LoaderInterface $loader |
|
113 | - ) { |
|
114 | - $this->loader = $loader; |
|
115 | - $this->request = $request; |
|
116 | - $this->current_page = $current_page; |
|
117 | - $this->setWpQuery($WP_Query); |
|
118 | - $this->setPostType($post_type); |
|
119 | - $this->setCptDetails($cpt_details); |
|
120 | - $this->init(); |
|
121 | - } |
|
122 | - |
|
123 | - |
|
124 | - /** |
|
125 | - * @return string |
|
126 | - */ |
|
127 | - public function postType() |
|
128 | - { |
|
129 | - return $this->post_type; |
|
130 | - } |
|
131 | - |
|
132 | - |
|
133 | - /** |
|
134 | - * @param string $post_type |
|
135 | - */ |
|
136 | - protected function setPostType($post_type) |
|
137 | - { |
|
138 | - $this->post_type = $post_type; |
|
139 | - } |
|
140 | - |
|
141 | - |
|
142 | - /** |
|
143 | - * @return array |
|
144 | - */ |
|
145 | - public function cptDetails() |
|
146 | - { |
|
147 | - return $this->cpt_details; |
|
148 | - } |
|
149 | - |
|
150 | - |
|
151 | - /** |
|
152 | - * @param array $cpt_details |
|
153 | - */ |
|
154 | - protected function setCptDetails($cpt_details) |
|
155 | - { |
|
156 | - $this->cpt_details = $cpt_details; |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - /** |
|
161 | - * @return EE_Table_Base[] |
|
162 | - */ |
|
163 | - public function modelTables() |
|
164 | - { |
|
165 | - return $this->model_tables; |
|
166 | - } |
|
167 | - |
|
168 | - |
|
169 | - /** |
|
170 | - * @param EE_Table_Base[] $model_tables |
|
171 | - */ |
|
172 | - protected function setModelTables($model_tables) |
|
173 | - { |
|
174 | - $this->model_tables = $model_tables; |
|
175 | - } |
|
176 | - |
|
177 | - |
|
178 | - /** |
|
179 | - * @return array |
|
180 | - * @throws InvalidArgumentException |
|
181 | - * @throws InvalidDataTypeException |
|
182 | - * @throws InvalidInterfaceException |
|
183 | - */ |
|
184 | - public function taxonomies() |
|
185 | - { |
|
186 | - if (empty($this->taxonomies)) { |
|
187 | - $this->initializeTaxonomies(); |
|
188 | - } |
|
189 | - return $this->taxonomies; |
|
190 | - } |
|
191 | - |
|
192 | - |
|
193 | - /** |
|
194 | - * @param array $taxonomies |
|
195 | - */ |
|
196 | - protected function setTaxonomies(array $taxonomies) |
|
197 | - { |
|
198 | - $this->taxonomies = $taxonomies; |
|
199 | - } |
|
200 | - |
|
201 | - |
|
202 | - /** |
|
203 | - * @return EE_Secondary_Table |
|
204 | - */ |
|
205 | - public function metaTable() |
|
206 | - { |
|
207 | - return $this->meta_table; |
|
208 | - } |
|
209 | - |
|
210 | - |
|
211 | - /** |
|
212 | - * @param EE_Secondary_Table $meta_table |
|
213 | - */ |
|
214 | - public function setMetaTable(EE_Secondary_Table $meta_table) |
|
215 | - { |
|
216 | - $this->meta_table = $meta_table; |
|
217 | - } |
|
218 | - |
|
219 | - |
|
220 | - /** |
|
221 | - * @return EEM_Base |
|
222 | - */ |
|
223 | - public function model() |
|
224 | - { |
|
225 | - return $this->model; |
|
226 | - } |
|
227 | - |
|
228 | - |
|
229 | - /** |
|
230 | - * @param EEM_Base $CPT_model |
|
231 | - */ |
|
232 | - protected function setModel(EEM_Base $CPT_model) |
|
233 | - { |
|
234 | - $this->model = $CPT_model; |
|
235 | - } |
|
236 | - |
|
237 | - |
|
238 | - /** |
|
239 | - * @deprecated 4.9.63.p |
|
240 | - * @return EE_Request_Handler |
|
241 | - */ |
|
242 | - public function request() |
|
243 | - { |
|
244 | - if (! $this->request_handler instanceof EE_Request_Handler) { |
|
245 | - $this->request_handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler'); |
|
246 | - } |
|
247 | - return $this->request_handler; |
|
248 | - } |
|
249 | - |
|
250 | - |
|
251 | - |
|
252 | - // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps |
|
253 | - |
|
254 | - |
|
255 | - /** |
|
256 | - * @return WP_Query |
|
257 | - */ |
|
258 | - public function WpQuery() |
|
259 | - { |
|
260 | - return $this->wp_query; |
|
261 | - } |
|
262 | - // phpcs:enable |
|
263 | - |
|
264 | - |
|
265 | - /** |
|
266 | - * @param WP_Query $wp_query |
|
267 | - */ |
|
268 | - public function setWpQuery(WP_Query $wp_query) |
|
269 | - { |
|
270 | - $this->wp_query = $wp_query; |
|
271 | - } |
|
272 | - |
|
273 | - |
|
274 | - /** |
|
275 | - * @return void |
|
276 | - * @throws InvalidDataTypeException |
|
277 | - * @throws InvalidInterfaceException |
|
278 | - * @throws InvalidArgumentException |
|
279 | - */ |
|
280 | - protected function initializeTaxonomies() |
|
281 | - { |
|
282 | - // check if taxonomies have already been set and that this CPT has taxonomies registered for it |
|
283 | - if ( |
|
284 | - empty($this->taxonomies) |
|
285 | - && isset($this->cpt_details['args']['taxonomies']) |
|
286 | - ) { |
|
287 | - // if so then grab them, but we want the taxonomy name as the key |
|
288 | - $taxonomies = array_flip($this->cpt_details['args']['taxonomies']); |
|
289 | - // then grab the list of ALL taxonomies |
|
290 | - /** @var CustomTaxonomyDefinitions |
|
291 | - * $taxonomy_definitions |
|
292 | - */ |
|
293 | - $taxonomy_definitions = $this->loader->getShared( |
|
294 | - 'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' |
|
295 | - ); |
|
296 | - $all_taxonomies = $taxonomy_definitions->getCustomTaxonomyDefinitions(); |
|
297 | - foreach ($taxonomies as $taxonomy => &$details) { |
|
298 | - // add details to our taxonomies if they exist |
|
299 | - $details = isset($all_taxonomies[ $taxonomy ]) |
|
300 | - ? $all_taxonomies[ $taxonomy ] |
|
301 | - : array(); |
|
302 | - } |
|
303 | - // ALWAYS unset() variables that were passed by reference |
|
304 | - unset($details); |
|
305 | - $this->setTaxonomies($taxonomies); |
|
306 | - } |
|
307 | - } |
|
308 | - |
|
309 | - |
|
310 | - /** |
|
311 | - * @since 4.9.63.p |
|
312 | - * @throws EE_Error |
|
313 | - */ |
|
314 | - protected function init() |
|
315 | - { |
|
316 | - $this->setAdditionalCptDetails(); |
|
317 | - $this->setRequestVarsIfCpt(); |
|
318 | - // convert post_type to model name |
|
319 | - $model_name = str_replace('EE_', '', $this->cpt_details['class_name']); |
|
320 | - // load all tables related to CPT |
|
321 | - $this->setupModelsAndTables($model_name); |
|
322 | - // load and instantiate CPT_*_Strategy |
|
323 | - $CPT_Strategy = $this->cptStrategyClass($model_name); |
|
324 | - // !!!!!!!!!! IMPORTANT !!!!!!!!!!!! |
|
325 | - // here's the list of available filters in the WP_Query object |
|
326 | - // 'posts_where_paged' |
|
327 | - // 'posts_groupby' |
|
328 | - // 'posts_join_paged' |
|
329 | - // 'posts_orderby' |
|
330 | - // 'posts_distinct' |
|
331 | - // 'post_limits' |
|
332 | - // 'posts_fields' |
|
333 | - // 'posts_join' |
|
334 | - add_filter('posts_fields', array($this, 'postsFields')); |
|
335 | - add_filter('posts_join', array($this, 'postsJoin')); |
|
336 | - add_filter( |
|
337 | - 'get_' . $this->post_type . '_metadata', |
|
338 | - array($CPT_Strategy, 'get_EE_post_type_metadata'), |
|
339 | - 1, |
|
340 | - 4 |
|
341 | - ); |
|
342 | - add_filter('the_posts', array($this, 'thePosts'), 1, 1); |
|
343 | - if ($this->wp_query->is_main_query()) { |
|
344 | - add_filter('get_edit_post_link', array($this, 'getEditPostLink'), 10, 2); |
|
345 | - $this->addTemplateFilters(); |
|
346 | - } |
|
347 | - } |
|
348 | - |
|
349 | - |
|
350 | - /** |
|
351 | - * sets some basic query vars that pertain to the CPT |
|
352 | - * |
|
353 | - * @access protected |
|
354 | - * @return void |
|
355 | - */ |
|
356 | - protected function setAdditionalCptDetails() |
|
357 | - { |
|
358 | - // the post or category or term that is triggering EE |
|
359 | - $this->cpt_details['espresso_page'] = $this->current_page->isEspressoPage(); |
|
360 | - // requested post name |
|
361 | - $this->cpt_details['post_name'] = $this->request->getRequestParam('post_name'); |
|
362 | - // add support for viewing 'private', 'draft', or 'pending' posts |
|
363 | - if ( |
|
364 | - isset($this->wp_query->query_vars['p']) |
|
365 | - && $this->wp_query->query_vars['p'] !== 0 |
|
366 | - && is_user_logged_in() |
|
367 | - && current_user_can('edit_post', $this->wp_query->query_vars['p']) |
|
368 | - ) { |
|
369 | - // we can just inject directly into the WP_Query object |
|
370 | - $this->wp_query->query['post_status'] = array('publish', 'private', 'draft', 'pending'); |
|
371 | - // now set the main 'ee' request var so that the appropriate module can load the appropriate template(s) |
|
372 | - $this->request->setRequestParam('ee', $this->cpt_details['singular_slug']); |
|
373 | - } |
|
374 | - } |
|
375 | - |
|
376 | - |
|
377 | - /** |
|
378 | - * Checks if we're on a EE-CPT archive-or-single page, and if we've never set the EE request var. |
|
379 | - * If so, sets the 'ee' request variable |
|
380 | - * so other parts of EE can know what CPT is getting queried. |
|
381 | - * To Mike's knowledge, this must be called from during or after the pre_get_posts hook |
|
382 | - * in order for is_archive() and is_single() methods to work properly. |
|
383 | - * |
|
384 | - * @return void |
|
385 | - */ |
|
386 | - public function setRequestVarsIfCpt() |
|
387 | - { |
|
388 | - // check if ee action var has been set |
|
389 | - if (! $this->request->requestParamIsSet('ee')) { |
|
390 | - // check that route exists for CPT archive slug |
|
391 | - if (is_archive() && EE_Config::get_route($this->cpt_details['plural_slug'])) { |
|
392 | - // ie: set "ee" to "events" |
|
393 | - $this->request->setRequestParam('ee', $this->cpt_details['plural_slug']); |
|
394 | - // or does it match a single page CPT like /event/ |
|
395 | - } elseif (is_single() && EE_Config::get_route($this->cpt_details['singular_slug'])) { |
|
396 | - // ie: set "ee" to "event" |
|
397 | - $this->request->setRequestParam('ee', $this->cpt_details['singular_slug']); |
|
398 | - } |
|
399 | - } |
|
400 | - } |
|
401 | - |
|
402 | - |
|
403 | - /** |
|
404 | - * setupModelsAndTables |
|
405 | - * |
|
406 | - * @access protected |
|
407 | - * @param string $model_name |
|
408 | - * @throws EE_Error |
|
409 | - */ |
|
410 | - protected function setupModelsAndTables($model_name) |
|
411 | - { |
|
412 | - // get CPT table data via CPT Model |
|
413 | - $full_model_name = strpos($model_name, 'EEM_') !== 0 |
|
414 | - ? 'EEM_' . $model_name |
|
415 | - : $model_name; |
|
416 | - $model = $this->loader->getShared($full_model_name); |
|
417 | - if (! $model instanceof EEM_Base) { |
|
418 | - throw new EE_Error( |
|
419 | - sprintf( |
|
420 | - esc_html__( |
|
421 | - 'The "%1$s" model could not be loaded.', |
|
422 | - 'event_espresso' |
|
423 | - ), |
|
424 | - $full_model_name |
|
425 | - ) |
|
426 | - ); |
|
427 | - } |
|
428 | - $this->setModel($model); |
|
429 | - $this->setModelTables($this->model->get_tables()); |
|
430 | - $meta_model = $model_name . '_Meta'; |
|
431 | - // is there a Meta Table for this CPT? |
|
432 | - if ( |
|
433 | - isset($this->cpt_details['tables'][ $meta_model ]) |
|
434 | - && $this->cpt_details['tables'][ $meta_model ] instanceof EE_Secondary_Table |
|
435 | - ) { |
|
436 | - $this->setMetaTable($this->cpt_details['tables'][ $meta_model ]); |
|
437 | - } |
|
438 | - } |
|
439 | - |
|
440 | - |
|
441 | - /** |
|
442 | - * cptStrategyClass |
|
443 | - * |
|
444 | - * @access protected |
|
445 | - * @param string $model_name |
|
446 | - * @return string |
|
447 | - */ |
|
448 | - protected function cptStrategyClass($model_name) |
|
449 | - { |
|
450 | - // creates classname like: CPT_Event_Strategy |
|
451 | - $CPT_Strategy_class_name = 'EE_CPT_' . $model_name . '_Strategy'; |
|
452 | - // load and instantiate |
|
453 | - $CPT_Strategy = $this->loader->getShared( |
|
454 | - $CPT_Strategy_class_name, |
|
455 | - array('WP_Query' => $this->wp_query, 'CPT' => $this->cpt_details) |
|
456 | - ); |
|
457 | - if ($CPT_Strategy === null) { |
|
458 | - $CPT_Strategy = $this->loader->getShared( |
|
459 | - 'EE_CPT_Default_Strategy', |
|
460 | - array('WP_Query' => $this->wp_query, 'CPT' => $this->cpt_details) |
|
461 | - ); |
|
462 | - } |
|
463 | - return $CPT_Strategy; |
|
464 | - } |
|
465 | - |
|
466 | - |
|
467 | - /** |
|
468 | - * postsFields |
|
469 | - * |
|
470 | - * @access public |
|
471 | - * @param $SQL |
|
472 | - * @return string |
|
473 | - */ |
|
474 | - public function postsFields($SQL) |
|
475 | - { |
|
476 | - // does this CPT have a meta table ? |
|
477 | - if ($this->meta_table instanceof EE_Secondary_Table) { |
|
478 | - // adds something like ", wp_esp_event_meta.* " to WP Query SELECT statement |
|
479 | - $SQL .= ', ' . $this->meta_table->get_table_name() . '.* '; |
|
480 | - } |
|
481 | - remove_filter('posts_fields', array($this, 'postsFields')); |
|
482 | - return $SQL; |
|
483 | - } |
|
484 | - |
|
485 | - |
|
486 | - /** |
|
487 | - * postsJoin |
|
488 | - * |
|
489 | - * @access public |
|
490 | - * @param $SQL |
|
491 | - * @return string |
|
492 | - */ |
|
493 | - public function postsJoin($SQL) |
|
494 | - { |
|
495 | - // does this CPT have a meta table ? |
|
496 | - if ($this->meta_table instanceof EE_Secondary_Table) { |
|
497 | - global $wpdb; |
|
498 | - // adds something like " LEFT JOIN wp_esp_event_meta ON ( wp_esp_event_meta.EVT_ID = wp_posts.ID ) " to WP Query JOIN statement |
|
499 | - $SQL .= ' LEFT JOIN ' |
|
500 | - . $this->meta_table->get_table_name() |
|
501 | - . ' ON ( ' |
|
502 | - . $this->meta_table->get_table_name() |
|
503 | - . '.' |
|
504 | - . $this->meta_table->get_fk_on_table() |
|
505 | - . ' = ' |
|
506 | - . $wpdb->posts |
|
507 | - . '.ID ) '; |
|
508 | - } |
|
509 | - remove_filter('posts_join', array($this, 'postsJoin')); |
|
510 | - return $SQL; |
|
511 | - } |
|
512 | - |
|
513 | - |
|
514 | - /** |
|
515 | - * thePosts |
|
516 | - * |
|
517 | - * @access public |
|
518 | - * @param WP_Post[] $posts |
|
519 | - * @return WP_Post[] |
|
520 | - */ |
|
521 | - public function thePosts($posts) |
|
522 | - { |
|
523 | - $CPT_class = $this->cpt_details['class_name']; |
|
524 | - // loop thru posts |
|
525 | - if (is_array($posts) && $this->model instanceof EEM_CPT_Base) { |
|
526 | - foreach ($posts as $post) { |
|
527 | - if ($post->post_type === $this->post_type) { |
|
528 | - $post->{$CPT_class} = $this->model->instantiate_class_from_post_object($post); |
|
529 | - } |
|
530 | - } |
|
531 | - } |
|
532 | - remove_filter('the_posts', array($this, 'thePosts'), 1); |
|
533 | - return $posts; |
|
534 | - } |
|
535 | - |
|
536 | - |
|
537 | - /** |
|
538 | - * @param $url |
|
539 | - * @param $ID |
|
540 | - * @return string |
|
541 | - */ |
|
542 | - public function getEditPostLink($url, $ID) |
|
543 | - { |
|
544 | - // need to make sure we only edit links if our cpt |
|
545 | - global $post; |
|
546 | - // notice if the cpt is registered with `show_ee_ui` set to false, we take that to mean that the WordPress core ui |
|
547 | - // for interacting with the CPT is desired and there is no EE UI for interacting with the CPT in the admin. |
|
548 | - if ( |
|
549 | - ! $post instanceof WP_Post |
|
550 | - || $post->post_type !== $this->post_type |
|
551 | - || ( |
|
552 | - isset($this->cpt_details['args']['show_ee_ui']) |
|
553 | - && ! $this->cpt_details['args']['show_ee_ui'] |
|
554 | - ) |
|
555 | - ) { |
|
556 | - return $url; |
|
557 | - } |
|
558 | - // k made it here so all is good. |
|
559 | - return wp_nonce_url( |
|
560 | - add_query_arg( |
|
561 | - array('page' => $this->post_type, 'post' => $ID, 'action' => 'edit'), |
|
562 | - admin_url('admin.php') |
|
563 | - ), |
|
564 | - 'edit', |
|
565 | - 'edit_nonce' |
|
566 | - ); |
|
567 | - } |
|
568 | - |
|
569 | - |
|
570 | - /** |
|
571 | - * Execute any template filters. |
|
572 | - * This method is only called if in main query. |
|
573 | - * |
|
574 | - * @return void |
|
575 | - */ |
|
576 | - public function addTemplateFilters() |
|
577 | - { |
|
578 | - // if requested cpt supports page_templates and it's the main query |
|
579 | - if (! empty($this->cpt_details['args']['page_templates']) && $this->wp_query->is_main_query()) { |
|
580 | - // then let's hook into the appropriate query_template hook |
|
581 | - add_filter('single_template', array($this, 'singleCptTemplate')); |
|
582 | - } |
|
583 | - } |
|
584 | - |
|
585 | - |
|
586 | - /** |
|
587 | - * Callback for single_template wp filter. |
|
588 | - * This is used to load the set page_template for a single ee cpt if its set. If "default" then we load the normal |
|
589 | - * hierarchy. |
|
590 | - * |
|
591 | - * @access public |
|
592 | - * @param string $current_template Existing default template path derived for this page call. |
|
593 | - * @return string the path to the full template file. |
|
594 | - */ |
|
595 | - public function singleCptTemplate($current_template) |
|
596 | - { |
|
597 | - $object = get_queried_object(); |
|
598 | - // does this called object HAVE a page template set that is something other than the default. |
|
599 | - $template = get_post_meta($object->ID, '_wp_page_template', true); |
|
600 | - // exit early if default or not set or invalid path (accounts for theme changes) |
|
601 | - if ( |
|
602 | - $template === 'default' |
|
603 | - || empty($template) |
|
604 | - || ! is_readable(get_stylesheet_directory() . '/' . $template) |
|
605 | - ) { |
|
606 | - return $current_template; |
|
607 | - } |
|
608 | - // made it here so we SHOULD be able to just locate the template and then return it. |
|
609 | - return locate_template(array($template)); |
|
610 | - } |
|
33 | + /** |
|
34 | + * @var CurrentPage $current_page |
|
35 | + */ |
|
36 | + protected $current_page; |
|
37 | + |
|
38 | + /** |
|
39 | + * @var string $post_type |
|
40 | + */ |
|
41 | + protected $post_type = ''; |
|
42 | + |
|
43 | + /** |
|
44 | + * CPT details from CustomPostTypeDefinitions for specific post type |
|
45 | + * |
|
46 | + * @var array $cpt_details |
|
47 | + */ |
|
48 | + protected $cpt_details = array(); |
|
49 | + |
|
50 | + /** |
|
51 | + * @var EE_Table_Base[] $model_tables |
|
52 | + */ |
|
53 | + protected $model_tables = array(); |
|
54 | + |
|
55 | + /** |
|
56 | + * @var array $taxonomies |
|
57 | + */ |
|
58 | + protected $taxonomies = array(); |
|
59 | + |
|
60 | + /** |
|
61 | + * meta table for the related CPT |
|
62 | + * |
|
63 | + * @var EE_Secondary_Table $meta_table |
|
64 | + */ |
|
65 | + protected $meta_table; |
|
66 | + |
|
67 | + /** |
|
68 | + * EEM_CPT_Base model for the related CPT |
|
69 | + * |
|
70 | + * @var EEM_CPT_Base $model |
|
71 | + */ |
|
72 | + protected $model; |
|
73 | + |
|
74 | + /** |
|
75 | + * @var EE_Request_Handler $request_handler |
|
76 | + */ |
|
77 | + protected $request_handler; |
|
78 | + |
|
79 | + /** |
|
80 | + * @var WP_Query $wp_query |
|
81 | + */ |
|
82 | + protected $wp_query; |
|
83 | + |
|
84 | + /** |
|
85 | + * @var LoaderInterface $loader |
|
86 | + */ |
|
87 | + protected $loader; |
|
88 | + |
|
89 | + /** |
|
90 | + * @var RequestInterface $request |
|
91 | + */ |
|
92 | + protected $request; |
|
93 | + |
|
94 | + |
|
95 | + /** |
|
96 | + * CptQueryModifier constructor |
|
97 | + * |
|
98 | + * @param string $post_type |
|
99 | + * @param array $cpt_details |
|
100 | + * @param WP_Query $WP_Query |
|
101 | + * @param CurrentPage $current_page |
|
102 | + * @param RequestInterface $request |
|
103 | + * @param LoaderInterface $loader |
|
104 | + * @throws EE_Error |
|
105 | + */ |
|
106 | + public function __construct( |
|
107 | + $post_type, |
|
108 | + array $cpt_details, |
|
109 | + WP_Query $WP_Query, |
|
110 | + CurrentPage $current_page, |
|
111 | + RequestInterface $request, |
|
112 | + LoaderInterface $loader |
|
113 | + ) { |
|
114 | + $this->loader = $loader; |
|
115 | + $this->request = $request; |
|
116 | + $this->current_page = $current_page; |
|
117 | + $this->setWpQuery($WP_Query); |
|
118 | + $this->setPostType($post_type); |
|
119 | + $this->setCptDetails($cpt_details); |
|
120 | + $this->init(); |
|
121 | + } |
|
122 | + |
|
123 | + |
|
124 | + /** |
|
125 | + * @return string |
|
126 | + */ |
|
127 | + public function postType() |
|
128 | + { |
|
129 | + return $this->post_type; |
|
130 | + } |
|
131 | + |
|
132 | + |
|
133 | + /** |
|
134 | + * @param string $post_type |
|
135 | + */ |
|
136 | + protected function setPostType($post_type) |
|
137 | + { |
|
138 | + $this->post_type = $post_type; |
|
139 | + } |
|
140 | + |
|
141 | + |
|
142 | + /** |
|
143 | + * @return array |
|
144 | + */ |
|
145 | + public function cptDetails() |
|
146 | + { |
|
147 | + return $this->cpt_details; |
|
148 | + } |
|
149 | + |
|
150 | + |
|
151 | + /** |
|
152 | + * @param array $cpt_details |
|
153 | + */ |
|
154 | + protected function setCptDetails($cpt_details) |
|
155 | + { |
|
156 | + $this->cpt_details = $cpt_details; |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + /** |
|
161 | + * @return EE_Table_Base[] |
|
162 | + */ |
|
163 | + public function modelTables() |
|
164 | + { |
|
165 | + return $this->model_tables; |
|
166 | + } |
|
167 | + |
|
168 | + |
|
169 | + /** |
|
170 | + * @param EE_Table_Base[] $model_tables |
|
171 | + */ |
|
172 | + protected function setModelTables($model_tables) |
|
173 | + { |
|
174 | + $this->model_tables = $model_tables; |
|
175 | + } |
|
176 | + |
|
177 | + |
|
178 | + /** |
|
179 | + * @return array |
|
180 | + * @throws InvalidArgumentException |
|
181 | + * @throws InvalidDataTypeException |
|
182 | + * @throws InvalidInterfaceException |
|
183 | + */ |
|
184 | + public function taxonomies() |
|
185 | + { |
|
186 | + if (empty($this->taxonomies)) { |
|
187 | + $this->initializeTaxonomies(); |
|
188 | + } |
|
189 | + return $this->taxonomies; |
|
190 | + } |
|
191 | + |
|
192 | + |
|
193 | + /** |
|
194 | + * @param array $taxonomies |
|
195 | + */ |
|
196 | + protected function setTaxonomies(array $taxonomies) |
|
197 | + { |
|
198 | + $this->taxonomies = $taxonomies; |
|
199 | + } |
|
200 | + |
|
201 | + |
|
202 | + /** |
|
203 | + * @return EE_Secondary_Table |
|
204 | + */ |
|
205 | + public function metaTable() |
|
206 | + { |
|
207 | + return $this->meta_table; |
|
208 | + } |
|
209 | + |
|
210 | + |
|
211 | + /** |
|
212 | + * @param EE_Secondary_Table $meta_table |
|
213 | + */ |
|
214 | + public function setMetaTable(EE_Secondary_Table $meta_table) |
|
215 | + { |
|
216 | + $this->meta_table = $meta_table; |
|
217 | + } |
|
218 | + |
|
219 | + |
|
220 | + /** |
|
221 | + * @return EEM_Base |
|
222 | + */ |
|
223 | + public function model() |
|
224 | + { |
|
225 | + return $this->model; |
|
226 | + } |
|
227 | + |
|
228 | + |
|
229 | + /** |
|
230 | + * @param EEM_Base $CPT_model |
|
231 | + */ |
|
232 | + protected function setModel(EEM_Base $CPT_model) |
|
233 | + { |
|
234 | + $this->model = $CPT_model; |
|
235 | + } |
|
236 | + |
|
237 | + |
|
238 | + /** |
|
239 | + * @deprecated 4.9.63.p |
|
240 | + * @return EE_Request_Handler |
|
241 | + */ |
|
242 | + public function request() |
|
243 | + { |
|
244 | + if (! $this->request_handler instanceof EE_Request_Handler) { |
|
245 | + $this->request_handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler'); |
|
246 | + } |
|
247 | + return $this->request_handler; |
|
248 | + } |
|
249 | + |
|
250 | + |
|
251 | + |
|
252 | + // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps |
|
253 | + |
|
254 | + |
|
255 | + /** |
|
256 | + * @return WP_Query |
|
257 | + */ |
|
258 | + public function WpQuery() |
|
259 | + { |
|
260 | + return $this->wp_query; |
|
261 | + } |
|
262 | + // phpcs:enable |
|
263 | + |
|
264 | + |
|
265 | + /** |
|
266 | + * @param WP_Query $wp_query |
|
267 | + */ |
|
268 | + public function setWpQuery(WP_Query $wp_query) |
|
269 | + { |
|
270 | + $this->wp_query = $wp_query; |
|
271 | + } |
|
272 | + |
|
273 | + |
|
274 | + /** |
|
275 | + * @return void |
|
276 | + * @throws InvalidDataTypeException |
|
277 | + * @throws InvalidInterfaceException |
|
278 | + * @throws InvalidArgumentException |
|
279 | + */ |
|
280 | + protected function initializeTaxonomies() |
|
281 | + { |
|
282 | + // check if taxonomies have already been set and that this CPT has taxonomies registered for it |
|
283 | + if ( |
|
284 | + empty($this->taxonomies) |
|
285 | + && isset($this->cpt_details['args']['taxonomies']) |
|
286 | + ) { |
|
287 | + // if so then grab them, but we want the taxonomy name as the key |
|
288 | + $taxonomies = array_flip($this->cpt_details['args']['taxonomies']); |
|
289 | + // then grab the list of ALL taxonomies |
|
290 | + /** @var CustomTaxonomyDefinitions |
|
291 | + * $taxonomy_definitions |
|
292 | + */ |
|
293 | + $taxonomy_definitions = $this->loader->getShared( |
|
294 | + 'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' |
|
295 | + ); |
|
296 | + $all_taxonomies = $taxonomy_definitions->getCustomTaxonomyDefinitions(); |
|
297 | + foreach ($taxonomies as $taxonomy => &$details) { |
|
298 | + // add details to our taxonomies if they exist |
|
299 | + $details = isset($all_taxonomies[ $taxonomy ]) |
|
300 | + ? $all_taxonomies[ $taxonomy ] |
|
301 | + : array(); |
|
302 | + } |
|
303 | + // ALWAYS unset() variables that were passed by reference |
|
304 | + unset($details); |
|
305 | + $this->setTaxonomies($taxonomies); |
|
306 | + } |
|
307 | + } |
|
308 | + |
|
309 | + |
|
310 | + /** |
|
311 | + * @since 4.9.63.p |
|
312 | + * @throws EE_Error |
|
313 | + */ |
|
314 | + protected function init() |
|
315 | + { |
|
316 | + $this->setAdditionalCptDetails(); |
|
317 | + $this->setRequestVarsIfCpt(); |
|
318 | + // convert post_type to model name |
|
319 | + $model_name = str_replace('EE_', '', $this->cpt_details['class_name']); |
|
320 | + // load all tables related to CPT |
|
321 | + $this->setupModelsAndTables($model_name); |
|
322 | + // load and instantiate CPT_*_Strategy |
|
323 | + $CPT_Strategy = $this->cptStrategyClass($model_name); |
|
324 | + // !!!!!!!!!! IMPORTANT !!!!!!!!!!!! |
|
325 | + // here's the list of available filters in the WP_Query object |
|
326 | + // 'posts_where_paged' |
|
327 | + // 'posts_groupby' |
|
328 | + // 'posts_join_paged' |
|
329 | + // 'posts_orderby' |
|
330 | + // 'posts_distinct' |
|
331 | + // 'post_limits' |
|
332 | + // 'posts_fields' |
|
333 | + // 'posts_join' |
|
334 | + add_filter('posts_fields', array($this, 'postsFields')); |
|
335 | + add_filter('posts_join', array($this, 'postsJoin')); |
|
336 | + add_filter( |
|
337 | + 'get_' . $this->post_type . '_metadata', |
|
338 | + array($CPT_Strategy, 'get_EE_post_type_metadata'), |
|
339 | + 1, |
|
340 | + 4 |
|
341 | + ); |
|
342 | + add_filter('the_posts', array($this, 'thePosts'), 1, 1); |
|
343 | + if ($this->wp_query->is_main_query()) { |
|
344 | + add_filter('get_edit_post_link', array($this, 'getEditPostLink'), 10, 2); |
|
345 | + $this->addTemplateFilters(); |
|
346 | + } |
|
347 | + } |
|
348 | + |
|
349 | + |
|
350 | + /** |
|
351 | + * sets some basic query vars that pertain to the CPT |
|
352 | + * |
|
353 | + * @access protected |
|
354 | + * @return void |
|
355 | + */ |
|
356 | + protected function setAdditionalCptDetails() |
|
357 | + { |
|
358 | + // the post or category or term that is triggering EE |
|
359 | + $this->cpt_details['espresso_page'] = $this->current_page->isEspressoPage(); |
|
360 | + // requested post name |
|
361 | + $this->cpt_details['post_name'] = $this->request->getRequestParam('post_name'); |
|
362 | + // add support for viewing 'private', 'draft', or 'pending' posts |
|
363 | + if ( |
|
364 | + isset($this->wp_query->query_vars['p']) |
|
365 | + && $this->wp_query->query_vars['p'] !== 0 |
|
366 | + && is_user_logged_in() |
|
367 | + && current_user_can('edit_post', $this->wp_query->query_vars['p']) |
|
368 | + ) { |
|
369 | + // we can just inject directly into the WP_Query object |
|
370 | + $this->wp_query->query['post_status'] = array('publish', 'private', 'draft', 'pending'); |
|
371 | + // now set the main 'ee' request var so that the appropriate module can load the appropriate template(s) |
|
372 | + $this->request->setRequestParam('ee', $this->cpt_details['singular_slug']); |
|
373 | + } |
|
374 | + } |
|
375 | + |
|
376 | + |
|
377 | + /** |
|
378 | + * Checks if we're on a EE-CPT archive-or-single page, and if we've never set the EE request var. |
|
379 | + * If so, sets the 'ee' request variable |
|
380 | + * so other parts of EE can know what CPT is getting queried. |
|
381 | + * To Mike's knowledge, this must be called from during or after the pre_get_posts hook |
|
382 | + * in order for is_archive() and is_single() methods to work properly. |
|
383 | + * |
|
384 | + * @return void |
|
385 | + */ |
|
386 | + public function setRequestVarsIfCpt() |
|
387 | + { |
|
388 | + // check if ee action var has been set |
|
389 | + if (! $this->request->requestParamIsSet('ee')) { |
|
390 | + // check that route exists for CPT archive slug |
|
391 | + if (is_archive() && EE_Config::get_route($this->cpt_details['plural_slug'])) { |
|
392 | + // ie: set "ee" to "events" |
|
393 | + $this->request->setRequestParam('ee', $this->cpt_details['plural_slug']); |
|
394 | + // or does it match a single page CPT like /event/ |
|
395 | + } elseif (is_single() && EE_Config::get_route($this->cpt_details['singular_slug'])) { |
|
396 | + // ie: set "ee" to "event" |
|
397 | + $this->request->setRequestParam('ee', $this->cpt_details['singular_slug']); |
|
398 | + } |
|
399 | + } |
|
400 | + } |
|
401 | + |
|
402 | + |
|
403 | + /** |
|
404 | + * setupModelsAndTables |
|
405 | + * |
|
406 | + * @access protected |
|
407 | + * @param string $model_name |
|
408 | + * @throws EE_Error |
|
409 | + */ |
|
410 | + protected function setupModelsAndTables($model_name) |
|
411 | + { |
|
412 | + // get CPT table data via CPT Model |
|
413 | + $full_model_name = strpos($model_name, 'EEM_') !== 0 |
|
414 | + ? 'EEM_' . $model_name |
|
415 | + : $model_name; |
|
416 | + $model = $this->loader->getShared($full_model_name); |
|
417 | + if (! $model instanceof EEM_Base) { |
|
418 | + throw new EE_Error( |
|
419 | + sprintf( |
|
420 | + esc_html__( |
|
421 | + 'The "%1$s" model could not be loaded.', |
|
422 | + 'event_espresso' |
|
423 | + ), |
|
424 | + $full_model_name |
|
425 | + ) |
|
426 | + ); |
|
427 | + } |
|
428 | + $this->setModel($model); |
|
429 | + $this->setModelTables($this->model->get_tables()); |
|
430 | + $meta_model = $model_name . '_Meta'; |
|
431 | + // is there a Meta Table for this CPT? |
|
432 | + if ( |
|
433 | + isset($this->cpt_details['tables'][ $meta_model ]) |
|
434 | + && $this->cpt_details['tables'][ $meta_model ] instanceof EE_Secondary_Table |
|
435 | + ) { |
|
436 | + $this->setMetaTable($this->cpt_details['tables'][ $meta_model ]); |
|
437 | + } |
|
438 | + } |
|
439 | + |
|
440 | + |
|
441 | + /** |
|
442 | + * cptStrategyClass |
|
443 | + * |
|
444 | + * @access protected |
|
445 | + * @param string $model_name |
|
446 | + * @return string |
|
447 | + */ |
|
448 | + protected function cptStrategyClass($model_name) |
|
449 | + { |
|
450 | + // creates classname like: CPT_Event_Strategy |
|
451 | + $CPT_Strategy_class_name = 'EE_CPT_' . $model_name . '_Strategy'; |
|
452 | + // load and instantiate |
|
453 | + $CPT_Strategy = $this->loader->getShared( |
|
454 | + $CPT_Strategy_class_name, |
|
455 | + array('WP_Query' => $this->wp_query, 'CPT' => $this->cpt_details) |
|
456 | + ); |
|
457 | + if ($CPT_Strategy === null) { |
|
458 | + $CPT_Strategy = $this->loader->getShared( |
|
459 | + 'EE_CPT_Default_Strategy', |
|
460 | + array('WP_Query' => $this->wp_query, 'CPT' => $this->cpt_details) |
|
461 | + ); |
|
462 | + } |
|
463 | + return $CPT_Strategy; |
|
464 | + } |
|
465 | + |
|
466 | + |
|
467 | + /** |
|
468 | + * postsFields |
|
469 | + * |
|
470 | + * @access public |
|
471 | + * @param $SQL |
|
472 | + * @return string |
|
473 | + */ |
|
474 | + public function postsFields($SQL) |
|
475 | + { |
|
476 | + // does this CPT have a meta table ? |
|
477 | + if ($this->meta_table instanceof EE_Secondary_Table) { |
|
478 | + // adds something like ", wp_esp_event_meta.* " to WP Query SELECT statement |
|
479 | + $SQL .= ', ' . $this->meta_table->get_table_name() . '.* '; |
|
480 | + } |
|
481 | + remove_filter('posts_fields', array($this, 'postsFields')); |
|
482 | + return $SQL; |
|
483 | + } |
|
484 | + |
|
485 | + |
|
486 | + /** |
|
487 | + * postsJoin |
|
488 | + * |
|
489 | + * @access public |
|
490 | + * @param $SQL |
|
491 | + * @return string |
|
492 | + */ |
|
493 | + public function postsJoin($SQL) |
|
494 | + { |
|
495 | + // does this CPT have a meta table ? |
|
496 | + if ($this->meta_table instanceof EE_Secondary_Table) { |
|
497 | + global $wpdb; |
|
498 | + // adds something like " LEFT JOIN wp_esp_event_meta ON ( wp_esp_event_meta.EVT_ID = wp_posts.ID ) " to WP Query JOIN statement |
|
499 | + $SQL .= ' LEFT JOIN ' |
|
500 | + . $this->meta_table->get_table_name() |
|
501 | + . ' ON ( ' |
|
502 | + . $this->meta_table->get_table_name() |
|
503 | + . '.' |
|
504 | + . $this->meta_table->get_fk_on_table() |
|
505 | + . ' = ' |
|
506 | + . $wpdb->posts |
|
507 | + . '.ID ) '; |
|
508 | + } |
|
509 | + remove_filter('posts_join', array($this, 'postsJoin')); |
|
510 | + return $SQL; |
|
511 | + } |
|
512 | + |
|
513 | + |
|
514 | + /** |
|
515 | + * thePosts |
|
516 | + * |
|
517 | + * @access public |
|
518 | + * @param WP_Post[] $posts |
|
519 | + * @return WP_Post[] |
|
520 | + */ |
|
521 | + public function thePosts($posts) |
|
522 | + { |
|
523 | + $CPT_class = $this->cpt_details['class_name']; |
|
524 | + // loop thru posts |
|
525 | + if (is_array($posts) && $this->model instanceof EEM_CPT_Base) { |
|
526 | + foreach ($posts as $post) { |
|
527 | + if ($post->post_type === $this->post_type) { |
|
528 | + $post->{$CPT_class} = $this->model->instantiate_class_from_post_object($post); |
|
529 | + } |
|
530 | + } |
|
531 | + } |
|
532 | + remove_filter('the_posts', array($this, 'thePosts'), 1); |
|
533 | + return $posts; |
|
534 | + } |
|
535 | + |
|
536 | + |
|
537 | + /** |
|
538 | + * @param $url |
|
539 | + * @param $ID |
|
540 | + * @return string |
|
541 | + */ |
|
542 | + public function getEditPostLink($url, $ID) |
|
543 | + { |
|
544 | + // need to make sure we only edit links if our cpt |
|
545 | + global $post; |
|
546 | + // notice if the cpt is registered with `show_ee_ui` set to false, we take that to mean that the WordPress core ui |
|
547 | + // for interacting with the CPT is desired and there is no EE UI for interacting with the CPT in the admin. |
|
548 | + if ( |
|
549 | + ! $post instanceof WP_Post |
|
550 | + || $post->post_type !== $this->post_type |
|
551 | + || ( |
|
552 | + isset($this->cpt_details['args']['show_ee_ui']) |
|
553 | + && ! $this->cpt_details['args']['show_ee_ui'] |
|
554 | + ) |
|
555 | + ) { |
|
556 | + return $url; |
|
557 | + } |
|
558 | + // k made it here so all is good. |
|
559 | + return wp_nonce_url( |
|
560 | + add_query_arg( |
|
561 | + array('page' => $this->post_type, 'post' => $ID, 'action' => 'edit'), |
|
562 | + admin_url('admin.php') |
|
563 | + ), |
|
564 | + 'edit', |
|
565 | + 'edit_nonce' |
|
566 | + ); |
|
567 | + } |
|
568 | + |
|
569 | + |
|
570 | + /** |
|
571 | + * Execute any template filters. |
|
572 | + * This method is only called if in main query. |
|
573 | + * |
|
574 | + * @return void |
|
575 | + */ |
|
576 | + public function addTemplateFilters() |
|
577 | + { |
|
578 | + // if requested cpt supports page_templates and it's the main query |
|
579 | + if (! empty($this->cpt_details['args']['page_templates']) && $this->wp_query->is_main_query()) { |
|
580 | + // then let's hook into the appropriate query_template hook |
|
581 | + add_filter('single_template', array($this, 'singleCptTemplate')); |
|
582 | + } |
|
583 | + } |
|
584 | + |
|
585 | + |
|
586 | + /** |
|
587 | + * Callback for single_template wp filter. |
|
588 | + * This is used to load the set page_template for a single ee cpt if its set. If "default" then we load the normal |
|
589 | + * hierarchy. |
|
590 | + * |
|
591 | + * @access public |
|
592 | + * @param string $current_template Existing default template path derived for this page call. |
|
593 | + * @return string the path to the full template file. |
|
594 | + */ |
|
595 | + public function singleCptTemplate($current_template) |
|
596 | + { |
|
597 | + $object = get_queried_object(); |
|
598 | + // does this called object HAVE a page template set that is something other than the default. |
|
599 | + $template = get_post_meta($object->ID, '_wp_page_template', true); |
|
600 | + // exit early if default or not set or invalid path (accounts for theme changes) |
|
601 | + if ( |
|
602 | + $template === 'default' |
|
603 | + || empty($template) |
|
604 | + || ! is_readable(get_stylesheet_directory() . '/' . $template) |
|
605 | + ) { |
|
606 | + return $current_template; |
|
607 | + } |
|
608 | + // made it here so we SHOULD be able to just locate the template and then return it. |
|
609 | + return locate_template(array($template)); |
|
610 | + } |
|
611 | 611 | } |
@@ -241,7 +241,7 @@ discard block |
||
241 | 241 | */ |
242 | 242 | public function request() |
243 | 243 | { |
244 | - if (! $this->request_handler instanceof EE_Request_Handler) { |
|
244 | + if ( ! $this->request_handler instanceof EE_Request_Handler) { |
|
245 | 245 | $this->request_handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler'); |
246 | 246 | } |
247 | 247 | return $this->request_handler; |
@@ -296,8 +296,8 @@ discard block |
||
296 | 296 | $all_taxonomies = $taxonomy_definitions->getCustomTaxonomyDefinitions(); |
297 | 297 | foreach ($taxonomies as $taxonomy => &$details) { |
298 | 298 | // add details to our taxonomies if they exist |
299 | - $details = isset($all_taxonomies[ $taxonomy ]) |
|
300 | - ? $all_taxonomies[ $taxonomy ] |
|
299 | + $details = isset($all_taxonomies[$taxonomy]) |
|
300 | + ? $all_taxonomies[$taxonomy] |
|
301 | 301 | : array(); |
302 | 302 | } |
303 | 303 | // ALWAYS unset() variables that were passed by reference |
@@ -334,7 +334,7 @@ discard block |
||
334 | 334 | add_filter('posts_fields', array($this, 'postsFields')); |
335 | 335 | add_filter('posts_join', array($this, 'postsJoin')); |
336 | 336 | add_filter( |
337 | - 'get_' . $this->post_type . '_metadata', |
|
337 | + 'get_'.$this->post_type.'_metadata', |
|
338 | 338 | array($CPT_Strategy, 'get_EE_post_type_metadata'), |
339 | 339 | 1, |
340 | 340 | 4 |
@@ -386,7 +386,7 @@ discard block |
||
386 | 386 | public function setRequestVarsIfCpt() |
387 | 387 | { |
388 | 388 | // check if ee action var has been set |
389 | - if (! $this->request->requestParamIsSet('ee')) { |
|
389 | + if ( ! $this->request->requestParamIsSet('ee')) { |
|
390 | 390 | // check that route exists for CPT archive slug |
391 | 391 | if (is_archive() && EE_Config::get_route($this->cpt_details['plural_slug'])) { |
392 | 392 | // ie: set "ee" to "events" |
@@ -411,10 +411,10 @@ discard block |
||
411 | 411 | { |
412 | 412 | // get CPT table data via CPT Model |
413 | 413 | $full_model_name = strpos($model_name, 'EEM_') !== 0 |
414 | - ? 'EEM_' . $model_name |
|
414 | + ? 'EEM_'.$model_name |
|
415 | 415 | : $model_name; |
416 | 416 | $model = $this->loader->getShared($full_model_name); |
417 | - if (! $model instanceof EEM_Base) { |
|
417 | + if ( ! $model instanceof EEM_Base) { |
|
418 | 418 | throw new EE_Error( |
419 | 419 | sprintf( |
420 | 420 | esc_html__( |
@@ -427,13 +427,13 @@ discard block |
||
427 | 427 | } |
428 | 428 | $this->setModel($model); |
429 | 429 | $this->setModelTables($this->model->get_tables()); |
430 | - $meta_model = $model_name . '_Meta'; |
|
430 | + $meta_model = $model_name.'_Meta'; |
|
431 | 431 | // is there a Meta Table for this CPT? |
432 | 432 | if ( |
433 | - isset($this->cpt_details['tables'][ $meta_model ]) |
|
434 | - && $this->cpt_details['tables'][ $meta_model ] instanceof EE_Secondary_Table |
|
433 | + isset($this->cpt_details['tables'][$meta_model]) |
|
434 | + && $this->cpt_details['tables'][$meta_model] instanceof EE_Secondary_Table |
|
435 | 435 | ) { |
436 | - $this->setMetaTable($this->cpt_details['tables'][ $meta_model ]); |
|
436 | + $this->setMetaTable($this->cpt_details['tables'][$meta_model]); |
|
437 | 437 | } |
438 | 438 | } |
439 | 439 | |
@@ -448,7 +448,7 @@ discard block |
||
448 | 448 | protected function cptStrategyClass($model_name) |
449 | 449 | { |
450 | 450 | // creates classname like: CPT_Event_Strategy |
451 | - $CPT_Strategy_class_name = 'EE_CPT_' . $model_name . '_Strategy'; |
|
451 | + $CPT_Strategy_class_name = 'EE_CPT_'.$model_name.'_Strategy'; |
|
452 | 452 | // load and instantiate |
453 | 453 | $CPT_Strategy = $this->loader->getShared( |
454 | 454 | $CPT_Strategy_class_name, |
@@ -476,7 +476,7 @@ discard block |
||
476 | 476 | // does this CPT have a meta table ? |
477 | 477 | if ($this->meta_table instanceof EE_Secondary_Table) { |
478 | 478 | // adds something like ", wp_esp_event_meta.* " to WP Query SELECT statement |
479 | - $SQL .= ', ' . $this->meta_table->get_table_name() . '.* '; |
|
479 | + $SQL .= ', '.$this->meta_table->get_table_name().'.* '; |
|
480 | 480 | } |
481 | 481 | remove_filter('posts_fields', array($this, 'postsFields')); |
482 | 482 | return $SQL; |
@@ -576,7 +576,7 @@ discard block |
||
576 | 576 | public function addTemplateFilters() |
577 | 577 | { |
578 | 578 | // if requested cpt supports page_templates and it's the main query |
579 | - if (! empty($this->cpt_details['args']['page_templates']) && $this->wp_query->is_main_query()) { |
|
579 | + if ( ! empty($this->cpt_details['args']['page_templates']) && $this->wp_query->is_main_query()) { |
|
580 | 580 | // then let's hook into the appropriate query_template hook |
581 | 581 | add_filter('single_template', array($this, 'singleCptTemplate')); |
582 | 582 | } |
@@ -601,7 +601,7 @@ discard block |
||
601 | 601 | if ( |
602 | 602 | $template === 'default' |
603 | 603 | || empty($template) |
604 | - || ! is_readable(get_stylesheet_directory() . '/' . $template) |
|
604 | + || ! is_readable(get_stylesheet_directory().'/'.$template) |
|
605 | 605 | ) { |
606 | 606 | return $current_template; |
607 | 607 | } |
@@ -38,7 +38,7 @@ discard block |
||
38 | 38 | */ |
39 | 39 | public static function instance() |
40 | 40 | { |
41 | - if (! self::$_instance instanceof EE_Cron_Tasks) { |
|
41 | + if ( ! self::$_instance instanceof EE_Cron_Tasks) { |
|
42 | 42 | self::$_instance = new self(); |
43 | 43 | } |
44 | 44 | return self::$_instance; |
@@ -72,7 +72,7 @@ discard block |
||
72 | 72 | */ |
73 | 73 | add_action( |
74 | 74 | 'AHEE__EE_System__load_core_configuration__complete', |
75 | - function () { |
|
75 | + function() { |
|
76 | 76 | EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true; |
77 | 77 | EE_Registry::instance()->NET_CFG->update_config(true, false); |
78 | 78 | add_option('ee_disabled_wp_cron_check', 1, '', false); |
@@ -124,16 +124,16 @@ discard block |
||
124 | 124 | 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
125 | 125 | ); |
126 | 126 | $crons = (array) get_option('cron'); |
127 | - if (! is_array($crons)) { |
|
127 | + if ( ! is_array($crons)) { |
|
128 | 128 | return; |
129 | 129 | } |
130 | 130 | foreach ($crons as $timestamp => $cron) { |
131 | 131 | /** @var array[] $cron */ |
132 | 132 | foreach ($ee_crons as $ee_cron) { |
133 | - if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) { |
|
133 | + if (isset($cron[$ee_cron]) && is_array($cron[$ee_cron])) { |
|
134 | 134 | do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron'); |
135 | - foreach ($cron[ $ee_cron ] as $ee_cron_details) { |
|
136 | - if (! empty($ee_cron_details['args'])) { |
|
135 | + foreach ($cron[$ee_cron] as $ee_cron_details) { |
|
136 | + if ( ! empty($ee_cron_details['args'])) { |
|
137 | 137 | do_action( |
138 | 138 | 'AHEE_log', |
139 | 139 | __CLASS__, |
@@ -160,7 +160,7 @@ discard block |
||
160 | 160 | */ |
161 | 161 | public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs) |
162 | 162 | { |
163 | - if (! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
163 | + if ( ! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
164 | 164 | throw new DomainException( |
165 | 165 | sprintf( |
166 | 166 | esc_html__('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'), |
@@ -169,7 +169,7 @@ discard block |
||
169 | 169 | ); |
170 | 170 | } |
171 | 171 | // reschedule the cron if we can't hit the db right now |
172 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
172 | + if ( ! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
173 | 173 | foreach ($TXN_IDs as $TXN_ID => $additional_vars) { |
174 | 174 | // ensure $additional_vars is an array |
175 | 175 | $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars); |
@@ -250,7 +250,7 @@ discard block |
||
250 | 250 | { |
251 | 251 | do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID'); |
252 | 252 | if (absint($TXN_ID)) { |
253 | - self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID; |
|
253 | + self::$_update_transactions_with_payment[$TXN_ID] = $PAY_ID; |
|
254 | 254 | add_action( |
255 | 255 | 'shutdown', |
256 | 256 | array('EE_Cron_Tasks', 'update_transaction_with_payment'), |
@@ -297,7 +297,7 @@ discard block |
||
297 | 297 | EE_Registry::instance()->load_model('Transaction'); |
298 | 298 | foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) { |
299 | 299 | // reschedule the cron if we can't hit the db right now |
300 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
300 | + if ( ! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
301 | 301 | // reset cron job for updating the TXN |
302 | 302 | EE_Cron_Tasks::schedule_update_transaction_with_payment( |
303 | 303 | time() + EE_Cron_Tasks::reschedule_timeout, |
@@ -313,7 +313,7 @@ discard block |
||
313 | 313 | // now try to update the TXN with any payments |
314 | 314 | $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true); |
315 | 315 | } |
316 | - unset(self::$_update_transactions_with_payment[ $TXN_ID ]); |
|
316 | + unset(self::$_update_transactions_with_payment[$TXN_ID]); |
|
317 | 317 | } |
318 | 318 | } |
319 | 319 | |
@@ -374,7 +374,7 @@ discard block |
||
374 | 374 | public static function expired_transaction_check($TXN_ID = 0) |
375 | 375 | { |
376 | 376 | if (absint($TXN_ID)) { |
377 | - self::$_expired_transactions[ $TXN_ID ] = $TXN_ID; |
|
377 | + self::$_expired_transactions[$TXN_ID] = $TXN_ID; |
|
378 | 378 | add_action( |
379 | 379 | 'shutdown', |
380 | 380 | array('EE_Cron_Tasks', 'process_expired_transactions'), |
@@ -502,7 +502,7 @@ discard block |
||
502 | 502 | break; |
503 | 503 | } |
504 | 504 | } |
505 | - unset(self::$_expired_transactions[ $TXN_ID ]); |
|
505 | + unset(self::$_expired_transactions[$TXN_ID]); |
|
506 | 506 | } |
507 | 507 | } |
508 | 508 | |
@@ -549,7 +549,7 @@ discard block |
||
549 | 549 | $reg_config = LoaderFactory::getLoader()->load('EE_Registration_Config'); |
550 | 550 | $time_diff_for_comparison = apply_filters( |
551 | 551 | 'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison', |
552 | - '-' . $reg_config->gateway_log_lifespan |
|
552 | + '-'.$reg_config->gateway_log_lifespan |
|
553 | 553 | ); |
554 | 554 | EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison)); |
555 | 555 | } |
@@ -14,607 +14,607 @@ |
||
14 | 14 | */ |
15 | 15 | class EE_Cron_Tasks extends EE_Base |
16 | 16 | { |
17 | - /** |
|
18 | - * WordPress doesn't allow duplicate crons within 10 minutes of the original, |
|
19 | - * so we'll set our retry time for just over 10 minutes to avoid that |
|
20 | - */ |
|
21 | - const reschedule_timeout = 605; |
|
22 | - |
|
23 | - |
|
24 | - /** |
|
25 | - * @var EE_Cron_Tasks |
|
26 | - */ |
|
27 | - private static $_instance; |
|
28 | - |
|
29 | - |
|
30 | - /** |
|
31 | - * @return EE_Cron_Tasks |
|
32 | - * @throws ReflectionException |
|
33 | - * @throws EE_Error |
|
34 | - * @throws InvalidArgumentException |
|
35 | - * @throws InvalidInterfaceException |
|
36 | - * @throws InvalidDataTypeException |
|
37 | - */ |
|
38 | - public static function instance() |
|
39 | - { |
|
40 | - if (! self::$_instance instanceof EE_Cron_Tasks) { |
|
41 | - self::$_instance = new self(); |
|
42 | - } |
|
43 | - return self::$_instance; |
|
44 | - } |
|
45 | - |
|
46 | - |
|
47 | - /** |
|
48 | - * @access private |
|
49 | - * @throws InvalidDataTypeException |
|
50 | - * @throws InvalidInterfaceException |
|
51 | - * @throws InvalidArgumentException |
|
52 | - * @throws EE_Error |
|
53 | - * @throws ReflectionException |
|
54 | - */ |
|
55 | - private function __construct() |
|
56 | - { |
|
57 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
58 | - // verify that WP Cron is enabled |
|
59 | - if ( |
|
60 | - defined('DISABLE_WP_CRON') |
|
61 | - && DISABLE_WP_CRON |
|
62 | - && is_admin() |
|
63 | - && ! get_option('ee_disabled_wp_cron_check') |
|
64 | - ) { |
|
65 | - /** |
|
66 | - * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before |
|
67 | - * config is loaded. |
|
68 | - * This is intentionally using a anonymous function so that its not easily de-registered. Client code |
|
69 | - * wanting to not have this functionality can just register its own action at a priority after this one to |
|
70 | - * reverse any changes. |
|
71 | - */ |
|
72 | - add_action( |
|
73 | - 'AHEE__EE_System__load_core_configuration__complete', |
|
74 | - function () { |
|
75 | - EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true; |
|
76 | - EE_Registry::instance()->NET_CFG->update_config(true, false); |
|
77 | - add_option('ee_disabled_wp_cron_check', 1, '', false); |
|
78 | - } |
|
79 | - ); |
|
80 | - } |
|
81 | - // UPDATE TRANSACTION WITH PAYMENT |
|
82 | - add_action( |
|
83 | - 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
84 | - array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'), |
|
85 | - 10, |
|
86 | - 2 |
|
87 | - ); |
|
88 | - // ABANDONED / EXPIRED TRANSACTION CHECK |
|
89 | - add_action( |
|
90 | - 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
91 | - array('EE_Cron_Tasks', 'expired_transaction_check'), |
|
92 | - 10, |
|
93 | - 1 |
|
94 | - ); |
|
95 | - // CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA |
|
96 | - add_action( |
|
97 | - 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
98 | - array('EE_Cron_Tasks', 'clean_out_junk_transactions') |
|
99 | - ); |
|
100 | - // logging |
|
101 | - add_action( |
|
102 | - 'AHEE__EE_System__load_core_configuration__complete', |
|
103 | - array('EE_Cron_Tasks', 'log_scheduled_ee_crons') |
|
104 | - ); |
|
105 | - EE_Registry::instance()->load_lib('Messages_Scheduler'); |
|
106 | - // clean out old gateway logs |
|
107 | - add_action( |
|
108 | - 'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs', |
|
109 | - array('EE_Cron_Tasks', 'clean_out_old_gateway_logs') |
|
110 | - ); |
|
111 | - } |
|
112 | - |
|
113 | - |
|
114 | - /** |
|
115 | - * @access protected |
|
116 | - * @return void |
|
117 | - */ |
|
118 | - public static function log_scheduled_ee_crons() |
|
119 | - { |
|
120 | - $ee_crons = array( |
|
121 | - 'AHEE__EE_Cron_Tasks__update_transaction_with_payment', |
|
122 | - 'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions', |
|
123 | - 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
124 | - ); |
|
125 | - $crons = (array) get_option('cron'); |
|
126 | - if (! is_array($crons)) { |
|
127 | - return; |
|
128 | - } |
|
129 | - foreach ($crons as $timestamp => $cron) { |
|
130 | - /** @var array[] $cron */ |
|
131 | - foreach ($ee_crons as $ee_cron) { |
|
132 | - if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) { |
|
133 | - do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron'); |
|
134 | - foreach ($cron[ $ee_cron ] as $ee_cron_details) { |
|
135 | - if (! empty($ee_cron_details['args'])) { |
|
136 | - do_action( |
|
137 | - 'AHEE_log', |
|
138 | - __CLASS__, |
|
139 | - __FUNCTION__, |
|
140 | - print_r($ee_cron_details['args'], true), |
|
141 | - "{$ee_cron} args" |
|
142 | - ); |
|
143 | - } |
|
144 | - } |
|
145 | - } |
|
146 | - } |
|
147 | - } |
|
148 | - } |
|
149 | - |
|
150 | - |
|
151 | - /** |
|
152 | - * reschedule_cron_for_transactions_if_maintenance_mode |
|
153 | - * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes |
|
154 | - * |
|
155 | - * @param string $cron_task |
|
156 | - * @param array $TXN_IDs |
|
157 | - * @return bool |
|
158 | - * @throws DomainException |
|
159 | - */ |
|
160 | - public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs) |
|
161 | - { |
|
162 | - if (! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
163 | - throw new DomainException( |
|
164 | - sprintf( |
|
165 | - esc_html__('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'), |
|
166 | - $cron_task |
|
167 | - ) |
|
168 | - ); |
|
169 | - } |
|
170 | - // reschedule the cron if we can't hit the db right now |
|
171 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
172 | - foreach ($TXN_IDs as $TXN_ID => $additional_vars) { |
|
173 | - // ensure $additional_vars is an array |
|
174 | - $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars); |
|
175 | - // reset cron job for the TXN |
|
176 | - call_user_func_array( |
|
177 | - array('EE_Cron_Tasks', $cron_task), |
|
178 | - array_merge( |
|
179 | - array( |
|
180 | - time() + (10 * MINUTE_IN_SECONDS), |
|
181 | - $TXN_ID, |
|
182 | - ), |
|
183 | - $additional_vars |
|
184 | - ) |
|
185 | - ); |
|
186 | - } |
|
187 | - return true; |
|
188 | - } |
|
189 | - return false; |
|
190 | - } |
|
191 | - |
|
192 | - |
|
193 | - |
|
194 | - |
|
195 | - /**************** UPDATE TRANSACTION WITH PAYMENT ****************/ |
|
196 | - |
|
197 | - |
|
198 | - /** |
|
199 | - * array of TXN IDs and the payment |
|
200 | - * |
|
201 | - * @var array |
|
202 | - */ |
|
203 | - protected static $_update_transactions_with_payment = array(); |
|
204 | - |
|
205 | - |
|
206 | - /** |
|
207 | - * schedule_update_transaction_with_payment |
|
208 | - * sets a wp_schedule_single_event() for updating any TXNs that may |
|
209 | - * require updating due to recently received payments |
|
210 | - * |
|
211 | - * @param int $timestamp |
|
212 | - * @param int $TXN_ID |
|
213 | - * @param int $PAY_ID |
|
214 | - */ |
|
215 | - public static function schedule_update_transaction_with_payment( |
|
216 | - $timestamp, |
|
217 | - $TXN_ID, |
|
218 | - $PAY_ID |
|
219 | - ) { |
|
220 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
221 | - // validate $TXN_ID and $timestamp |
|
222 | - $TXN_ID = absint($TXN_ID); |
|
223 | - $timestamp = absint($timestamp); |
|
224 | - if ($TXN_ID && $timestamp) { |
|
225 | - wp_schedule_single_event( |
|
226 | - $timestamp, |
|
227 | - 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
228 | - array($TXN_ID, $PAY_ID) |
|
229 | - ); |
|
230 | - } |
|
231 | - } |
|
232 | - |
|
233 | - |
|
234 | - /** |
|
235 | - * setup_update_for_transaction_with_payment |
|
236 | - * this is the callback for the action hook: |
|
237 | - * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment' |
|
238 | - * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment(). |
|
239 | - * The passed TXN_ID and associated payment gets added to an array, and then |
|
240 | - * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into |
|
241 | - * 'shutdown' which will actually handle the processing of any |
|
242 | - * transactions requiring updating, because doing so now would be too early |
|
243 | - * and the required resources may not be available |
|
244 | - * |
|
245 | - * @param int $TXN_ID |
|
246 | - * @param int $PAY_ID |
|
247 | - */ |
|
248 | - public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0) |
|
249 | - { |
|
250 | - do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID'); |
|
251 | - if (absint($TXN_ID)) { |
|
252 | - self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID; |
|
253 | - add_action( |
|
254 | - 'shutdown', |
|
255 | - array('EE_Cron_Tasks', 'update_transaction_with_payment'), |
|
256 | - 5 |
|
257 | - ); |
|
258 | - } |
|
259 | - } |
|
260 | - |
|
261 | - |
|
262 | - /** |
|
263 | - * update_transaction_with_payment |
|
264 | - * loops through the self::$_abandoned_transactions array |
|
265 | - * and attempts to finalize any TXNs that have not been completed |
|
266 | - * but have had their sessions expired, most likely due to a user not |
|
267 | - * returning from an off-site payment gateway |
|
268 | - * |
|
269 | - * @throws EE_Error |
|
270 | - * @throws DomainException |
|
271 | - * @throws InvalidDataTypeException |
|
272 | - * @throws InvalidInterfaceException |
|
273 | - * @throws InvalidArgumentException |
|
274 | - * @throws ReflectionException |
|
275 | - * @throws RuntimeException |
|
276 | - */ |
|
277 | - public static function update_transaction_with_payment() |
|
278 | - { |
|
279 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
280 | - if ( |
|
17 | + /** |
|
18 | + * WordPress doesn't allow duplicate crons within 10 minutes of the original, |
|
19 | + * so we'll set our retry time for just over 10 minutes to avoid that |
|
20 | + */ |
|
21 | + const reschedule_timeout = 605; |
|
22 | + |
|
23 | + |
|
24 | + /** |
|
25 | + * @var EE_Cron_Tasks |
|
26 | + */ |
|
27 | + private static $_instance; |
|
28 | + |
|
29 | + |
|
30 | + /** |
|
31 | + * @return EE_Cron_Tasks |
|
32 | + * @throws ReflectionException |
|
33 | + * @throws EE_Error |
|
34 | + * @throws InvalidArgumentException |
|
35 | + * @throws InvalidInterfaceException |
|
36 | + * @throws InvalidDataTypeException |
|
37 | + */ |
|
38 | + public static function instance() |
|
39 | + { |
|
40 | + if (! self::$_instance instanceof EE_Cron_Tasks) { |
|
41 | + self::$_instance = new self(); |
|
42 | + } |
|
43 | + return self::$_instance; |
|
44 | + } |
|
45 | + |
|
46 | + |
|
47 | + /** |
|
48 | + * @access private |
|
49 | + * @throws InvalidDataTypeException |
|
50 | + * @throws InvalidInterfaceException |
|
51 | + * @throws InvalidArgumentException |
|
52 | + * @throws EE_Error |
|
53 | + * @throws ReflectionException |
|
54 | + */ |
|
55 | + private function __construct() |
|
56 | + { |
|
57 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
58 | + // verify that WP Cron is enabled |
|
59 | + if ( |
|
60 | + defined('DISABLE_WP_CRON') |
|
61 | + && DISABLE_WP_CRON |
|
62 | + && is_admin() |
|
63 | + && ! get_option('ee_disabled_wp_cron_check') |
|
64 | + ) { |
|
65 | + /** |
|
66 | + * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before |
|
67 | + * config is loaded. |
|
68 | + * This is intentionally using a anonymous function so that its not easily de-registered. Client code |
|
69 | + * wanting to not have this functionality can just register its own action at a priority after this one to |
|
70 | + * reverse any changes. |
|
71 | + */ |
|
72 | + add_action( |
|
73 | + 'AHEE__EE_System__load_core_configuration__complete', |
|
74 | + function () { |
|
75 | + EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true; |
|
76 | + EE_Registry::instance()->NET_CFG->update_config(true, false); |
|
77 | + add_option('ee_disabled_wp_cron_check', 1, '', false); |
|
78 | + } |
|
79 | + ); |
|
80 | + } |
|
81 | + // UPDATE TRANSACTION WITH PAYMENT |
|
82 | + add_action( |
|
83 | + 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
84 | + array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'), |
|
85 | + 10, |
|
86 | + 2 |
|
87 | + ); |
|
88 | + // ABANDONED / EXPIRED TRANSACTION CHECK |
|
89 | + add_action( |
|
90 | + 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
91 | + array('EE_Cron_Tasks', 'expired_transaction_check'), |
|
92 | + 10, |
|
93 | + 1 |
|
94 | + ); |
|
95 | + // CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA |
|
96 | + add_action( |
|
97 | + 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
98 | + array('EE_Cron_Tasks', 'clean_out_junk_transactions') |
|
99 | + ); |
|
100 | + // logging |
|
101 | + add_action( |
|
102 | + 'AHEE__EE_System__load_core_configuration__complete', |
|
103 | + array('EE_Cron_Tasks', 'log_scheduled_ee_crons') |
|
104 | + ); |
|
105 | + EE_Registry::instance()->load_lib('Messages_Scheduler'); |
|
106 | + // clean out old gateway logs |
|
107 | + add_action( |
|
108 | + 'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs', |
|
109 | + array('EE_Cron_Tasks', 'clean_out_old_gateway_logs') |
|
110 | + ); |
|
111 | + } |
|
112 | + |
|
113 | + |
|
114 | + /** |
|
115 | + * @access protected |
|
116 | + * @return void |
|
117 | + */ |
|
118 | + public static function log_scheduled_ee_crons() |
|
119 | + { |
|
120 | + $ee_crons = array( |
|
121 | + 'AHEE__EE_Cron_Tasks__update_transaction_with_payment', |
|
122 | + 'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions', |
|
123 | + 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
124 | + ); |
|
125 | + $crons = (array) get_option('cron'); |
|
126 | + if (! is_array($crons)) { |
|
127 | + return; |
|
128 | + } |
|
129 | + foreach ($crons as $timestamp => $cron) { |
|
130 | + /** @var array[] $cron */ |
|
131 | + foreach ($ee_crons as $ee_cron) { |
|
132 | + if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) { |
|
133 | + do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron'); |
|
134 | + foreach ($cron[ $ee_cron ] as $ee_cron_details) { |
|
135 | + if (! empty($ee_cron_details['args'])) { |
|
136 | + do_action( |
|
137 | + 'AHEE_log', |
|
138 | + __CLASS__, |
|
139 | + __FUNCTION__, |
|
140 | + print_r($ee_cron_details['args'], true), |
|
141 | + "{$ee_cron} args" |
|
142 | + ); |
|
143 | + } |
|
144 | + } |
|
145 | + } |
|
146 | + } |
|
147 | + } |
|
148 | + } |
|
149 | + |
|
150 | + |
|
151 | + /** |
|
152 | + * reschedule_cron_for_transactions_if_maintenance_mode |
|
153 | + * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes |
|
154 | + * |
|
155 | + * @param string $cron_task |
|
156 | + * @param array $TXN_IDs |
|
157 | + * @return bool |
|
158 | + * @throws DomainException |
|
159 | + */ |
|
160 | + public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs) |
|
161 | + { |
|
162 | + if (! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
163 | + throw new DomainException( |
|
164 | + sprintf( |
|
165 | + esc_html__('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'), |
|
166 | + $cron_task |
|
167 | + ) |
|
168 | + ); |
|
169 | + } |
|
170 | + // reschedule the cron if we can't hit the db right now |
|
171 | + if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
172 | + foreach ($TXN_IDs as $TXN_ID => $additional_vars) { |
|
173 | + // ensure $additional_vars is an array |
|
174 | + $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars); |
|
175 | + // reset cron job for the TXN |
|
176 | + call_user_func_array( |
|
177 | + array('EE_Cron_Tasks', $cron_task), |
|
178 | + array_merge( |
|
179 | + array( |
|
180 | + time() + (10 * MINUTE_IN_SECONDS), |
|
181 | + $TXN_ID, |
|
182 | + ), |
|
183 | + $additional_vars |
|
184 | + ) |
|
185 | + ); |
|
186 | + } |
|
187 | + return true; |
|
188 | + } |
|
189 | + return false; |
|
190 | + } |
|
191 | + |
|
192 | + |
|
193 | + |
|
194 | + |
|
195 | + /**************** UPDATE TRANSACTION WITH PAYMENT ****************/ |
|
196 | + |
|
197 | + |
|
198 | + /** |
|
199 | + * array of TXN IDs and the payment |
|
200 | + * |
|
201 | + * @var array |
|
202 | + */ |
|
203 | + protected static $_update_transactions_with_payment = array(); |
|
204 | + |
|
205 | + |
|
206 | + /** |
|
207 | + * schedule_update_transaction_with_payment |
|
208 | + * sets a wp_schedule_single_event() for updating any TXNs that may |
|
209 | + * require updating due to recently received payments |
|
210 | + * |
|
211 | + * @param int $timestamp |
|
212 | + * @param int $TXN_ID |
|
213 | + * @param int $PAY_ID |
|
214 | + */ |
|
215 | + public static function schedule_update_transaction_with_payment( |
|
216 | + $timestamp, |
|
217 | + $TXN_ID, |
|
218 | + $PAY_ID |
|
219 | + ) { |
|
220 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
221 | + // validate $TXN_ID and $timestamp |
|
222 | + $TXN_ID = absint($TXN_ID); |
|
223 | + $timestamp = absint($timestamp); |
|
224 | + if ($TXN_ID && $timestamp) { |
|
225 | + wp_schedule_single_event( |
|
226 | + $timestamp, |
|
227 | + 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
228 | + array($TXN_ID, $PAY_ID) |
|
229 | + ); |
|
230 | + } |
|
231 | + } |
|
232 | + |
|
233 | + |
|
234 | + /** |
|
235 | + * setup_update_for_transaction_with_payment |
|
236 | + * this is the callback for the action hook: |
|
237 | + * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment' |
|
238 | + * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment(). |
|
239 | + * The passed TXN_ID and associated payment gets added to an array, and then |
|
240 | + * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into |
|
241 | + * 'shutdown' which will actually handle the processing of any |
|
242 | + * transactions requiring updating, because doing so now would be too early |
|
243 | + * and the required resources may not be available |
|
244 | + * |
|
245 | + * @param int $TXN_ID |
|
246 | + * @param int $PAY_ID |
|
247 | + */ |
|
248 | + public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0) |
|
249 | + { |
|
250 | + do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID'); |
|
251 | + if (absint($TXN_ID)) { |
|
252 | + self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID; |
|
253 | + add_action( |
|
254 | + 'shutdown', |
|
255 | + array('EE_Cron_Tasks', 'update_transaction_with_payment'), |
|
256 | + 5 |
|
257 | + ); |
|
258 | + } |
|
259 | + } |
|
260 | + |
|
261 | + |
|
262 | + /** |
|
263 | + * update_transaction_with_payment |
|
264 | + * loops through the self::$_abandoned_transactions array |
|
265 | + * and attempts to finalize any TXNs that have not been completed |
|
266 | + * but have had their sessions expired, most likely due to a user not |
|
267 | + * returning from an off-site payment gateway |
|
268 | + * |
|
269 | + * @throws EE_Error |
|
270 | + * @throws DomainException |
|
271 | + * @throws InvalidDataTypeException |
|
272 | + * @throws InvalidInterfaceException |
|
273 | + * @throws InvalidArgumentException |
|
274 | + * @throws ReflectionException |
|
275 | + * @throws RuntimeException |
|
276 | + */ |
|
277 | + public static function update_transaction_with_payment() |
|
278 | + { |
|
279 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
280 | + if ( |
|
281 | 281 | // are there any TXNs that need cleaning up ? |
282 | - empty(self::$_update_transactions_with_payment) |
|
283 | - // reschedule the cron if we can't hit the db right now |
|
284 | - || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
285 | - 'schedule_update_transaction_with_payment', |
|
286 | - self::$_update_transactions_with_payment |
|
287 | - ) |
|
288 | - ) { |
|
289 | - return; |
|
290 | - } |
|
291 | - /** @type EE_Payment_Processor $payment_processor */ |
|
292 | - $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
293 | - // set revisit flag for payment processor |
|
294 | - $payment_processor->set_revisit(); |
|
295 | - // load EEM_Transaction |
|
296 | - EE_Registry::instance()->load_model('Transaction'); |
|
297 | - foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) { |
|
298 | - // reschedule the cron if we can't hit the db right now |
|
299 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
300 | - // reset cron job for updating the TXN |
|
301 | - EE_Cron_Tasks::schedule_update_transaction_with_payment( |
|
302 | - time() + EE_Cron_Tasks::reschedule_timeout, |
|
303 | - $TXN_ID, |
|
304 | - $PAY_ID |
|
305 | - ); |
|
306 | - continue; |
|
307 | - } |
|
308 | - $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
309 | - $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID); |
|
310 | - // verify transaction |
|
311 | - if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) { |
|
312 | - // now try to update the TXN with any payments |
|
313 | - $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true); |
|
314 | - } |
|
315 | - unset(self::$_update_transactions_with_payment[ $TXN_ID ]); |
|
316 | - } |
|
317 | - } |
|
318 | - |
|
319 | - |
|
320 | - |
|
321 | - /************ END OF UPDATE TRANSACTION WITH PAYMENT ************/ |
|
322 | - |
|
323 | - |
|
324 | - /***************** EXPIRED TRANSACTION CHECK *****************/ |
|
325 | - |
|
326 | - |
|
327 | - /** |
|
328 | - * array of TXN IDs |
|
329 | - * |
|
330 | - * @var array |
|
331 | - */ |
|
332 | - protected static $_expired_transactions = array(); |
|
333 | - |
|
334 | - |
|
335 | - /** |
|
336 | - * schedule_expired_transaction_check |
|
337 | - * sets a wp_schedule_single_event() for following up on TXNs after their session has expired |
|
338 | - * |
|
339 | - * @param int $timestamp |
|
340 | - * @param int $TXN_ID |
|
341 | - */ |
|
342 | - public static function schedule_expired_transaction_check( |
|
343 | - $timestamp, |
|
344 | - $TXN_ID |
|
345 | - ) { |
|
346 | - // validate $TXN_ID and $timestamp |
|
347 | - $TXN_ID = absint($TXN_ID); |
|
348 | - $timestamp = absint($timestamp); |
|
349 | - if ($TXN_ID && $timestamp) { |
|
350 | - wp_schedule_single_event( |
|
351 | - $timestamp, |
|
352 | - 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
353 | - array($TXN_ID) |
|
354 | - ); |
|
355 | - } |
|
356 | - } |
|
357 | - |
|
358 | - |
|
359 | - /** |
|
360 | - * expired_transaction_check |
|
361 | - * this is the callback for the action hook: |
|
362 | - * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check' |
|
363 | - * which is utilized by wp_schedule_single_event() |
|
364 | - * in \EED_Single_Page_Checkout::_initialize_transaction(). |
|
365 | - * The passed TXN_ID gets added to an array, and then the |
|
366 | - * process_expired_transactions() function is hooked into |
|
367 | - * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the |
|
368 | - * processing of any failed transactions, because doing so now would be |
|
369 | - * too early and the required resources may not be available |
|
370 | - * |
|
371 | - * @param int $TXN_ID |
|
372 | - */ |
|
373 | - public static function expired_transaction_check($TXN_ID = 0) |
|
374 | - { |
|
375 | - if (absint($TXN_ID)) { |
|
376 | - self::$_expired_transactions[ $TXN_ID ] = $TXN_ID; |
|
377 | - add_action( |
|
378 | - 'shutdown', |
|
379 | - array('EE_Cron_Tasks', 'process_expired_transactions'), |
|
380 | - 5 |
|
381 | - ); |
|
382 | - } |
|
383 | - } |
|
384 | - |
|
385 | - |
|
386 | - /** |
|
387 | - * process_expired_transactions |
|
388 | - * loops through the self::$_expired_transactions array and processes any failed TXNs |
|
389 | - * |
|
390 | - * @throws EE_Error |
|
391 | - * @throws InvalidDataTypeException |
|
392 | - * @throws InvalidInterfaceException |
|
393 | - * @throws InvalidArgumentException |
|
394 | - * @throws ReflectionException |
|
395 | - * @throws DomainException |
|
396 | - * @throws RuntimeException |
|
397 | - */ |
|
398 | - public static function process_expired_transactions() |
|
399 | - { |
|
400 | - if ( |
|
282 | + empty(self::$_update_transactions_with_payment) |
|
283 | + // reschedule the cron if we can't hit the db right now |
|
284 | + || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
285 | + 'schedule_update_transaction_with_payment', |
|
286 | + self::$_update_transactions_with_payment |
|
287 | + ) |
|
288 | + ) { |
|
289 | + return; |
|
290 | + } |
|
291 | + /** @type EE_Payment_Processor $payment_processor */ |
|
292 | + $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
293 | + // set revisit flag for payment processor |
|
294 | + $payment_processor->set_revisit(); |
|
295 | + // load EEM_Transaction |
|
296 | + EE_Registry::instance()->load_model('Transaction'); |
|
297 | + foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) { |
|
298 | + // reschedule the cron if we can't hit the db right now |
|
299 | + if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
300 | + // reset cron job for updating the TXN |
|
301 | + EE_Cron_Tasks::schedule_update_transaction_with_payment( |
|
302 | + time() + EE_Cron_Tasks::reschedule_timeout, |
|
303 | + $TXN_ID, |
|
304 | + $PAY_ID |
|
305 | + ); |
|
306 | + continue; |
|
307 | + } |
|
308 | + $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
309 | + $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID); |
|
310 | + // verify transaction |
|
311 | + if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) { |
|
312 | + // now try to update the TXN with any payments |
|
313 | + $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true); |
|
314 | + } |
|
315 | + unset(self::$_update_transactions_with_payment[ $TXN_ID ]); |
|
316 | + } |
|
317 | + } |
|
318 | + |
|
319 | + |
|
320 | + |
|
321 | + /************ END OF UPDATE TRANSACTION WITH PAYMENT ************/ |
|
322 | + |
|
323 | + |
|
324 | + /***************** EXPIRED TRANSACTION CHECK *****************/ |
|
325 | + |
|
326 | + |
|
327 | + /** |
|
328 | + * array of TXN IDs |
|
329 | + * |
|
330 | + * @var array |
|
331 | + */ |
|
332 | + protected static $_expired_transactions = array(); |
|
333 | + |
|
334 | + |
|
335 | + /** |
|
336 | + * schedule_expired_transaction_check |
|
337 | + * sets a wp_schedule_single_event() for following up on TXNs after their session has expired |
|
338 | + * |
|
339 | + * @param int $timestamp |
|
340 | + * @param int $TXN_ID |
|
341 | + */ |
|
342 | + public static function schedule_expired_transaction_check( |
|
343 | + $timestamp, |
|
344 | + $TXN_ID |
|
345 | + ) { |
|
346 | + // validate $TXN_ID and $timestamp |
|
347 | + $TXN_ID = absint($TXN_ID); |
|
348 | + $timestamp = absint($timestamp); |
|
349 | + if ($TXN_ID && $timestamp) { |
|
350 | + wp_schedule_single_event( |
|
351 | + $timestamp, |
|
352 | + 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
353 | + array($TXN_ID) |
|
354 | + ); |
|
355 | + } |
|
356 | + } |
|
357 | + |
|
358 | + |
|
359 | + /** |
|
360 | + * expired_transaction_check |
|
361 | + * this is the callback for the action hook: |
|
362 | + * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check' |
|
363 | + * which is utilized by wp_schedule_single_event() |
|
364 | + * in \EED_Single_Page_Checkout::_initialize_transaction(). |
|
365 | + * The passed TXN_ID gets added to an array, and then the |
|
366 | + * process_expired_transactions() function is hooked into |
|
367 | + * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the |
|
368 | + * processing of any failed transactions, because doing so now would be |
|
369 | + * too early and the required resources may not be available |
|
370 | + * |
|
371 | + * @param int $TXN_ID |
|
372 | + */ |
|
373 | + public static function expired_transaction_check($TXN_ID = 0) |
|
374 | + { |
|
375 | + if (absint($TXN_ID)) { |
|
376 | + self::$_expired_transactions[ $TXN_ID ] = $TXN_ID; |
|
377 | + add_action( |
|
378 | + 'shutdown', |
|
379 | + array('EE_Cron_Tasks', 'process_expired_transactions'), |
|
380 | + 5 |
|
381 | + ); |
|
382 | + } |
|
383 | + } |
|
384 | + |
|
385 | + |
|
386 | + /** |
|
387 | + * process_expired_transactions |
|
388 | + * loops through the self::$_expired_transactions array and processes any failed TXNs |
|
389 | + * |
|
390 | + * @throws EE_Error |
|
391 | + * @throws InvalidDataTypeException |
|
392 | + * @throws InvalidInterfaceException |
|
393 | + * @throws InvalidArgumentException |
|
394 | + * @throws ReflectionException |
|
395 | + * @throws DomainException |
|
396 | + * @throws RuntimeException |
|
397 | + */ |
|
398 | + public static function process_expired_transactions() |
|
399 | + { |
|
400 | + if ( |
|
401 | 401 | // are there any TXNs that need cleaning up ? |
402 | - empty(self::$_expired_transactions) |
|
403 | - // reschedule the cron if we can't hit the db right now |
|
404 | - || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
405 | - 'schedule_expired_transaction_check', |
|
406 | - self::$_expired_transactions |
|
407 | - ) |
|
408 | - ) { |
|
409 | - return; |
|
410 | - } |
|
411 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
412 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
413 | - // set revisit flag for txn processor |
|
414 | - $transaction_processor->set_revisit(); |
|
415 | - // load EEM_Transaction |
|
416 | - EE_Registry::instance()->load_model('Transaction'); |
|
417 | - foreach (self::$_expired_transactions as $TXN_ID) { |
|
418 | - $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
419 | - // verify transaction and whether it is failed or not |
|
420 | - if ($transaction instanceof EE_Transaction) { |
|
421 | - switch ($transaction->status_ID()) { |
|
422 | - // Completed TXNs |
|
423 | - case EEM_Transaction::complete_status_code: |
|
424 | - // Don't update the transaction/registrations if the Primary Registration is Not Approved. |
|
425 | - $primary_registration = $transaction->primary_registration(); |
|
426 | - if ( |
|
427 | - $primary_registration instanceof EE_Registration |
|
428 | - && $primary_registration->status_ID() !== EEM_Registration::status_id_not_approved |
|
429 | - ) { |
|
430 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
431 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
432 | - $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
433 | - $transaction, |
|
434 | - $transaction->last_payment() |
|
435 | - ); |
|
436 | - do_action( |
|
437 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction', |
|
438 | - $transaction |
|
439 | - ); |
|
440 | - } |
|
441 | - break; |
|
442 | - // Overpaid TXNs |
|
443 | - case EEM_Transaction::overpaid_status_code: |
|
444 | - do_action( |
|
445 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction', |
|
446 | - $transaction |
|
447 | - ); |
|
448 | - break; |
|
449 | - // Incomplete TXNs |
|
450 | - case EEM_Transaction::incomplete_status_code: |
|
451 | - do_action( |
|
452 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction', |
|
453 | - $transaction |
|
454 | - ); |
|
455 | - // todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions |
|
456 | - break; |
|
457 | - // Abandoned TXNs |
|
458 | - case EEM_Transaction::abandoned_status_code: |
|
459 | - // run hook before updating transaction, primarily so |
|
460 | - // EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets |
|
461 | - do_action( |
|
462 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction', |
|
463 | - $transaction |
|
464 | - ); |
|
465 | - // don't finalize the TXN if it has already been completed |
|
466 | - if ($transaction->all_reg_steps_completed() !== true) { |
|
467 | - /** @type EE_Payment_Processor $payment_processor */ |
|
468 | - $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
469 | - // let's simulate an IPN here which will trigger any notifications that need to go out |
|
470 | - $payment_processor->update_txn_based_on_payment( |
|
471 | - $transaction, |
|
472 | - $transaction->last_payment(), |
|
473 | - true, |
|
474 | - true |
|
475 | - ); |
|
476 | - } |
|
477 | - break; |
|
478 | - // Failed TXNs |
|
479 | - case EEM_Transaction::failed_status_code: |
|
480 | - do_action( |
|
481 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction', |
|
482 | - $transaction |
|
483 | - ); |
|
484 | - // todo : |
|
485 | - // perform garbage collection here and remove clean_out_junk_transactions() |
|
486 | - // $registrations = $transaction->registrations(); |
|
487 | - // if (! empty($registrations)) { |
|
488 | - // foreach ($registrations as $registration) { |
|
489 | - // if ($registration instanceof EE_Registration) { |
|
490 | - // $delete_registration = true; |
|
491 | - // if ($registration->attendee() instanceof EE_Attendee) { |
|
492 | - // $delete_registration = false; |
|
493 | - // } |
|
494 | - // if ($delete_registration) { |
|
495 | - // $registration->delete_permanently(); |
|
496 | - // $registration->delete_related_permanently(); |
|
497 | - // } |
|
498 | - // } |
|
499 | - // } |
|
500 | - // } |
|
501 | - break; |
|
502 | - } |
|
503 | - } |
|
504 | - unset(self::$_expired_transactions[ $TXN_ID ]); |
|
505 | - } |
|
506 | - } |
|
507 | - |
|
508 | - |
|
509 | - |
|
510 | - /************* END OF EXPIRED TRANSACTION CHECK *************/ |
|
511 | - |
|
512 | - |
|
513 | - /************* START CLEAN UP BOT TRANSACTIONS **********************/ |
|
514 | - |
|
515 | - |
|
516 | - /** |
|
517 | - * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions' |
|
518 | - * which is setup during activation to run on an hourly cron |
|
519 | - * |
|
520 | - * @throws EE_Error |
|
521 | - * @throws InvalidArgumentException |
|
522 | - * @throws InvalidDataTypeException |
|
523 | - * @throws InvalidInterfaceException |
|
524 | - * @throws DomainException |
|
525 | - */ |
|
526 | - public static function clean_out_junk_transactions() |
|
527 | - { |
|
528 | - if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
529 | - EED_Ticket_Sales_Monitor::reset_reservation_counts(); |
|
530 | - EEM_Transaction::instance('')->delete_junk_transactions(); |
|
531 | - EEM_Registration::instance('')->delete_registrations_with_no_transaction(); |
|
532 | - EEM_Line_Item::instance('')->delete_line_items_with_no_transaction(); |
|
533 | - } |
|
534 | - } |
|
535 | - |
|
536 | - |
|
537 | - /** |
|
538 | - * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that. |
|
539 | - * |
|
540 | - * @throws EE_Error |
|
541 | - * @throws InvalidDataTypeException |
|
542 | - * @throws InvalidInterfaceException |
|
543 | - * @throws InvalidArgumentException |
|
544 | - */ |
|
545 | - public static function clean_out_old_gateway_logs() |
|
546 | - { |
|
547 | - if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
548 | - $reg_config = LoaderFactory::getLoader()->load('EE_Registration_Config'); |
|
549 | - $time_diff_for_comparison = apply_filters( |
|
550 | - 'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison', |
|
551 | - '-' . $reg_config->gateway_log_lifespan |
|
552 | - ); |
|
553 | - EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison)); |
|
554 | - } |
|
555 | - } |
|
556 | - |
|
557 | - |
|
558 | - /***************** FINALIZE ABANDONED TRANSACTIONS *****************/ |
|
559 | - |
|
560 | - |
|
561 | - /** |
|
562 | - * @var array |
|
563 | - */ |
|
564 | - protected static $_abandoned_transactions = array(); |
|
565 | - |
|
566 | - |
|
567 | - /** |
|
568 | - * @deprecated |
|
569 | - * @param int $timestamp |
|
570 | - * @param int $TXN_ID |
|
571 | - */ |
|
572 | - public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID) |
|
573 | - { |
|
574 | - EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID); |
|
575 | - } |
|
576 | - |
|
577 | - |
|
578 | - /** |
|
579 | - * @deprecated |
|
580 | - * @param int $TXN_ID |
|
581 | - */ |
|
582 | - public static function check_for_abandoned_transactions($TXN_ID = 0) |
|
583 | - { |
|
584 | - EE_Cron_Tasks::expired_transaction_check($TXN_ID); |
|
585 | - } |
|
586 | - |
|
587 | - |
|
588 | - /** |
|
589 | - * @deprecated |
|
590 | - * @throws EE_Error |
|
591 | - * @throws DomainException |
|
592 | - * @throws InvalidDataTypeException |
|
593 | - * @throws InvalidInterfaceException |
|
594 | - * @throws InvalidArgumentException |
|
595 | - * @throws ReflectionException |
|
596 | - * @throws RuntimeException |
|
597 | - */ |
|
598 | - public static function finalize_abandoned_transactions() |
|
599 | - { |
|
600 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
601 | - if ( |
|
402 | + empty(self::$_expired_transactions) |
|
403 | + // reschedule the cron if we can't hit the db right now |
|
404 | + || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
405 | + 'schedule_expired_transaction_check', |
|
406 | + self::$_expired_transactions |
|
407 | + ) |
|
408 | + ) { |
|
409 | + return; |
|
410 | + } |
|
411 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
412 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
413 | + // set revisit flag for txn processor |
|
414 | + $transaction_processor->set_revisit(); |
|
415 | + // load EEM_Transaction |
|
416 | + EE_Registry::instance()->load_model('Transaction'); |
|
417 | + foreach (self::$_expired_transactions as $TXN_ID) { |
|
418 | + $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
419 | + // verify transaction and whether it is failed or not |
|
420 | + if ($transaction instanceof EE_Transaction) { |
|
421 | + switch ($transaction->status_ID()) { |
|
422 | + // Completed TXNs |
|
423 | + case EEM_Transaction::complete_status_code: |
|
424 | + // Don't update the transaction/registrations if the Primary Registration is Not Approved. |
|
425 | + $primary_registration = $transaction->primary_registration(); |
|
426 | + if ( |
|
427 | + $primary_registration instanceof EE_Registration |
|
428 | + && $primary_registration->status_ID() !== EEM_Registration::status_id_not_approved |
|
429 | + ) { |
|
430 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
431 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
432 | + $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
433 | + $transaction, |
|
434 | + $transaction->last_payment() |
|
435 | + ); |
|
436 | + do_action( |
|
437 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction', |
|
438 | + $transaction |
|
439 | + ); |
|
440 | + } |
|
441 | + break; |
|
442 | + // Overpaid TXNs |
|
443 | + case EEM_Transaction::overpaid_status_code: |
|
444 | + do_action( |
|
445 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction', |
|
446 | + $transaction |
|
447 | + ); |
|
448 | + break; |
|
449 | + // Incomplete TXNs |
|
450 | + case EEM_Transaction::incomplete_status_code: |
|
451 | + do_action( |
|
452 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction', |
|
453 | + $transaction |
|
454 | + ); |
|
455 | + // todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions |
|
456 | + break; |
|
457 | + // Abandoned TXNs |
|
458 | + case EEM_Transaction::abandoned_status_code: |
|
459 | + // run hook before updating transaction, primarily so |
|
460 | + // EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets |
|
461 | + do_action( |
|
462 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction', |
|
463 | + $transaction |
|
464 | + ); |
|
465 | + // don't finalize the TXN if it has already been completed |
|
466 | + if ($transaction->all_reg_steps_completed() !== true) { |
|
467 | + /** @type EE_Payment_Processor $payment_processor */ |
|
468 | + $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
469 | + // let's simulate an IPN here which will trigger any notifications that need to go out |
|
470 | + $payment_processor->update_txn_based_on_payment( |
|
471 | + $transaction, |
|
472 | + $transaction->last_payment(), |
|
473 | + true, |
|
474 | + true |
|
475 | + ); |
|
476 | + } |
|
477 | + break; |
|
478 | + // Failed TXNs |
|
479 | + case EEM_Transaction::failed_status_code: |
|
480 | + do_action( |
|
481 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction', |
|
482 | + $transaction |
|
483 | + ); |
|
484 | + // todo : |
|
485 | + // perform garbage collection here and remove clean_out_junk_transactions() |
|
486 | + // $registrations = $transaction->registrations(); |
|
487 | + // if (! empty($registrations)) { |
|
488 | + // foreach ($registrations as $registration) { |
|
489 | + // if ($registration instanceof EE_Registration) { |
|
490 | + // $delete_registration = true; |
|
491 | + // if ($registration->attendee() instanceof EE_Attendee) { |
|
492 | + // $delete_registration = false; |
|
493 | + // } |
|
494 | + // if ($delete_registration) { |
|
495 | + // $registration->delete_permanently(); |
|
496 | + // $registration->delete_related_permanently(); |
|
497 | + // } |
|
498 | + // } |
|
499 | + // } |
|
500 | + // } |
|
501 | + break; |
|
502 | + } |
|
503 | + } |
|
504 | + unset(self::$_expired_transactions[ $TXN_ID ]); |
|
505 | + } |
|
506 | + } |
|
507 | + |
|
508 | + |
|
509 | + |
|
510 | + /************* END OF EXPIRED TRANSACTION CHECK *************/ |
|
511 | + |
|
512 | + |
|
513 | + /************* START CLEAN UP BOT TRANSACTIONS **********************/ |
|
514 | + |
|
515 | + |
|
516 | + /** |
|
517 | + * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions' |
|
518 | + * which is setup during activation to run on an hourly cron |
|
519 | + * |
|
520 | + * @throws EE_Error |
|
521 | + * @throws InvalidArgumentException |
|
522 | + * @throws InvalidDataTypeException |
|
523 | + * @throws InvalidInterfaceException |
|
524 | + * @throws DomainException |
|
525 | + */ |
|
526 | + public static function clean_out_junk_transactions() |
|
527 | + { |
|
528 | + if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
529 | + EED_Ticket_Sales_Monitor::reset_reservation_counts(); |
|
530 | + EEM_Transaction::instance('')->delete_junk_transactions(); |
|
531 | + EEM_Registration::instance('')->delete_registrations_with_no_transaction(); |
|
532 | + EEM_Line_Item::instance('')->delete_line_items_with_no_transaction(); |
|
533 | + } |
|
534 | + } |
|
535 | + |
|
536 | + |
|
537 | + /** |
|
538 | + * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that. |
|
539 | + * |
|
540 | + * @throws EE_Error |
|
541 | + * @throws InvalidDataTypeException |
|
542 | + * @throws InvalidInterfaceException |
|
543 | + * @throws InvalidArgumentException |
|
544 | + */ |
|
545 | + public static function clean_out_old_gateway_logs() |
|
546 | + { |
|
547 | + if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
548 | + $reg_config = LoaderFactory::getLoader()->load('EE_Registration_Config'); |
|
549 | + $time_diff_for_comparison = apply_filters( |
|
550 | + 'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison', |
|
551 | + '-' . $reg_config->gateway_log_lifespan |
|
552 | + ); |
|
553 | + EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison)); |
|
554 | + } |
|
555 | + } |
|
556 | + |
|
557 | + |
|
558 | + /***************** FINALIZE ABANDONED TRANSACTIONS *****************/ |
|
559 | + |
|
560 | + |
|
561 | + /** |
|
562 | + * @var array |
|
563 | + */ |
|
564 | + protected static $_abandoned_transactions = array(); |
|
565 | + |
|
566 | + |
|
567 | + /** |
|
568 | + * @deprecated |
|
569 | + * @param int $timestamp |
|
570 | + * @param int $TXN_ID |
|
571 | + */ |
|
572 | + public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID) |
|
573 | + { |
|
574 | + EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID); |
|
575 | + } |
|
576 | + |
|
577 | + |
|
578 | + /** |
|
579 | + * @deprecated |
|
580 | + * @param int $TXN_ID |
|
581 | + */ |
|
582 | + public static function check_for_abandoned_transactions($TXN_ID = 0) |
|
583 | + { |
|
584 | + EE_Cron_Tasks::expired_transaction_check($TXN_ID); |
|
585 | + } |
|
586 | + |
|
587 | + |
|
588 | + /** |
|
589 | + * @deprecated |
|
590 | + * @throws EE_Error |
|
591 | + * @throws DomainException |
|
592 | + * @throws InvalidDataTypeException |
|
593 | + * @throws InvalidInterfaceException |
|
594 | + * @throws InvalidArgumentException |
|
595 | + * @throws ReflectionException |
|
596 | + * @throws RuntimeException |
|
597 | + */ |
|
598 | + public static function finalize_abandoned_transactions() |
|
599 | + { |
|
600 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
601 | + if ( |
|
602 | 602 | // are there any TXNs that need cleaning up ? |
603 | - empty(self::$_abandoned_transactions) |
|
604 | - // reschedule the cron if we can't hit the db right now |
|
605 | - || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
606 | - 'schedule_expired_transaction_check', |
|
607 | - self::$_abandoned_transactions |
|
608 | - ) |
|
609 | - ) { |
|
610 | - return; |
|
611 | - } |
|
612 | - // combine our arrays of transaction IDs |
|
613 | - self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions; |
|
614 | - // and deal with abandoned transactions here now... |
|
615 | - EE_Cron_Tasks::process_expired_transactions(); |
|
616 | - } |
|
617 | - |
|
618 | - |
|
619 | - /************* END OF FINALIZE ABANDONED TRANSACTIONS *************/ |
|
603 | + empty(self::$_abandoned_transactions) |
|
604 | + // reschedule the cron if we can't hit the db right now |
|
605 | + || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
606 | + 'schedule_expired_transaction_check', |
|
607 | + self::$_abandoned_transactions |
|
608 | + ) |
|
609 | + ) { |
|
610 | + return; |
|
611 | + } |
|
612 | + // combine our arrays of transaction IDs |
|
613 | + self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions; |
|
614 | + // and deal with abandoned transactions here now... |
|
615 | + EE_Cron_Tasks::process_expired_transactions(); |
|
616 | + } |
|
617 | + |
|
618 | + |
|
619 | + /************* END OF FINALIZE ABANDONED TRANSACTIONS *************/ |
|
620 | 620 | } |