RegistrationMailService::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 12
dl 0
loc 16
rs 10
c 0
b 0
f 0

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
 * Copyright 2016 SURFnet B.V.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Service;
20
21
use Assert\Assertion;
22
use DateInterval;
23
use Psr\Log\LoggerInterface;
24
use Surfnet\Stepup\Configuration\Value\Institution;
25
use Surfnet\Stepup\DateTime\DateTime;
26
use Surfnet\Stepup\Identity\Value\SecondFactorId;
27
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Service\InstitutionConfigurationOptionsService;
28
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Service\RaLocationService;
29
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\IdentityService;
30
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\RaListingService;
31
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SecondFactorService;
32
use Surfnet\StepupMiddleware\ApiBundle\Identity\Value\RegistrationAuthorityCredentials;
33
use Surfnet\StepupMiddleware\CommandHandlingBundle\Configuration\Service\EmailTemplateService;
34
use Surfnet\StepupMiddleware\CommandHandlingBundle\Value\Sender;
35
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
36
use Symfony\Component\Mailer\MailerInterface as Mailer;
37
use Symfony\Component\Mime\Address;
38
use Symfony\Contracts\Translation\TranslatorInterface;
39
40
/**
41
 * @SuppressWarnings("PHPMD.CouplingBetweenObjects")
42
 */
43
class RegistrationMailService
44
{
45
    private readonly string $fallbackLocale;
46
47
    /**
48
     * @SuppressWarnings("PHPMD.ExcessiveParameterList")
49
     */
50
    public function __construct(
51
        private readonly Mailer $mailer,
52
        private readonly Sender $sender,
53
        private readonly TranslatorInterface $translator,
54
        private readonly EmailTemplateService $emailTemplateService,
55
        string $fallbackLocale,
56
        private readonly string $selfServiceUrl,
57
        public InstitutionConfigurationOptionsService $institutionConfigurationOptionsService,
58
        private readonly IdentityService $identityService,
59
        private readonly SecondFactorService $secondFactorService,
60
        private readonly RaLocationService $raLocationsService,
61
        private readonly RaListingService $raListingService,
62
        private readonly LoggerInterface $logger,
63
    ) {
64
        Assertion::string($fallbackLocale, 'Fallback locale "%s" expected to be string, type %s given');
65
        $this->fallbackLocale = $fallbackLocale;
0 ignored issues
show
Bug introduced by
The property fallbackLocale is declared read-only in Surfnet\StepupMiddleware...RegistrationMailService.
Loading history...
66
    }
67
68
    public function send(string $identityId, string $secondFactorId): void
69
    {
70
        $this->logger->notice(sprintf('Start processing of a registration email for %s', $identityId));
71
        $identity = $this->identityService->find($identityId);
72
        $institution = new Institution($identity->institution->getInstitution());
73
        $institutionConfigurationOptions = $this->institutionConfigurationOptionsService
74
            ->findInstitutionConfigurationOptionsFor($institution);
75
        $verifiedSecondFactor = $this->secondFactorService->findVerified(new SecondFactorId($secondFactorId));
76
77
        if ($institutionConfigurationOptions->useRaLocationsOption->isEnabled()) {
78
            $this->logger->notice('Sending a registration mail with ra locations');
79
80
            $this->sendRegistrationEmailWithRaLocations(
81
                $identity->preferredLocale->getLocale(),
82
                $identity->commonName->getCommonName(),
83
                $identity->email->getEmail(),
84
                $verifiedSecondFactor->registrationCode,
85
                $this->getExpirationDateOfRegistration(
86
                    DateTime::fromString($verifiedSecondFactor->registrationRequestedAt->format(DateTime::FORMAT)),
87
                ),
88
                $this->raLocationsService->listRaLocationsFor($institution),
89
            );
90
91
            return;
92
        }
93
94
        $ras = $this->raListingService->listRegistrationAuthoritiesFor($identity->institution);
95
        if ($institutionConfigurationOptions->showRaaContactInformationOption->isEnabled()) {
96
            $this->logger->notice('Sending a registration mail with raa contact information');
97
            $this->sendRegistrationEmailWithRas(
98
                $identity->preferredLocale->getLocale(),
99
                $identity->commonName->getCommonName(),
100
                $identity->email->getEmail(),
101
                $verifiedSecondFactor->registrationCode,
102
                $this->getExpirationDateOfRegistration(
103
                    DateTime::fromString($verifiedSecondFactor->registrationRequestedAt->format(DateTime::FORMAT)),
104
                ),
105
                $ras,
106
            );
107
            return;
108
        }
109
110
        $rasWithoutRaas = array_filter($ras, fn(RegistrationAuthorityCredentials $ra): bool => !$ra->isRaa());
111
        $this->logger->notice(
112
            'Sending a registration mail with ra contact information as there are no RAAs at this location',
113
        );
114
        $this->sendRegistrationEmailWithRas(
115
            $identity->preferredLocale->getLocale(),
116
            $identity->commonName->getCommonName(),
117
            $identity->email->getEmail(),
118
            $verifiedSecondFactor->registrationCode,
119
            $this->getExpirationDateOfRegistration(
120
                DateTime::fromString($verifiedSecondFactor->registrationRequestedAt->format(DateTime::FORMAT)),
121
            ),
122
            $rasWithoutRaas,
123
        );
124
    }
125
126
    private function sendRegistrationEmailWithRas(
127
        string $locale,
128
        string $commonName,
129
        string $email,
130
        string $registrationCode,
131
        DateTime $expirationDate,
132
        array $ras,
133
    ): void {
134
        $subject = $this->translator->trans(
135
            'ss.mail.registration_email.subject',
136
            ['%commonName%' => $commonName],
137
            'messages',
138
            $locale,
139
        );
140
141
        $emailTemplate = $this->emailTemplateService->findByName(
142
            'registration_code_with_ras',
143
            $locale,
144
            $this->fallbackLocale,
145
        );
146
147
        // In TemplatedEmail email is a reserved keyword, we also use it as a parameter that can be used in the mail
148
        // message, to prevent having to update all templates, and prevent a 500 error from the mailer, we perform a
149
        // search and replace of the {email} parameter in the template.
150
        $emailTemplate->htmlContent = str_replace(
151
            '{email}',
152
            '{emailAddress}',
153
            $emailTemplate->htmlContent,
154
        );
155
        $parameters = [
156
            'templateString' => $emailTemplate->htmlContent,
157
            'locale' => $locale,
158
            'commonName' => $commonName,
159
            'emailAddress' => $email,
160
            'registrationCode' => $registrationCode,
161
            'expirationDate' => (string)$expirationDate,
162
            'ras' => $ras,
163
            'selfServiceUrl' => $this->selfServiceUrl,
164
        ];
165
166
        $message = new TemplatedEmail();
167
        $message
168
            ->from(new Address($this->sender->getEmail(), $this->sender->getName()))
169
            ->to(new Address($email, $commonName))
170
            ->subject($subject)
171
            ->htmlTemplate('@SurfnetStepupMiddlewareCommandHandling/SecondFactorMailService/email.html.twig')
172
            ->context($parameters);
173
        $this->mailer->send($message);
174
    }
175
176
    private function sendRegistrationEmailWithRaLocations(
177
        string $locale,
178
        string $commonName,
179
        string $email,
180
        string $registrationCode,
181
        DateTime $expirationDate,
182
        array $raLocations,
183
    ): void {
184
        $subject = $this->translator->trans(
185
            'ss.mail.registration_email.subject',
186
            ['%commonName%' => $commonName],
187
            'messages',
188
            $locale,
189
        );
190
191
        $emailTemplate = $this->emailTemplateService->findByName(
192
            'registration_code_with_ra_locations',
193
            $locale,
194
            $this->fallbackLocale,
195
        );
196
        // In TemplatedEmail email is a reserved keyword, we also use it as a parameter that can be used in the mail
197
        // message, to prevent having to update all templates, and prevent a 500 error from the mailer, we perform a
198
        // search and replace of the {email} parameter in the template.
199
        $emailTemplate->htmlContent = str_replace(
200
            '{email}',
201
            '{emailAddress}',
202
            $emailTemplate->htmlContent,
203
        );
204
205
        $parameters = [
206
            'templateString' => $emailTemplate->htmlContent,
207
            'locale' => $locale,
208
            'commonName' => $commonName,
209
            'emailAddress' => $email,
210
            'registrationCode' => $registrationCode,
211
            'expirationDate' => (string)$expirationDate,
212
            'raLocations' => $raLocations,
213
            'selfServiceUrl' => $this->selfServiceUrl,
214
        ];
215
216
        $message = new TemplatedEmail();
217
        $message
218
            ->from(new Address($this->sender->getEmail(), $this->sender->getName()))
219
            ->to(new Address($email, $commonName))
220
            ->subject($subject)
221
            ->htmlTemplate('@SurfnetStepupMiddlewareCommandHandling/SecondFactorMailService/email.html.twig')
222
            ->context($parameters);
223
        $this->mailer->send($message);
224
    }
225
226
    private function getExpirationDateOfRegistration(DateTime $date): DateTime
227
    {
228
        return $date->add(
229
            new DateInterval('P14D'),
230
        );
231
    }
232
}
233