Failed Conditions
Push — master ( b209ea...7f1a1e )
by Adrien
06:58
created

Mailer::sendMessage()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4.0466

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 8
nop 1
dl 0
loc 21
rs 9.8333
c 0
b 0
f 0
ccs 12
cts 14
cp 0.8571
crap 4.0466
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Service;
6
7
use Application\DBAL\Types\MessageTypeType;
8
use Application\Model\Message;
9
use Application\Model\User;
10
use Cake\Chronos\Chronos;
11
use Doctrine\ORM\EntityManager;
12
use Zend\Mail;
13
use Zend\Mail\Transport\TransportInterface;
14
use Zend\Mime\Message as MimeMessage;
15
use Zend\Mime\Part as MimePart;
16
use Zend\View\Model\ViewModel;
17
use Zend\View\Renderer\RendererInterface;
18
19
class Mailer
20
{
21
    /**
22
     * @var EntityManager
23
     */
24
    private $entityManager;
25
26
    /**
27
     * @var TransportInterface
28
     */
29
    private $transport;
30
31
    /**
32
     * @var string
33
     */
34
    private $hostname;
35
36
    /**
37
     * @var null|string
38
     */
39
    private $emailOverride;
40
41
    /**
42
     * @var RendererInterface
43
     */
44
    private $viewRendered;
45
46 5
    public function __construct(EntityManager $entityManager, TransportInterface $transport, RendererInterface $viewRenderer, string $hostname, ?string $emailOverride)
47
    {
48 5
        $this->entityManager = $entityManager;
49 5
        $this->transport = $transport;
50 5
        $this->hostname = $hostname;
51 5
        $this->emailOverride = $emailOverride;
52 5
        $this->viewRendered = $viewRenderer;
53 5
    }
54
55 2
    public function queueRegister(User $user): Message
56
    {
57 2
        $subject = 'Demande de création de compte Ichtus';
58
        $mailParams = [
59 2
            'token' => $user->createToken(),
60
        ];
61
62 2
        $message = $this->createMessage($user, $user->getEmail(), $subject, MessageTypeType::REGISTER, $mailParams);
0 ignored issues
show
Bug introduced by
It seems like $user->getEmail() can also be of type null; however, parameter $email of Application\Service\Mailer::createMessage() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

62
        $message = $this->createMessage($user, /** @scrutinizer ignore-type */ $user->getEmail(), $subject, MessageTypeType::REGISTER, $mailParams);
Loading history...
63
64 2
        return $message;
65
    }
66
67 2
    public function queueUnregister(User $admin, User $unregisteredUser): Message
68
    {
69 2
        $subject = 'Démission';
70
        $mailParams = [
71 2
            'unregisteredUser' => $unregisteredUser,
72
        ];
73
74 2
        $message = $this->createMessage($admin, $admin->getEmail(), $subject, MessageTypeType::UNREGISTER, $mailParams);
0 ignored issues
show
Bug introduced by
It seems like $admin->getEmail() can also be of type null; however, parameter $email of Application\Service\Mailer::createMessage() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

74
        $message = $this->createMessage($admin, /** @scrutinizer ignore-type */ $admin->getEmail(), $subject, MessageTypeType::UNREGISTER, $mailParams);
Loading history...
75
76 2
        return $message;
77
    }
78
79
    /**
80
     * Queue a reset password email to specified user
81
     *
82
     * @param User $user The user for which a password reset will be done
83
     * @param string $email the addresse to send the email to. Might be different than the user's email
84
     *
85
     * @return Message
86
     */
87 3
    public function queueResetPassword(User $user, string $email): Message
88
    {
89 3
        $subject = 'Demande de modification de mot de passe';
90
        $mailParams = [
91 3
            'token' => $user->createToken(),
92
        ];
93
94 3
        $message = $this->createMessage($user, $email, $subject, MessageTypeType::RESET_PASSWORD, $mailParams);
95
96 3
        return $message;
97
    }
98
99
    /**
100
     * Create a message by rendering the template
101
     *
102
     * @param null|User $user
103
     * @param string $email
104
     * @param string $subject
105
     * @param string $type
106
     * @param array $mailParams
107
     *
108
     * @return Message
109
     */
110 7
    private function createMessage(?User $user, string $email, string $subject, string $type, array $mailParams): Message
111
    {
112
113
        // First render the view
114 7
        $serverUrl = 'https://' . $this->hostname;
115 7
        $model = new ViewModel($mailParams);
116 7
        $model->setTemplate(str_replace('_', '-', $type));
117 7
        $model->setVariable('email', $email);
118 7
        $model->setVariable('user', $user);
119 7
        $model->setVariable('serverUrl', $serverUrl);
120 7
        $partialContent = $this->viewRendered->render($model);
121
122
        // Then inject it into layout
123 7
        $layoutModel = new ViewModel([$model->captureTo() => $partialContent]);
124 7
        $layoutModel->setTemplate('layout');
125 7
        $layoutModel->setVariable('subject', $subject);
126 7
        $layoutModel->setVariable('user', $user);
127 7
        $layoutModel->setVariable('serverUrl', $serverUrl);
128 7
        $layoutModel->setVariable('hostname', $this->hostname);
129 7
        $content = $this->viewRendered->render($layoutModel);
130
131 7
        $message = new Message();
132 7
        $message->setType($type);
133 7
        $message->setRecipient($user);
134 7
        $message->setSubject($subject);
135 7
        $message->setBody($content);
136 7
        $message->setEmail($email);
137 7
        $this->entityManager->persist($message);
138
139 7
        return $message;
140
    }
141
142
    /**
143
     * Send a message asynchronously in a separate process.
144
     *
145
     * This should be the preferred way to send a message, unless if we are the cron.
146
     *
147
     * @param Message $message
148
     */
149 4
    public function sendMessageAsync(Message $message): void
150
    {
151
        // Be sure we have an ID before "forking" process
152 4
        if ($message->getId() === null) {
0 ignored issues
show
introduced by
The condition $message->getId() === null is always false.
Loading history...
153 4
            _em()->flush();
154
        }
155
156 4
        $dispatcher = realpath('bin/send-message.php');
157 4
        $cmd = $dispatcher . ' ' . $message->getId() . ' > /dev/null 2>&1 &';
158 4
        exec($cmd);
159 4
    }
160
161
    /**
162
     * Send a message
163
     *
164
     * @param Message $message
165
     */
166 1
    public function sendMessage(Message $message): void
167
    {
168 1
        $mailMessage = $this->modelMessageToMailMessage($message);
169
170 1
        $email = $message->getEmail();
171 1
        $overriddenBy = '';
172 1
        if ($this->emailOverride) {
173
            $email = $this->emailOverride;
174
            $overriddenBy = ' overridden by ' . $email;
175
        }
176
177 1
        $recipientName = $message->getRecipient() ? $message->getRecipient()->getName() : null;
178 1
        if ($email) {
179 1
            $mailMessage->addTo($email, $recipientName);
180 1
            $this->transport->send($mailMessage);
181
        }
182
183 1
        $message->setDateSent(new Chronos());
184 1
        $this->entityManager->flush();
185
186 1
        echo 'email sent to: ' . $message->getEmail() . "\t" . $overriddenBy . "\t" . $message->getSubject() . PHP_EOL;
187 1
    }
188
189
    /**
190
     * Convert our model message to a mail message
191
     *
192
     * @param Message $message
193
     *
194
     * @return Mail\Message
195
     */
196 1
    private function modelMessageToMailMessage(Message $message): Mail\Message
197
    {
198
        // set Mime type html
199 1
        $htmlPart = new MimePart($message->getBody());
200 1
        $htmlPart->type = 'text/html';
201 1
        $body = new MimeMessage();
202 1
        $body->setParts([$htmlPart]);
203
204 1
        $message = new Mail\Message();
205 1
        $message->setSubject($message->getSubject());
206 1
        $message->setBody($body);
207 1
        $message->setFrom('noreply@' . $this->hostname, 'Ichtus');
208
209 1
        return $message;
210
    }
211
212
    /**
213
     * Send all messages that are not sent yet
214
     */
215
    public function sendAllMessages(): void
216
    {
217
        $messages = $this->entityManager->getRepository(Message::class)->getAllMessageToSend();
218
        foreach ($messages as $message) {
219
            $this->sendMessage($message);
220
        }
221
    }
222
}
223