Failed Conditions
Pull Request — master (#968)
by Edi
02:04
created

DiffCommand::execute()   B

Complexity

Conditions 10
Paths 76

Size

Total Lines 85
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 11.476

Importance

Changes 0
Metric Value
cc 10
eloc 53
c 0
b 0
f 0
nc 76
nop 2
dl 0
loc 85
ccs 40
cts 53
cp 0.7547
crap 11.476
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 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 1
    protected function configure() : void
35
    {
36 1
        parent::configure();
37
38
        $this
39 1
            ->setAliases(['diff'])
40 1
            ->setDescription('Generate a migration by comparing your current database to your mapping information.')
41 1
            ->setHelp(<<<EOT
42 1
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 1
            ->addOption(
49 1
                'namespace',
50 1
                null,
51 1
                InputOption::VALUE_REQUIRED,
52 1
                'The namespace to use for the migration (must be in the list of configured namespaces)'
53
            )
54 1
            ->addOption(
55 1
                'filter-expression',
56 1
                null,
57 1
                InputOption::VALUE_REQUIRED,
58 1
                'Tables which are filtered by Regular Expression.'
59
            )
60 1
            ->addOption(
61 1
                'formatted',
62 1
                null,
63 1
                InputOption::VALUE_NONE,
64 1
                'Format the generated SQL.'
65
            )
66 1
            ->addOption(
67 1
                'line-length',
68 1
                null,
69 1
                InputOption::VALUE_REQUIRED,
70 1
                'Max line length of unformatted lines.',
71 1
                120
72
            )
73 1
            ->addOption(
74 1
                'check-database-platform',
75 1
                null,
76 1
                InputOption::VALUE_OPTIONAL,
77 1
                'Check Database Platform to the generated code.',
78 1
                false
79
            )
80 1
            ->addOption(
81 1
                'allow-empty-diff',
82 1
                null,
83 1
                InputOption::VALUE_NONE,
84 1
                'Do not throw an exception when no changes are detected.'
85
            );
86 1
    }
87
88
    /**
89
     * @throws InvalidOptionUsage
90
     */
91 1
    protected function execute(
92
        InputInterface $input,
93
        OutputInterface $output
94
    ) : int {
95 1
        $filterExpression = (string) $input->getOption('filter-expression');
96 1
        if ($filterExpression === '') {
97
            $filterExpression = null;
98
        }
99
100 1
        $formatted       = filter_var($input->getOption('formatted'), FILTER_VALIDATE_BOOLEAN);
101 1
        $lineLength      = (int) $input->getOption('line-length');
102 1
        $allowEmptyDiff  = $input->getOption('allow-empty-diff');
103 1
        $checkDbPlatform = filter_var($input->getOption('check-database-platform'), FILTER_VALIDATE_BOOLEAN);
104 1
        $namespace       = $input->getOption('namespace');
105 1
        if ($namespace === '') {
106
            $namespace = null;
107
        }
108
109 1
        if ($formatted) {
110 1
            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 1
        $configuration = $this->getDependencyFactory()->getConfiguration();
118
119 1
        $dirs = $configuration->getMigrationDirectories();
120 1
        if ($namespace === null) {
121
            $namespace = key($dirs);
122 1
        } 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 1
        assert(is_string($namespace));
127
128 1
        $statusCalculator              = $this->getDependencyFactory()->getMigrationStatusCalculator();
129 1
        $executedUnavailableMigrations = $statusCalculator->getExecutedUnavailableMigrations();
130 1
        $newMigrations                 = $statusCalculator->getNewMigrations();
131
132 1
        if (! $this->checkNewMigrationsOrExecutedUnavailable($newMigrations, $executedUnavailableMigrations, $input, $output)) {
133
            $this->io->error('Migration cancelled!');
134
135
            return 3;
136
        }
137
138 1
        $fqcn = $this->getDependencyFactory()->getClassNameGenerator()->generateClassName($namespace);
139
140 1
        $diffGenerator = $this->getDependencyFactory()->getDiffGenerator();
141
142
        try {
143 1
            $path = $diffGenerator->generate(
144 1
                $fqcn,
145 1
                $filterExpression,
146 1
                $formatted,
147 1
                $lineLength,
148 1
                $checkDbPlatform
149
            );
150
        } catch (NoChangesDetected $exception) {
151
            if ($allowEmptyDiff) {
152
                $this->io->error($exception->getMessage());
153
154
                return 0;
155
            }
156
157
            throw $exception;
158
        }
159
160 1
        $this->io->text([
161 1
            sprintf('Generated new migration class to "<info>%s</info>"', $path),
162 1
            '',
163 1
            sprintf(
164 1
                'To run just this migration for testing purposes, you can use <info>migrations:execute --up \'%s\'</info>',
165 1
                addslashes($fqcn)
166
            ),
167 1
            '',
168 1
            sprintf(
169 1
                'To revert the migration you can use <info>migrations:execute --down \'%s\'</info>',
170 1
                addslashes($fqcn)
171
            ),
172 1
            '',
173
        ]);
174
175 1
        return 0;
176
    }
177
178 1
    private function checkNewMigrationsOrExecutedUnavailable(
179
        AvailableMigrationsList $newMigrations,
180
        ExecutedMigrationsSet $executedUnavailableMigrations,
181
        InputInterface $input,
182
        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

182
        /** @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...
183
    ) : bool {
184 1
        if (count($newMigrations) === 0 && count($executedUnavailableMigrations) === 0) {
185 1
            return true;
186
        }
187
188
        if (count($newMigrations) !== 0) {
189
            $this->io->error(sprintf(
190
                'WARNING! You have %d available migrations to execute.',
191
                count($newMigrations)
192
            ));
193
        }
194
195
        if (count($executedUnavailableMigrations) !== 0) {
196
            $this->io->error(sprintf(
197
                'WARNING! You have %d previously executed migrations in the database that are not registered migrations.',
198
                count($executedUnavailableMigrations)
199
            ));
200
        }
201
202
        return $this->canExecute('Are you sure you wish to continue?', $input);
203
    }
204
}
205