Passed
Push — feature/unit-tests ( 632e05...3f6f78 )
by Daniel
06:05
created

UserMailer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 22
ccs 11
cts 11
cp 1
rs 9.9332
nc 1
nop 10
cc 1
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/*
4
 * This file is part of the Silverback API Component Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentBundle\Mailer;
15
16
use Silverback\ApiComponentBundle\Entity\User\AbstractUser;
17
use Silverback\ApiComponentBundle\Exception\InvalidArgumentException;
18
use Silverback\ApiComponentBundle\Exception\MailerTransportException;
19
use Silverback\ApiComponentBundle\Url\RefererUrlHelper;
20
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
21
use Symfony\Component\HttpFoundation\RequestStack;
22
use Symfony\Component\Mailer\Envelope;
23
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
24
use Symfony\Component\Mailer\MailerInterface;
25
use Symfony\Component\Mime\Address;
26
use Symfony\Component\Mime\RawMessage;
27
28
/**
29
 * @author Daniel West <[email protected]>
30
 */
31
class UserMailer
32
{
33
    private MailerInterface $mailer;
34
    private RefererUrlHelper $refererUrlHelper;
35
    private RequestStack $requestStack;
36
    private string $websiteName;
37
    private string $defaultPasswordResetPath;
38
    private string $defaultChangeEmailVerifyPath;
39
    private bool $sendUserWelcomeEmailEnabled;
40
    private bool $sendUserEnabledEmailEnabled;
41
    private bool $sendUserUsernameChangedEmailEnabled;
42
    private bool $sendUserPasswordChangedEmailEnabled;
43
44 5
    public function __construct(
45
        MailerInterface $mailer,
46
        RefererUrlHelper $refererUrlHelper,
47
        RequestStack $requestStack,
48
        string $websiteName,
49
        string $defaultPasswordResetPath,
50
        string $defaultChangeEmailVerifyPath,
51
        bool $sendUserWelcomeEmailEnabled = true,
52
        bool $sendUserEnabledEmailEnabled = true,
53
        bool $sendUserUsernameChangedEmailEnabled = true,
54
        bool $sendUserPasswordChangedEmailEnabled = true
55
    ) {
56 5
        $this->mailer = $mailer;
57 5
        $this->refererUrlHelper = $refererUrlHelper;
58 5
        $this->requestStack = $requestStack;
59 5
        $this->defaultPasswordResetPath = $defaultPasswordResetPath;
60 5
        $this->defaultChangeEmailVerifyPath = $defaultChangeEmailVerifyPath;
61 5
        $this->websiteName = $websiteName;
62 5
        $this->sendUserWelcomeEmailEnabled = $sendUserWelcomeEmailEnabled;
63 5
        $this->sendUserEnabledEmailEnabled = $sendUserEnabledEmailEnabled;
64 5
        $this->sendUserUsernameChangedEmailEnabled = $sendUserUsernameChangedEmailEnabled;
65 5
        $this->sendUserPasswordChangedEmailEnabled = $sendUserPasswordChangedEmailEnabled;
66 5
    }
67
68
    public function sendPasswordResetEmail(AbstractUser $user): void
69
    {
70
        $userUsername = $this->getUserUsername($user);
71
        $token = $user->getNewPasswordConfirmationToken();
72
        if (!$token) {
73
            throw new InvalidArgumentException('A new password confirmation token must be set to send the `password reset` email');
74
        }
75
        $resetUrl = $this->pathToReferrerUrl(
76
            $token,
77
            $userUsername,
78
            'resetPath',
79
            $this->defaultPasswordResetPath
80
        );
81
        $email = $this->createEmailMessage(
82
            'Your password reset request',
83
            'user_forgot_password.html.twig',
84
            $user,
85
            [
86
                'reset_url' => $resetUrl,
87
            ]
88
        );
89
        $this->send($email);
90
    }
91
92
    public function sendChangeEmailConfirmationEmail(AbstractUser $user): void
93
    {
94
        $userUsername = $this->getUserUsername($user);
95
        $verifyUrl = $this->getEmailConfirmationUrl($user, $userUsername);
96
        $email = $this->createEmailMessage(
97
            'Your password reset request',
98
            'user_verify_email.html.twig',
99
            $user,
100
            [
101
                'verify_url' => $verifyUrl,
102
            ]
103
        );
104
        $this->send($email);
105
    }
106
107 5
    public function sendUserWelcomeEmail(AbstractUser $user): void
108
    {
109 5
        if (!$this->sendUserWelcomeEmailEnabled) {
110
            return;
111
        }
112 5
        $userUsername = $this->getUserUsername($user);
113
        try {
114 5
            $verifyUrl = $this->getEmailConfirmationUrl($user, $userUsername);
115 5
        } catch (InvalidArgumentException $exception) {
116
            // if we have not set the email verify token this will be thrown. this is an optional token though.
117 5
            $verifyUrl = null;
118
        }
119 5
        $email = $this->createEmailMessage(
120 5
            sprintf('Welcome to %s', $this->websiteName),
121 5
            'user_welcome.html.twig',
122
            $user,
123
            [
124 5
                'verify_url' => $verifyUrl,
125
            ]
126
        );
127 5
        $this->send($email);
128 5
    }
129
130
    public function sendUserEnabledEmail(AbstractUser $user): void
131
    {
132
        if (!$this->sendUserEnabledEmailEnabled) {
133
            return;
134
        }
135
        $email = $this->createEmailMessage(
136
            'Your account has been enabled',
137
            'user_enabled.html.twig',
138
            $user
139
        );
140
        $this->send($email);
141
    }
142
143
    public function sendUsernameChangedEmail(AbstractUser $user): void
144
    {
145
        if (!$this->sendUserUsernameChangedEmailEnabled) {
146
            return;
147
        }
148
        $email = $this->createEmailMessage(
149
            'Your username has been changed',
150
            'username_changed.html.twig',
151
            $user
152
        );
153
        $this->send($email);
154
    }
155
156
    public function sendPasswordChangedEmail(AbstractUser $user): void
157
    {
158
        if (!$this->sendUserPasswordChangedEmailEnabled) {
159
            return;
160
        }
161
        $email = $this->createEmailMessage(
162
            'Your password has been changed',
163
            'user_password_changed.html.twig',
164
            $user
165
        );
166
        $this->send($email);
167
    }
168
169 5
    private function createEmailMessage(string $subject, string $htmlTemplate, AbstractUser $user, array $context = [], ?string $toEmail = null)
170
    {
171
        $defaultContext = [
172 5
            'user' => $user,
173 5
            'username' => $this->getUserUsername($user),
174 5
            'website_name' => $this->websiteName,
175
        ];
176 5
        if (null === $toEmail) {
177 5
            $toEmail = $this->getUserEmail($user);
178
        }
179
180 5
        return (new TemplatedEmail())
181 5
            ->to(Address::fromString($toEmail))
182 5
            ->subject($subject)
183 5
            ->htmlTemplate('@SilverbackApiComponent/emails/' . $htmlTemplate)
184 5
            ->context(array_merge($defaultContext, $context));
185
    }
186
187 5
    private function send(RawMessage $message, Envelope $envelope = null): void
188
    {
189
        try {
190 5
            $this->mailer->send($message, $envelope);
191
        } catch (TransportExceptionInterface $exception) {
192
            $exception = new MailerTransportException($exception->getMessage());
193
            $exception->appendDebug($exception->getDebug());
194
            throw $exception;
195
        }
196 5
    }
197
198 5
    private function getUserEmail(AbstractUser $user): string
199
    {
200 5
        if (!($userEmail = $user->getEmailAddress())) {
201
            throw new InvalidArgumentException('The user must have an email address set to send them any email');
202
        }
203
204 5
        return $userEmail;
205
    }
206
207 5
    private function getUserUsername(AbstractUser $user): string
208
    {
209 5
        if (!($userUsername = $user->getUsername())) {
210
            throw new InvalidArgumentException('The user must have a username set to send them any email');
211
        }
212
213 5
        return $userUsername;
214
    }
215
216 5
    private function getEmailConfirmationUrl(AbstractUser $user, string $userUsername): string
217
    {
218 5
        $token = $user->getNewEmailVerificationToken();
219 5
        if (!$token) {
220 4
            throw new InvalidArgumentException('A new email confirmation token must be set to send the `email verification` email');
221
        }
222
223 1
        return $this->pathToReferrerUrl(
224 1
            $token,
225
            $userUsername,
226 1
            'verifyPath',
227 1
            $this->defaultChangeEmailVerifyPath
228
        );
229
    }
230
231 1
    private function pathToReferrerUrl(string $token, string $email, string $queryKey, string $defaultPath): string
232
    {
233 1
        $request = $this->requestStack->getMasterRequest();
234 1
        $path = $request ? $request->query->get($queryKey, $defaultPath) : $defaultPath;
235 1
        $path = str_replace(['{{ token }}', '{{ email }}'], [$token, $email], $path);
236
237 1
        return $this->refererUrlHelper->getAbsoluteUrl($path);
238
    }
239
}
240