Passed
Pull Request — master (#130)
by
unknown
02:57
created

Mailer::getFrom()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.0
13
 */
14
15
namespace Quantum\Libraries\Mailer;
16
17
use Quantum\Libraries\Storage\FileSystem;
18
use PHPMailer\PHPMailer\PHPMailer;
19
use Quantum\Debugger\Debugger;
20
use Quantum\Logger\FileLogger;
21
use PHPMailer\PHPMailer\SMTP;
22
use Quantum\Loader\Setup;
23
use Psr\Log\LogLevel;
24
use Quantum\Di\Di;
25
26
/**
27
 * Mailer class
28
 * @package Quantum\Libraries\Mailer
29
 * @uses \PHPMailer\PHPMailer\PHPMailer
30
 */
31
class Mailer
32
{
33
34
    /**
35
     * PHP Mailer instance
36
     * @var \PHPMailer\PHPMailer\PHPMailer
37
     */
38
    private $mailer;
39
40
    /**
41
     * From address and name
42
     * @var array
43
     */
44
    private $from = [];
45
46
    /**
47
     * To addresses
48
     * @var array
49
     */
50
    private $addresses = [];
51
52
    /**
53
     * Reply To addresses
54
     * @var array
55
     */
56
    private $replyToAddresses = [];
57
58
    /**
59
     * CC addresses
60
     * @var array
61
     */
62
    private $ccAddresses = [];
63
64
    /**
65
     * BCC addresses
66
     * @var array
67
     */
68
    private $bccAddresses = [];
69
70
    /**
71
     * Email subject
72
     * @var string
73
     */
74
    private $subject = null;
75
76
    /**
77
     * Email body
78
     * @var string|array
79
     */
80
    private $message = null;
81
82
    /**
83
     * Email data
84
     * @var string|array
85
     */
86
    private $data = null;
87
88
    /**
89
     * Email attachments
90
     * @var array
91
     */
92
    private $attachments = [];
93
94
    /**
95
     * Email attachments created from string
96
     * @var array
97
     */
98
    private $stringAttachments = [];
99
100
    /**
101
     * Template path
102
     * @var string
103
     */
104
    private $templatePath;
105
106
    /**
107
     * Sendinblue api key
108
     * @var string | null
109
     */
110
    private $api_key = null;
0 ignored issues
show
introduced by
The private property $api_key is not used, and could be removed.
Loading history...
111
112
    /**
113
     * Html message content
114
     * @var string | null
115
     */
116
    private $htmlContent = null;
117
118
    /**
119
     * mailerAdapter
120
     * @var mixed
121
     */
122
    private $mailerAdapter;
123
124
    /**
125
     * Mailer constructor.
126
     */
127
    public function __construct(MailerInterface $mailerAdapter)
128
    {
129
        if (!config()->has('mailer') || !config()->has('mailer.current')) {
130
            config()->import(new Setup('config', 'mailer'));
131
        }
132
133
134
        $this->mailer = new PHPMailer(true);
135
        $this->mailer->CharSet = 'UTF-8';
136
        if (config()->has('mailer.default.mail_host')) {
137
            $this->setupSmtp();
138
            $this->setupDebugging();
139
        } else {
140
            $this->mailer->isMail();
141
        }
142
        $this->mailer->AllowEmpty = true;
143
        $this->mailer->isHTML(true);
144
        $this->mailerAdapter = $mailerAdapter;
145
    }
146
147
    /**
148
     * Sets the from email and the name
149
     * @param string $email
150
     * @param string|null $name
151
     * @return $this
152
     */
153
    public function setFrom(string $email, ?string $name = null): Mailer
154
    {
155
        $this->from['email'] = $email;
156
        $this->from['name'] = $name;
157
        return $this;
158
    }
159
160
    /**
161
     * Gets from email and the name
162
     * @return array
163
     */
164
    public function getFrom(): array
165
    {
166
        return $this->from;
167
    }
168
169
    /**
170
     * Sets "To" addresses
171
     * @param string $email
172
     * @param string|null $name
173
     * @return $this
174
     */
175
    public function setAddress(string $email, ?string $name = null): Mailer
176
    {
177
        array_push($this->addresses, [
178
            'email' => $email,
179
            'name' => $name
180
        ]);
181
182
        return $this;
183
    }
184
185
    /**
186
     * Gets "To" addresses
187
     * @return array
188
     */
189
    public function getAddresses(): array
190
    {
191
        return $this->addresses;
192
    }
193
194
    /**
195
     * Sets "Reply-To" addresses
196
     * @param string $email
197
     * @param string|null $name
198
     * @return $this
199
     */
200
    public function setReplay(string $email, ?string $name = null): Mailer
201
    {
202
        array_push($this->replyToAddresses, [
203
            'email' => $email,
204
            'name' => $name
205
        ]);
206
207
        return $this;
208
    }
209
210
    /**
211
     * Gets "Reply-To" addresses
212
     * @return array
213
     */
214
    public function getReplays(): array
215
    {
216
        return $this->replyToAddresses;
217
    }
218
219
    /**
220
     * Sets "CC" addresses
221
     * @param string $email
222
     * @param string|null $name
223
     * @return $this
224
     */
225
    public function setCC(string $email, ?string $name = null): Mailer
226
    {
227
        array_push($this->ccAddresses, [
228
            'email' => $email,
229
            'name' => $name
230
        ]);
231
232
        return $this;
233
    }
234
235
    /**
236
     * Gets "CC" addresses
237
     * @return array
238
     */
239
    public function getCCs(): array
240
    {
241
        return $this->ccAddresses;
242
    }
243
244
    /**
245
     * Sets "BCC" addresses
246
     * @param string $email
247
     * @param string|null $name
248
     * @return $this
249
     */
250
    public function setBCC(string $email, ?string $name = null): Mailer
251
    {
252
        array_push($this->bccAddresses, [
253
            'email' => $email,
254
            'name' => $name
255
        ]);
256
257
        return $this;
258
    }
259
260
    /**
261
     * Get "BCC" addresses
262
     * @return array
263
     */
264
    public function getBCCs(): array
265
    {
266
        return $this->bccAddresses;
267
    }
268
269
    /**
270
     * Sets the subject
271
     * @param string|null $subject
272
     * @return $this
273
     */
274
    public function setSubject(?string $subject): Mailer
275
    {
276
        $this->subject = $subject;
277
        return $this;
278
    }
279
280
    /**
281
     * Gets the subject
282
     * @return string
283
     */
284
    public function getSubject(): ?string
285
    {
286
        return $this->subject;
287
    }
288
289
    /**
290
     * Sets the template
291
     * @param string $templatePath
292
     * @return $this
293
     */
294
    public function setTemplate(string $templatePath): Mailer
295
    {
296
        $this->templatePath = $templatePath;
297
        return $this;
298
    }
299
300
    /**
301
     * Gets the template
302
     * @return string
303
     */
304
    public function getTemplate(): string
305
    {
306
        return $this->templatePath;
307
    }
308
309
    /**
310
     * Sets the body
311
     * @param string|array $message
312
     * @return $this
313
     */
314
    public function setBody($message): Mailer
315
    {
316
        $this->message = $message;
317
        return $this;
318
    }
319
320
    /**
321
     * Gets the body
322
     * @return string|array
323
     */
324
    public function getBody()
325
    {
326
        return $this->message;
327
    }
328
329
    /**
330
     * Sets attachments from the path on the filesystem
331
     * @param string $attachments
332
     * @return $this
333
     */
334
    public function setAttachment(string $attachments): Mailer
335
    {
336
        array_push($this->attachments, $attachments);
337
        return $this;
338
    }
339
340
    /**
341
     * Gets the attachments
342
     * @return array
343
     */
344
    public function getAttachments(): array
345
    {
346
        return $this->attachments;
347
    }
348
349
    /**
350
     * Sets attachment from the string
351
     * @param string $content
352
     * @param string $filename
353
     * @return $this
354
     */
355
    public function setStringAttachment(string $content, string $filename): Mailer
356
    {
357
        array_push($this->stringAttachments, [
358
            'content' => $content,
359
            'filename' => $filename
360
        ]);
361
362
        return $this;
363
    }
364
365
    /**
366
     * Gets the string attachments
367
     * @return array
368
     */
369
    public function getStringAttachments(): array
370
    {
371
        return $this->stringAttachments;
372
    }
373
374
    /**
375
     * Sends the email
376
     * @param array|null $from
377
     * @param array|null $address
378
     * @param string|null $message
379
     * @param array|null $options
380
     * @return bool
381
     * @throws \PHPMailer\PHPMailer\Exception
382
     * @throws \Quantum\Exceptions\DiException
383
     * @throws \ReflectionException
384
     */
385
    public function send(?array $from = null, ?array $address = null, ?string $message = null, ?array $options = []): bool
386
    {
387
        if ($from) {
388
            $this->setFrom(...$from);
0 ignored issues
show
Bug introduced by
$from is expanded, but the parameter $email of Quantum\Libraries\Mailer\Mailer::setFrom() does not expect variable arguments. ( Ignorable by Annotation )

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

388
            $this->setFrom(/** @scrutinizer ignore-type */ ...$from);
Loading history...
389
        }
390
391
        if ($address) {
392
            $this->setAddress(...$address);
0 ignored issues
show
Bug introduced by
$address is expanded, but the parameter $email of Quantum\Libraries\Mailer\Mailer::setAddress() does not expect variable arguments. ( Ignorable by Annotation )

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

392
            $this->setAddress(/** @scrutinizer ignore-type */ ...$address);
Loading history...
393
        }
394
395
        if ($message) {
396
            $this->setBody($message);
397
        }
398
399
        $this->setOptions($options);
400
401
        $this->prepare();
402
        if ($this->message) {
403
            if ($this->templatePath) {
404
                $body = $this->createFromTemplate();
405
            } else {
406
                $body = is_array($this->message) ? implode($this->message) : $this->message;
407
            }
408
409
            $this->htmlContent = $body;
410
        }
411
        if (config()->get('mailer.mail_trap')) {
412
            $sent = $this->mailer->preSend();
413
            $this->saveMessage($this->mailer->getLastMessageID(), $this->mailer->getSentMIMEMessage());
414
            return $sent;
415
        }
416
        if (config()->get('mailer.current') == 'smtp') {
417
            return $this->mailer->send();
418
        } else if (config()->get('mailer.current') == 'sendinblue') {
419
            $this->data = '{  
420
                "sender":' . json_encode($this->from) . ',
421
                "to":' . json_encode($this->addresses) . ',
422
                "subject":"' . $this->subject . '",
423
                "htmlContent":"' . trim(str_replace("\n", "", $this->htmlContent)) . '"
424
                }';
425
        } else if (config()->get('mailer.current') == 'mailgun') {
426
            $to = [];
427
            foreach ($this->addresses as $key => $value) {
428
                array_push($to, $value['email']);
429
            }
430
431
            $this->data = [
432
                "from" => $this->from['name'] . " " . $this->from['email'],
433
                "to" => implode(',', $to),
434
                "subject" => $this->subject,
435
                "html" => trim(str_replace("\n", "", $this->htmlContent))
436
            ];
437
        } else if (config()->get('mailer.current') == 'mandrill') {
438
            $this->data = [
439
                'message' => [
440
                    'subject' => $this->subject,
441
                    'html' => trim(str_replace("\n", "", $this->htmlContent)),
442
                    'from_email' => $this->from['email'],
443
                    'from_name' => $this->from['name'],
444
                    'to' => $this->addresses,
445
                ]
446
            ];
447
        }
448
        return $this->mailerAdapter->sendMail($this->data);
449
    }
450
451
    /**
452
     * Save the message on local file
453
     * @param string $id
454
     * @param string $content
455
     * @throws \Quantum\Exceptions\DiException
456
     * @throws \ReflectionException
457
     */
458
    private function saveMessage(string $id, string $content)
459
    {
460
        $fs = Di::get(FileSystem::class);
461
462
        $emailsDirectory = base_dir() . DS . 'shared' . DS . 'emails';
463
464
        if ($fs->isDirectory($emailsDirectory)) {
465
            $fs->put($emailsDirectory . DS . $this->getFilename($id), $content);
466
        }
467
    }
468
469
    /**
470
     * Sets the options
471
     * @param array $options
472
     */
473
    private function setOptions(array $options)
474
    {
475
        foreach ($options as $name => $params) {
476
            if (method_exists(__CLASS__, $method = 'set' . ucfirst($name))) {
477
                if (is_array($params)) {
478
                    $this->$method(...$params);
479
                } else {
480
                    $this->$method($params);
481
                }
482
            }
483
        }
484
    }
485
486
    /**
487
     * Fetches message ID
488
     * @param string $lastMessageId
489
     * @return string
490
     */
491
    private function getFilename(string $lastMessageId): string
492
    {
493
        preg_match('/<(.*?)@/', $lastMessageId, $matches);
494
        return $matches[1] . '.eml';
495
    }
496
497
    /**
498
     * Prepares the data
499
     * @throws \PHPMailer\PHPMailer\Exception
500
     */
501
    private function prepare()
502
    {
503
        $this->mailer->setFrom($this->from['email'], $this->from['name']);
504
505
        if ($this->subject) {
506
            $this->mailer->Subject = $this->subject;
507
        }
508
509
        if ($this->message) {
510
            if ($this->templatePath) {
511
                $body = $this->createFromTemplate();
512
            } else {
513
                $body = is_array($this->message) ? implode($this->message) : $this->message;
514
            }
515
516
            $this->mailer->Body = $body;
517
        }
518
519
        $this->fillProperties('addAddress', $this->addresses);
520
521
        $this->fillProperties('addReplyTo', $this->replyToAddresses);
522
523
        $this->fillProperties('addCC', $this->ccAddresses);
524
525
        $this->fillProperties('addBCC', $this->bccAddresses);
526
527
        $this->fillProperties('addAttachment', $this->attachments);
528
529
        $this->fillProperties('addStringAttachment', $this->stringAttachments);
530
    }
531
532
    /**
533
     * Files the php mailer properties
534
     * @param string $method
535
     * @param array $fields
536
     */
537
    private function fillProperties(string $method, array $fields = [])
538
    {
539
        if (!empty($fields)) {
540
            foreach ($fields as $field) {
541
                if (is_string($field)) {
542
                    $this->mailer->$method($field);
543
                } else {
544
                    $valOne = current($field);
545
                    next($field);
546
                    $valTwo = current($field);
547
                    $this->mailer->$method($valOne, $valTwo);
548
                    reset($field);
549
                }
550
            }
551
        }
552
    }
553
554
    /**
555
     * Setups SMTP
556
     */
557
    private function setupSmtp()
558
    {
559
        $this->mailer->isSMTP();
560
        $this->mailer->SMTPAuth = true;
561
        $this->mailer->Host = config()->get('mailer.default.mail_host');
562
        $this->mailer->SMTPSecure = config()->get('mailer.default.mail_secure');
563
        $this->mailer->Port = config()->get('mailer.default.mail_port');
564
        $this->mailer->Username = config()->get('mailer.default.mail_username');
565
        $this->mailer->Password = config()->get('mailer.default.mail_password');
566
    }
567
568
    /**
569
     * Setups the debugging
570
     */
571
    private function setupDebugging()
572
    {
573
        if (config()->get('debug')) {
574
            $this->mailer->SMTPDebug = SMTP::DEBUG_SERVER;
575
576
            $this->mailer->Debugoutput = function ($message) {
577
                Debugger::addToStore(Debugger::MAILS, LogLevel::WARNING, $message);
578
579
                $logFile = logs_dir() . DS . date('Y-m-d') . '.log';
580
                $logMessage = '[' . date('Y-m-d H:i:s') . '] ' . LogLevel::WARNING . ': ' . $message . PHP_EOL;
581
582
                warning($logMessage, new FileLogger($logFile));
583
            };
584
        } else {
585
            $this->mailer->SMTPDebug = SMTP::DEBUG_OFF;
586
        }
587
    }
588
589
    /**
590
     * Create message body from email template
591
     * @return string
592
     */
593
    private function createFromTemplate(): string
594
    {
595
        ob_start();
596
        ob_implicit_flush(0);
597
598
        if (!empty($this->message) && is_array($this->message)) {
599
            extract($this->message, EXTR_OVERWRITE);
600
        }
601
602
        require $this->templatePath . '.php';
603
604
        return ob_get_clean();
605
    }
606
}
607