Failed Conditions
Push — master ( 4252f4...9d8e13 )
by Adrien
07:13
created

Mailer::modelMessageToMailMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 1
dl 0
loc 14
rs 9.9666
c 0
b 0
f 0
ccs 10
cts 10
cp 1
crap 1
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 3
    public function __construct(EntityManager $entityManager, TransportInterface $transport, RendererInterface $viewRenderer, string $hostname, ?string $emailOverride)
47
    {
48 3
        $this->entityManager = $entityManager;
49 3
        $this->transport = $transport;
50 3
        $this->hostname = $hostname;
51 3
        $this->emailOverride = $emailOverride;
52 3
        $this->viewRendered = $viewRenderer;
53 3
    }
54
55
    /**
56
     * Queue a reset password email to specified user
57
     *
58
     * @param User $user The user for which a password reset will be done
59
     * @param string $email the addresse to send the email to. Might be different than the user's email
60
     *
61
     * @return Message
62
     */
63 3
    public function queueResetPassword(User $user, string $email): Message
64
    {
65 3
        $user->createToken();
66
67 3
        $subject = 'Demande de modification de mot de passe';
68
        $mailParams = [
69 3
            'token' => $user->createToken(),
70
        ];
71
72 3
        $message = $this->createMessage($user, $email, $subject, MessageTypeType::RESET_PASSWORD, new ViewModel($mailParams));
73
74 3
        return $message;
75
    }
76
77
    /**
78
     * Create a message by rendering the template
79
     *
80
     * @param null|User $user
81
     * @param string $email
82
     * @param string $subject
83
     * @param string $type
84
     * @param ViewModel $model
85
     *
86
     * @return Message
87
     */
88 3
    private function createMessage(?User $user, string $email, string $subject, string $type, ViewModel $model): Message
89
    {
90
        // First render the view
91 3
        $serverUrl = 'https://' . $this->hostname;
92 3
        $model->setTemplate(str_replace('_', '-', $type));
93 3
        $model->setVariable('email', $email);
94 3
        $model->setVariable('user', $user);
95 3
        $model->setVariable('serverUrl', $serverUrl);
96 3
        $partialContent = $this->viewRendered->render($model);
97
98
        // Then inject it into layout
99 3
        $layoutModel = new ViewModel([$model->captureTo() => $partialContent]);
100 3
        $layoutModel->setTemplate('layout');
101 3
        $layoutModel->setVariable('subject', $subject);
102 3
        $layoutModel->setVariable('user', $user);
103 3
        $layoutModel->setVariable('serverUrl', $serverUrl);
104 3
        $layoutModel->setVariable('hostname', $this->hostname);
105 3
        $content = $this->viewRendered->render($layoutModel);
106
107 3
        $message = new Message();
108 3
        $message->setType($type);
109 3
        $message->setRecipient($user);
110 3
        $message->setSubject($subject);
111 3
        $message->setBody($content);
112 3
        $message->setEmail($email);
113 3
        $this->entityManager->persist($message);
114
115 3
        return $message;
116
    }
117
118
    /**
119
     * Send a message asynchronously in a separate process.
120
     *
121
     * This should be the preferred way to send a message, unless if we are the cron.
122
     *
123
     * @param Message $message
124
     */
125 2
    public function sendMessageAsync(Message $message): void
126
    {
127
        // Be sure we have an ID before "forking" process
128 2
        if ($message->getId() === null) {
0 ignored issues
show
introduced by
The condition $message->getId() === null is always false.
Loading history...
129 2
            _em()->flush();
130
        }
131
132 2
        $dispatcher = realpath('bin/send-message.php');
133 2
        $cmd = $dispatcher . ' ' . $message->getId() . ' > /dev/null 2>&1 &';
134 2
        exec($cmd);
135 2
    }
136
137
    /**
138
     * Send a message
139
     *
140
     * @param Message $message
141
     */
142 1
    public function sendMessage(Message $message): void
143
    {
144 1
        $mailMessage = $this->modelMessageToMailMessage($message);
145
146 1
        $email = $message->getEmail();
147 1
        $overriddenBy = '';
148 1
        if ($this->emailOverride) {
149 1
            $email = $this->emailOverride;
150 1
            $overriddenBy = ' overridden by ' . $email;
151
        }
152
153 1
        $recipientName = $message->getRecipient() ? $message->getRecipient()->getName() : null;
154 1
        if ($email) {
155 1
            $mailMessage->addTo($email, $recipientName);
156 1
            $this->transport->send($mailMessage);
157
        }
158
159 1
        $message->setDateSent(new Chronos());
160 1
        $this->entityManager->flush();
161
162 1
        echo 'email sent to: ' . $message->getEmail() . "\t" . $overriddenBy . "\t" . $message->getSubject() . PHP_EOL;
163 1
    }
164
165
    /**
166
     * Convert our model message to a mail message
167
     *
168
     * @param Message $message
169
     *
170
     * @return Mail\Message
171
     */
172 1
    private function modelMessageToMailMessage(Message $message): Mail\Message
173
    {
174
        // set Mime type html
175 1
        $htmlPart = new MimePart($message->getBody());
176 1
        $htmlPart->type = 'text/html';
177 1
        $body = new MimeMessage();
178 1
        $body->setParts([$htmlPart]);
179
180 1
        $message = new Mail\Message();
181 1
        $message->setSubject($message->getSubject());
182 1
        $message->setBody($body);
183 1
        $message->setFrom('noreply@' . $this->hostname, 'Ichtus');
184
185 1
        return $message;
186
    }
187
188
    /**
189
     * Send all messages that are not sent yet
190
     */
191
    public function sendAllMessages(): void
192
    {
193
        $messages = $this->entityManager->getRepository(Message::class)->getAllMessageToSend();
194
        foreach ($messages as $message) {
195
            $this->sendMessage($message);
196
        }
197
    }
198
}
199