Completed
Branch BUG-11108-ticket-reserved-coun... (144d27)
by
unknown
14:21 queued 17s
created

EE_Messages_Queue   F

Complexity

Total Complexity 83

Size/Duplication

Total Lines 694
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 0
Metric Value
dl 0
loc 694
rs 3.4705
c 0
b 0
f 0
wmc 83
lcom 1
cbo 12

25 Methods

Rating   Name   Duplication   Size   Complexity  
A lock_queue() 0 4 1
A unlock_queue() 0 4 1
A _get_lock_key() 0 4 1
A _get_lock_expiry() 0 4 1
A _get_rate_limit_key() 0 4 1
A _get_rate_limit_expiry() 0 4 1
A _default_rate_limit() 0 4 1
A _get_priority_orderby() 0 7 1
A __construct() 0 5 1
A add() 0 6 1
B remove() 0 18 7
A save() 0 4 1
A get_message_repository() 0 4 1
B get_batch_to_generate() 0 29 5
C get_to_send_batch_and_send() 0 46 7
B is_locked() 0 29 3
B get_rate_limit() 0 17 6
A set_rate_limit() 0 10 1
B initiate_request_by_priority() 0 35 6
C execute() 0 63 13
C _process_message() 0 28 8
A count_STS_in_queue() 0 12 4
A _do_preview() 0 17 3
A _do_send() 0 16 3
B _set_error_message() 0 21 5

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
use \EventEspresso\core\exceptions\SendMessageException;
3
4
if (! defined('EVENT_ESPRESSO_VERSION')) {
5
    exit('No direct script access allowed');
6
}
7
8
/**
9
 * This class is used for managing and interacting with the EE_messages Queue.  An instance
10
 * of this object is used for interacting with a specific batch of EE_Message objects.
11
 *
12
 * @package    Event Espresso
13
 * @subpackage messages
14
 * @author     Darren Ethier
15
 * @since      4.9.0
16
 */
17
class EE_Messages_Queue
18
{
19
20
21
    /**
22
     * @type    string  reference for sending action
23
     */
24
    const action_sending = 'sending';
25
26
    /**
27
     * @type    string  reference for generation action
28
     */
29
    const action_generating = 'generation';
30
31
32
    /**
33
     * @type EE_Message_Repository $_message_repository
34
     */
35
    protected $_message_repository;
36
37
    /**
38
     * Sets the limit of how many messages are generated per process.
39
     *
40
     * @type int
41
     */
42
    protected $_batch_count;
43
44
45
    /**
46
     * This is an array of cached queue items being stored in this object.
47
     * The array keys will be the ID of the EE_Message in the db if saved.  If the EE_Message
48
     * is not saved to the db then its key will be an increment of "UNS" (i.e. UNS1, UNS2 etc.)
49
     *
50
     * @type EE_Message[]
51
     */
52
    protected $_cached_queue_items;
53
54
    /**
55
     * Tracks the number of unsaved queue items.
56
     *
57
     * @type int
58
     */
59
    protected $_unsaved_count = 0;
60
61
    /**
62
     * used to record if a do_messenger_hooks has already been called for a message type.  This prevents multiple
63
     * hooks getting fired if users have setup their action/filter hooks to prevent duplicate calls.
64
     *
65
     * @type array
66
     */
67
    protected $_did_hook = array();
68
69
70
    /**
71
     * Constructor.
72
     * Setup all the initial properties and load a EE_Message_Repository.
73
     *
74
     * @param \EE_Message_Repository $message_repository
75
     */
76
    public function __construct(EE_Message_Repository $message_repository)
77
    {
78
        $this->_batch_count        = apply_filters('FHEE__EE_Messages_Queue___batch_count', 50);
79
        $this->_message_repository = $message_repository;
80
    }
81
82
83
    /**
84
     * Add a EE_Message object to the queue
85
     *
86
     * @param EE_Message $message
87
     * @param array      $data         This will be an array of data to attach to the object in the repository.  If the
88
     *                                 object is persisted, this data will be saved on an extra_meta object related to
89
     *                                 EE_Message.
90
     * @param  bool      $preview      Whether this EE_Message represents a preview or not.
91
     * @param  bool      $test_send    This indicates whether to do a test send instead of actual send. A test send will
92
     *                                 use the messenger send method but typically is based on preview data.
93
     * @return bool          Whether the message was successfully added to the repository or not.
94
     */
95
    public function add(EE_Message $message, $data = array(), $preview = false, $test_send = false)
96
    {
97
        $data['preview']   = $preview;
98
        $data['test_send'] = $test_send;
99
        return $this->_message_repository->add($message, $data);
100
    }
101
102
103
    /**
104
     * Removes EE_Message from _queue that matches the given EE_Message if the pointer is on a matching EE_Message
105
     *
106
     * @param EE_Message $message The message to detach from the queue
107
     * @param bool       $persist This flag indicates whether to attempt to delete the object from the db as well.
108
     * @return bool
109
     */
110
    public function remove(EE_Message $message, $persist = false)
111
    {
112
        if ($persist && $this->_message_repository->current() !== $message) {
113
            //get pointer on right message
114
            if ($this->_message_repository->has($message)) {
115
                $this->_message_repository->rewind();
116
                while ($this->_message_repository->valid()) {
117
                    if ($this->_message_repository->current() === $message) {
118
                        break;
119
                    }
120
                    $this->_message_repository->next();
121
                }
122
            } else {
123
                return false;
124
            }
125
        }
126
        return $persist ? $this->_message_repository->delete() : $this->_message_repository->remove($message);
127
    }
128
129
130
    /**
131
     * Persists all queued EE_Message objects to the db.
132
     *
133
     * @param bool $do_hooks_only       @see EE_Message_Repository::saveAll
134
     * @return array @see EE_Messages_Repository::saveAll() for return values.
135
     */
136
    public function save($do_hooks_only = false)
137
    {
138
        return $this->_message_repository->saveAll($do_hooks_only);
139
    }
140
141
142
    /**
143
     * @return EE_Message_Repository
144
     */
145
    public function get_message_repository()
146
    {
147
        return $this->_message_repository;
148
    }
149
150
151
    /**
152
     * This does the following things:
153
     * 1. Checks if there is a lock on generation (prevents race conditions).  If there is a lock then exits (return
154
     * false).
155
     * 2. If no lock, sets lock, then retrieves a batch of non-generated EE_Message objects and adds to queue
156
     * 3. Returns bool.  True = batch ready.  False = no batch ready (or nothing available for generation).
157
     * Note: Callers should make sure they release the lock otherwise batch generation will be prevented from
158
     * continuing. The lock is on a transient that is set to expire after one hour as a fallback in case locks are not
159
     * removed.
160
     *
161
     * @return bool  true if successfully retrieved batch, false no batch ready.
162
     */
163
    public function get_batch_to_generate()
164
    {
165
        if ($this->is_locked(EE_Messages_Queue::action_generating)) {
166
            return false;
167
        }
168
169
        //lock batch generation to prevent race conditions.
170
        $this->lock_queue(EE_Messages_Queue::action_generating);
171
172
        $query_args = array(
173
            // key 0 = where conditions
174
            0          => array('STS_ID' => EEM_Message::status_incomplete),
175
            'order_by' => $this->_get_priority_orderby(),
176
            'limit'    => $this->_batch_count,
177
        );
178
        $messages   = EEM_Message::instance()->get_all($query_args);
179
180
        if ( ! $messages) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $messages of type EE_Base_Class[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
181
            return false; //nothing to generate
182
        }
183
184
        foreach ($messages as $message) {
185
            if ($message instanceof EE_Message) {
186
                $data = $message->all_extra_meta_array();
187
                $this->add($message, $data);
188
            }
189
        }
190
        return true;
191
    }
192
193
194
    /**
195
     * This does the following things:
196
     * 1. Checks if there is a lock on sending (prevents race conditions).  If there is a lock then exits (return
197
     * false).
198
     * 2. Grabs the allowed number of messages to send for the rate_limit.  If cannot send any more messages, then
199
     * return false.
200
     * 2. If no lock, sets lock, then retrieves a batch of EE_Message objects, adds to queue and triggers execution.
201
     * 3. On success or unsuccessful send, sets status appropriately.
202
     * 4. Saves messages via the queue
203
     * 5. Releases lock.
204
     *
205
     * @return bool  true on success, false if something preventing sending (i.e. lock set).  Note: true does not
206
     *               necessarily mean that all messages were successfully sent.  It just means that this method
207
     *               successfully completed. On true, client may want to call $this->count_STS_in_queue(
208
     *               EEM_Message::status_failed ) to see if any failed EE_Message objects.  Each failed message object
209
     *               will also have a saved error message on it to assist with notifying user.
210
     */
211
    public function get_to_send_batch_and_send()
212
    {
213
        $rate_limit = $this->get_rate_limit();
214
        if ($rate_limit < 1 || $this->is_locked(EE_Messages_Queue::action_sending)) {
215
            return false;
216
        }
217
218
        $this->lock_queue(EE_Messages_Queue::action_sending);
219
220
        $batch = $this->_batch_count < $rate_limit ? $this->_batch_count : $rate_limit;
221
222
        $query_args = array(
223
            // key 0 = where conditions
224
            0          => array('STS_ID' => array('IN', EEM_Message::instance()->stati_indicating_to_send())),
225
            'order_by' => $this->_get_priority_orderby(),
226
            'limit'    => $batch,
227
        );
228
229
        $messages_to_send = EEM_Message::instance()->get_all($query_args);
230
231
232
        //any to send?
233
        if ( ! $messages_to_send) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $messages_to_send of type EE_Base_Class[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
234
            $this->unlock_queue(EE_Messages_Queue::action_sending);
235
            return false;
236
        }
237
238
        $queue_count = 0;
239
240
        //add to queue.
241
        foreach ($messages_to_send as $message) {
242
            if ($message instanceof EE_Message) {
243
                $queue_count++;
244
                $this->add($message);
245
            }
246
        }
247
248
        //send messages  (this also updates the rate limit)
249
        $this->execute();
250
251
        //release lock
252
        $this->unlock_queue(EE_Messages_Queue::action_sending);
253
        //update rate limit
254
        $this->set_rate_limit($queue_count);
255
        return true;
256
    }
257
258
259
    /**
260
     * Locks the queue so that no other queues can call the "batch" methods.
261
     *
262
     * @param   string $type The type of queue being locked.
263
     */
264
    public function lock_queue($type = EE_Messages_Queue::action_generating)
265
    {
266
        update_option($this->_get_lock_key($type), $this->_get_lock_expiry($type));
267
    }
268
269
270
    /**
271
     * Unlocks the queue so that batch methods can be used.
272
     *
273
     * @param   string $type The type of queue being unlocked.
274
     */
275
    public function unlock_queue($type = EE_Messages_Queue::action_generating)
276
    {
277
        delete_option($this->_get_lock_key($type));
278
    }
279
280
281
    /**
282
     * Retrieve the key used for the lock transient.
283
     *
284
     * @param string $type The type of lock.
285
     * @return string
286
     */
287
    protected function _get_lock_key($type = EE_Messages_Queue::action_generating)
288
    {
289
        return '_ee_lock_' . $type;
290
    }
291
292
293
    /**
294
     * Retrieve the expiry time for the lock transient.
295
     *
296
     * @param string $type The type of lock
297
     * @return int   time to expiry in seconds.
298
     */
299
    protected function _get_lock_expiry($type = EE_Messages_Queue::action_generating)
300
    {
301
        return time() + (int) apply_filters('FHEE__EE_Messages_Queue__lock_expiry', HOUR_IN_SECONDS, $type);
302
    }
303
304
305
    /**
306
     * Returns the key used for rate limit transient.
307
     *
308
     * @return string
309
     */
310
    protected function _get_rate_limit_key()
311
    {
312
        return '_ee_rate_limit';
313
    }
314
315
316
    /**
317
     * Returns the rate limit expiry time.
318
     *
319
     * @return int
320
     */
321
    protected function _get_rate_limit_expiry()
322
    {
323
        return time() + (int) apply_filters('FHEE__EE_Messages_Queue__rate_limit_expiry', HOUR_IN_SECONDS);
324
    }
325
326
327
    /**
328
     * Returns the default rate limit for sending messages.
329
     *
330
     * @return int
331
     */
332
    protected function _default_rate_limit()
333
    {
334
        return (int) apply_filters('FHEE__EE_Messages_Queue___rate_limit', 200);
335
    }
336
337
338
    /**
339
     * Return the orderby array for priority.
340
     *
341
     * @return array
342
     */
343
    protected function _get_priority_orderby()
344
    {
345
        return array(
346
            'MSG_priority' => 'ASC',
347
            'MSG_modified' => 'DESC',
348
        );
349
    }
350
351
352
    /**
353
     * Returns whether batch methods are "locked" or not.
354
     *
355
     * @param  string $type The type of lock being checked for.
356
     * @return bool
357
     */
358
    public function is_locked($type = EE_Messages_Queue::action_generating)
359
    {
360
        $lock = (int) get_option($this->_get_lock_key($type), 0);
361
        /**
362
         * This filters the default is_locked behaviour.
363
         */
364
        $is_locked = filter_var(
365
            apply_filters(
366
                'FHEE__EE_Messages_Queue__is_locked',
367
                $lock > time(),
368
                $this
369
            ),
370
            FILTER_VALIDATE_BOOLEAN
371
        );
372
373
        /**
374
         * @see usage of this filter in EE_Messages_Queue::initiate_request_by_priority() method.
375
         *            Also implemented here because messages processed on the same request should not have any locks applied.
376
         */
377
        if (
378
            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
379
            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
380
        ) {
381
            $is_locked = false;
382
        }
383
384
385
        return $is_locked;
386
    }
387
388
389
    /**
390
     * Retrieves the rate limit that may be cached as a transient.
391
     * If the rate limit is not set, then this sets the default rate limit and expiry and returns it.
392
     *
393
     * @param bool $return_expiry  If true then return the expiry time not the rate_limit.
394
     * @return int
395
     */
396
    protected function get_rate_limit($return_expiry = false)
397
    {
398
        $stored_rate_info = get_option($this->_get_rate_limit_key(), array());
399
        $rate_limit = isset($stored_rate_info[0])
400
            ? (int) $stored_rate_info[0]
401
            : 0;
402
        $expiry = isset($stored_rate_info[1])
403
            ? (int) $stored_rate_info[1]
404
            : 0;
405
        //set the default for tracking?
406
        if (empty($stored_rate_info) || time() > $expiry) {
407
            $expiry = $this->_get_rate_limit_expiry();
408
            $rate_limit = $this->_default_rate_limit();
409
            update_option($this->_get_rate_limit_key(), array($rate_limit, $expiry));
410
        }
411
        return $return_expiry ? $expiry : $rate_limit;
412
    }
413
414
415
    /**
416
     * This updates existing rate limit with the new limit which is the old minus the batch.
417
     *
418
     * @param int $batch_completed This sets the new rate limit based on the given batch that was completed.
419
     */
420
    protected function set_rate_limit($batch_completed)
421
    {
422
        //first get the most up to date rate limit (in case its expired and reset)
423
        $rate_limit = $this->get_rate_limit();
424
        $expiry = $this->get_rate_limit(true);
425
        $new_limit  = $rate_limit - $batch_completed;
426
        //updating the transient option directly to avoid resetting the expiry.
427
428
        update_option($this->_get_rate_limit_key(), array($new_limit, $expiry));
429
    }
430
431
432
    /**
433
     * This method checks the queue for ANY EE_Message objects with a priority matching the given priority passed in.
434
     * If that exists, then we immediately initiate a non-blocking request to do the requested action type.
435
     * Note: Keep in mind that there is the possibility that the request will not execute if there is already another
436
     * request running on a queue for the given task.
437
     *
438
     * @param string $task     This indicates what type of request is going to be initiated.
439
     * @param int    $priority This indicates the priority that triggers initiating the request.
440
     */
441
    public function initiate_request_by_priority($task = 'generate', $priority = EEM_Message::priority_high)
442
    {
443
        //determine what status is matched with the priority as part of the trigger conditions.
444
        $status = $task == 'generate'
445
            ? EEM_Message::status_incomplete
446
            : EEM_Message::instance()->stati_indicating_to_send();
447
        // always make sure we save because either this will get executed immediately on a separate request
448
        // or remains in the queue for the regularly scheduled queue batch.
449
        $this->save();
450
        /**
451
         * This filter/option allows users to override processing of messages on separate requests and instead have everything
452
         * happen on the same request.  If this is utilized remember:
453
         * - message priorities don't matter
454
         * - existing unprocessed messages in the queue will not get processed unless manually triggered.
455
         * - things will be perceived to take longer to happen for end users (i.e. registrations) because of the additional
456
         *   processing happening on the same request.
457
         * - any race condition protection (locks) are removed because they don't apply when things are processed on
458
         *   the same request.
459
         */
460
        if (
461
            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
462
            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
463
        ) {
464
            $messages_processor = EE_Registry::instance()->load_lib('Messages_Processor');
465
            if ($messages_processor instanceof EE_Messages_Processor) {
466
                return $messages_processor->process_immediately_from_queue($this);
467
            }
468
            //if we get here then that means the messages processor couldn't be loaded so messages will just remain
469
            //queued for manual triggering by end user.
470
        }
471
472
        if ($this->_message_repository->count_by_priority_and_status($priority, $status)) {
473
            EE_Messages_Scheduler::initiate_scheduled_non_blocking_request($task);
474
        }
475
    }
476
477
478
    /**
479
     *  Loops through the EE_Message objects in the _queue and calls the messenger send methods for each message.
480
     *
481
     * @param   bool     $save                    Used to indicate whether to save the message queue after sending
482
     *                                            (default will save).
483
     * @param   mixed    $sending_messenger       (optional) When the sending messenger is different than
484
     *                                            what is on the EE_Message object in the queue.
485
     *                                            For instance, showing the browser view of an email message,
486
     *                                            or giving a pdf generated view of an html document.
487
     *                                            This should be an instance of EE_messenger but if you call this
488
     *                                            method
489
     *                                            intending it to be a sending messenger but a valid one could not be
490
     *                                            retrieved then send in an instance of EE_Error that contains the
491
     *                                            related error message.
492
     * @param   bool|int $by_priority             When set, this indicates that only messages
493
     *                                            matching the given priority should be executed.
494
     * @return int        Number of messages sent.  Note, 0 does not mean that no messages were processed.
495
     *                                            Also, if the messenger is an request type messenger (or a preview),
496
     *                                            its entirely possible that the messenger will exit before
497
     */
498
    public function execute($save = true, $sending_messenger = null, $by_priority = false)
499
    {
500
        $messages_sent   = 0;
501
        $this->_did_hook = array();
502
        $this->_message_repository->rewind();
503
504
        while ($this->_message_repository->valid()) {
505
            $error_messages = array();
506
            /** @type EE_Message $message */
507
            $message = $this->_message_repository->current();
508
            //only process things that are queued for sending
509
            if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
510
                $this->_message_repository->next();
511
                continue;
512
            }
513
            //if $by_priority is set and does not match then continue;
514
            if ($by_priority && $by_priority != $message->priority()) {
515
                $this->_message_repository->next();
516
                continue;
517
            }
518
            //error checking
519
            if (! $message->valid_messenger()) {
520
                $error_messages[] = sprintf(
521
                    __('The %s messenger is not active at time of sending.', 'event_espresso'),
522
                    $message->messenger()
523
                );
524
            }
525
            if (! $message->valid_message_type()) {
526
                $error_messages[] = sprintf(
527
                    __('The %s message type is not active at the time of sending.', 'event_espresso'),
528
                    $message->message_type()
529
                );
530
            }
531
            // if there was supposed to be a sending messenger for this message, but it was invalid/inactive,
532
            // then it will instead be an EE_Error object, so let's check for that
533
            if ($sending_messenger instanceof EE_Error) {
534
                $error_messages[] = $sending_messenger->getMessage();
535
            }
536
            // if there are no errors, then let's process the message
537
            if (empty($error_messages)) {
538
                if ($save) {
539
                    $message->set_messenger_is_executing();
540
                }
541
                if ($this->_process_message($message, $sending_messenger)) {
542
                    $messages_sent++;
543
                }
544
            }
545
            $this->_set_error_message($message, $error_messages);
546
            //add modified time
547
            $message->set_modified(time());
548
            //we save each message after its processed to make sure its status persists in case PHP times-out or runs
549
            //out of memory. @see https://events.codebasehq.com/projects/event-espresso/tickets/10281
550
            if ($save) {
551
                $message->save();
552
            }
553
554
            $this->_message_repository->next();
555
        }
556
        if ($save) {
557
            $this->save(true);
558
        }
559
        return $messages_sent;
560
    }
561
562
563
    /**
564
     * _process_message
565
     *
566
     * @param EE_Message $message
567
     * @param mixed      $sending_messenger (optional)
568
     * @return bool
569
     */
570
    protected function _process_message(EE_Message $message, $sending_messenger = null)
571
    {
572
        // these *should* have been validated in the execute() method above
573
        $messenger    = $message->messenger_object();
574
        $message_type = $message->message_type_object();
575
        //do actions for sending messenger if it differs from generating messenger and swap values.
576
        if (
577
            $sending_messenger instanceof EE_messenger
578
            && $messenger instanceof EE_messenger
579
            && $sending_messenger->name != $messenger->name
580
        ) {
581
            $messenger->do_secondary_messenger_hooks($sending_messenger->name);
582
            $messenger = $sending_messenger;
583
        }
584
        // send using messenger, but double check objects
585
        if ($messenger instanceof EE_messenger && $message_type instanceof EE_message_type) {
586
            //set hook for message type (but only if not using another messenger to send).
587
            if ( ! isset($this->_did_hook[$message_type->name])) {
588
                $message_type->do_messenger_hooks($messenger);
589
                $this->_did_hook[$message_type->name] = 1;
590
            }
591
            //if preview then use preview method
592
            return $this->_message_repository->is_preview()
593
                ? $this->_do_preview($message, $messenger, $message_type, $this->_message_repository->is_test_send())
594
                : $this->_do_send($message, $messenger, $message_type);
595
        }
596
        return false;
597
    }
598
599
600
    /**
601
     * The intention of this method is to count how many EE_Message objects
602
     * are in the queue with a given status.
603
     * Example usage:
604
     * After a caller calls the "EE_Message_Queue::execute()" method, the caller can check if there were any failed
605
     * sends by calling $queue->count_STS_in_queue( EEM_Message_Queue::status_failed ).
606
     *
607
     * @param array|string $status Stati to check for in queue
608
     * @return int  Count of EE_Message's matching the given status.
609
     */
610
    public function count_STS_in_queue($status)
611
    {
612
        $count  = 0;
613
        $status = is_array($status) ? $status : array($status);
614
        $this->_message_repository->rewind();
615
        foreach ($this->_message_repository as $message) {
616
            if (in_array($message->STS_ID(), $status)) {
617
                $count++;
618
            }
619
        }
620
        return $count;
621
    }
622
623
624
    /**
625
     * Executes the get_preview method on the provided messenger.
626
     *
627
     * @param EE_Message      $message
628
     * @param EE_messenger    $messenger
629
     * @param EE_message_type $message_type
630
     * @param                 $test_send
631
     * @return bool   true means all went well, false means, not so much.
632
     */
633
    protected function _do_preview(
634
        EE_Message $message,
635
        EE_messenger $messenger,
636
        EE_message_type $message_type,
637
        $test_send
638
    ) {
639
        if ($preview = $messenger->get_preview($message, $message_type, $test_send)) {
640
            if ( ! $test_send) {
641
                $message->set_content($preview);
642
            }
643
            $message->set_STS_ID(EEM_Message::status_sent);
644
            return true;
645
        } else {
646
            $message->set_STS_ID(EEM_Message::status_failed);
647
            return false;
648
        }
649
    }
650
651
652
    /**
653
     * Executes the send method on the provided messenger
654
     * EE_Messengers are expected to:
655
     * - return true if the send was successful.
656
     * - return false if the send was unsuccessful but can be tried again.
657
     * - throw an Exception if the send was unsuccessful and cannot be tried again.
658
     *
659
     * @param EE_Message      $message
660
     * @param EE_messenger    $messenger
661
     * @param EE_message_type $message_type
662
     * @return bool true means all went well, false means, not so much.
663
     */
664
    protected function _do_send(EE_Message $message, EE_messenger $messenger, EE_message_type $message_type)
665
    {
666
        try {
667
            if ($messenger->send_message($message, $message_type)) {
668
                $message->set_STS_ID(EEM_Message::status_sent);
669
                return true;
670
            } else {
671
                $message->set_STS_ID(EEM_Message::status_retry);
672
                return false;
673
            }
674
        } catch (SendMessageException $e) {
675
            $message->set_STS_ID(EEM_Message::status_failed);
676
            $message->set_error_message($e->getMessage());
677
            return false;
678
        }
679
    }
680
681
682
    /**
683
     * This sets any necessary error messages on the message object and its status to failed.
684
     *
685
     * @param EE_Message $message
686
     * @param array      $error_messages the response from the messenger.
687
     */
688
    protected function _set_error_message(EE_Message $message, $error_messages)
689
    {
690
        $error_messages = (array)$error_messages;
691
        if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) {
692
            $notices          = EE_Error::has_notices();
693
            $error_messages[] = __(
694
                'Messenger and Message Type were valid and active, but the messenger send method failed.',
695
                'event_espresso'
696
            );
697
            if ($notices === 1) {
698
                $notices           = EE_Error::get_vanilla_notices();
699
                $notices['errors'] = isset($notices['errors']) ? $notices['errors'] : array();
700
                $error_messages[]  = implode("\n", $notices['errors']);
701
            }
702
        }
703
        if (count($error_messages) > 0) {
704
            $msg = __('Message was not executed successfully.', 'event_espresso');
705
            $msg = $msg . "\n" . implode("\n", $error_messages);
706
            $message->set_error_message($msg);
707
        }
708
    }
709
710
} //end EE_Messages_Queue class
711