MailService   B
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 236
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Test Coverage

Coverage 96.91%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 18
dl 0
loc 236
c 0
b 0
f 0
rs 7.3333
ccs 94
cts 97
cp 0.9691

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A initEventManager() 0 9 2
B send() 0 40 6
A createMailEvent() 0 12 2
A createMessageFromEmail() 0 9 2
A buildBody() 0 16 4
B attachFiles() 0 34 6
A getEventManager() 0 4 1
A attachMailListener() 0 4 1
A detachMailListener() 0 4 1
1
<?php
2
declare(strict_types=1);
3
4
namespace AcMailer\Service;
5
6
use AcMailer\Attachment\AttachmentParserManagerInterface;
7
use AcMailer\Attachment\Parser\AttachmentParserInterface;
8
use AcMailer\Event\MailEvent;
9
use AcMailer\Event\MailListenerAwareInterface;
10
use AcMailer\Event\MailListenerInterface;
11
use AcMailer\Exception;
12
use AcMailer\Mail\MessageFactory;
13
use AcMailer\Model\Email;
14
use AcMailer\Model\EmailBuilderInterface;
15
use AcMailer\Result\MailResult;
16
use AcMailer\Result\ResultInterface;
17
use Psr\Container\ContainerExceptionInterface;
18
use Psr\Container\NotFoundExceptionInterface;
19
use Zend\EventManager\EventManager;
20
use Zend\EventManager\EventManagerInterface;
21
use Zend\EventManager\EventsCapableInterface;
22
use Zend\EventManager\SharedEventManager;
23
use Zend\Expressive\Template\TemplateRendererInterface;
24
use Zend\Mail\Exception\InvalidArgumentException;
25
use Zend\Mail\Message;
26
use Zend\Mail\Transport\TransportInterface;
27
use Zend\Mime;
28
29
/**
30
 * Wraps Zend\Mail functionality
31
 * @author Alejandro Celaya Alastrué
32
 * @link http://www.alejandrocelaya.com
33
 */
34
class MailService implements MailServiceInterface, EventsCapableInterface, MailListenerAwareInterface
35
{
36
    /**
37
     * @var TransportInterface
38
     */
39
    private $transport;
40
    /**
41
     * @var TemplateRendererInterface
42
     */
43
    private $renderer;
44
    /**
45
     * @var EventManagerInterface
46
     */
47
    private $events;
48
    /**
49
     * @var EmailBuilderInterface
50
     */
51
    private $emailBuilder;
52
    /**
53
     * @var AttachmentParserManagerInterface
54
     */
55
    private $attachmentParserManager;
56
57
    /**
58
     * Creates a new MailService
59
     * @param TransportInterface $transport
60
     * @param TemplateRendererInterface $renderer
61 33
     * @param EmailBuilderInterface $emailBuilder
62
     * @param AttachmentParserManagerInterface $attachmentParserManager
63 33
     * @param EventManagerInterface|null $events
64 33
     */
65 33
    public function __construct(
66 33
        TransportInterface $transport,
67 33
        TemplateRendererInterface $renderer,
68
        EmailBuilderInterface $emailBuilder,
69
        AttachmentParserManagerInterface $attachmentParserManager,
70
        EventManagerInterface $events = null
71
    ) {
72
        $this->transport = $transport;
73
        $this->renderer = $renderer;
74 13
        $this->emailBuilder = $emailBuilder;
75
        $this->attachmentParserManager = $attachmentParserManager;
76 13
        $this->events = $this->initEventManager($events);
77
    }
78
79
    private function initEventManager(EventManagerInterface $events = null): EventManagerInterface
80
    {
81
        $events = $events ?: new EventManager(new SharedEventManager());
82
        $events->setIdentifiers([
83
            __CLASS__,
84 9
            static::class,
85
        ]);
86 9
        return $events;
87
    }
88
89 9
    /**
90
     * Tries to send the message, returning a MailResult object
91
     * @param string|array|Email $email
92 9
     * @param array $options
93
     * @return ResultInterface
94
     * @throws NotFoundExceptionInterface
95 9
     * @throws ContainerExceptionInterface
96
     * @throws Exception\InvalidArgumentException
97
     * @throws Exception\EmailNotFoundException
98 5
     * @throws Exception\MailException
99 9
     */
100 4
    public function send($email, array $options = []): ResultInterface
101
    {
102 4
        // Try to resolve the email to be sent
103
        if (\is_string($email)) {
104
            $email = $this->emailBuilder->build($email, $options);
105 4
        } elseif (\is_array($email)) {
106 1
            $email = $this->emailBuilder->build(Email::class, $email);
107
        } elseif (! $email instanceof Email) {
108
            throw Exception\InvalidArgumentException::fromValidTypes(['string', 'array', Email::class], $email);
109
        }
110 8
111
        // Trigger pre send event, an cancel email sending if any listener returned false
112
        $eventResp = $this->events->triggerEvent($this->createMailEvent($email));
113
        if ($eventResp->contains(false)) {
114
            return new MailResult($email, false);
115
        }
116
117
        try {
118
            // Build the message object to send
119 9
            $message = $this->createMessageFromEmail($email);
120
            $this->attachFiles($message, $email);
121 9
122 9
            // Try to send the message
123 9
            $this->transport->send($message);
124 9
125 9
            // Trigger post send event
126
            $result = new MailResult($email);
127
            $this->events->triggerEvent($this->createMailEvent($email, MailEvent::EVENT_MAIL_POST_SEND, $result));
128
            return $result;
129
        } catch (\Throwable $e) {
130
            // Trigger error event, notifying listeners of the error
131
            $this->events->triggerEvent($this->createMailEvent($email, MailEvent::EVENT_MAIL_SEND_ERROR, new MailResult(
132
                $email,
133 4
                false,
134
                $e
135 4
            )));
136
137
            throw new Exception\MailException('An error occurred while trying to send the email', $e->getCode(), $e);
138
        }
139
    }
140
141
    /**
142
     * Creates a new MailEvent object
143
     * @param Email $email
144
     * @param string $name
145
     * @param ResultInterface $result
146 21
     * @return MailEvent
147
     */
148 21
    private function createMailEvent(
149
        Email $email,
150 17
        $name = MailEvent::EVENT_MAIL_PRE_SEND,
151 17
        ResultInterface $result = null
152 17
    ): MailEvent {
153 17
        $event = new MailEvent($email, $name);
154 17
        if ($result !== null) {
155 21
            $event->setResult($result);
156
        }
157 2
158 1
        return $event;
159 1
    }
160
161 2
    private function createMessageFromEmail(Email $email): Message
162 2
    {
163 2
        $message = MessageFactory::createMessageFromEmail($email);
164 2
        $rawBody = $email->hasTemplate()
165
            ? $this->renderer->render($email->getTemplate(), $email->getTemplateParams())
166
            : $email->getBody();
167 21
168 1
        return $message->setBody($this->buildBody($rawBody, $email->getCharset()));
169 1
    }
170 1
171 1
    /**
172 1
     * Sets the message body
173
     * @param string|Mime\Part|Mime\Message $body
174
     * @param string $charset
175
     * @return Mime\Message
176
     * @throws Mime\Exception\InvalidArgumentException
177 20
     */
178 20
    private function buildBody($body, string $charset): Mime\Message
179 20
    {
180 20
        if ($body instanceof Mime\Message) {
181
            return $body;
182
        }
183
184
        // If the body is a string, wrap it into a Mime\Part
185
        if (\is_string($body)) {
186
            $mimePart = new Mime\Part($body);
187
            $mimePart->type = $body !== \strip_tags($body) ? Mime\Mime::TYPE_HTML : Mime\Mime::TYPE_TEXT;
188
            $body = $mimePart;
189 5
        }
190
191 5
        $body->charset = $charset;
192 2
        return (new Mime\Message())->setParts([$body]);
193 2
    }
194 3
195 3
    /**
196 3
     * Attaches files to the message if any
197
     * @param Message $message
198
     * @param Email $email
199
     * @throws Exception\InvalidAttachmentException
200 5
     * @throws NotFoundExceptionInterface
201 2
     * @throws ContainerExceptionInterface
202 2
     * @throws InvalidArgumentException
203 2
     */
204 2
    private function attachFiles(Message $message, Email $email)
205
    {
206 5
        if (! $email->hasAttachments()) {
207
            return;
208 5
        }
209 5
        $attachments = $email->getComputedAttachments();
210 4
211
        // Get old message parts
212
        /** @var Mime\Message $mimeMessage */
213
        $mimeMessage = $message->getBody();
214
        $oldParts = $mimeMessage->getParts();
215
216
        // Generate a new Mime\Part for each attachment
217
        $attachmentParts = [];
218 33
        $info = null;
0 ignored issues
show
Unused Code introduced by
$info is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
219
        foreach ($attachments as $key => $attachment) {
220 33
            $parserName = \is_object($attachment) ? \get_class($attachment) : \gettype($attachment);
221 33
            if (! $this->attachmentParserManager->has($parserName)) {
222
                continue;
223
            }
224
225
            /** @var AttachmentParserInterface $parser */
226
            $parser = $this->attachmentParserManager->get($parserName);
227
            $part = $parser->parse($attachment, \is_string($key) ? $key : null);
228
229 5
            $part->charset = $email->getCharset();
230
            $attachmentParts[] = $part;
231 5
        }
232 5
233
        // Create a new body for the message, merging the attachment parts and all the old parts
234
        $body = new Mime\Message();
235
        $body->setParts(\array_merge($oldParts, $attachmentParts));
236 3
        $message->setBody($body);
237 3
    }
238 3
239
    /**
240 3
     * Retrieve the event manager
241 3
     * Lazy-loads an EventManager instance if none registered.
242
     * @return EventManagerInterface
243 3
     */
244
    public function getEventManager(): EventManagerInterface
245
    {
246
        return $this->events;
247 3
    }
248
249 3
    /**
250 3
     * Attaches a new MailListenerInterface
251 3
     * @param MailListenerInterface $mailListener
252
     * @param int $priority
253
     * @return void
254
     */
255
    public function attachMailListener(MailListenerInterface $mailListener, $priority = 1)
256 9
    {
257
        $mailListener->attach($this->events, $priority);
258 9
    }
259 7
260
    /**
261
     * Detaches provided MailListener
262
     * @param MailListenerInterface $mailListener
263 2
     * @return void
264 2
     */
265 1
    public function detachMailListener(MailListenerInterface $mailListener)
266 1
    {
267 1
        $mailListener->detach($this->events);
268 1
    }
269
}
270