Test Failed
Pull Request — master (#24)
by Evgeniy
07:58
created

Mailer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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