Completed
Pull Request — master (#4286)
by Craig
04:49
created

UpgradeCommand::migrateUsers()   B

Complexity

Conditions 9
Paths 19

Size

Total Lines 30
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 23
nc 19
nop 3
dl 0
loc 30
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula - https://ziku.la/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Zikula\Bundle\CoreInstallerBundle\Command;
15
16
use Symfony\Component\Console\Helper\ProgressBar;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Input\InputOption;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Console\Style\StyleInterface;
21
use Symfony\Component\Console\Style\SymfonyStyle;
22
use Symfony\Contracts\Translation\TranslatorInterface;
23
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
24
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaKernel;
25
use Zikula\Bundle\CoreBundle\YamlDumper;
26
use Zikula\Bundle\CoreInstallerBundle\Controller\UpgraderController;
27
use Zikula\Bundle\CoreInstallerBundle\Form\Type\LoginType;
28
use Zikula\Bundle\CoreInstallerBundle\Helper\MigrationHelper;
29
use Zikula\Bundle\CoreInstallerBundle\Helper\PhpHelper;
30
use Zikula\Bundle\CoreInstallerBundle\Helper\StageHelper;
31
use Zikula\Bundle\CoreInstallerBundle\Stage\Upgrade\AjaxUpgraderStage;
32
use Zikula\SettingsModule\Api\ApiInterface\LocaleApiInterface;
33
34
class UpgradeCommand extends AbstractCoreInstallerCommand
35
{
36
    protected static $defaultName = 'zikula:upgrade';
37
38
    /**
39
     * @var string
40
     */
41
    private $installed;
42
43
    /**
44
     * @var PhpHelper
45
     */
46
    private $phpHelper;
47
48
    /**
49
     * @var MigrationHelper
50
     */
51
    private $migrationHelper;
52
53
    /**
54
     * @var LocaleApiInterface
55
     */
56
    private $localeApi;
57
58
    /**
59
     * @var StageHelper
60
     */
61
    private $stageHelper;
62
63
    /**
64
     * @var AjaxUpgraderStage
65
     */
66
    private $ajaxUpgraderStage;
67
68
    /**
69
     * @var array
70
     */
71
    private $selectedSettings = [
72
        'username',
73
        'password',
74
        'locale',
75
        'router:request_context:host',
76
        'router:request_context:scheme',
77
        'router:request_context:base_url'
78
    ];
79
80
    public function __construct(
81
        ZikulaHttpKernelInterface $kernel,
82
        PhpHelper $phpHelper,
83
        MigrationHelper $migrationHelper,
84
        LocaleApiInterface $localeApi,
85
        StageHelper $stageHelper,
86
        AjaxUpgraderStage $ajaxUpgraderStage,
87
        TranslatorInterface $translator,
88
        string $installed
89
    ) {
90
        $this->phpHelper = $phpHelper;
91
        $this->migrationHelper = $migrationHelper;
92
        $this->localeApi = $localeApi;
93
        $this->stageHelper = $stageHelper;
94
        $this->ajaxUpgraderStage = $ajaxUpgraderStage;
95
        $this->installed = $installed;
96
        parent::__construct($kernel, $translator);
97
    }
98
99
    protected function configure()
100
    {
101
        $this->setDescription('Upgrade Zikula from the command line.');
102
103
        foreach ($this->settings as $name => $setting) {
104
            if (!in_array($name, $this->selectedSettings, true)) {
105
                // only use selected settings for upgrade
106
                continue;
107
            }
108
            $this->addOption(
109
                $name,
110
                null,
111
                InputOption::VALUE_REQUIRED,
112
                $setting['description'],
113
                $setting['default']
114
            );
115
        }
116
    }
117
118
    protected function execute(InputInterface $input, OutputInterface $output): int
119
    {
120
        if (version_compare($this->installed, UpgraderController::ZIKULACORE_MINIMUM_UPGRADE_VERSION, '<')) {
121
            $output->writeln($this->translator->trans('The currently installed version of Zikula (%currentVersion%) is too old. You must upgrade to version %minimumVersion% before you can use this upgrade.', ['%currentVersion%' => $this->installed, '%minimumVersion%' => UpgraderController::ZIKULACORE_MINIMUM_UPGRADE_VERSION]));
122
123
            return 1;
124
        }
125
126
        $io = new SymfonyStyle($input, $output);
127
        if ($input->isInteractive()) {
128
            $io->title($this->translator->trans('Zikula Upgrader Script'));
129
            $io->section($this->translator->trans('*** UPGRADING TO ZIKULA CORE %version% ***', ['%version%' => ZikulaKernel::VERSION]));
130
            $io->text($this->translator->trans('Upgrading Zikula in %env% environment.', ['%env%' => $this->kernel->getEnvironment()]));
131
        }
132
133
        $iniWarnings = $this->phpHelper->setUp();
134
        if (!empty($iniWarnings)) {
135
            $this->printWarnings($output, $iniWarnings);
136
137
            return 2;
138
        }
139
140
        $yamlManager = new YamlDumper($this->kernel->getProjectDir() . '/config', 'services_custom.yaml');
141
        $yamlManager->setParameter('upgrading', true); // tell the core that we are upgrading
142
143
        $this->migrateUsers($input, $output, $io);
144
145
        // get the settings from user input
146
        $settings = $this->doLocale($input, $output, $io);
147
        $settings = array_merge($settings, $this->doAdminLogin($input, $output, $io));
148
        if (false === $mailSettings = $this->doMailer($input, $output, $io)) {
149
            $io->error($this->translator->trans('Cannot write mailer DSN to %file% file.', ['%file%' => '/.env.local']));
150
        } else {
151
            $settings = array_merge($settings, $mailSettings);
152
        }
153
        $settings = array_merge($settings, $this->doRequestContext($input, $output, $io));
154
155
        if ($input->isInteractive()) {
156
            $this->printSettings($settings, $io);
157
            $io->newLine();
158
        }
159
160
        $params = array_merge($yamlManager->getParameters(), $settings);
161
        $yamlManager->setParameters($params);
162
163
        // upgrade!
164
        $this->stageHelper->handleAjaxStage($this->ajaxUpgraderStage, $io);
165
166
        $io->success($this->translator->trans('UPGRADE SUCCESSFUL!'));
167
168
        return 0;
169
    }
170
171
    private function migrateUsers(InputInterface $input, OutputInterface $output, SymfonyStyle $io): void
172
    {
173
        if (version_compare($this->installed, '2.0.0', '>=')) {
174
            return;
175
        }
176
        $count = $this->migrationHelper->countUnMigratedUsers();
177
        if ($count > 0) {
178
            if ($input->isInteractive()) {
179
                $io->text($this->translator->trans('Beginning user migration...'));
180
            }
181
            $userMigrationMaxuid = (int)$this->migrationHelper->getMaxUnMigratedUid();
182
            if ($input->isInteractive()) {
183
                $progressBar = new ProgressBar($output, (int) ceil($count / MigrationHelper::BATCH_LIMIT));
184
                $progressBar->start();
185
            }
186
            $lastUid = 0;
187
            do {
188
                $result = $this->migrationHelper->migrateUsers($lastUid);
189
                $lastUid = $result['lastUid'];
190
                if ($input->isInteractive()) {
191
                    $progressBar->advance();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $progressBar does not seem to be defined for all execution paths leading up to this point.
Loading history...
192
                }
193
            } while ($lastUid < $userMigrationMaxuid);
194
            if ($input->isInteractive()) {
195
                $progressBar->finish();
196
                $io->success($this->translator->trans('User migration complete!'));
197
            }
198
        } else {
199
            if ($input->isInteractive()) {
200
                $io->text($this->translator->trans('There was no need to migrate any users.'));
201
            }
202
        }
203
    }
204
205
    private function doAdminLogin(InputInterface $input, OutputInterface $output, StyleInterface $io): array
206
    {
207
        if ($input->isInteractive()) {
208
            $io->newLine();
209
            $io->section($this->translator->trans('Admin Login'));
210
        }
211
        $data = $this->getHelper('form')->interactUsingForm(LoginType::class, $input, $output);
212
        foreach ($data as $k => $v) {
213
            $data[$k] = base64_encode($v); // encode so values are 'safe' for json
214
        }
215
216
        return $data;
217
    }
218
}
219