Passed
Push — master ( 77cd29...c7d0d5 )
by Jonathan
02:04
created

MigrateCommand::execute()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 60
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 6.0067

Importance

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