Passed
Pull Request — master (#24)
by Alexander
02:20
created

FileMailer   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Test Coverage

Coverage 95%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 17
c 2
b 1
f 0
dl 0
loc 79
ccs 19
cts 20
cp 0.95
rs 10
wmc 8

3 Methods

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