Completed
Pull Request — master (#973)
by Asmir
02:18
created

DiffCommand::execute()   B

Complexity

Conditions 10
Paths 76

Size

Total Lines 85
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 10.5186

Importance

Changes 0
Metric Value
cc 10
eloc 53
c 0
b 0
f 0
nc 76
nop 2
dl 0
loc 85
ccs 43
cts 52
cp 0.8269
crap 10.5186
rs 7.1587

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

124
            throw new OutOfBoundsException(sprintf('Path not defined for the namespace %s', /** @scrutinizer ignore-type */ $namespace));
Loading history...
125
        }
126 3
127
        assert(is_string($namespace));
128 3
129 3
        $statusCalculator              = $this->getDependencyFactory()->getMigrationStatusCalculator();
130 3
        $executedUnavailableMigrations = $statusCalculator->getExecutedUnavailableMigrations();
131
        $newMigrations                 = $statusCalculator->getNewMigrations();
132 3
133 2
        if (! $this->checkNewMigrationsOrExecutedUnavailable($newMigrations, $executedUnavailableMigrations, $input, $output)) {
134
            $this->io->error('Migration cancelled!');
135 2
136
            return 3;
137
        }
138 1
139
        $fqcn = $this->getDependencyFactory()->getClassNameGenerator()->generateClassName($namespace);
140 1
141
        $diffGenerator = $this->getDependencyFactory()->getDiffGenerator();
142
143 1
        try {
144 1
            $path = $diffGenerator->generate(
145 1
                $fqcn,
146 1
                $filterExpression,
147 1
                $formatted,
148 1
                $lineLength,
149
                $checkDbPlatform
150
            );
151
        } catch (NoChangesDetected $exception) {
152
            if ($allowEmptyDiff) {
153
                $this->io->error($exception->getMessage());
154
155
                return 0;
156
            }
157
158
            throw $exception;
159
        }
160 1
161 1
        $this->io->text([
162 1
            sprintf('Generated new migration class to "<info>%s</info>"', $path),
163 1
            '',
164 1
            sprintf(
165 1
                'To run just this migration for testing purposes, you can use <info>migrations:execute --up \'%s\'</info>',
166
                addslashes($fqcn)
167 1
            ),
168 1
            '',
169 1
            sprintf(
170 1
                'To revert the migration you can use <info>migrations:execute --down \'%s\'</info>',
171
                addslashes($fqcn)
172 1
            ),
173
            '',
174
        ]);
175 1
176
        return 0;
177
    }
178 3
179
    private function checkNewMigrationsOrExecutedUnavailable(
180
        AvailableMigrationsList $newMigrations,
181
        ExecutedMigrationsSet $executedUnavailableMigrations,
182
        InputInterface $input,
183
        OutputInterface $output
0 ignored issues
show
Unused Code introduced by
The parameter $output is not used and could be removed. ( Ignorable by Annotation )

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

183
        /** @scrutinizer ignore-unused */ OutputInterface $output

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
184 3
    ) : bool {
185 1
        if (count($newMigrations) === 0 && count($executedUnavailableMigrations) === 0) {
186
            return true;
187
        }
188 2
189 2
        if (count($newMigrations) !== 0) {
190 2
            $this->io->warning(sprintf(
191 2
                'You have %d available migrations to execute.',
192
                count($newMigrations)
193
            ));
194
        }
195 2
196 1
        if (count($executedUnavailableMigrations) !== 0) {
197 1
            $this->io->warning(sprintf(
198 1
                'You have %d previously executed migrations in the database that are not registered migrations.',
199
                count($executedUnavailableMigrations)
200
            ));
201
        }
202 2
203
        return $this->canExecute('Are you sure you wish to continue?', $input);
204
    }
205
}
206