Completed
Pull Request — master (#971)
by Grégoire
03:53
created

DiffCommand::execute()   B

Complexity

Conditions 10
Paths 76

Size

Total Lines 84
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 29.2

Importance

Changes 0
Metric Value
cc 10
eloc 52
c 0
b 0
f 0
nc 76
nop 2
dl 0
loc 84
ccs 22
cts 52
cp 0.4231
crap 29.2
rs 7.1806

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
declare(strict_types=1);
4
5
namespace Doctrine\Migrations\Tools\Console\Command;
6
7
use Doctrine\Migrations\Generator\Exception\NoChangesDetected;
8
use Doctrine\Migrations\Metadata\AvailableMigrationsList;
9
use Doctrine\Migrations\Metadata\ExecutedMigrationsSet;
10
use Doctrine\Migrations\Tools\Console\Exception\InvalidOptionUsage;
11
use OutOfBoundsException;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Input\InputOption;
14
use Symfony\Component\Console\Output\OutputInterface;
15
use function addslashes;
16
use function assert;
17
use function class_exists;
18
use function count;
19
use function filter_var;
20
use function is_string;
21
use function key;
22
use function sprintf;
23
use const FILTER_VALIDATE_BOOLEAN;
24
25
/**
26
 * The DiffCommand class is responsible for generating a migration by comparing your current database schema to
27
 * your mapping information.
28
 */
29
final class DiffCommand extends DoctrineCommand
30
{
31
    /** @var string */
32
    protected static $defaultName = 'migrations:diff';
33
34 2
    protected function configure() : void
35
    {
36 2
        parent::configure();
37
38
        $this
39 2
            ->setAliases(['diff'])
40 2
            ->setDescription('Generate a migration by comparing your current database to your mapping information.')
41 2
            ->setHelp(<<<EOT
42 2
The <info>%command.name%</info> command generates a migration by comparing your current database to your mapping information:
43
44
    <info>%command.full_name%</info>
45
46
EOT
47
            )
48 2
            ->addOption(
49 2
                'namespace',
50 2
                null,
51 2
                InputOption::VALUE_REQUIRED,
52 2
                'The namespace to use for the migration (must be in the list of configured namespaces)'
53
            )
54 2
            ->addOption(
55 2
                'filter-expression',
56 2
                null,
57 2
                InputOption::VALUE_REQUIRED,
58 2
                'Tables which are filtered by Regular Expression.'
59
            )
60 2
            ->addOption(
61 2
                'formatted',
62 2
                null,
63 2
                InputOption::VALUE_NONE,
64 2
                'Format the generated SQL.'
65
            )
66 2
            ->addOption(
67 2
                'line-length',
68 2
                null,
69 2
                InputOption::VALUE_REQUIRED,
70 2
                'Max line length of unformatted lines.',
71 2
                120
72
            )
73 2
            ->addOption(
74 2
                'check-database-platform',
75 2
                null,
76 2
                InputOption::VALUE_OPTIONAL,
77 2
                'Check Database Platform to the generated code.',
78 2
                false
79
            )
80 2
            ->addOption(
81 2
                'allow-empty-diff',
82 2
                null,
83 2
                InputOption::VALUE_NONE,
84 2
                'Do not throw an exception when no changes are detected.'
85
            );
86 2
    }
87
88
    /**
89
     * @throws InvalidOptionUsage
90
     */
91 2
    protected function execute(
92
        InputInterface $input,
93
        OutputInterface $output
94
    ) : int {
95 2
        $filterExpression = (string) $input->getOption('filter-expression');
96 2
        if ($filterExpression === '') {
97 2
            $filterExpression = null;
98
        }
99
100 2
        $formatted       = filter_var($input->getOption('formatted'), FILTER_VALIDATE_BOOLEAN);
101 2
        $lineLength      = (int) $input->getOption('line-length');
102 2
        $allowEmptyDiff  = $input->getOption('allow-empty-diff');
103 2
        $checkDbPlatform = filter_var($input->getOption('check-database-platform'), FILTER_VALIDATE_BOOLEAN);
104 2
        $namespace       = $input->getOption('namespace');
105 2
        if ($namespace === '') {
106
            $namespace = null;
107
        }
108
109 2
        if ($formatted) {
110
            if (! class_exists('SqlFormatter')) {
111
                throw InvalidOptionUsage::new(
112
                    'The "--formatted" option can only be used if the sql formatter is installed. Please run "composer require jdorn/sql-formatter".'
113
                );
114
            }
115
        }
116
117 2
        $configuration = $this->getDependencyFactory()->getConfiguration();
118
119 2
        $dirs = $configuration->getMigrationDirectories();
120 2
        if ($namespace === null) {
121 2
            $namespace = key($dirs);
122
        } elseif (! isset($dirs[$namespace])) {
123
            throw new OutOfBoundsException(sprintf('Path not defined for the namespace %s', $namespace));
0 ignored issues
show
Bug introduced by
It seems like $namespace can also be of type string[]; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

123
            throw new OutOfBoundsException(sprintf('Path not defined for the namespace %s', /** @scrutinizer ignore-type */ $namespace));
Loading history...
124
        }
125
126 2
        assert(is_string($namespace));
127
128 2
        $statusCalculator              = $this->getDependencyFactory()->getMigrationStatusCalculator();
129 2
        $executedUnavailableMigrations = $statusCalculator->getExecutedUnavailableMigrations();
130 2
        $newMigrations                 = $statusCalculator->getNewMigrations();
131
132 2
        if (! $this->checkNewMigrationsOrExecutedUnavailable($newMigrations, $executedUnavailableMigrations, $input, $output)) {
133 2
            $output->writeln('<error>Migration cancelled!</error>');
134
135 2
            return 3;
136
        }
137
138
        $fqcn = $this->getDependencyFactory()->getClassNameGenerator()->generateClassName($namespace);
139
140
        $diffGenerator = $this->getDependencyFactory()->getDiffGenerator();
141
142
        try {
143
            $path = $diffGenerator->generate(
144
                $fqcn,
145
                $filterExpression,
146
                $formatted,
147
                $lineLength,
148
                $checkDbPlatform
149
            );
150
        } catch (NoChangesDetected $exception) {
151
            if ($allowEmptyDiff) {
152
                $output->writeln($exception->getMessage());
153
154
                return 0;
155
            }
156
157
            throw $exception;
158
        }
159
160
        $output->writeln([
161
            sprintf('Generated new migration class to "<info>%s</info>"', $path),
162
            '',
163
            sprintf(
164
                'To run just this migration for testing purposes, you can use <info>migrations:execute --up \'%s\'</info>',
165
                addslashes($fqcn)
166
            ),
167
            '',
168
            sprintf(
169
                'To revert the migration you can use <info>migrations:execute --down \'%s\'</info>',
170
                addslashes($fqcn)
171
            ),
172
        ]);
173
174
        return 0;
175
    }
176
177 2
    private function checkNewMigrationsOrExecutedUnavailable(
178
        AvailableMigrationsList $newMigrations,
179
        ExecutedMigrationsSet $executedUnavailableMigrations,
180
        InputInterface $input,
181
        OutputInterface $output
182
    ) : bool {
183 2
        if (count($newMigrations) === 0 && count($executedUnavailableMigrations) === 0) {
184
            return true;
185
        }
186
187 2
        if (count($newMigrations) !== 0) {
188 2
            $output->writeln(sprintf(
189 2
                '<error>WARNING! You have %d available migrations to execute.</error>',
190 2
                count($newMigrations)
191
            ));
192
        }
193
194 2
        if (count($executedUnavailableMigrations) !== 0) {
195 1
            $output->writeln(sprintf(
196 1
                '<error>WARNING! You have %d previously executed migrations in the database that are not registered migrations.</error>',
197 1
                count($executedUnavailableMigrations)
198
            ));
199
        }
200
201 2
        return $this->canExecute('Are you sure you wish to continue? (y/n)', $input, $output);
202
    }
203
}
204