Message::addMetadata()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
/**
4
 * This file is part of the theroadbunch/mandrill-sdk package.
5
 *
6
 * (c) Dan McAdams <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace RoadBunch\Mandrill\Message;
13
14
15
use RoadBunch\Mandrill\Exception\ValidationException;
16
use RoadBunch\Mandrill\HeaderTrait;
17
18
/**
19
 * Class Message
20
 *
21
 * @author  Dan McAdams
22
 * @package RoadBunch\Mandrill
23
 */
24
class Message implements MessageInterface, MessageOptionsInterface
25
{
26
    use HeaderTrait;
27
28
    const MERGE_LANGUAGE_MAILCHIMP  = 'mailchimp';
29
    const MERGE_LANGUAGE_HANDLEBARS = 'handlebars';
30
31
    /**
32
     * whether or not this message is important,
33
     * and should be delivered ahead of non-important messages
34
     *
35
     * @var boolean $isImportant
36
     */
37
    protected $isImportant = false;
38
39
    /**
40
     * whether or not to turn on open tracking for the message
41
     *
42
     * @var boolean $trackOpens
43
     */
44
    protected $trackOpens;
45
46
    /**
47
     * whether or not to turn on click tracking for the message
48
     *
49
     * @var boolean $trackClicks
50
     */
51
    protected $trackClicks;
52
53
    /**
54
     * whether or not to automatically generate a text part for messages that are not given text
55
     *
56
     * @var boolean $autoText
57
     */
58
    protected $autoText;
59
60
    /**
61
     * whether or not to automatically generate an HTML part for messages that are not given HTML
62
     *
63
     * @var boolean $autoHtml
64
     */
65
    protected $autoHtml;
66
67
    /**
68
     * -- only for HTML documents less than 256KB in size --
69
     * whether or not to automatically inline all CSS styles provided in the message HTML
70
     *
71
     * @var boolean $inlineCss
72
     */
73
    protected $inlineCss;
74
75
    /**
76
     * whether or not to strip the query string from URLs when aggregating tracked URL data
77
     *
78
     * @var boolean $urlStripQs
79
     */
80
    protected $urlStripQs;
81
82
    /**
83
     * whether or not to expose all recipients in to "To" header for each email
84
     *
85
     * @var boolean $preserveRecipients
86
     */
87
    protected $preserveRecipients;
88
89
    /**
90
     * set to false to remove content logging for sensitive emails
91
     * (disables the 'view content' link on in the mandrill app)
92
     *
93
     * @var boolean $viewContentLink
94
     */
95
    protected $viewContentLink;
96
97
    /**
98
     * an optional address to receive an exact copy of each recipient's email
99
     *
100
     * @var string $bccAddress
101
     */
102
    protected $bccAddress;
103
104
    /**
105
     * a custom domain to use for tracking opens and clicks instead of mandrillapp.com
106
     *
107
     * @var string $trackingDomain
108
     */
109
    protected $trackingDomain;
110
111
    /**
112
     * a custom domain to use for SPF/DKIM signing instead of mandrill (for "via" or "on behalf of" in email clients)
113
     *
114
     * @var string $signingDomain
115
     */
116
    protected $signingDomain;
117
118
    /**
119
     * a custom domain to use for the messages's return-path
120
     *
121
     * @var string $returnPathDomain
122
     */
123
    protected $returnPathDomain;
124
125
    /**
126
     * metadata an associative array of user metadata.
127
     *  Mandrill will store this metadata and make it available for retrieval.
128
     *  In addition, you can select up to 10 metadata fields to index and make searchable using the Mandrill search api.
129
     *
130
     * @var array $metadata
131
     */
132
    protected $metadata = [];
133
134
    /**
135
     * global merge variables to use for all recipients. You can override these per recipient.
136
     *
137
     * @var array $globalMergeVars
138
     */
139
    protected $globalMergeVars = [];
140
141
    /**
142
     * the full HTML content to be sent
143
     *
144
     * @var string $html
145
     */
146
    protected $html = '';
147
148
    /**
149
     * optional full text content to be sent
150
     *
151
     * @var string $text
152
     */
153
    protected $text;
154
155
    /**
156
     * the message subject
157
     *
158
     * @var string $subject
159
     */
160
    protected $subject;
161
162
    /**
163
     * the sender email address
164
     *
165
     * @var string $fromEmail
166
     */
167
    protected $fromEmail;
168
169
    /**
170
     * optional from name to be used
171
     *
172
     * @var string $fromName
173
     */
174
    protected $fromName;
175
176
    /**
177
     * a collection of RecipientInterface - useful for easily building metadata and merge vars for recipients
178
     *
179
     * @var RecipientInterface[] $to
180
     */
181
    protected $to = [];
182
183
    /**
184
     * an array of strings indicating for which any matching URLs
185
     *  will automatically have Google Analytics parameters appended to their query string automatically.
186
     *
187
     * @var string[] $googleAnalyticsDomains
188
     */
189
    protected $googleAnalyticsDomains = [];
190
191
    /**
192
     * optional string indicating the value to set for the utm_campaign tracking parameter.
193
     *  If this isn't provided the email's from address will be used instead.
194
     *
195
     * @var string $googleAnalyticsCampaign
196
     */
197
    protected $googleAnalyticsCampaign;
198
199
    /**
200
     * an array of strings to tag the message with. Stats are accumulated using tags,
201
     *  though we only store the first 100 we see, so this should not be unique or change frequently.
202
     *  Tags should be 50 characters or less.
203
     *  Any tags starting with an underscore are reserved for internal use and will cause errors.
204
     *
205
     * @var array $tags
206
     */
207
    protected $tags = [];
208
209
    /**
210
     * the unique id of a subaccount for this message - must already exist or will fail with an error
211
     *
212
     * @var string $subaccount
213
     */
214
    protected $subaccount;
215
216
    /**
217
     * whether to evaluate merge tags in the message.
218
     *  Will automatically be set to true if either merge_vars or global_merge_vars are provided.
219
     *
220
     * @var bool $merge
221
     */
222
    protected $merge = false;
223
224
    /**
225
     * the merge tag language to use when evaluating merge tags, either mailchimp or handlebars
226
     *  one of mailchimp|handlebars
227
     *
228
     * @var string $mergeLanguage
229
     */
230
    protected $mergeLanguage = self::MERGE_LANGUAGE_MAILCHIMP;
231
232
    /**
233
     * an array of supported attachments to add to the message
234
     *
235
     * @var array $attachments
236
     */
237
    protected $attachments = [];
238
239
    /**
240
     * an array of embedded images to add to the message
241
     *
242
     * @var array $images
243
     */
244
    protected $images = [];
245
246
    /**
247
     * @param string $subject
248
     */
249
    public function setSubject(string $subject)
250
    {
251
        $this->subject = $subject;
252
    }
253
254
    /**
255
     * @param string      $email
256
     * @param string|null $name
257
     */
258
    public function setFrom(string $email, string $name = null)
259
    {
260
        $this->fromEmail = $email;
261
        $this->fromName  = $name;
262
    }
263
264
    /**
265
     * @param string $html
266
     */
267
    public function setHtml(string $html)
268
    {
269
        $this->html = $html;
270
    }
271
272
    /**
273
     * @param string $text
274
     */
275
    public function setText(string $text)
276
    {
277
        $this->text = $text;
278
    }
279
280
    /**
281
     * @param string $email
282
     */
283
    public function setReplyTo(string $email)
284
    {
285
        $this->addHeader('Reply-To', $email);
286
    }
287
288
    /**
289
     * @param string $email
290
     * @param string $name
291
     *
292
     * @return RecipientBuilderInterface
293
     * @throws ValidationException
294
     */
295
    public function addTo(string $email, string $name = ''): RecipientBuilderInterface
296
    {
297
        return $this->to[] = new ToRecipient($email, $name);
298
    }
299
300
    /**
301
     * @param string $email
302
     * @param string $name
303
     *
304
     * @return RecipientBuilderInterface
305
     * @throws ValidationException
306
     */
307
    public function addCc(string $email, string $name = ''): RecipientBuilderInterface
308
    {
309
        return $this->to[] = new CcRecipient($email, $name);
310
    }
311
312
    /**
313
     * @param string $email
314
     * @param string $name
315
     *
316
     * @return RecipientBuilderInterface
317
     * @throws ValidationException
318
     */
319
    public function addBcc(string $email, string $name = ''): RecipientBuilderInterface
320
    {
321
        return $this->to[] = new BccRecipient($email, $name);
322
    }
323
324
    /**
325
     * set important headers (I'm pretty sure mandrill does this already, but it can't hurt)
326
     */
327
    public function isImportant()
328
    {
329
        $this->isImportant = true;
330
331
        $this->addHeader('X-Priority', 1);
332
        $this->addHeader('X-MSMail-Priority', 'high');
333
        $this->addHeader('Importance', 'high');
334
    }
335
336
    /**
337
     * turn on tracking when an email is opened
338
     */
339
    public function trackOpens()
340
    {
341
        $this->trackOpens = true;
342
    }
343
344
    /**
345
     * turn on click tracking
346
     */
347
    public function trackClicks()
348
    {
349
        $this->trackClicks = true;
350
    }
351
352
    /**
353
     * tell mandrill to automatically generate text parts for messages that are not given text
354
     */
355
    public function autoGenerateText()
356
    {
357
        $this->autoText = true;
358
    }
359
360
    /**
361
     * tell mandrill to automatically generate text parts for messages that are not given text
362
     */
363
    public function autoGenerateHtml()
364
    {
365
        $this->autoHtml = true;
366
    }
367
368
    /**
369
     * tell mandrill to automatically inline all CSS styles provided in the message HTML
370
     */
371
    public function inlineCss()
372
    {
373
        $this->inlineCss = true;
374
    }
375
376
    /**
377
     * tell mandrill to strip the query string from URLs when aggregating tracked URL data
378
     */
379
    public function urlStripQs()
380
    {
381
        $this->urlStripQs = true;
382
    }
383
384
    /**
385
     * tell mandrill to expose all recipients in to "To" header for each email
386
     */
387
    public function preserveRecipients()
388
    {
389
        $this->preserveRecipients = true;
390
    }
391
392
    /**
393
     * disables the view content link for sensitive emails (will disable the link in the mandrill app)
394
     */
395
    public function disableContentLink()
396
    {
397
        $this->viewContentLink = false;
398
    }
399
400
    /**
401
     * an optional address to receive an exact copy of each recipient's email
402
     *
403
     * @param string $email
404
     */
405
    public function setBccAddress(string $email)
406
    {
407
        $this->bccAddress = $email;
408
    }
409
410
    /**
411
     * set a custom domain to use for tracking opens and clicks instead of mandrillapp.com
412
     *
413
     * @param string $domain
414
     */
415
    public function setTrackingDomain(string $domain)
416
    {
417
        $this->trackingDomain = $domain;
418
    }
419
420
    /**
421
     * set a custom domain to use for SPF/DKIM signing instead of mandrill (for "via" or "on behalf of" in email clients)
422
     *
423
     * @param string $domain
424
     */
425
    public function setSigningDomain(string $domain)
426
    {
427
        $this->signingDomain = $domain;
428
    }
429
430
    /**
431
     * set a custom domain to use for the messages's return-path
432
     *
433
     * @param string $domain
434
     */
435
    public function setReturnPathDomain(string $domain)
436
    {
437
        $this->returnPathDomain = $domain;
438
    }
439
440
    /**
441
     * using this method will overwrite all global metadata
442
     * but allows the user of this method to easily set metadata without a loop
443
     *
444
     * @param array $metadata
445
     */
446
    public function setMetadata(array $metadata)
447
    {
448
        $this->metadata = $metadata;
449
    }
450
451
    /**
452
     * add a key to the metadata array
453
     *
454
     * @param $key
455
     * @param $value
456
     */
457
    public function addMetadata($key, $value)
458
    {
459
        $this->metadata[$key] = $value;
460
    }
461
462
    /**
463
     * add a global merge variable
464
     *
465
     * @param string $name
466
     * @param        $content
467
     *
468
     * @throws ValidationException
469
     */
470
    public function addMergeVar(string $name, $content)
471
    {
472
        $this->merge = true;
473
        if ($this->stringStartsWithUnderscore($name)) {
474
            throw new ValidationException('Merge variables may not start with an underscore');
475
        }
476
        $this->globalMergeVars[] = ['name' => $name, 'content' => $content];
477
    }
478
479
    /**
480
     * A string to tag the message with. Stats are accumulated using tags,
481
     *  though we only store the first 100 we see, so this should not be unique or change frequently.
482
     *  Tags should be 50 characters or less.
483
     *  Any tags starting with an underscore are reserved for internal use and will cause errors.
484
     *
485
     * @param string $tag
486
     *
487
     * @throws ValidationException
488
     */
489
    public function addTag(string $tag)
490
    {
491
        if ($this->stringStartsWithUnderscore($tag)) {
492
            throw new ValidationException('Tags may not start with an underscore');
493
        }
494
        $this->tags[] = $tag;
495
    }
496
497
    /**
498
     * an array of strings indicating for which any matching URLs
499
     *  will automatically have Google Analytics parameters appended to their query string automatically.
500
     *
501
     * @param string $domain
502
     */
503
    public function addGoogleAnalyticsDomain(string $domain)
504
    {
505
        $this->googleAnalyticsDomains[] = $domain;
506
    }
507
508
    /**
509
     * optional string indicating the value to set for the utm_campaign tracking parameter.
510
     *  If this isn't provided the email's from address will be used instead.
511
     *
512
     * @param string $campaign
513
     */
514
    public function setGoogleAnalyticsCampaign(string $campaign)
515
    {
516
        $this->googleAnalyticsCampaign = $campaign;
517
    }
518
519
    /**
520
     * the unique id of a subaccount for this message - must already exist or will fail with an error
521
     *
522
     * @param string $subaccount
523
     */
524
    public function setSubaccount(string $subaccount)
525
    {
526
        $this->subaccount = $subaccount;
527
    }
528
529
    /**
530
     * set the merge language
531
     * mailchimp|handlebars
532
     *
533
     * @param string $mergeLanguage
534
     */
535
    public function setMergeLanguage(string $mergeLanguage)
536
    {
537
        $this->mergeLanguage = $mergeLanguage;
538
    }
539
540
    /**
541
     * a single supported attachment
542
     *
543
     * @param string $type    the MIME type of the attachment
544
     * @param string $name    the file name of the attachment
545
     * @param string $content the content of the attachment as a base64-encoded string
546
     */
547
    public function addAttachment(string $type, string $name, string $content)
548
    {
549
        $this->attachments[] = [
550
            'type'    => $type,
551
            'name'    => $name,
552
            'content' => $content
553
        ];
554
    }
555
556
    /**
557
     * an array of embedded images to add to the message
558
     *
559
     * @param string $type    the MIME type of the image - must start with "image/"
560
     * @param string $name    the Content ID of the image
561
     *                        use <img src="cid:THIS_VALUE"> to reference the image in your HTML content
562
     * @param string $content the content of the image as a base64-encoded string
563
     */
564
    public function addImage(string $type, string $name, string $content)
565
    {
566
        $this->images[] = [
567
            'type'    => $type,
568
            'name'    => $name,
569
            'content' => $content
570
        ];
571
    }
572
573
    /**
574
     * @return array
575
     */
576
    public function toArray(): array
577
    {
578
        return [
579
            'html'                      => $this->html,
580
            'text'                      => $this->text,
581
            'subject'                   => $this->subject,
582
            'from_email'                => $this->fromEmail,
583
            'from_name'                 => $this->fromName,
584
            'to'                        => $this->extractRecipients(),
585
            'headers'                   => $this->headers,
586
            'merge_vars'                => $this->extractRecipientMergeVars(),
587
            'recipient_metadata'        => $this->extractRecipientMetadata(),
588
            'important'                 => $this->isImportant,
589
            'track_opens'               => $this->trackOpens,
590
            'track_clicks'              => $this->trackClicks,
591
            'auto_text'                 => $this->autoText,
592
            'auto_html'                 => $this->autoHtml,
593
            'inline_css'                => $this->inlineCss,
594
            'url_strip_qs'              => $this->urlStripQs,
595
            'preserve_recipients'       => $this->preserveRecipients,
596
            'view_content_link'         => $this->viewContentLink,
597
            'bcc_address'               => $this->bccAddress,
598
            'tracking_domain'           => $this->trackingDomain,
599
            'signing_domain'            => $this->signingDomain,
600
            'return_path_domain'        => $this->returnPathDomain,
601
            'metadata'                  => $this->metadata,
602
            'global_merge_vars'         => $this->globalMergeVars,
603
            'google_analytics_domains'  => $this->googleAnalyticsDomains,
604
            'google_analytics_campaign' => $this->googleAnalyticsCampaign,
605
            'tags'                      => $this->tags,
606
            'subaccount'                => $this->subaccount,
607
            'merge'                     => $this->merge,
608
            'merge_language'            => $this->mergeLanguage,
609
            'attachments'               => $this->attachments,
610
            'images'                    => $this->images
611
        ];
612
    }
613
614
    /**
615
     * build the 'to' array for sending off to Mandrill.
616
     *
617
     * @return array
618
     */
619
    private function extractRecipients()
620
    {
621
        $ret = [];
622
        foreach ($this->to as $recipient) {
623
            $ret[] = [
624
                'email' => $recipient->getEmail(),
625
                'name'  => $recipient->getName(),
626
                'type'  => $recipient->getType()
627
            ];
628
        }
629
        return $ret;
630
    }
631
632
    private function extractRecipientMergeVars(): array
633
    {
634
        $ret = [];
635
        foreach ($this->to as $recipient) {
636
            if ($mergeVars = $recipient->getMergeVars()) {
637
                $ret[] = [
638
                    'rcpt' => $recipient->getEmail(),
639
                    'vars' => $mergeVars
640
                ];
641
            }
642
        }
643
        $this->merge = $this->merge ?: !empty($ret);
644
        return $ret;
645
    }
646
647
    private function extractRecipientMetadata(): array
648
    {
649
        $ret = [];
650
        foreach ($this->to as $recipient) {
651
            if ($metadata = $recipient->getMetadata()) {
652
                $ret[] = [
653
                    'rcpt'   => $recipient->getEmail(),
654
                    'values' => $metadata
655
                ];
656
            }
657
        }
658
        return $ret;
659
    }
660
661
    /**
662
     * @param string $str
663
     *
664
     * @return bool
665
     */
666
    private function stringStartsWithUnderscore(string $str)
667
    {
668
        return substr($str, 0, 1) === '_';
669
    }
670
}
671