Completed
Push — master ( ff8ed5...dcad7a )
by Mike
15:53 queued 12:44
created

MigrateCommand::execute()   C

Complexity

Conditions 10
Paths 16

Size

Total Lines 67
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 24.2809

Importance

Changes 0
Metric Value
dl 0
loc 67
c 0
b 0
f 0
ccs 21
cts 44
cp 0.4773
rs 6.1506
cc 10
eloc 41
nc 16
nop 2
crap 24.2809

How to fix   Long Method    Complexity   

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
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
21
22
use Doctrine\DBAL\Migrations\Configuration\Configuration;
23
use Doctrine\DBAL\Migrations\Migration;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Output\OutputInterface;
26
use Symfony\Component\Console\Input\InputArgument;
27
use Symfony\Component\Console\Input\InputOption;
28
29
/**
30
 * Command for executing a migration to a specified version or the latest available version.
31
 *
32
 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
33
 * @link    www.doctrine-project.org
34
 * @since   2.0
35
 * @author  Jonathan Wage <[email protected]>
36
 */
37
class MigrateCommand extends AbstractCommand
38
{
39 9
    protected function configure()
40
    {
41 9
        $this
42 9
            ->setName('migrations:migrate')
43 9
            ->setDescription('Execute a migration to a specified version or the latest available version.')
44 9
            ->addArgument('version', InputArgument::OPTIONAL, 'The version number (YYYYMMDDHHMMSS) or alias (first, prev, next, latest) to migrate to.', 'latest')
45 9
            ->addOption('write-sql', null, InputOption::VALUE_NONE, 'The path to output the migration SQL file instead of executing it.')
46 9
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Execute the migration as a dry run.')
47 9
            ->addOption('query-time', null, InputOption::VALUE_NONE, 'Time all the queries individually.')
48 9
            ->addOption('allow-no-migration', null, InputOption::VALUE_NONE, 'Don\'t throw an exception if no migration is available (CI).')
49 9
            ->setHelp(<<<EOT
50
The <info>%command.name%</info> command executes a migration to a specified version or the latest available version:
51
52
    <info>%command.full_name%</info>
53
54
You can optionally manually specify the version you wish to migrate to:
55
56
    <info>%command.full_name% YYYYMMDDHHMMSS</info>
57
58
You can specify the version you wish to migrate to using an alias:
59
60
    <info>%command.full_name% prev</info>
61
62
You can also execute the migration as a <comment>--dry-run</comment>:
63
64
    <info>%command.full_name% YYYYMMDDHHMMSS --dry-run</info>
65
66
You can output the would be executed SQL statements to a file with <comment>--write-sql</comment>:
67
68
    <info>%command.full_name% YYYYMMDDHHMMSS --write-sql</info>
69
70
Or you can also execute the migration without a warning message which you need to interact with:
71
72
    <info>%command.full_name% --no-interaction</info>
73
74
You can also time all the different queries if you wanna know which one is taking so long:
75
76
    <info>%command.full_name% --query-time</info>
77
EOT
78 9
        );
79
80 9
        parent::configure();
81 9
    }
82
83 1
    public function execute(InputInterface $input, OutputInterface $output)
84
    {
85 1
        $configuration = $this->getMigrationConfiguration($input, $output);
86 1
        $migration = new Migration($configuration);
87
88 1
        $this->outputHeader($configuration, $output);
89
90 1
        $timeAllqueries = $input->getOption('query-time');
91
92 1
        $executedMigrations = $configuration->getMigratedVersions();
93 1
        $availableMigrations = $configuration->getAvailableVersions();
94
95 1
        $version = $this->getVersionNameFromAlias($input->getArgument('version'), $output, $configuration);
96 1
        if ($version === false) {
97
            return 1;
98
        }
99
100 1
        $executedUnavailableMigrations = array_diff($executedMigrations, $availableMigrations);
101 1
        if (!empty($executedUnavailableMigrations)) {
102
            $output->writeln(sprintf(
103
                '<error>WARNING! You have %s previously executed migrations'
104
                . ' in the database that are not registered migrations.</error>',
105
                count($executedUnavailableMigrations)
106
            ));
107
108
            foreach ($executedUnavailableMigrations as $executedUnavailableMigration) {
109
                $output->writeln(sprintf(
110
                    '    <comment>>></comment> %s (<comment>%s</comment>)',
111
                    $configuration->getDateTime($executedUnavailableMigration),
112
                    $executedUnavailableMigration
113
                ));
114
            }
115
116
            $question = 'Are you sure you wish to continue? (y/n)';
117
            if (! $this->canExecute($question, $input, $output)) {
118
                $output->writeln('<error>Migration cancelled!</error>');
119
120
                return 1;
121
            }
122
        }
123
124 1
        if ($path = $input->getOption('write-sql')) {
125
            $path = is_bool($path) ? getcwd() : $path;
126
            $migration->writeSqlFile($path, $version);
127
        } else {
128 1
            $dryRun = (boolean) $input->getOption('dry-run');
129
130
            // warn the user if no dry run and interaction is on
131 1
            if (! $dryRun) {
132
                $question = 'WARNING! You are about to execute a database migration'
133
                    . ' that could result in schema changes and data lost.'
134 1
                    . ' Are you sure you wish to continue? (y/n)';
135 1
                if (! $this->canExecute($question, $input, $output)) {
136
                    $output->writeln('<error>Migration cancelled!</error>');
137
138
                    return 1;
139
                }
140 1
            }
141
142 1
            $migration->setNoMigrationException($input->getOption('allow-no-migration'));
143 1
            $sql = $migration->migrate($version, $dryRun, $timeAllqueries);
144
145 1
            if (empty($sql)) {
146
                $output->writeln('<comment>No migrations to execute.</comment>');
147
            }
148
        }
149 1
    }
150
151
    /**
152
     * @param string $question
153
     * @param InputInterface $input
154
     * @param OutputInterface $output
155
     * @return bool
156
     */
157 1
    private function canExecute($question, InputInterface $input, OutputInterface $output)
158
    {
159 1
        if ($input->isInteractive() && ! $this->askConfirmation($question, $input, $output)) {
160
            return false;
161
        }
162
163 1
        return true;
164
    }
165
166
    /**
167
     * @param string $versionAlias
168
     * @param OutputInterface $output
169
     * @param Configuration $configuration
170
     * @return bool|string
171
     */
172 2
    private function getVersionNameFromAlias($versionAlias, OutputInterface $output, Configuration $configuration)
173
    {
174 2
        $version = $configuration->resolveVersionAlias($versionAlias);
175 2
        if ($version === null) {
176 1
            if ($versionAlias == 'prev') {
177 1
                $output->writeln('<error>Already at first version.</error>');
178 1
                return false;
179
            }
180 1
            if ($versionAlias == 'next') {
181 1
                $output->writeln('<error>Already at latest version.</error>');
182 1
                return false;
183
            }
184
185 1
            $output->writeln(sprintf(
186 1
                '<error>Unknown version: %s</error>',
187 1
                $output->getFormatter()->escape($versionAlias)
188 1
            ));
189 1
            return false;
190
        }
191
192 2
        return $version;
193
    }
194
}
195