Passed
Pull Request — master (#24)
by Evgeniy
02:22
created

FileMailer::sendMessage()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4.074

Importance

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