Passed
Pull Request — 4 (#10065)
by Steve
07:48
created

Email::debug()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Control\Email;
4
5
use DateTime;
6
use Egulias\EmailValidator\EmailValidator;
7
use Egulias\EmailValidator\Validation\RFCValidation;
8
use SilverStripe\Control\Director;
9
use SilverStripe\Control\HTTP;
10
use SilverStripe\Core\Convert;
11
use SilverStripe\Core\Environment;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\ORM\FieldType\DBDatetime;
14
use SilverStripe\ORM\FieldType\DBField;
15
use SilverStripe\ORM\FieldType\DBHTMLText;
16
use SilverStripe\View\Requirements;
17
use SilverStripe\View\SSViewer;
18
use SilverStripe\View\ThemeResourceLoader;
19
use SilverStripe\View\ViewableData;
20
use Swift_Message;
21
use Swift_MimePart;
22
23
/**
24
 * Class to support sending emails.
25
 */
26
class Email extends ViewableData
27
{
28
29
    /**
30
     * @var array
31
     * @config
32
     */
33
    private static $send_all_emails_to = [];
34
35
    /**
36
     * @var array
37
     * @config
38
     */
39
    private static $cc_all_emails_to = [];
40
41
    /**
42
     * @var array
43
     * @config
44
     */
45
    private static $bcc_all_emails_to = [];
46
47
    /**
48
     * @var array
49
     * @config
50
     */
51
    private static $send_all_emails_from = [];
52
53
    /**
54
     * This will be set in the config on a site-by-site basis
55
     * @see https://docs.silverstripe.org/en/4/developer_guides/email/#administrator-emails
56
     *
57
     * @config
58
     * @var string|array The default administrator email address or array of [email => name]
59
     */
60
    private static $admin_email = null;
61
62
    /**
63
     * @var Swift_Message
64
     */
65
    private $swiftMessage;
66
67
    /**
68
     * @var string The name of the HTML template to render the email with (without *.ss extension)
69
     */
70
    private $HTMLTemplate = null;
71
72
    /**
73
     * @var string The name of the plain text template to render the plain part of the email with
74
     */
75
    private $plainTemplate = null;
76
77
    /**
78
     * @var Swift_MimePart
79
     */
80
    private $plainPart;
81
82
    /**
83
     * @var array|ViewableData Additional data available in a template.
84
     * Used in the same way than {@link ViewableData->customize()}.
85
     */
86
    private $data = [];
87
88
    /**
89
     * @var array
90
     */
91
    private $failedRecipients = [];
92
93
    /**
94
     * Checks for RFC822-valid email format.
95
     *
96
     * @param string $address
97
     * @return boolean
98
     *
99
     * @copyright Cal Henderson <[email protected]>
100
     *    This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
101
     *    http://creativecommons.org/licenses/by-sa/2.5/
102
     */
103
    public static function is_valid_address($address)
104
    {
105
        $validator = new EmailValidator();
106
        return $validator->isValid($address, new RFCValidation());
107
    }
108
109
    /**
110
     * Get send_all_emails_to
111
     *
112
     * @return array Keys are addresses, values are names
113
     */
114
    public static function getSendAllEmailsTo()
115
    {
116
        return static::mergeConfiguredEmails('send_all_emails_to', 'SS_SEND_ALL_EMAILS_TO');
117
    }
118
119
    /**
120
     * Get cc_all_emails_to
121
     *
122
     * @return array
123
     */
124
    public static function getCCAllEmailsTo()
125
    {
126
        return static::mergeConfiguredEmails('cc_all_emails_to', 'SS_CC_ALL_EMAILS_TO');
127
    }
128
129
    /**
130
     * Get bcc_all_emails_to
131
     *
132
     * @return array
133
     */
134
    public static function getBCCAllEmailsTo()
135
    {
136
        return static::mergeConfiguredEmails('bcc_all_emails_to', 'SS_BCC_ALL_EMAILS_TO');
137
    }
138
139
    /**
140
     * Get send_all_emails_from
141
     *
142
     * @return array
143
     */
144
    public static function getSendAllEmailsFrom()
145
    {
146
        return static::mergeConfiguredEmails('send_all_emails_from', 'SS_SEND_ALL_EMAILS_FROM');
147
    }
148
149
    /**
150
     * Normalise email list from config merged with env vars
151
     *
152
     * @param string $config Config key
153
     * @param string $env Env variable key
154
     * @return array Array of email addresses
155
     */
156
    protected static function mergeConfiguredEmails($config, $env)
157
    {
158
        // Normalise config list
159
        $normalised = [];
160
        $source = (array)static::config()->get($config);
161
        foreach ($source as $address => $name) {
162
            if ($address && !is_numeric($address)) {
163
                $normalised[$address] = $name;
164
            } elseif ($name) {
165
                $normalised[$name] = null;
166
            }
167
        }
168
        $extra = Environment::getEnv($env);
169
        if ($extra) {
170
            $normalised[$extra] = null;
171
        }
172
        return $normalised;
173
    }
174
175
    /**
176
     * Encode an email-address to protect it from spambots.
177
     * At the moment only simple string substitutions,
178
     * which are not 100% safe from email harvesting.
179
     *
180
     * @param string $email Email-address
181
     * @param string $method Method for obfuscating/encoding the address
182
     *    - 'direction': Reverse the text and then use CSS to put the text direction back to normal
183
     *    - 'visible': Simple string substitution ('@' to '[at]', '.' to '[dot], '-' to [dash])
184
     *    - 'hex': Hexadecimal URL-Encoding - useful for mailto: links
185
     * @return string
186
     */
187
    public static function obfuscate($email, $method = 'visible')
188
    {
189
        switch ($method) {
190
            case 'direction':
191
                Requirements::customCSS('span.codedirection { unicode-bidi: bidi-override; direction: rtl; }', 'codedirectionCSS');
192
193
                return '<span class="codedirection">' . strrev($email) . '</span>';
194
            case 'visible':
195
                $obfuscated = ['@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '];
196
197
                return strtr($email, $obfuscated);
198
            case 'hex':
199
                $encoded = '';
200
                $emailLength = strlen($email);
201
                for ($x = 0; $x < $emailLength; $x++) {
202
                    $encoded .= '&#x' . bin2hex($email[$x]) . ';';
203
                }
204
205
                return $encoded;
206
            default:
207
                user_error('Email::obfuscate(): Unknown obfuscation method', E_USER_NOTICE);
208
209
                return $email;
210
        }
211
    }
212
213
    /**
214
     * Email constructor.
215
     * @param string|array|null $from
216
     * @param string|array|null $to
217
     * @param string|null $subject
218
     * @param string|null $body
219
     * @param string|array|null $cc
220
     * @param string|array|null $bcc
221
     * @param string|null $returnPath
222
     */
223
    public function __construct(
224
        $from = null,
225
        $to = null,
226
        $subject = null,
227
        $body = null,
228
        $cc = null,
229
        $bcc = null,
230
        $returnPath = null
231
    ) {
232
        if ($from) {
233
            $this->setFrom($from);
234
        }
235
        if ($to) {
236
            $this->setTo($to);
237
        }
238
        if ($subject) {
239
            $this->setSubject($subject);
240
        }
241
        if ($body) {
242
            $this->setBody($body);
243
        }
244
        if ($cc) {
245
            $this->setCC($cc);
246
        }
247
        if ($bcc) {
248
            $this->setBCC($bcc);
249
        }
250
        if ($returnPath) {
251
            $this->setReturnPath($returnPath);
252
        }
253
254
        parent::__construct();
255
    }
256
257
    /**
258
     * @return Swift_Message
259
     */
260
    public function getSwiftMessage()
261
    {
262
        if (!$this->swiftMessage) {
263
            $this->setSwiftMessage(new Swift_Message(null, null, 'text/html', 'utf-8'));
264
        }
265
266
        return $this->swiftMessage;
267
    }
268
269
    /**
270
     * @param Swift_Message $swiftMessage
271
     *
272
     * @return $this
273
     */
274
    public function setSwiftMessage($swiftMessage)
275
    {
276
        $dateTime = new DateTime();
277
        $dateTime->setTimestamp(DBDatetime::now()->getTimestamp());
278
        $swiftMessage->setDate($dateTime);
279
        if (!$swiftMessage->getFrom() && ($defaultFrom = $this->config()->get('admin_email'))) {
280
            $swiftMessage->setFrom($defaultFrom);
281
        }
282
        $this->swiftMessage = $swiftMessage;
283
284
        return $this;
285
    }
286
287
    /**
288
     * @return string[]
289
     */
290
    public function getFrom()
291
    {
292
        return $this->getSwiftMessage()->getFrom();
293
    }
294
295
    /**
296
     * @param string|array $address
297
     * @return string|array
298
     */
299
    private function sanitiseAddress($address)
300
    {
301
        if (is_array($address)) {
302
            return array_map('trim', $address);
303
        }
304
        return trim($address);
305
    }
306
307
    /**
308
     * @param string|array $address
309
     * @param string|null $name
310
     * @return $this
311
     */
312
    public function setFrom($address, $name = null)
313
    {
314
        $address = $this->sanitiseAddress($address);
315
        $this->getSwiftMessage()->setFrom($address, $name);
316
317
        return $this;
318
    }
319
320
    /**
321
     * @param string|array $address
322
     * @param string|null $name
323
     * @return $this
324
     */
325
    public function addFrom($address, $name = null)
326
    {
327
        $address = $this->sanitiseAddress($address);
328
        $this->getSwiftMessage()->addFrom($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addFrom() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

328
        $this->getSwiftMessage()->addFrom(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
329
330
        return $this;
331
    }
332
333
    /**
334
     * @return string
335
     */
336
    public function getSender()
337
    {
338
        return $this->getSwiftMessage()->getSender();
339
    }
340
341
    /**
342
     * @param string $address
343
     * @param string|null $name
344
     * @return $this
345
     */
346
    public function setSender($address, $name = null)
347
    {
348
        $address = $this->sanitiseAddress($address);
349
        $this->getSwiftMessage()->setSender($address, $name);
350
351
        return $this;
352
    }
353
354
    /**
355
     * @return string
356
     */
357
    public function getReturnPath()
358
    {
359
        return $this->getSwiftMessage()->getReturnPath();
360
    }
361
362
    /**
363
     * The bounce handler address
364
     *
365
     * @param string $address Email address where bounce notifications should be sent
366
     * @return $this
367
     */
368
    public function setReturnPath($address)
369
    {
370
        $address = $this->sanitiseAddress($address);
371
        $this->getSwiftMessage()->setReturnPath($address);
372
        return $this;
373
    }
374
375
    /**
376
     * @return array
377
     */
378
    public function getTo()
379
    {
380
        return $this->getSwiftMessage()->getTo();
381
    }
382
383
    /**
384
     * Set recipient(s) of the email
385
     *
386
     * To send to many, pass an array:
387
     * ['[email protected]' => 'My Name', '[email protected]'];
388
     *
389
     * @param string|array $address The message recipient(s) - if sending to multiple, use an array of address => name
390
     * @param string|null $name The name of the recipient (if one)
391
     * @return $this
392
     */
393
    public function setTo($address, $name = null)
394
    {
395
        $address = $this->sanitiseAddress($address);
396
        $this->getSwiftMessage()->setTo($address, $name);
397
398
        return $this;
399
    }
400
401
    /**
402
     * @param string|array $address
403
     * @param string|null $name
404
     * @return $this
405
     */
406
    public function addTo($address, $name = null)
407
    {
408
        $address = $this->sanitiseAddress($address);
409
        $this->getSwiftMessage()->addTo($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addTo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

409
        $this->getSwiftMessage()->addTo(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
410
411
        return $this;
412
    }
413
414
    /**
415
     * @return array
416
     */
417
    public function getCC()
418
    {
419
        return $this->getSwiftMessage()->getCc();
420
    }
421
422
    /**
423
     * @param string|array $address
424
     * @param string|null $name
425
     * @return $this
426
     */
427
    public function setCC($address, $name = null)
428
    {
429
        $address = $this->sanitiseAddress($address);
430
        $this->getSwiftMessage()->setCc($address, $name);
431
432
        return $this;
433
    }
434
435
    /**
436
     * @param string|array $address
437
     * @param string|null $name
438
     * @return $this
439
     */
440
    public function addCC($address, $name = null)
441
    {
442
        $address = $this->sanitiseAddress($address);
443
        $this->getSwiftMessage()->addCc($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addCc() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

443
        $this->getSwiftMessage()->addCc(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
444
445
        return $this;
446
    }
447
448
    /**
449
     * @return array
450
     */
451
    public function getBCC()
452
    {
453
        return $this->getSwiftMessage()->getBcc();
454
    }
455
456
    /**
457
     * @param string|array $address
458
     * @param string|null $name
459
     * @return $this
460
     */
461
    public function setBCC($address, $name = null)
462
    {
463
        $address = $this->sanitiseAddress($address);
464
        $this->getSwiftMessage()->setBcc($address, $name);
465
466
        return $this;
467
    }
468
469
    /**
470
     * @param string|array $address
471
     * @param string|null $name
472
     * @return $this
473
     */
474
    public function addBCC($address, $name = null)
475
    {
476
        $address = $this->sanitiseAddress($address);
477
        $this->getSwiftMessage()->addBcc($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addBcc() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

477
        $this->getSwiftMessage()->addBcc(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
478
479
        return $this;
480
    }
481
482
    /**
483
     * @return mixed
484
     */
485
    public function getReplyTo()
486
    {
487
        return $this->getSwiftMessage()->getReplyTo();
488
    }
489
490
    /**
491
     * @param string|array $address
492
     * @param string|null $name
493
     * @return $this
494
     */
495
    public function setReplyTo($address, $name = null)
496
    {
497
        $address = $this->sanitiseAddress($address);
498
        $this->getSwiftMessage()->setReplyTo($address, $name);
499
500
        return $this;
501
    }
502
503
    /**
504
     * @param string|array $address
505
     * @param string|null $name
506
     * @return $this
507
     */
508
    public function addReplyTo($address, $name = null)
509
    {
510
        $address = $this->sanitiseAddress($address);
511
        $this->getSwiftMessage()->addReplyTo($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addReplyTo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

511
        $this->getSwiftMessage()->addReplyTo(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
512
513
        return $this;
514
    }
515
516
    /**
517
     * @return string
518
     */
519
    public function getSubject()
520
    {
521
        return $this->getSwiftMessage()->getSubject();
522
    }
523
524
    /**
525
     * @param string $subject The Subject line for the email
526
     * @return $this
527
     */
528
    public function setSubject($subject)
529
    {
530
        $this->getSwiftMessage()->setSubject($subject);
531
532
        return $this;
533
    }
534
535
    /**
536
     * @return int
537
     */
538
    public function getPriority()
539
    {
540
        return $this->getSwiftMessage()->getPriority();
541
    }
542
543
    /**
544
     * @param int $priority
545
     * @return $this
546
     */
547
    public function setPriority($priority)
548
    {
549
        $this->getSwiftMessage()->setPriority($priority);
550
551
        return $this;
552
    }
553
554
    /**
555
     * @param string $path Path to file
556
     * @param string $alias An override for the name of the file
557
     * @param string $mime The mime type for the attachment
558
     * @return $this
559
     */
560
    public function addAttachment($path, $alias = null, $mime = null)
561
    {
562
        $attachment = \Swift_Attachment::fromPath($path);
563
        if ($alias) {
564
            $attachment->setFilename($alias);
565
        }
566
        if ($mime) {
567
            $attachment->setContentType($mime);
568
        }
569
        $this->getSwiftMessage()->attach($attachment);
570
571
        return $this;
572
    }
573
574
    /**
575
     * @param string $data
576
     * @param string $name
577
     * @param string $mime
578
     * @return $this
579
     */
580
    public function addAttachmentFromData($data, $name, $mime = null)
581
    {
582
        $attachment = new \Swift_Attachment($data, $name);
583
        if ($mime) {
584
            $attachment->setContentType($mime);
585
        }
586
        $this->getSwiftMessage()->attach($attachment);
587
588
        return $this;
589
    }
590
591
    /**
592
     * @return array|ViewableData The template data
593
     */
594
    public function getData()
595
    {
596
        return $this->data;
597
    }
598
599
    /**
600
     * @param array|ViewableData $data The template data to set
601
     * @return $this
602
     */
603
    public function setData($data)
604
    {
605
        $this->data = $data;
606
        $this->invalidateBody();
607
608
        return $this;
609
    }
610
611
    /**
612
     * @param string|array $name The data name to add or array to names => value
613
     * @param string|null $value The value of the data to add
614
     * @return $this
615
     */
616
    public function addData($name, $value = null)
617
    {
618
        if (is_array($name)) {
619
            $this->data = array_merge($this->data, $name);
0 ignored issues
show
Bug introduced by
It seems like $this->data can also be of type SilverStripe\View\ViewableData; however, parameter $arrays of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

619
            $this->data = array_merge(/** @scrutinizer ignore-type */ $this->data, $name);
Loading history...
620
        } elseif (is_array($this->data)) {
621
            $this->data[$name] = $value;
622
        } else {
623
            $this->data->$name = $value;
624
        }
625
626
        $this->invalidateBody();
627
628
        return $this;
629
    }
630
631
    /**
632
     * Remove a datum from the message
633
     *
634
     * @param string $name
635
     * @return $this
636
     */
637
    public function removeData($name)
638
    {
639
        if (is_array($this->data)) {
640
            unset($this->data[$name]);
641
        } else {
642
            $this->data->$name = null;
643
        }
644
645
        $this->invalidateBody();
646
647
        return $this;
648
    }
649
650
    /**
651
     * @return string
652
     */
653
    public function getBody()
654
    {
655
        return $this->getSwiftMessage()->getBody();
656
    }
657
658
    /**
659
     * @param string $body The email body
660
     * @return $this
661
     */
662
    public function setBody($body)
663
    {
664
        $plainPart = $this->findPlainPart();
665
        if ($plainPart) {
666
            $this->getSwiftMessage()->detach($plainPart);
667
        }
668
        unset($plainPart);
669
670
        $body = HTTP::absoluteURLs($body);
671
        $this->getSwiftMessage()->setBody($body);
672
673
        return $this;
674
    }
675
676
    /**
677
     * @return $this
678
     */
679
    public function invalidateBody()
680
    {
681
        $this->setBody(null);
682
683
        return $this;
684
    }
685
686
    /**
687
     * @return string The base URL for the email
688
     */
689
    public function BaseURL()
690
    {
691
        return Director::absoluteBaseURL();
692
    }
693
694
    /**
695
     * Debugging help
696
     *
697
     * @return string Debug info
698
     */
699
    public function debug()
700
    {
701
        $this->render();
702
703
        $class = static::class;
704
        return "<h2>Email template {$class}:</h2>\n" . '<pre>' . $this->getSwiftMessage()->toString() . '</pre>';
705
    }
706
707
    /**
708
     * @return string
709
     */
710
    public function getHTMLTemplate()
711
    {
712
        if ($this->HTMLTemplate) {
713
            return $this->HTMLTemplate;
714
        }
715
716
        return ThemeResourceLoader::inst()->findTemplate(
717
            SSViewer::get_templates_by_class(static::class, '', self::class),
718
            SSViewer::get_themes()
719
        );
720
    }
721
722
    /**
723
     * Set the template to render the email with
724
     *
725
     * @param string $template
726
     * @return $this
727
     */
728
    public function setHTMLTemplate($template)
729
    {
730
        if (substr($template, -3) == '.ss') {
731
            $template = substr($template, 0, -3);
732
        }
733
        $this->HTMLTemplate = $template;
734
735
        return $this;
736
    }
737
738
    /**
739
     * Get the template to render the plain part with
740
     *
741
     * @return string
742
     */
743
    public function getPlainTemplate()
744
    {
745
        return $this->plainTemplate;
746
    }
747
748
    /**
749
     * Set the template to render the plain part with
750
     *
751
     * @param string $template
752
     * @return $this
753
     */
754
    public function setPlainTemplate($template)
755
    {
756
        if (substr($template, -3) == '.ss') {
757
            $template = substr($template, 0, -3);
758
        }
759
        $this->plainTemplate = $template;
760
761
        return $this;
762
    }
763
764
    /**
765
     * @param array $recipients
766
     * @return $this
767
     */
768
    public function setFailedRecipients($recipients)
769
    {
770
        $this->failedRecipients = $recipients;
771
772
        return $this;
773
    }
774
775
    /**
776
     * @return array
777
     */
778
    public function getFailedRecipients()
779
    {
780
        return $this->failedRecipients;
781
    }
782
783
    /**
784
     * Used by {@link SSViewer} templates to detect if we're rendering an email template rather than a page template
785
     *
786
     * @return bool
787
     */
788
    public function IsEmail()
789
    {
790
        return true;
791
    }
792
793
    /**
794
     * Send the message to the recipients
795
     *
796
     * @return bool true if successful or array of failed recipients
797
     */
798
    public function send()
799
    {
800
        if (!$this->getBody()) {
801
            $this->render();
802
        }
803
        if (!$this->hasPlainPart()) {
804
            $this->generatePlainPartFromBody();
805
        }
806
        return Injector::inst()->get(Mailer::class)->send($this);
807
    }
808
809
    /**
810
     * @return array|bool
811
     */
812
    public function sendPlain()
813
    {
814
        if (!$this->hasPlainPart()) {
815
            $this->render(true);
816
        }
817
        return Injector::inst()->get(Mailer::class)->send($this);
818
    }
819
820
    /**
821
     * Render the email
822
     * @param bool $plainOnly Only render the message as plain text
823
     * @return $this
824
     */
825
    public function render($plainOnly = false)
826
    {
827
        if ($existingPlainPart = $this->findPlainPart()) {
828
            $this->getSwiftMessage()->detach($existingPlainPart);
829
        }
830
        unset($existingPlainPart);
831
832
        // Respect explicitly set body
833
        $htmlPart = $plainOnly ? null : $this->getBody();
834
        $plainPart = $plainOnly ? $this->getBody() : null;
835
836
        // Ensure we can at least render something
837
        $htmlTemplate = $this->getHTMLTemplate();
838
        $plainTemplate = $this->getPlainTemplate();
839
        if (!$htmlTemplate && !$plainTemplate && !$plainPart && !$htmlPart) {
840
            return $this;
841
        }
842
843
        // Do not interfere with emails styles
844
        Requirements::clear();
845
846
        // Render plain part
847
        if ($plainTemplate && !$plainPart) {
848
            $plainPart = $this->renderWith($plainTemplate, $this->getData())->Plain();
0 ignored issues
show
Bug introduced by
It seems like $this->getData() can also be of type SilverStripe\View\ViewableData; however, parameter $customFields of SilverStripe\View\ViewableData::renderWith() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

848
            $plainPart = $this->renderWith($plainTemplate, /** @scrutinizer ignore-type */ $this->getData())->Plain();
Loading history...
849
        }
850
851
        // Render HTML part, either if sending html email, or a plain part is lacking
852
        if (!$htmlPart && $htmlTemplate && (!$plainOnly || empty($plainPart))) {
853
            $htmlPart = $this->renderWith($htmlTemplate, $this->getData());
854
        }
855
856
        // Plain part fails over to generated from html
857
        if (!$plainPart && $htmlPart) {
858
            /** @var DBHTMLText $htmlPartObject */
859
            $htmlPartObject = DBField::create_field('HTMLFragment', $htmlPart);
860
            $plainPart = $htmlPartObject->Plain();
861
        }
862
863
        // Rendering is finished
864
        Requirements::restore();
865
866
        // Fail if no email to send
867
        if (!$plainPart && !$htmlPart) {
868
            return $this;
869
        }
870
871
        // Build HTML / Plain components
872
        if ($htmlPart && !$plainOnly) {
873
            $this->setBody($htmlPart);
874
            $this->getSwiftMessage()->setContentType('text/html');
875
            $this->getSwiftMessage()->setCharset('utf-8');
876
            if ($plainPart) {
877
                $this->getSwiftMessage()->addPart($plainPart, 'text/plain', 'utf-8');
878
            }
879
        } else {
880
            if ($plainPart) {
881
                $this->setBody($plainPart);
882
            }
883
            $this->getSwiftMessage()->setContentType('text/plain');
884
            $this->getSwiftMessage()->setCharset('utf-8');
885
        }
886
887
        return $this;
888
    }
889
890
    /**
891
     * @return Swift_MimePart|false
892
     */
893
    public function findPlainPart()
894
    {
895
        foreach ($this->getSwiftMessage()->getChildren() as $child) {
896
            if ($child instanceof Swift_MimePart && $child->getContentType() == 'text/plain') {
897
                return $child;
898
            }
899
        }
900
        return false;
901
    }
902
903
    /**
904
     * @return bool
905
     */
906
    public function hasPlainPart()
907
    {
908
        if ($this->getSwiftMessage()->getContentType() === 'text/plain') {
909
            return true;
910
        }
911
        return (bool) $this->findPlainPart();
912
    }
913
914
    /**
915
     * Automatically adds a plain part to the email generated from the current Body
916
     *
917
     * @return $this
918
     */
919
    public function generatePlainPartFromBody()
920
    {
921
        $plainPart = $this->findPlainPart();
922
        if ($plainPart) {
923
            $this->getSwiftMessage()->detach($plainPart);
924
        }
925
        unset($plainPart);
926
927
        $this->getSwiftMessage()->addPart(
928
            Convert::xml2raw($this->getBody()),
929
            'text/plain',
930
            'utf-8'
931
        );
932
933
        return $this;
934
    }
935
}
936