Completed
Pull Request — master (#4286)
by Craig
04:48
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 StageHelper
55
     */
56
    private $stageHelper;
57
58
    /**
59
     * @var AjaxUpgraderStage
60
     */
61
    private $ajaxUpgraderStage;
62
63
    /**
64
     * @var array
65
     */
66
    private $upgradeSettings = [
67
        'username',
68
        'password',
69
        'locale',
70
        'router:request_context:host',
71
        'router:request_context:scheme',
72
        'router:request_context:base_url',
73
        'transport'
74
    ];
75
76
    public function __construct(
77
        ZikulaHttpKernelInterface $kernel,
78
        PhpHelper $phpHelper,
79
        MigrationHelper $migrationHelper,
80
        LocaleApiInterface $localeApi,
81
        StageHelper $stageHelper,
82
        AjaxUpgraderStage $ajaxUpgraderStage,
83
        TranslatorInterface $translator,
84
        string $installed
85
    ) {
86
        $this->phpHelper = $phpHelper;
87
        $this->migrationHelper = $migrationHelper;
88
        $this->stageHelper = $stageHelper;
89
        $this->ajaxUpgraderStage = $ajaxUpgraderStage;
90
        $this->installed = $installed;
91
        parent::__construct($kernel, $translator, $localeApi);
92
    }
93
94
    protected function configure()
95
    {
96
        $this->setDescription('Upgrade Zikula from the command line.');
97
98
        foreach ($this->settings as $name => $setting) {
99
            if (!in_array($name, $this->upgradeSettings, true)) {
100
                // only use selected settings for upgrade
101
                continue;
102
            }
103
            $this->addOption(
104
                $name,
105
                null,
106
                InputOption::VALUE_REQUIRED,
107
                $setting['description'],
108
                $setting['default']
109
            );
110
        }
111
    }
112
113
    protected function execute(InputInterface $input, OutputInterface $output): int
114
    {
115
        if (version_compare($this->installed, UpgraderController::ZIKULACORE_MINIMUM_UPGRADE_VERSION, '<')) {
116
            $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]));
117
118
            return 1;
119
        }
120
121
        $io = new SymfonyStyle($input, $output);
122
        if ($input->isInteractive()) {
123
            $io->title($this->translator->trans('Zikula Upgrader Script'));
124
            $io->section($this->translator->trans('*** UPGRADING TO ZIKULA CORE %version% ***', ['%version%' => ZikulaKernel::VERSION]));
125
            $io->text($this->translator->trans('Upgrading Zikula in %env% environment.', ['%env%' => $this->kernel->getEnvironment()]));
126
        }
127
128
        $iniWarnings = $this->phpHelper->setUp();
129
        if (!empty($iniWarnings)) {
130
            $this->printWarnings($output, $iniWarnings);
131
132
            return 2;
133
        }
134
135
        $yamlManager = new YamlDumper($this->kernel->getProjectDir() . '/config', 'services_custom.yaml');
136
        $yamlManager->setParameter('upgrading', true); // tell the core that we are upgrading
137
138
        $this->migrateUsers($input, $output, $io);
139
140
        // get the settings from user input
141
        $settings = $this->doLocale($input, $output, $io);
142
        $settings = array_merge($settings, $this->doAdminLogin($input, $output, $io));
143
        if (false === $mailSettings = $this->doMailer($input, $output, $io)) {
144
            $io->error($this->translator->trans('Cannot write mailer DSN to %file% file.', ['%file%' => '/.env.local']));
145
        } else {
146
            $settings = array_merge($settings, $mailSettings);
147
        }
148
        $settings = array_merge($settings, $this->doRequestContext($input, $output, $io));
149
150
        if ($input->isInteractive()) {
151
            $this->printSettings($settings, $io);
152
            $io->newLine();
153
        }
154
155
        $params = array_merge($yamlManager->getParameters(), $settings);
156
        $yamlManager->setParameters($params);
157
158
        // upgrade!
159
        $this->stageHelper->handleAjaxStage($this->ajaxUpgraderStage, $io);
160
161
        $io->success($this->translator->trans('UPGRADE SUCCESSFUL!'));
162
163
        return 0;
164
    }
165
166
    private function migrateUsers(InputInterface $input, OutputInterface $output, SymfonyStyle $io): void
167
    {
168
        if (version_compare($this->installed, '2.0.0', '>=')) {
169
            return;
170
        }
171
        $count = $this->migrationHelper->countUnMigratedUsers();
172
        if ($count > 0) {
173
            if ($input->isInteractive()) {
174
                $io->text($this->translator->trans('Beginning user migration...'));
175
            }
176
            $userMigrationMaxuid = (int)$this->migrationHelper->getMaxUnMigratedUid();
177
            if ($input->isInteractive()) {
178
                $progressBar = new ProgressBar($output, (int) ceil($count / MigrationHelper::BATCH_LIMIT));
179
                $progressBar->start();
180
            }
181
            $lastUid = 0;
182
            do {
183
                $result = $this->migrationHelper->migrateUsers($lastUid);
184
                $lastUid = $result['lastUid'];
185
                if ($input->isInteractive()) {
186
                    $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...
187
                }
188
            } while ($lastUid < $userMigrationMaxuid);
189
            if ($input->isInteractive()) {
190
                $progressBar->finish();
191
                $io->success($this->translator->trans('User migration complete!'));
192
            }
193
        } else {
194
            if ($input->isInteractive()) {
195
                $io->text($this->translator->trans('There was no need to migrate any users.'));
196
            }
197
        }
198
    }
199
200
    private function doAdminLogin(InputInterface $input, OutputInterface $output, StyleInterface $io): array
201
    {
202
        if ($input->isInteractive()) {
203
            $io->newLine();
204
            $io->section($this->translator->trans('Admin Login'));
205
        }
206
        $data = $this->getHelper('form')->interactUsingForm(LoginType::class, $input, $output);
207
        foreach ($data as $k => $v) {
208
            $data[$k] = base64_encode($v); // encode so values are 'safe' for json
209
        }
210
211
        return $data;
212
    }
213
}
214