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

Mailer::createMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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