Passed
Pull Request — master (#42)
by Arman
03:27
created

Mailer::send()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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

363
            $this->setFrom(/** @scrutinizer ignore-type */ ...$from);
Loading history...
364
        }
365
366
        if ($address) {
367
            $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

367
            $this->setAddress(/** @scrutinizer ignore-type */ ...$address);
Loading history...
368
        }
369
370
        if ($message) {
371
            $this->setBody($message);
372
        }
373
374
        $this->setOptions($options);
375
376
        $this->prepare();
377
378
        if (config()->has('mail_trap')) {
379
            $sent = $this->mailer->preSend();
380
            $this->saveMessage($this->mailer->getLastMessageID(), $this->mailer->getSentMIMEMessage());
381
            return $sent;
382
        } else {
383
            return $this->mailer->send();
384
        }
385
    }
386
387
    /**
388
     * Save the message on local file
389
     * @param string $id
390
     * @param string $content
391
     * @throws \Quantum\Exceptions\DiException
392
     * @throws \ReflectionException
393
     */
394
    private function saveMessage(string $id, string $content)
395
    {
396
        $fs = Di::get(FileSystem::class);
397
398
        $emailsDirectory = base_dir() . DS . 'base' . DS . 'emails';
399
400
        if ($fs->isDirectory($emailsDirectory)) {
401
            $fs->put($emailsDirectory . DS . $this->getFilename($id), $content);
402
        }
403
    }
404
405
    /**
406
     * Sets the options
407
     * @param array $options
408
     */
409
    private function setOptions(array $options)
410
    {
411
        foreach ($options as $name => $params) {
412
            if (method_exists(__CLASS__, $method = 'set' . ucfirst($name))) {
413
                if (is_array($params)) {
414
                    $this->$method(...$params);
415
                } else {
416
                    $this->$method($params);
417
                }
418
            }
419
        }
420
    }
421
422
    /**
423
     * Fetches message ID
424
     * @param string $lastMessageId
425
     * @return string
426
     */
427
    private function getFilename(string $lastMessageId): string
428
    {
429
        preg_match('/<(.*?)@/', $lastMessageId, $matches);
430
        return $matches[1] . '.eml';
431
    }
432
433
    /**
434
     * Prepares the data
435
     * @throws \PHPMailer\PHPMailer\Exception
436
     */
437
    private function prepare()
438
    {
439
        $this->mailer->setFrom($this->from['email'], $this->from['name']);
440
441
        if ($this->subject) {
442
            $this->mailer->Subject = $this->subject;
443
        }
444
445
        if ($this->message) {
446
            if ($this->templatePath) {
447
                $body = $this->createFromTemplate();
448
            } else {
449
                $body = is_array($this->message) ? implode($this->message) : $this->message;
450
            }
451
452
            $this->mailer->Body = $body;
453
        }
454
455
        $this->fillProperties('addAddress', $this->addresses);
456
457
        $this->fillProperties('addReplyTo', $this->replyToAddresses);
458
459
        $this->fillProperties('addCC', $this->ccAddresses);
460
461
        $this->fillProperties('addBCC', $this->bccAddresses);
462
463
        $this->fillProperties('addAttachment', $this->attachments);
464
465
        $this->fillProperties('addStringAttachment', $this->stringAttachments);
466
    }
467
468
    /**
469
     * Files the php mailer properties
470
     * @param string $method
471
     * @param array $fields
472
     */
473
    private function fillProperties(string $method, array $fields = [])
474
    {
475
        if (!empty($fields)) {
476
            foreach ($fields as $field) {
477
                if (is_string($field)) {
478
                    $this->mailer->$method($field);
479
                } else {
480
                    $valOne = current($field);
481
                    next($field);
482
                    $valTwo = current($field);
483
                    $this->mailer->$method($valOne, $valTwo);
484
                    reset($field);
485
                }
486
            }
487
        }
488
    }
489
490
    /**
491
     * Setups SMTP
492
     */
493
    private function setupSmtp()
494
    {
495
        $this->mailer->isSMTP();
496
        $this->mailer->SMTPAuth = true;
497
        $this->mailer->Host = config()->get('mail_host');
498
        $this->mailer->SMTPSecure = config()->get('mail_secure');
499
        $this->mailer->Port = config()->get('mail_port');
500
        $this->mailer->Username = config()->get('mail_username');
501
        $this->mailer->Password = config()->get('mail_password');
502
    }
503
504
    /**
505
     * Setups the debugging
506
     */
507
    private function setupDebugging()
508
    {
509
        if (config()->has('debug')) {
510
            $this->mailer->SMTPDebug = 1;
511
            $this->mailer->Debugoutput = function ($str, $level) {
512
                $this->log .= $str . '&';
513
                session()->set('_qt_mailer_log', $this->log);
514
            };
515
        } else {
516
            $this->mailer->SMTPDebug = 0;
517
        }
518
    }
519
520
    /**
521
     * Create message body from email template
522
     * @return string
523
     */
524
    private function createFromTemplate(): string
525
    {
526
        ob_start();
527
        ob_implicit_flush(0);
528
529
        if (!empty($this->message) && is_array($this->message)) {
530
            extract($this->message, EXTR_OVERWRITE);
531
        }
532
533
        require $this->templatePath . '.php';
534
535
        return ob_get_clean();
536
    }
537
538
}
539