Passed
Pull Request — master (#128)
by
unknown
03:15
created

Mailer::getReplays()   A

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

386
            $this->setFrom(/** @scrutinizer ignore-type */ ...$from);
Loading history...
387
        }
388
389
        if ($address) {
390
            $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

390
            $this->setAddress(/** @scrutinizer ignore-type */ ...$address);
Loading history...
391
        }
392
393
        if ($message) {
394
            $this->setBody($message);
395
        }
396
397
        $this->setOptions($options);
398
399
        if (config()->get('mailer.current') == 'smtp') {
400
            $this->prepare();
401
402
            if (config()->get('mailer.mail_trap')) {
403
                $sent = $this->mailer->preSend();
404
                $this->saveMessage($this->mailer->getLastMessageID(), $this->mailer->getSentMIMEMessage());
405
                return $sent;
406
            } else {
407
                return $this->mailer->send();
408
            }
409
        } else if (config()->get('mailer.current') == 'sendinblue') {
410
            if ($this->message) {
411
                if ($this->templatePath) {
412
                    $body = $this->createFromTemplate();
413
                } else {
414
                    $body = is_array($this->message) ? implode($this->message) : $this->message;
415
                }
416
417
                $this->htmlContent = $body;
418
            }
419
420
            $data = '{  
421
                "sender":' . json_encode($this->from) . ',
422
                "to":' . json_encode($this->addresses) . ',
423
                "subject":"' . $this->subject . '",
424
                "htmlContent":"' . trim(str_replace("\n", "", $this->htmlContent)) . '"
425
                }';
426
427
            return $this->mailerAdapter->sendMail($data);
428
        }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 409 is false. This is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
429
    }
430
431
    /**
432
     * Save the message on local file
433
     * @param string $id
434
     * @param string $content
435
     * @throws \Quantum\Exceptions\DiException
436
     * @throws \ReflectionException
437
     */
438
    private function saveMessage(string $id, string $content)
439
    {
440
        $fs = Di::get(FileSystem::class);
441
442
        $emailsDirectory = base_dir() . DS . 'shared' . DS . 'emails';
443
444
        if ($fs->isDirectory($emailsDirectory)) {
445
            $fs->put($emailsDirectory . DS . $this->getFilename($id), $content);
446
        }
447
    }
448
449
    /**
450
     * Sets the options
451
     * @param array $options
452
     */
453
    private function setOptions(array $options)
454
    {
455
        foreach ($options as $name => $params) {
456
            if (method_exists(__CLASS__, $method = 'set' . ucfirst($name))) {
457
                if (is_array($params)) {
458
                    $this->$method(...$params);
459
                } else {
460
                    $this->$method($params);
461
                }
462
            }
463
        }
464
    }
465
466
    /**
467
     * Fetches message ID
468
     * @param string $lastMessageId
469
     * @return string
470
     */
471
    private function getFilename(string $lastMessageId): string
472
    {
473
        preg_match('/<(.*?)@/', $lastMessageId, $matches);
474
        return $matches[1] . '.eml';
475
    }
476
477
    /**
478
     * Prepares the data
479
     * @throws \PHPMailer\PHPMailer\Exception
480
     */
481
    private function prepare()
482
    {
483
        $this->mailer->setFrom($this->from['email'], $this->from['name']);
484
485
        if ($this->subject) {
486
            $this->mailer->Subject = $this->subject;
487
        }
488
489
        if ($this->message) {
490
            if ($this->templatePath) {
491
                $body = $this->createFromTemplate();
492
            } else {
493
                $body = is_array($this->message) ? implode($this->message) : $this->message;
494
            }
495
496
            $this->mailer->Body = $body;
497
        }
498
499
        $this->fillProperties('addAddress', $this->addresses);
500
501
        $this->fillProperties('addReplyTo', $this->replyToAddresses);
502
503
        $this->fillProperties('addCC', $this->ccAddresses);
504
505
        $this->fillProperties('addBCC', $this->bccAddresses);
506
507
        $this->fillProperties('addAttachment', $this->attachments);
508
509
        $this->fillProperties('addStringAttachment', $this->stringAttachments);
510
    }
511
512
    /**
513
     * Files the php mailer properties
514
     * @param string $method
515
     * @param array $fields
516
     */
517
    private function fillProperties(string $method, array $fields = [])
518
    {
519
        if (!empty($fields)) {
520
            foreach ($fields as $field) {
521
                if (is_string($field)) {
522
                    $this->mailer->$method($field);
523
                } else {
524
                    $valOne = current($field);
525
                    next($field);
526
                    $valTwo = current($field);
527
                    $this->mailer->$method($valOne, $valTwo);
528
                    reset($field);
529
                }
530
            }
531
        }
532
    }
533
534
    /**
535
     * Setups SMTP
536
     */
537
    private function setupSmtp()
538
    {
539
        $this->mailer->isSMTP();
540
        $this->mailer->SMTPAuth = true;
541
        $this->mailer->Host = config()->get('mailer.default.mail_host');
542
        $this->mailer->SMTPSecure = config()->get('mailer.default.mail_secure');
543
        $this->mailer->Port = config()->get('mailer.default.mail_port');
544
        $this->mailer->Username = config()->get('mailer.default.mail_username');
545
        $this->mailer->Password = config()->get('mailer.default.mail_password');
546
    }
547
548
    /**
549
     * Setups the debugging
550
     */
551
    private function setupDebugging()
552
    {
553
        if (config()->get('debug')) {
554
            $this->mailer->SMTPDebug = SMTP::DEBUG_SERVER;
555
556
            $this->mailer->Debugoutput = function ($message) {
557
                Debugger::addToStore(Debugger::MAILS, LogLevel::WARNING, $message);
558
559
                $logFile = logs_dir() . DS . date('Y-m-d') . '.log';
560
                $logMessage = '[' . date('Y-m-d H:i:s') . '] ' . LogLevel::WARNING . ': ' . $message . PHP_EOL;
561
562
                warning($logMessage, new FileLogger($logFile));
563
            };
564
        } else {
565
            $this->mailer->SMTPDebug = SMTP::DEBUG_OFF;
566
        }
567
    }
568
569
    /**
570
     * Create message body from email template
571
     * @return string
572
     */
573
    private function createFromTemplate(): string
574
    {
575
        ob_start();
576
        ob_implicit_flush(0);
577
578
        if (!empty($this->message) && is_array($this->message)) {
579
            extract($this->message, EXTR_OVERWRITE);
580
        }
581
582
        require $this->templatePath . '.php';
583
584
        return ob_get_clean();
585
    }
586
}
587