Completed
Push — master ( ead074...fd19fe )
by Jonathan
12s
created

MigrateCommand::configure()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 76
Code Lines 66

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 66
nc 1
nop 0
dl 0
loc 76
ccs 34
cts 34
cp 1
crap 1
rs 8.9667
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations\Tools\Console\Command;
6
7
use Doctrine\Migrations\Migrator;
8
use Symfony\Component\Console\Formatter\OutputFormatter;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use function count;
14
use function getcwd;
15
use function sprintf;
16
use function substr;
17
18
class MigrateCommand extends AbstractCommand
19
{
20 17
    protected function configure() : void
21
    {
22
        $this
23 17
            ->setName('migrations:migrate')
24 17
            ->setAliases(['migrate'])
25 17
            ->setDescription(
26 17
                'Execute a migration to a specified version or the latest available version.'
27
            )
28 17
            ->addArgument(
29 17
                'version',
30 17
                InputArgument::OPTIONAL,
31 17
                'The version number (YYYYMMDDHHMMSS) or alias (first, prev, next, latest) to migrate to.',
32 17
                'latest'
33
            )
34 17
            ->addOption(
35 17
                'write-sql',
36 17
                null,
37 17
                InputOption::VALUE_OPTIONAL,
38 17
                'The path to output the migration SQL file instead of executing it. Defaults to current working directory.',
39 17
                false
40
            )
41 17
            ->addOption(
42 17
                'dry-run',
43 17
                null,
44 17
                InputOption::VALUE_NONE,
45 17
                'Execute the migration as a dry run.'
46
            )
47 17
            ->addOption(
48 17
                'query-time',
49 17
                null,
50 17
                InputOption::VALUE_NONE,
51 17
                'Time all the queries individually.'
52
            )
53 17
            ->addOption(
54 17
                'allow-no-migration',
55 17
                null,
56 17
                InputOption::VALUE_NONE,
57 17
                'Don\'t throw an exception if no migration is available (CI).'
58
            )
59 17
            ->setHelp(<<<EOT
60 17
The <info>%command.name%</info> command executes a migration to a specified version or the latest available version:
61
62
    <info>%command.full_name%</info>
63
64
You can optionally manually specify the version you wish to migrate to:
65
66
    <info>%command.full_name% YYYYMMDDHHMMSS</info>
67
68
You can specify the version you wish to migrate to using an alias:
69
70
    <info>%command.full_name% prev</info>
71
    <info>These alias are defined : first, latest, prev, current and next</info>
72
73
You can specify the version you wish to migrate to using an number against the current version:
74
75
    <info>%command.full_name% current+3</info>
76
77
You can also execute the migration as a <comment>--dry-run</comment>:
78
79
    <info>%command.full_name% YYYYMMDDHHMMSS --dry-run</info>
80
81
You can output the would be executed SQL statements to a file with <comment>--write-sql</comment>:
82
83
    <info>%command.full_name% YYYYMMDDHHMMSS --write-sql</info>
84
85
Or you can also execute the migration without a warning message which you need to interact with:
86
87
    <info>%command.full_name% --no-interaction</info>
88
89
You can also time all the different queries if you wanna know which one is taking so long:
90
91
    <info>%command.full_name% --query-time</info>
92
EOT
93
        );
94
95 17
        parent::configure();
96 17
    }
97
98 10
    public function execute(InputInterface $input, OutputInterface $output) : int
99
    {
100 10
        $migrator = $this->createMigrator();
101
102 10
        $this->outputHeader($output);
103
104 10
        $version          = (string) $input->getArgument('version');
105 10
        $path             = $input->getOption('write-sql');
106 10
        $allowNoMigration = (bool) $input->getOption('allow-no-migration');
107 10
        $timeAllqueries   = (bool) $input->getOption('query-time');
108 10
        $dryRun           = (bool) $input->getOption('dry-run');
109
110 10
        $this->configuration->setIsDryRun($dryRun);
111
112 10
        $version = $this->getVersionNameFromAlias(
113 10
            $version,
114 10
            $output
115
        );
116
117 10
        if ($version === '') {
118 5
            return 1;
119
        }
120
121 5
        if ($this->checkExecutedUnavailableMigrations($input, $output) === 1) {
122 1
            return 1;
123
        }
124
125 4
        if ($path !== false) {
126 2
            $path = $path === null ? getcwd() : $path;
127
128 2
            $migrator->writeSqlFile($path, $version);
129
130 2
            return 0;
131
        }
132
133 2
        $cancelled = false;
134
135 2
        $migrator->setNoMigrationException($allowNoMigration);
136
137 2
        $result = $migrator->migrate(
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
138 2
            $version,
139 2
            $dryRun,
140 2
            $timeAllqueries,
141
            function () use ($input, $output, &$cancelled) {
142 1
                $question = 'WARNING! You are about to execute a database migration that could result in schema changes and data loss. Are you sure you wish to continue? (y/n)';
143
144 1
                $canContinue = $this->canExecute($question, $input, $output);
145 1
                $cancelled   = ! $canContinue;
146
147 1
                return $canContinue;
148 2
            }
149
        );
150
151 2
        if ($cancelled) {
152
            $output->writeln('<error>Migration cancelled!</error>');
153
154
            return 1;
155
        }
156
157 2
        return 0;
158
    }
159
160 10
    protected function createMigrator() : Migrator
161
    {
162 10
        return $this->dependencyFactory->getMigrator();
163
    }
164
165 5
    private function checkExecutedUnavailableMigrations(
166
        InputInterface $input,
167
        OutputInterface $output
168
    ) : int {
169 5
        $executedUnavailableMigrations = $this->migrationRepository->getExecutedUnavailableMigrations();
170
171 5
        if (count($executedUnavailableMigrations) !== 0) {
172 4
            $output->writeln(sprintf(
173 4
                '<error>WARNING! You have %s previously executed migrations in the database that are not registered migrations.</error>',
174 4
                count($executedUnavailableMigrations)
175
            ));
176
177 4
            foreach ($executedUnavailableMigrations as $executedUnavailableMigration) {
178 4
                $output->writeln(sprintf(
179 4
                    '    <comment>>></comment> %s (<comment>%s</comment>)',
180 4
                    $this->configuration->getDateTime($executedUnavailableMigration),
181 4
                    $executedUnavailableMigration
182
                ));
183
            }
184
185 4
            $question = 'Are you sure you wish to continue? (y/n)';
186
187 4
            if (! $this->canExecute($question, $input, $output)) {
188 1
                $output->writeln('<error>Migration cancelled!</error>');
189
190 1
                return 1;
191
            }
192
        }
193
194 4
        return 0;
195
    }
196
197 10
    private function getVersionNameFromAlias(
198
        string $versionAlias,
199
        OutputInterface $output
200
    ) : string {
201 10
        $version = $this->configuration->resolveVersionAlias($versionAlias);
202
203 10
        if ($version === null) {
204 4
            if ($versionAlias === 'prev') {
205 1
                $output->writeln('<error>Already at first version.</error>');
206
207 1
                return '';
208
            }
209
210 3
            if ($versionAlias === 'next') {
211 1
                $output->writeln('<error>Already at latest version.</error>');
212
213 1
                return '';
214
            }
215
216 2
            if (substr($versionAlias, 0, 7) === 'current') {
217 1
                $output->writeln('<error>The delta couldn\'t be reached.</error>');
218
219 1
                return '';
220
            }
221
222 1
            $output->writeln(sprintf(
223 1
                '<error>Unknown version: %s</error>',
224 1
                OutputFormatter::escape($versionAlias)
225
            ));
226
227 1
            return '';
228
        }
229
230 6
        return $version;
231
    }
232
}
233