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

Mailer::compose()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Mailer;
6
7
use Psr\EventDispatcher\EventDispatcherInterface;
8
use Throwable;
9
use Yiisoft\Mailer\Event\AfterSend;
10
use Yiisoft\Mailer\Event\BeforeSend;
11
12
/**
13
 * Mailer serves as a base class that implements the basic functions required by {@see MailerInterface}.
14
 *
15
 * Concrete child classes may focus on implementing the {@see Mailer::sendMessage()} method.
16
 */
17
abstract class Mailer implements MailerInterface
18
{
19
    private MessageFactoryInterface $messageFactory;
20
    private MessageBodyRenderer $messageBodyRenderer;
21
    private EventDispatcherInterface $eventDispatcher;
22
23 16
    public function __construct(
24
        MessageFactoryInterface $messageFactory,
25
        MessageBodyRenderer $messageBodyRenderer,
26
        EventDispatcherInterface $eventDispatcher
27
    ) {
28 16
        $this->messageFactory = $messageFactory;
29 16
        $this->messageBodyRenderer = $messageBodyRenderer;
30 16
        $this->eventDispatcher = $eventDispatcher;
31 16
    }
32
33
    /**
34
     * Creates a new message instance and optionally composes its body content via view rendering.
35
     *
36
     * @param array<string, string>|string|null $view The view to be used for rendering the message body.
37
     * This can be:
38
     * - a string, which represents the view name for rendering the HTML body of the email.
39
     *   In this case, the text body will be generated by applying `strip_tags()` to the HTML body.
40
     * - an array with 'html' and/or 'text' elements. The 'html' element refers to the view name
41
     *   for rendering the HTML body, while 'text' element is for rendering the text body. For example,
42
     *   `['html' => 'contact-html', 'text' => 'contact-text']`.
43
     * - null, meaning the message instance will be returned without body content.
44
     *
45
     * The view to be rendered can be specified in one of the following formats:
46
     * - a relative view name (e.g. "contact") located under {@see MessageBodyRenderer::$viewPath}.
47
     * @param array $parameters The parameters (name-value pairs) that will be extracted and available in the view file.
48
     *
49
     * @throws Throwable If an error occurred during rendering.
50
     *
51
     * @return MessageInterface The message instance.
52
     */
53 5
    public function compose($view = null, array $parameters = []): MessageInterface
54
    {
55 5
        $message = $this->createMessage();
56
57 5
        if ($view === null) {
58 4
            return $message;
59
        }
60
61 1
        return $this->messageBodyRenderer->addToMessage($message, $view, $parameters);
62
    }
63
64
    /**
65
     * Sends the given email message.
66
     * This method will log a message about the email being sent.
67
     * Child classes should implement [[sendMessage()]] with the actual email sending logic.
68
     *
69
     * @param MessageInterface $message email message instance to be sent
70
     *
71
     * @throws Throwable If sending failed.
72
     */
73 13
    public function send(MessageInterface $message): void
74
    {
75 13
        if (!$this->beforeSend($message)) {
76 1
            return;
77
        }
78
79 12
        $this->sendMessage($message);
80 6
        $this->afterSend($message);
81 6
    }
82
83
    /**
84
     * Sends multiple messages at once.
85
     *
86
     * The default implementation simply calls {@see Mailer::send()} multiple times.
87
     * Child classes may override this method to implement more efficient way of
88
     * sending multiple messages.
89
     *
90
     * @param MessageInterface[] $messages List of email messages, which should be sent.
91
     *
92
     * @return MessageInterface[] List of fails messages, the corresponding
93
     * error can be retrieved by {@see MessageInterface::getError()}.
94
     */
95 4
    public function sendMultiple(array $messages): array
96
    {
97 4
        $failed = [];
98
99 4
        foreach ($messages as $message) {
100
            try {
101 3
                $this->send($message);
102 1
            } catch (Throwable $e) {
103 1
                $failed[] = $message->withError($e);
104
            }
105
        }
106
107 4
        return $failed;
108
    }
109
110
    /**
111
     * Sends the specified message.
112
     *
113
     * This method should be implemented by child classes with the actual email sending logic.
114
     *
115
     * @param MessageInterface $message the message to be sent
116
     *
117
     * @throws Throwable If sending failed.
118
     */
119
    abstract protected function sendMessage(MessageInterface $message): void;
120
121
    /**
122
     * Creates a new message instance.
123
     *
124
     * @return MessageInterface The message instance.
125
     */
126 5
    protected function createMessage(): MessageInterface
127
    {
128 5
        return $this->messageFactory->create();
129
    }
130
131
    /**
132
     * This method is invoked right before mail send.
133
     *
134
     * You may override this method to do last-minute preparation for the message.
135
     * If you override this method, please make sure you call the parent implementation first.
136
     *
137
     * @param MessageInterface $message The message instance.
138
     *
139
     * @return bool Whether to continue sending an email.
140
     */
141 13
    protected function beforeSend(MessageInterface $message): bool
142
    {
143
        /** @var BeforeSend $event */
144 13
        $event = $this->eventDispatcher->dispatch(new BeforeSend($message));
145 13
        return !$event->isPropagationStopped();
146
    }
147
148
    /**
149
     * This method is invoked right after mail was send.
150
     *
151
     * You may override this method to do some postprocessing or logging based on mail send status.
152
     * If you override this method, please make sure you call the parent implementation first.
153
     *
154
     * @param MessageInterface $message
155
     */
156 6
    protected function afterSend(MessageInterface $message): void
157
    {
158 6
        $this->eventDispatcher->dispatch(new AfterSend($message));
159 6
    }
160
}
161