Passed
Push — master ( 4fb9b2...704ca7 )
by Evgeniy
03:08
created

Mailer::withMessageFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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