SetupCommand   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 184
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 13

Importance

Changes 0
Metric Value
wmc 17
lcom 2
cbo 13
dl 0
loc 184
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A configure() 0 11 1
A execute() 0 6 1
A setupAdministratorUser() 0 17 2
A configureNewUser() 0 33 4
A createEmailQuestion() 0 15 2
A getAdministratorPassword() 0 20 3
A getPasswordQuestionValidator() 0 12 2
A createPasswordQuestion() 0 9 1
1
<?php
2
3
/*
4
 * This file is part of AppName.
5
 *
6
 * (c) Monofony
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
namespace App\Command\Installer;
13
14
use App\Entity\User\AdminUserInterface;
15
use Doctrine\Common\Persistence\ObjectManager;
16
use Sylius\Component\Resource\Factory\FactoryInterface;
17
use Sylius\Component\User\Repository\UserRepositoryInterface;
18
use Symfony\Component\Console\Command\Command;
19
use Symfony\Component\Console\Helper\QuestionHelper;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Console\Question\Question;
23
use Symfony\Component\Validator\Constraints\Email;
24
use Symfony\Component\Validator\Constraints\NotBlank;
25
use Symfony\Component\Validator\ConstraintViolationListInterface;
26
use Symfony\Component\Validator\Validator\ValidatorInterface;
27
use Webmozart\Assert\Assert;
28
29
final class SetupCommand extends Command
30
{
31
    /** @var ObjectManager */
32
    private $adminUserManager;
33
34
    /** @var FactoryInterface */
35
    private $adminUserFactory;
36
37
    /** @var UserRepositoryInterface */
38
    private $adminUserRepository;
39
40
    /** @var ValidatorInterface */
41
    private $validator;
42
43
    public function __construct(
44
        ObjectManager $adminUserManager,
45
        FactoryInterface $adminUserFactory,
46
        UserRepositoryInterface $adminUserRepository,
47
        ValidatorInterface $validator
48
    ) {
49
        $this->adminUserManager = $adminUserManager;
50
        $this->adminUserFactory = $adminUserFactory;
51
        $this->adminUserRepository = $adminUserRepository;
52
        $this->validator = $validator;
53
54
        parent::__construct();
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    protected function configure()
61
    {
62
        $this
63
            ->setName('app:install:setup')
64
            ->setDescription('AppName configuration setup.')
65
            ->setHelp(<<<EOT
66
The <info>%command.name%</info> command allows user to configure basic AppName data.
67
EOT
68
            )
69
        ;
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    protected function execute(InputInterface $input, OutputInterface $output)
76
    {
77
        $this->setupAdministratorUser($input, $output);
78
79
        return 0;
80
    }
81
82
    /**
83
     * @param InputInterface  $input
84
     * @param OutputInterface $output
85
     */
86
    protected function setupAdministratorUser(InputInterface $input, OutputInterface $output): void
87
    {
88
        $output->writeln('Create your administrator account.');
89
90
        try {
91
            $user = $this->configureNewUser($this->adminUserFactory->createNew(), $input, $output);
92
        } catch (\InvalidArgumentException $exception) {
93
            return;
94
        }
95
96
        $user->setEnabled(true);
97
98
        $this->adminUserManager->persist($user);
99
        $this->adminUserManager->flush();
100
101
        $output->writeln('Administrator account successfully registered.');
102
    }
103
104
    private function configureNewUser(
105
        AdminUserInterface $user,
106
        InputInterface $input,
107
        OutputInterface $output
108
    ): AdminUserInterface {
109
        if ($input->getOption('no-interaction')) {
110
            Assert::null($this->adminUserRepository->findOneByEmail('[email protected]'));
111
112
            $user->setEmail('[email protected]');
113
            $user->setUsername('admin');
114
            $user->setPlainPassword('admin');
115
116
            return $user;
117
        }
118
119
        $questionHelper = $this->getHelper('question');
120
121
        do {
122
            $question = $this->createEmailQuestion();
123
            $email = $questionHelper->ask($input, $output, $question);
124
            $exists = null !== $this->adminUserRepository->findOneByEmail($email);
125
126
            if ($exists) {
127
                $output->writeln('<error>E-Mail is already in use!</error>');
128
            }
129
        } while ($exists);
130
131
        $user->setEmail($email);
132
        $user->setUsername($email);
133
        $user->setPlainPassword($this->getAdministratorPassword($input, $output));
134
135
        return $user;
136
    }
137
138
    private function createEmailQuestion(): Question
139
    {
140
        return (new Question('E-mail:'))
141
            ->setValidator(function ($value) {
142
                /** @var ConstraintViolationListInterface $errors */
143
                $errors = $this->validator->validate((string) $value, [new Email(), new NotBlank()]);
144
                foreach ($errors as $error) {
145
                    throw new \DomainException($error->getMessage());
146
                }
147
148
                return $value;
149
            })
150
            ->setMaxAttempts(3)
151
            ;
152
    }
153
154
    /**
155
     * @param InputInterface  $input
156
     * @param OutputInterface $output
157
     *
158
     * @return mixed
159
     */
160
    private function getAdministratorPassword(InputInterface $input, OutputInterface $output)
161
    {
162
        /** @var QuestionHelper $questionHelper */
163
        $questionHelper = $this->getHelper('question');
164
        $validator = $this->getPasswordQuestionValidator();
165
166
        do {
167
            $passwordQuestion = $this->createPasswordQuestion('Choose password:', $validator);
168
            $confirmPasswordQuestion = $this->createPasswordQuestion('Confirm password:', $validator);
169
170
            $password = $questionHelper->ask($input, $output, $passwordQuestion);
171
            $repeatedPassword = $questionHelper->ask($input, $output, $confirmPasswordQuestion);
172
173
            if ($repeatedPassword !== $password) {
174
                $output->writeln('<error>Passwords do not match!</error>');
175
            }
176
        } while ($repeatedPassword !== $password);
177
178
        return $password;
179
    }
180
181
    /**
182
     * @return \Closure
183
     */
184
    private function getPasswordQuestionValidator()
185
    {
186
        return function ($value) {
187
            /** @var ConstraintViolationListInterface $errors */
188
            $errors = $this->validator->validate($value, [new NotBlank()]);
189
            foreach ($errors as $error) {
190
                throw new \DomainException($error->getMessage());
191
            }
192
193
            return $value;
194
        };
195
    }
196
197
    /**
198
     * @param string   $message
199
     * @param \Closure $validator
200
     *
201
     * @return Question
202
     */
203
    private function createPasswordQuestion($message, \Closure $validator)
204
    {
205
        return (new Question($message))
206
            ->setValidator($validator)
207
            ->setMaxAttempts(3)
208
            ->setHidden(true)
209
            ->setHiddenFallback(false)
210
            ;
211
    }
212
}
213