FileMailer   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 71
Duplicated Lines 0 %

Test Coverage

Coverage 92.86%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 15
dl 0
loc 71
c 2
b 1
f 0
ccs 13
cts 14
cp 0.9286
rs 10
wmc 8

3 Methods

Rating   Name   Duplication   Size   Complexity  
A generateMessageFilename() 0 14 3
A sendMessage() 0 10 4
A __construct() 0 9 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Mailer;
6
7
use Exception;
8
use Psr\EventDispatcher\EventDispatcherInterface;
9
use RuntimeException;
10
11
use function date;
12
use function dirname;
13
use function file_put_contents;
14
use function gettype;
15
use function is_dir;
16
use function is_string;
17
use function microtime;
18
use function mkdir;
19
use function random_int;
20
use function sprintf;
21
22
/**
23
 * `FileMailer` is a mock mailer that save email messages in files instead of sending them.
24
 */
25
final class FileMailer extends Mailer
26
{
27
    /**
28
     * @var callable|null A PHP callback that return a file name which will be used to save the email message.
29
     *
30
     * If not set, the file name will be generated based on the current
31
     * timestamp {@see FileMailer::generateMessageFilename()}.
32
     *
33
     * The signature of the callback is:
34
     *
35
     * ```php
36
     * function (MessageInterface $message): string;
37
     * ```
38
     */
39
    private $filenameCallback;
40
41
    /**
42
     * @param MessageFactoryInterface $messageFactory The message factory instance.
43
     * @param MessageBodyRenderer $messageBodyRenderer The message body renderer instance.
44
     * @param EventDispatcherInterface $eventDispatcher The event dispatcher instance.
45
     * @param string $path The path where message files located.
46
     * @param callable|null $filenameCallback A PHP callback that return a file name which will be used to save
47
     * the email message.
48
     */
49
    public function __construct(
50
        MessageFactoryInterface $messageFactory,
51
        MessageBodyRenderer $messageBodyRenderer,
52
        EventDispatcherInterface $eventDispatcher,
53
        private string $path,
54
        callable $filenameCallback = null
55
    ) {
56 9
        parent::__construct($messageFactory, $messageBodyRenderer, $eventDispatcher);
57
        $this->filenameCallback = $filenameCallback;
58
    }
59
60
    protected function sendMessage(MessageInterface $message): void
61
    {
62
        $filename = $this->path . DIRECTORY_SEPARATOR . $this->generateMessageFilename($message);
63 9
        $filepath = dirname($filename);
64 9
65 9
        if (!is_dir($filepath) && !mkdir($filepath, 0777, true) && !is_dir($filepath)) {
66
            throw new RuntimeException(sprintf('Directory "%s" was not created.', $filepath));
67
        }
68 9
69
        file_put_contents($filename, $message->__toString());
70 9
    }
71 3
72
    /**
73 3
     * Generates a filename based on the current timestamp.
74
     *
75
     * @param MessageInterface $message The message instance.
76
     *
77 3
     * @throws Exception {@see https://www.php.net/manual/en/function.random-int.php}
78
     * @throws RuntimeException If {@see FileMailer::$filenameCallback} does not return a string.
79
     *
80
     * @return string The filename for saving the message.
81
     */
82
    private function generateMessageFilename(MessageInterface $message): string
83
    {
84
        if ($this->filenameCallback === null) {
85
            $time = (int) microtime(true);
86
            return date('Ymd-His-', $time) . sprintf('%04d', $time) . '-' . sprintf('%04d', random_int(0, 10000)) . '.eml';
87
        }
88
89
        $filename = ($this->filenameCallback)($message);
90 9
91
        if (!is_string($filename)) {
92 9
            throw new RuntimeException(sprintf('Filename must be a string. "%s" received.', gettype($filename)));
93 1
        }
94 1
95
        return $filename;
96
    }
97
}
98