Completed
Branch FET-10766-extract-activation-d... (99f7dd)
by
unknown
134:15 queued 121:56
created

EE_Messages_Generator::generate()   D

Complexity

Conditions 9
Paths 20

Size

Total Lines 106
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 56
nc 20
nop 1
dl 0
loc 106
rs 4.8196
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
defined('EVENT_ESPRESSO_VERSION') || exit('No direct access allowed.');
3
4
/**
5
 * This class is used for generating EE_Message objects with given info.
6
 *
7
 * @package    Event Espresso
8
 * @subpackage messages
9
 * @author     Darren Ethier
10
 * @since      4.9.0
11
 */
12
class EE_Messages_Generator
13
{
14
15
16
    /**
17
     * @type EE_Messages_Data_Handler_Collection
18
     */
19
    protected $_data_handler_collection;
20
21
    /**
22
     * @type  EE_Message_Template_Group_Collection
23
     */
24
    protected $_template_collection;
25
26
    /**
27
     * This will hold the data handler for the current EE_Message being generated.
28
     *
29
     * @type EE_Messages_incoming_data
30
     */
31
    protected $_current_data_handler;
32
33
    /**
34
     * This holds the EE_Messages_Queue that contains the messages to generate.
35
     *
36
     * @type EE_Messages_Queue
37
     */
38
    protected $_generation_queue;
39
40
    /**
41
     * This holds the EE_Messages_Queue that will store the generated EE_Message objects.
42
     *
43
     * @type EE_Messages_Queue
44
     */
45
    protected $_ready_queue;
46
47
    /**
48
     * This is a container for any error messages that get created through the generation
49
     * process.
50
     *
51
     * @type array
52
     */
53
    protected $_error_msg = array();
54
55
    /**
56
     * Flag used to set when the current EE_Message in the generation queue has been verified.
57
     *
58
     * @type bool
59
     */
60
    protected $_verified = false;
61
62
    /**
63
     * This will hold the current messenger object corresponding with the current EE_Message in the generation queue.
64
     *
65
     * @type EE_messenger
66
     */
67
    protected $_current_messenger;
68
69
    /**
70
     * This will hold the current message type object corresponding with the current EE_Message in the generation queue.
71
     *
72
     * @type EE_message_type
73
     */
74
    protected $_current_message_type;
75
76
    /**
77
     * @type EEH_Parse_Shortcodes
78
     */
79
    protected $_shortcode_parser;
80
81
82
    /**
83
     * @param EE_Messages_Queue                     $generation_queue
84
     * @param \EE_Messages_Queue                    $ready_queue
85
     * @param \EE_Messages_Data_Handler_Collection  $data_handler_collection
86
     * @param \EE_Message_Template_Group_Collection $template_collection
87
     * @param \EEH_Parse_Shortcodes                 $shortcode_parser
88
     */
89
    public function __construct(
90
        EE_Messages_Queue $generation_queue,
91
        EE_Messages_Queue $ready_queue,
92
        EE_Messages_Data_Handler_Collection $data_handler_collection,
93
        EE_Message_Template_Group_Collection $template_collection,
94
        EEH_Parse_Shortcodes $shortcode_parser
95
    ) {
96
        $this->_generation_queue        = $generation_queue;
97
        $this->_ready_queue             = $ready_queue;
98
        $this->_data_handler_collection = $data_handler_collection;
99
        $this->_template_collection     = $template_collection;
100
        $this->_shortcode_parser        = $shortcode_parser;
101
    }
102
103
104
    /**
105
     * @return EE_Messages_Queue
106
     */
107
    public function generation_queue()
108
    {
109
        return $this->_generation_queue;
110
    }
111
112
113
    /**
114
     *  This iterates through the provided queue and generates the EE_Message objects.
115
     *  When iterating through the queue, the queued item that served as the base for generating other EE_Message
116
     *  objects gets removed and the new EE_Message objects get added to a NEW queue.  The NEW queue is then returned
117
     *  for the caller to decide what to do with it.
118
     *
119
     * @param   bool $save Whether to save the EE_Message objects in the new queue or just return.
120
     * @return EE_Messages_Queue  The new queue for holding generated EE_Message objects.
121
     */
122
    public function generate($save = true)
123
    {
124
        //iterate through the messages in the queue, generate, and add to new queue.
125
        $this->_generation_queue->get_message_repository()->rewind();
126
        while ($this->_generation_queue->get_message_repository()->valid()) {
127
            //reset "current" properties
128
            $this->_reset_current_properties();
129
130
            /** @type EE_Message $msg */
131
            $msg = $this->_generation_queue->get_message_repository()->current();
132
133
            /**
134
             * need to get the next object and capture it for setting manually after deletes.  The reason is that when
135
             * an object is removed from the repo then valid for the next object will fail.
136
             */
137
            $this->_generation_queue->get_message_repository()->next();
138
            $next_msg = $this->_generation_queue->get_message_repository()->current();
139
            //restore pointer to current item
140
            $this->_generation_queue->get_message_repository()->set_current($msg);
141
142
            //skip and delete if the current $msg is NOT incomplete (queued for generation)
143
            if ($msg->STS_ID() !== EEM_Message::status_incomplete) {
144
                //we keep this item in the db just remove from the repo.
145
                $this->_generation_queue->get_message_repository()->remove($msg);
146
                //next item
147
                $this->_generation_queue->get_message_repository()->set_current($next_msg);
148
                continue;
149
            }
150
151
            if ($this->_verify()) {
152
                //let's get generating!
153
                $this->_generate();
154
            }
155
156
            //don't persist debug_only messages if the messages system is not in debug mode.
157
            if ($msg->STS_ID() === EEM_Message::status_debug_only
158
                && ! EEM_Message::debug()
159
            ) {
160
                do_action(
161
                    'AHEE__EE_Messages_Generator__generate__before_debug_delete',
162
                    $msg,
163
                    $this->_error_msg,
164
                    $this->_current_messenger,
165
                    $this->_current_message_type,
166
                    $this->_current_data_handler
167
                );
168
                $this->_generation_queue->get_message_repository()->delete();
169
                $this->_generation_queue->get_message_repository()->set_current($next_msg);
170
                continue;
171
            }
172
173
            //if there are error messages then let's set the status and the error message.
174
            if ($this->_error_msg) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_error_msg of type array 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...
175
                //if the status is already debug only, then let's leave it at that.
176
                if ($msg->STS_ID() !== EEM_Message::status_debug_only) {
177
                    $msg->set_STS_ID(EEM_Message::status_failed);
178
                }
179
                do_action(
180
                    'AHEE__EE_Messages_Generator__generate__processing_failed_message',
181
                    $msg,
182
                    $this->_error_msg,
183
                    $this->_current_messenger,
184
                    $this->_current_message_type,
185
                    $this->_current_data_handler
186
                );
187
                $msg->set_error_message(
188
                    esc_html__('Message failed to generate for the following reasons: ', 'event_espresso')
189
                    . "\n"
190
                    . implode("\n", $this->_error_msg)
191
                );
192
                $msg->set_modified(time());
193
            } else {
194
                do_action(
195
                    'AHEE__EE_Messages_Generator__generate__before_successful_generated_message_delete',
196
                    $msg,
197
                    $this->_error_msg,
198
                    $this->_current_messenger,
199
                    $this->_current_message_type,
200
                    $this->_current_data_handler
201
                );
202
                //remove from db
203
                $this->_generation_queue->get_message_repository()->delete();
204
            }
205
            //next item
206
            $this->_generation_queue->get_message_repository()->set_current($next_msg);
207
        }
208
209
        //generation queue is ALWAYS saved to record any errors in the generation process.
210
        $this->_generation_queue->save();
211
212
        /**
213
         * save _ready_queue if flag set.
214
         * Note: The EE_Message objects have values set via the EE_Base_Class::set_field_or_extra_meta() method.  This
215
         * means if a field was added that is not a valid database column.  The EE_Message was already saved to the db
216
         * so a EE_Extra_Meta entry could be created and attached to the EE_Message.  In those cases the save flag is
217
         * irrelevant.
218
         */
219
        if ($save) {
220
            $this->_ready_queue->save();
221
        }
222
223
        //final reset of properties
224
        $this->_reset_current_properties();
225
226
        return $this->_ready_queue;
227
    }
228
229
230
    /**
231
     * This resets all the properties used for holding "current" values corresponding to the current EE_Message object
232
     * in the generation queue.
233
     */
234
    protected function _reset_current_properties()
235
    {
236
        $this->_verified = false;
237
        //make sure any _data value in the current message type is reset
238
        if ($this->_current_message_type instanceof EE_message_type) {
239
            $this->_current_message_type->reset_data();
240
        }
241
        $this->_current_messenger = $this->_current_message_type = $this->_current_data_handler = null;
242
    }
243
244
245
    /**
246
     * This proceeds with the actual generation of a message.  By the time this is called, there should already be a
247
     * $_current_data_handler set and all incoming information should be validated for the current EE_Message in the
248
     * _generating_queue.
249
     *
250
     * @return bool Whether the message was successfully generated or not.
251
     * @throws EE_Error
252
     */
253
    protected function _generate()
254
    {
255
        //double check verification has run and that everything is ready to work with (saves us having to validate
256
        // everything again).
257
        if (! $this->_verified) {
258
            return false; //get out because we don't have a valid setup to work with.
259
        }
260
261
262
        try {
263
            $addressees = $this->_current_message_type->get_addressees(
264
                $this->_current_data_handler,
265
                $this->_generation_queue->get_message_repository()->current()->context()
266
            );
267
        } catch (EE_Error $e) {
268
            $this->_error_msg[] = $e->getMessage();
269
            return false;
270
        }
271
272
273
        //if no addressees then get out because there is nothing to generation (possible bad data).
274
        if (! $this->_valid_addressees($addressees)) {
275
            do_action(
276
                'AHEE__EE_Messages_Generator___generate__invalid_addressees',
277
                $this->_generation_queue->get_message_repository()->current(),
278
                $addressees,
279
                $this->_current_messenger,
280
                $this->_current_message_type,
281
                $this->_current_data_handler
282
            );
283
            $this->_generation_queue->get_message_repository()->current()->set_STS_ID(
284
                EEM_Message::status_debug_only
285
            );
286
            $this->_error_msg[] = esc_html__(
287
                'This is not a critical error but an informational notice. Unable to generate messages EE_Messages_Addressee objects.  There were no attendees prepared by the data handler. Sometimes this is because messages only get generated for certain registration statuses. For example, the ticket notice message type only goes to approved registrations.',
288
                'event_espresso'
289
            );
290
            return false;
291
        }
292
293
        $message_template_group = $this->_get_message_template_group();
294
295
        //in the unlikely event there is no EE_Message_Template_Group available, get out!
296
        if (! $message_template_group instanceof EE_Message_Template_Group) {
297
            $this->_error_msg[] = esc_html__(
298
                'Unable to get the Message Templates for the Message being generated.  No message template group accessible.',
299
                'event_espresso'
300
            );
301
            return false;
302
        }
303
304
        //get formatted templates for using to parse and setup EE_Message objects.
305
        $templates = $this->_get_templates($message_template_group);
306
307
308
        //setup new EE_Message objects (and add to _ready_queue)
309
        return $this->_assemble_messages($addressees, $templates, $message_template_group);
310
    }
311
312
313
    /**
314
     * Retrieves the message template group being used for generating messages.
315
     * Note: this also utilizes the EE_Message_Template_Group_Collection to avoid having to hit the db multiple times.
316
     *
317
     * @return EE_Message_Template_Group|null
318
     * @throws EE_Error
319
     */
320
    protected function _get_message_template_group()
321
    {
322
        //first see if there is a specific message template group requested (current message in the queue has a specific
323
        //GRP_ID
324
        $message_template_group = $this->_specific_message_template_group_from_queue();
325
        if ($message_template_group instanceof EE_Message_Template_Group) {
326
            return $message_template_group;
327
        }
328
329
        //get event_ids from the datahandler so we can check to see if there's already a message template group for them
330
        //in the collection.
331
        $event_ids              = $this->_get_event_ids_from_current_data_handler();
332
        $message_template_group = $this->_template_collection->get_by_key(
333
            $this->_template_collection->getKey(
334
                $this->_current_messenger->name,
335
                $this->_current_message_type->name,
336
                $event_ids
337
            )
338
        );
339
340
        //if we have a message template group then no need to hit the database, just return it.
341
        if ($message_template_group instanceof EE_Message_Template_Group) {
342
            return $message_template_group;
343
        }
344
345
        //okay made it here, so let's get the global group first for this messenger and message type to ensure
346
        //there is no override set.
347
        $global_message_template_group = $this->_get_global_message_template_group_for_current_messenger_and_message_type();
348
349
        if ($global_message_template_group instanceof EE_Message_Template_Group
350
            && $global_message_template_group->get('MTP_is_override')
351
        ) {
352
            return $global_message_template_group;
353
        }
354
355
        //if we're still here, that means there was no message template group for the events in the collection and
356
        //the global message template group for the messenger and message type is not set for override.  So next step is
357
        //to see if there is a common shared custom message template group for this set of events.
358
        $message_template_group = $this->_get_shared_message_template_for_events($event_ids);
359
        if ($message_template_group instanceof EE_Message_Template_Group) {
360
            return $message_template_group;
361
        }
362
363
        //STILL here?  Okay that means the fallback is to just use the global message template group for this event set.
364
        //So we'll cache the global group for this event set (so this logic doesn't have to be repeated in this request)
365
        //and return it.
366
        if ($global_message_template_group instanceof EE_Message_Template_Group) {
367
            $this->_template_collection->add(
368
                $global_message_template_group,
369
                $event_ids
370
            );
371
            return $global_message_template_group;
372
        }
373
374
        //if we land here that means there's NO active message template group for this set.
375
        //TODO this will be a good target for some optimization down the road.  Whenever there is no active message
376
        //template group for a given event set then cache that result so we don't repeat the logic.  However, for now,
377
        //this should likely bit hit rarely enough that it's not a significant issue.
378
        return null;
379
    }
380
381
382
    /**
383
     * This checks the current message in the queue and determines if there is a specific Message Template Group
384
     * requested for that message.
385
     *
386
     * @return EE_Message_Template_Group|null
387
     */
388
    protected function _specific_message_template_group_from_queue()
389
    {
390
        //is there a GRP_ID already on the EE_Message object?  If there is, then a specific template has been requested
391
        //so let's use that.
392
        $GRP_ID = $this->_generation_queue->get_message_repository()->current()->GRP_ID();
393
394
        if ($GRP_ID) {
395
            //attempt to retrieve from repo first
396
            $message_template_group = $this->_template_collection->get_by_ID($GRP_ID);
397
            if ($message_template_group instanceof EE_Message_Template_Group) {
398
                return $message_template_group;  //got it!
399
            }
400
401
            //nope don't have it yet.  Get from DB then add to repo if its not here, then that means the current GRP_ID
402
            //is not valid, so we'll continue on in the code assuming there's NO GRP_ID.
403
            $message_template_group = EEM_Message_Template_Group::instance()->get_one_by_ID($GRP_ID);
404
            if ($message_template_group instanceof EE_Message_Template_Group) {
405
                $this->_template_collection->add($message_template_group);
406
                return $message_template_group;
407
            }
408
        }
409
        return null;
410
    }
411
412
413
    /**
414
     * Returns whether the event ids passed in all share the same message template group for the current message type
415
     * and messenger.
416
     *
417
     * @param array $event_ids
418
     * @return bool true means they DO share the same message template group, false means they don't.
419
     * @throws EE_Error
420
     */
421
    protected function _queue_shares_same_message_template_group_for_events(array $event_ids)
422
    {
423
        foreach ($this->_current_data_handler->events as $event) {
424
            $event_ids[$event['ID']] = $event['ID'];
425
        }
426
        $count_of_message_template_groups = EEM_Message_Template_Group::instance()->count(
427
            array(
428
                array(
429
                    'Event.EVT_ID'           => array('IN', $event_ids),
430
                    'MTP_messenger'    => $this->_current_messenger->name,
431
                    'MTP_message_type' => $this->_current_message_type->name,
432
                ),
433
            ),
434
            'GRP_ID',
435
            true
436
        );
437
        return $count_of_message_template_groups === 1;
438
    }
439
440
441
    /**
442
     * This will get the shared message template group for events that are in the current data handler but ONLY if
443
     * there's a single shared message template group among all the events.  Otherwise it returns null.
444
     *
445
     * @param array $event_ids
446
     * @return EE_Message_Template_Group|null
447
     * @throws EE_Error
448
     */
449
    protected function _get_shared_message_template_for_events(array $event_ids)
450
    {
451
        $message_template_group = null;
452
        if ($this->_queue_shares_same_message_template_group_for_events($event_ids)) {
453
            $message_template_group = EEM_Message_Template_Group::instance()->get_one(
454
                array(
455
                    array(
456
                        'Event.EVT_ID'           => array('IN', $event_ids),
457
                        'MTP_messenger'    => $this->_current_messenger->name,
458
                        'MTP_message_type' => $this->_current_message_type->name,
459
                        'MTP_is_active'    => true,
460
                    ),
461
                    'group_by' => 'GRP_ID',
462
                )
463
            );
464
            //store this in the collection if its valid
465
            if ($message_template_group instanceof EE_Message_Template_Group) {
466
                $this->_template_collection->add(
467
                    $message_template_group,
468
                    $event_ids
469
                );
470
            }
471
        }
472
        return $message_template_group;
473
    }
474
475
476
    /**
477
     * Retrieves the global message template group for the current messenger and message type.
478
     *
479
     * @return EE_Message_Template_Group|null
480
     * @throws EE_Error
481
     */
482
    protected function _get_global_message_template_group_for_current_messenger_and_message_type()
483
    {
484
        //first check the collection (we use an array with 0 in it to represent global groups).
485
        $global_message_template_group = $this->_template_collection->get_by_key(
486
            $this->_template_collection->getKey(
487
                $this->_current_messenger->name,
488
                $this->_current_message_type->name,
489
                array(0)
490
            )
491
        );
492
493
        //if we don't have a group lets hit the db.
494
        if (! $global_message_template_group instanceof EE_Message_Template_Group) {
495
            $global_message_template_group = EEM_Message_Template_Group::instance()->get_one(
496
                array(
497
                    array(
498
                        'MTP_messenger'    => $this->_current_messenger->name,
499
                        'MTP_message_type' => $this->_current_message_type->name,
500
                        'MTP_is_active'    => true,
501
                        'MTP_is_global'    => true,
502
                    ),
503
                )
504
            );
505
            //if we have a group, add it to the collection.
506
            if ($global_message_template_group instanceof EE_Message_Template_Group) {
507
                $this->_template_collection->add(
508
                    $global_message_template_group,
509
                    array(0)
510
                );
511
            }
512
        }
513
        return $global_message_template_group;
514
    }
515
516
517
    /**
518
     * Returns an array of event ids for all the events within the current data handler.
519
     *
520
     * @return array
521
     */
522
    protected function _get_event_ids_from_current_data_handler()
523
    {
524
        $event_ids = array();
525
        foreach ($this->_current_data_handler->events as $event) {
526
            $event_ids[$event['ID']] = $event['ID'];
527
        }
528
        return $event_ids;
529
    }
530
531
532
    /**
533
     *  Retrieves formatted array of template information for each context specific to the given
534
     *  EE_Message_Template_Group
535
     *
536
     * @param EE_Message_Template_Group $message_template_group
537
     * @return array The returned array is in this structure:
538
     *                          array(
539
     *                          'field_name' => array(
540
     *                          'context' => 'content'
541
     *                          )
542
     *                          )
543
     * @throws EE_Error
544
     */
545
    protected function _get_templates(EE_Message_Template_Group $message_template_group)
546
    {
547
        $templates         = array();
548
        $context_templates = $message_template_group->context_templates();
549
        foreach ($context_templates as $context => $template_fields) {
550
            foreach ($template_fields as $template_field => $template_obj) {
551
                if (! $template_obj instanceof EE_Message_Template) {
552
                    continue;
553
                }
554
                $templates[$template_field][$context] = $template_obj->get('MTP_content');
555
            }
556
        }
557
        return $templates;
558
    }
559
560
561
    /**
562
     * Assembles new fully generated EE_Message objects and adds to _ready_queue
563
     *
564
     * @param array                     $addressees  Array of EE_Messages_Addressee objects indexed by message type
565
     *                                               context.
566
     * @param array                     $templates   formatted array of templates used for parsing data.
567
     * @param EE_Message_Template_Group $message_template_group
568
     * @return bool   true if message generation went a-ok.  false if some sort of exception occurred.  Note: The
569
     *                                               method will attempt to generate ALL EE_Message objects and add to
570
     *                                               the _ready_queue.  Successfully generated messages get added to the
571
     *                                               queue with EEM_Message::status_idle, unsuccessfully generated
572
     *                                               messages will get added to the queue as EEM_Message::status_failed.
573
     *                                               Very rarely should "false" be returned from this method.
574
     */
575
    protected function _assemble_messages($addressees, $templates, EE_Message_Template_Group $message_template_group)
576
    {
577
578
        //if templates are empty then get out because we can't generate anything.
579
        if (! $templates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $templates of type array 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...
580
            $this->_error_msg[] = esc_html__(
581
                'Unable to assemble messages because there are no templates retrieved for generating the messages with',
582
                'event_espresso'
583
            );
584
            return false;
585
        }
586
587
        //We use this as the counter for generated messages because don't forget we may be executing this inside of a
588
        //generation_queue.  So _ready_queue may have generated EE_Message objects already.
589
        $generated_count = 0;
590
        foreach ($addressees as $context => $recipients) {
591
            foreach ($recipients as $recipient) {
592
                $message = $this->_setup_message_object($context, $recipient, $templates, $message_template_group);
593
                if ($message instanceof EE_Message) {
594
                    $this->_ready_queue->add(
595
                        $message,
596
                        array(),
597
                        $this->_generation_queue->get_message_repository()->is_preview(),
598
                        $this->_generation_queue->get_message_repository()->is_test_send()
599
                    );
600
                    $generated_count++;
601
                }
602
603
                //if the current MSG being generated is for a test send then we'll only use ONE message in the generation.
604
                if ($this->_generation_queue->get_message_repository()->is_test_send()) {
605
                    break 2;
606
                }
607
            }
608
        }
609
610
        //if there are no generated messages then something else fatal went wrong.
611
        return $generated_count > 0;
612
    }
613
614
615
    /**
616
     * @param string                    $context   The context for the generated message.
617
     * @param EE_Messages_Addressee     $recipient
618
     * @param array                     $templates formatted array of templates used for parsing data.
619
     * @param EE_Message_Template_Group $message_template_group
620
     * @return bool|EE_Message
621
     * @throws EE_Error
622
     */
623
    protected function _setup_message_object(
624
        $context,
625
        EE_Messages_Addressee $recipient,
626
        $templates,
627
        EE_Message_Template_Group $message_template_group
628
    ) {
629
        //stuff we already know
630
        $transaction_id = $recipient->txn instanceof EE_Transaction ? $recipient->txn->ID() : 0;
631
        $transaction_id = empty($transaction_id) && $this->_current_data_handler->txn instanceof EE_Transaction
632
            ? $this->_current_data_handler->txn->ID()
633
            : $transaction_id;
634
        $message_fields = array(
635
            'GRP_ID'           => $message_template_group->ID(),
636
            'TXN_ID'           => $transaction_id,
637
            'MSG_messenger'    => $this->_current_messenger->name,
638
            'MSG_message_type' => $this->_current_message_type->name,
639
            'MSG_context'      => $context,
640
        );
641
642
        //recipient id and type should be on the EE_Messages_Addressee object but if this is empty, let's try to grab
643
        // the info from the att_obj found in the EE_Messages_Addressee object.
644
        if (empty($recipient->recipient_id) || empty($recipient->recipient_type)) {
645
            $message_fields['MSG_recipient_ID']   = $recipient->att_obj instanceof EE_Attendee
646
                ? $recipient->att_obj->ID()
647
                : 0;
648
            $message_fields['MSG_recipient_type'] = 'Attendee';
649
        } else {
650
            $message_fields['MSG_recipient_ID']   = $recipient->recipient_id;
651
            $message_fields['MSG_recipient_type'] = $recipient->recipient_type;
652
        }
653
        $message = EE_Message_Factory::create($message_fields);
654
655
        //grab valid shortcodes for shortcode parser
656
        $mt_shortcodes = $this->_current_message_type->get_valid_shortcodes();
657
        $m_shortcodes  = $this->_current_messenger->get_valid_shortcodes();
658
659
        //if the 'to' field is empty (messages will ALWAYS have a "to" field, then we get out because that means this
660
        //context is turned off) EXCEPT if we're previewing
661
        if (empty($templates['to'][$context])
662
            && ! $this->_generation_queue->get_message_repository()->is_preview()
663
            && ! $this->_current_messenger->allow_empty_to_field()
664
        ) {
665
            //we silently exit here and do NOT record a fail because the message is "turned off" by having no "to"
666
            //field.
667
            return false;
668
        }
669
        $error_msg = array();
670
        foreach ($templates as $field => $field_context) {
671
            $error_msg = array();
672
            //let's setup the valid shortcodes for the incoming context.
673
            $valid_shortcodes = $mt_shortcodes[$context];
674
            //merge in valid shortcodes for the field.
675
            $shortcodes = isset($m_shortcodes[$field]) ? $m_shortcodes[$field] : $valid_shortcodes;
676
            if (isset($templates[$field][$context])) {
677
                //prefix field.
678
                $column_name = 'MSG_' . $field;
679
                try {
680
                    $content = $this->_shortcode_parser->parse_message_template(
681
                        $templates[$field][$context],
682
                        $recipient,
683
                        $shortcodes,
684
                        $this->_current_message_type,
685
                        $this->_current_messenger,
686
                        $message
687
                    );
688
                    $message->set_field_or_extra_meta($column_name, $content);
689
                } catch (EE_Error $e) {
690
                    $error_msg[] = sprintf(
691
                        esc_html__(
692
                            'There was a problem generating the content for the field %s: %s',
693
                            'event_espresso'
694
                        ),
695
                        $field,
696
                        $e->getMessage()
697
                    );
698
                    $message->set_STS_ID(EEM_Message::status_failed);
699
                }
700
            }
701
        }
702
703
        if ($message->STS_ID() === EEM_Message::status_failed) {
704
            $error_msg = esc_html__('There were problems generating this message:', 'event_espresso')
705
                         . "\n"
706
                         . implode("\n", $error_msg);
707
            $message->set_error_message($error_msg);
708
        } else {
709
            $message->set_STS_ID(EEM_Message::status_idle);
710
        }
711
        return $message;
712
    }
713
714
715
    /**
716
     * This verifies that the incoming array has a EE_messenger object and a EE_message_type object and sets appropriate
717
     * error message if either is missing.
718
     *
719
     * @return bool         true means there were no errors, false means there were errors.
720
     */
721
    protected function _verify()
722
    {
723
        //reset error message to an empty array.
724
        $this->_error_msg = array();
725
        $valid            = true;
726
        $valid            = $valid ? $this->_validate_messenger_and_message_type() : $valid;
727
        $valid            = $valid ? $this->_validate_and_setup_data() : $valid;
728
729
        //set the verified flag so we know everything has been validated.
730
        $this->_verified = $valid;
731
732
        return $valid;
733
    }
734
735
736
    /**
737
     * This accepts an array and validates that it is an array indexed by context with each value being an array of
738
     * EE_Messages_Addressee objects.
739
     *
740
     * @param array $addressees Keys correspond to contexts for the message type and values are EE_Messages_Addressee[]
741
     * @return bool
742
     */
743
    protected function _valid_addressees($addressees)
744
    {
745
        if (! $addressees || ! is_array($addressees)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $addressees of type array 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...
746
            return false;
747
        }
748
749
        foreach ($addressees as $addressee_array) {
750
            foreach ($addressee_array as $addressee) {
751
                if (! $addressee instanceof EE_Messages_Addressee) {
752
                    return false;
753
                }
754
            }
755
        }
756
        return true;
757
    }
758
759
760
    /**
761
     * This validates the messenger, message type, and presences of generation data for the current EE_Message in the
762
     * queue. This process sets error messages if something is wrong.
763
     *
764
     * @return bool   true is if there are no errors.  false is if there is.
765
     */
766
    protected function _validate_messenger_and_message_type()
767
    {
768
769
        //first are there any existing error messages?  If so then return.
770
        if ($this->_error_msg) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_error_msg of type array 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...
771
            return false;
772
        }
773
        /** @type EE_Message $message */
774
        $message = $this->_generation_queue->get_message_repository()->current();
775
        try {
776
            $this->_current_messenger = $message->valid_messenger(true)
777
                ? $message->messenger_object()
778
                : null;
779
        } catch (Exception $e) {
780
            $this->_error_msg[] = $e->getMessage();
781
        }
782
        try {
783
            $this->_current_message_type = $message->valid_message_type(true)
784
                ? $message->message_type_object()
785
                : null;
786
        } catch (Exception $e) {
787
            $this->_error_msg[] = $e->getMessage();
788
        }
789
790
        /**
791
         * Check if there is any generation data, but only if this is not for a preview.
792
         */
793
        if (! $this->_generation_queue->get_message_repository()->get_generation_data()
794
            && (
795
                ! $this->_generation_queue->get_message_repository()->is_preview()
796
                && $this->_generation_queue->get_message_repository()->get_data_handler()
797
                   !== 'EE_Messages_Preview_incoming_data'
798
            )
799
        ) {
800
            $this->_error_msg[] = esc_html__(
801
                'There is no generation data for this message. Unable to generate.',
802
                'event_espresso'
803
            );
804
        }
805
806
        return empty($this->_error_msg);
807
    }
808
809
810
    /**
811
     * This method retrieves the expected data handler for the message type and validates the generation data for that
812
     * data handler.
813
     *
814
     * @return bool true means there are no errors.  false means there were errors (and handler did not get setup).
815
     */
816
    protected function _validate_and_setup_data()
817
    {
818
819
        //First, are there any existing error messages?  If so, return because if there were errors elsewhere this can't
820
        //be used anyways.
821
        if ($this->_error_msg) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_error_msg of type array 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...
822
            return false;
823
        }
824
825
        $generation_data = $this->_generation_queue->get_message_repository()->get_generation_data();
826
827
        /** @type EE_Messages_incoming_data $data_handler_class_name - well not really... just the class name actually */
828
        $data_handler_class_name = $this->_generation_queue->get_message_repository()->get_data_handler()
829
            ? $this->_generation_queue->get_message_repository()->get_data_handler()
830
            : 'EE_Messages_' . $this->_current_message_type->get_data_handler($generation_data) . '_incoming_data';
831
832
        //If this EE_Message is for a preview, then let's switch out to the preview data handler.
833
        if ($this->_generation_queue->get_message_repository()->is_preview()) {
834
            $data_handler_class_name = 'EE_Messages_Preview_incoming_data';
835
        }
836
837
        //First get the class name for the data handler (and also verifies it exists.
838
        if (! class_exists($data_handler_class_name)) {
839
            $this->_error_msg[] = sprintf(
840
                esc_html__(
841
                    'The included data handler class name does not match any valid, accessible, "%1$s" classes.  Looking for %2$s.',
842
                    'event_espresso'
843
                ),
844
                'EE_Messages_incoming_data',
845
                $data_handler_class_name
846
            );
847
            return false;
848
        }
849
850
        //convert generation_data for data_handler_instantiation.
851
        $generation_data = $data_handler_class_name::convert_data_from_persistent_storage($generation_data);
852
853
        //note, this may set error messages as well.
854
        $this->_set_data_handler($generation_data, $data_handler_class_name);
855
856
        return empty($this->_error_msg);
857
    }
858
859
860
    /**
861
     * Sets the $_current_data_handler property that is used for generating the current EE_Message in the queue, and
862
     * adds it to the _data repository.
863
     *
864
     * @param mixed  $generating_data           This is data expected by the instantiated data handler.
865
     * @param string $data_handler_class_name   This is the reference string indicating what data handler is being
866
     *                                          instantiated.
867
     * @return void .
868
     * @throws EE_Error
869
     * @throws ReflectionException
870
     */
871
    protected function _set_data_handler($generating_data, $data_handler_class_name)
872
    {
873
        //valid classname for the data handler.  Now let's setup the key for the data handler repository to see if there
874
        //is already a ready data handler in the repository.
875
        $this->_current_data_handler = $this->_data_handler_collection->get_by_key(
876
            $this->_data_handler_collection->get_key(
877
                $data_handler_class_name,
878
                $generating_data
879
            )
880
        );
881
        if (! $this->_current_data_handler instanceof EE_Messages_incoming_data) {
882
            //no saved data_handler in the repo so let's set one up and add it to the repo.
883
            try {
884
                $this->_current_data_handler = new $data_handler_class_name($generating_data);
885
                $this->_data_handler_collection->add($this->_current_data_handler, $generating_data);
886
            } catch (EE_Error $e) {
887
                $this->_error_msg[] = $e->get_error();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->_error_msg[] is correct as $e->get_error() (which targets EE_Error::get_error()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
888
            }
889
        }
890
    }
891
892
893
    /**
894
     * The queued EE_Message for generation does not save the data used for generation as objects
895
     * because serialization of those objects could be problematic if the data is saved to the db.
896
     * So this method calls the static method on the associated data_handler for the given message_type
897
     * and that preps the data for later instantiation when generating.
898
     *
899
     * @param EE_Message_To_Generate $message_to_generate
900
     * @param bool                   $preview Indicate whether this is being used for a preview or not.
901
     * @return mixed Prepped data for persisting to the queue.  false is returned if unable to prep data.
902
     */
903
    protected function _prepare_data_for_queue(EE_Message_To_Generate $message_to_generate, $preview)
904
    {
905
        /** @type EE_Messages_incoming_data $data_handler - well not really... just the class name actually */
906
        $data_handler = $message_to_generate->get_data_handler_class_name($preview);
907
        if (! $message_to_generate->valid()) {
908
            return false; //unable to get the data because the info in the EE_Message_To_Generate class is invalid.
909
        }
910
        return $data_handler::convert_data_for_persistent_storage($message_to_generate->data());
911
    }
912
913
914
    /**
915
     * This sets up a EEM_Message::status_incomplete EE_Message object and adds it to the generation queue.
916
     *
917
     * @param EE_Message_To_Generate $message_to_generate
918
     * @param bool                   $test_send Whether this is just a test send or not.  Typically used for previews.
919
     */
920
    public function create_and_add_message_to_queue(EE_Message_To_Generate $message_to_generate, $test_send = false)
921
    {
922
        //prep data
923
        $data = $this->_prepare_data_for_queue($message_to_generate, $message_to_generate->preview());
924
925
        $message = $message_to_generate->get_EE_Message();
926
927
        //is there a GRP_ID in the request?
928
        if ($GRP_ID = EE_Registry::instance()->REQ->get('GRP_ID')) {
929
            $message->set_GRP_ID($GRP_ID);
930
        }
931
932
        if ($data === false) {
933
            $message->set_STS_ID(EEM_Message::status_failed);
934
            $message->set_error_message(
935
                esc_html__(
936
                    'Unable to prepare data for persistence to the database.',
937
                    'event_espresso'
938
                )
939
            );
940
        } else {
941
            //make sure that the data handler is cached on the message as well
942
            $data['data_handler_class_name'] = $message_to_generate->get_data_handler_class_name();
943
        }
944
945
        $this->_generation_queue->add($message, $data, $message_to_generate->preview(), $test_send);
946
    }
947
}
948