Completed
Push — master ( 90fa2c...b55ca8 )
by Kamil
31:00 queued 14:59
created

SetupCommand::getAdminUserRepository()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
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 Sylius\Bundle\CoreBundle\Command;
15
16
use Sylius\Component\Core\Model\AdminUserInterface;
17
use Sylius\Component\User\Repository\UserRepositoryInterface;
18
use Symfony\Component\Console\Helper\QuestionHelper;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Output\OutputInterface;
21
use Symfony\Component\Console\Question\Question;
22
use Symfony\Component\Console\Style\SymfonyStyle;
23
use Symfony\Component\Validator\Constraints\Email;
24
use Symfony\Component\Validator\Constraints\NotBlank;
25
use Symfony\Component\Validator\ConstraintViolationListInterface;
26
use Webmozart\Assert\Assert;
27
28
/**
29
 * @author Paweł Jędrzejewski <[email protected]>
30
 */
31
final class SetupCommand extends AbstractInstallCommand
32
{
33
    /**
34
     * {@inheritdoc}
35
     */
36
    protected function configure(): void
37
    {
38
        $this
39
            ->setName('sylius:install:setup')
40
            ->setDescription('Sylius configuration setup.')
41
            ->setHelp(<<<EOT
42
The <info>%command.name%</info> command allows user to configure basic Sylius data.
43
EOT
44
            )
45
        ;
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    protected function execute(InputInterface $input, OutputInterface $output): void
52
    {
53
        $currency = $this->get('sylius.setup.currency')->setup($input, $output, $this->getHelper('question'));
54
        $locale = $this->get('sylius.setup.locale')->setup($input, $output);
55
        $this->get('sylius.setup.channel')->setup($locale, $currency);
56
        $this->setupAdministratorUser($input, $output, $locale->getCode());
57
    }
58
59
    /**
60
     * @param InputInterface $input
61
     * @param OutputInterface $output
62
     * @param string $localeCode
63
     */
64
    protected function setupAdministratorUser(InputInterface $input, OutputInterface $output, string $localeCode): void
65
    {
66
        $outputStyle = new SymfonyStyle($input, $output);
67
        $outputStyle->writeln('Create your administrator account.');
68
69
        $userManager = $this->get('sylius.manager.admin_user');
70
        $userFactory = $this->get('sylius.factory.admin_user');
71
72
        try {
73
            $user = $this->configureNewUser($userFactory->createNew(), $input, $output);
74
        } catch (\InvalidArgumentException $exception) {
75
            return;
76
        }
77
78
        $user->setEnabled(true);
79
        $user->setLocaleCode($localeCode);
80
81
        $userManager->persist($user);
82
        $userManager->flush();
83
84
        $outputStyle->writeln('<info>Administrator account successfully registered.</info>');
85
        $outputStyle->newLine();
86
    }
87
88
    /**
89
     * @param AdminUserInterface $user
90
     * @param InputInterface $input
91
     * @param OutputInterface $output
92
     *
93
     * @return AdminUserInterface
94
     */
95
    private function configureNewUser(
96
        AdminUserInterface $user,
97
        InputInterface $input,
98
        OutputInterface $output
99
    ): AdminUserInterface {
100
        /** @var UserRepositoryInterface $userRepository */
101
        $userRepository = $this->getAdminUserRepository();
102
103
        if ($input->getOption('no-interaction')) {
104
            Assert::null($userRepository->findOneByEmail('[email protected]'));
105
106
            $user->setEmail('[email protected]');
107
            $user->setUsername('sylius');
108
            $user->setPlainPassword('sylius');
109
110
            return $user;
111
        }
112
113
        $email = $this->getAdministratorEmail($input, $output);
114
        $user->setEmail($email);
115
        $user->setUsername($this->getAdministratorUsername($input, $output, $email));
116
        $user->setPlainPassword($this->getAdministratorPassword($input, $output));
117
118
        return $user;
119
    }
120
121
    /**
122
     * @param OutputInterface $output
123
     *
124
     * @return Question
125
     */
126
    private function createEmailQuestion(OutputInterface $output): Question
127
    {
128
        return (new Question('E-mail: '))
129
            ->setValidator(function ($value) use ($output) {
130
                /** @var ConstraintViolationListInterface $errors */
131
                $errors = $this->get('validator')->validate((string) $value, [new Email(), new NotBlank()]);
132
                foreach ($errors as $error) {
133
                    throw new \DomainException($error->getMessage());
134
                }
135
136
                return $value;
137
            })
138
            ->setMaxAttempts(3)
139
        ;
140
    }
141
142
    /**
143
     * @param InputInterface $input
144
     * @param OutputInterface $output
145
     *
146
     * @return string
147
     */
148
    private function getAdministratorEmail(InputInterface $input, OutputInterface $output): string
149
    {
150
        /** @var QuestionHelper $questionHelper */
151
        $questionHelper = $this->getHelper('question');
152
        /** @var UserRepositoryInterface $userRepository */
153
        $userRepository = $this->getAdminUserRepository();
154
155
        do {
156
            $question = $this->createEmailQuestion($output);
157
            $email = $questionHelper->ask($input, $output, $question);
158
            $exists = null !== $userRepository->findOneByEmail($email);
159
160
            if ($exists) {
161
                $output->writeln('<error>E-Mail is already in use!</error>');
162
            }
163
        } while ($exists);
164
165
        return $email;
166
    }
167
168
    /**
169
     * @param InputInterface $input
170
     * @param OutputInterface $output
171
     * @param string $email
172
     *
173
     * @return string
174
     */
175
    private function getAdministratorUsername(InputInterface $input, OutputInterface $output, string $email): string
176
    {
177
        /** @var QuestionHelper $questionHelper */
178
        $questionHelper = $this->getHelper('question');
179
        /** @var UserRepositoryInterface $userRepository */
180
        $userRepository = $this->getAdminUserRepository();
181
182
        do {
183
            $question = new Question('Username (press enter to use email): ', $email);
184
            $username = $questionHelper->ask($input, $output, $question);
185
            $exists = null !== $userRepository->findOneBy(['username' => $username]);
186
187
            if ($exists) {
188
                $output->writeln('<error>Username is already in use!</error>');
189
            }
190
        } while ($exists);
191
192
        return $username;
193
    }
194
195
    /**
196
     * @param InputInterface $input
197
     * @param OutputInterface $output
198
     *
199
     * @return mixed
200
     */
201
    private function getAdministratorPassword(InputInterface $input, OutputInterface $output)
202
    {
203
        /** @var QuestionHelper $questionHelper */
204
        $questionHelper = $this->getHelper('question');
205
        $validator = $this->getPasswordQuestionValidator($output);
206
207
        do {
208
            $passwordQuestion = $this->createPasswordQuestion('Choose password:', $validator);
209
            $confirmPasswordQuestion = $this->createPasswordQuestion('Confirm password:', $validator);
210
211
            $password = $questionHelper->ask($input, $output, $passwordQuestion);
212
            $repeatedPassword = $questionHelper->ask($input, $output, $confirmPasswordQuestion);
213
214
            if ($repeatedPassword !== $password) {
215
                $output->writeln('<error>Passwords do not match!</error>');
216
            }
217
        } while ($repeatedPassword !== $password);
218
219
        return $password;
220
    }
221
222
    /**
223
     * @param OutputInterface $output
224
     *
225
     * @return \Closure
226
     *
227
     * @throws \DomainException
228
     */
229
    private function getPasswordQuestionValidator(OutputInterface $output): \Closure
230
    {
231
        return function ($value) use ($output) {
232
            /** @var ConstraintViolationListInterface $errors */
233
            $errors = $this->get('validator')->validate($value, [new NotBlank()]);
234
            foreach ($errors as $error) {
235
                throw new \DomainException($error->getMessage());
236
            }
237
238
            return $value;
239
        };
240
    }
241
242
    /**
243
     * @param string $message
244
     * @param \Closure $validator
245
     *
246
     * @return Question
247
     */
248
    private function createPasswordQuestion(string $message, \Closure $validator): Question
249
    {
250
        return (new Question($message))
251
            ->setValidator($validator)
252
            ->setMaxAttempts(3)
253
            ->setHidden(true)
254
            ->setHiddenFallback(false)
255
        ;
256
    }
257
258
    /**
259
     * @return UserRepositoryInterface
260
     */
261
    private function getAdminUserRepository(): UserRepositoryInterface
262
    {
263
        return $this->get('sylius.repository.admin_user');
264
    }
265
}
266