Passed
Push — master ( 311548...93d467 )
by Evgeniy
02:02
created

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