Completed
Pull Request — master (#968)
by Edi
02:42
created

DiffCommand::execute()   B

Complexity

Conditions 10
Paths 76

Size

Total Lines 85
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 10.4895

Importance

Changes 0
Metric Value
cc 10
eloc 53
nc 76
nop 2
dl 0
loc 85
ccs 44
cts 53
cp 0.8302
crap 10.4895
rs 7.1587
c 0
b 0
f 0

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 3
    protected function configure() : void
35
    {
36 3
        parent::configure();
37
38
        $this
39 3
            ->setAliases(['diff'])
40 3
            ->setDescription('Generate a migration by comparing your current database to your mapping information.')
41 3
            ->setHelp(<<<EOT
42 3
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 3
            ->addOption(
49 3
                'namespace',
50 3
                null,
51 3
                InputOption::VALUE_REQUIRED,
52 3
                'The namespace to use for the migration (must be in the list of configured namespaces)'
53
            )
54 3
            ->addOption(
55 3
                'filter-expression',
56 3
                null,
57 3
                InputOption::VALUE_REQUIRED,
58 3
                'Tables which are filtered by Regular Expression.'
59
            )
60 3
            ->addOption(
61 3
                'formatted',
62 3
                null,
63 3
                InputOption::VALUE_NONE,
64 3
                'Format the generated SQL.'
65
            )
66 3
            ->addOption(
67 3
                'line-length',
68 3
                null,
69 3
                InputOption::VALUE_REQUIRED,
70 3
                'Max line length of unformatted lines.',
71 3
                120
72
            )
73 3
            ->addOption(
74 3
                'check-database-platform',
75 3
                null,
76 3
                InputOption::VALUE_OPTIONAL,
77 3
                'Check Database Platform to the generated code.',
78 3
                false
79
            )
80 3
            ->addOption(
81 3
                'allow-empty-diff',
82 3
                null,
83 3
                InputOption::VALUE_NONE,
84 3
                'Do not throw an exception when no changes are detected.'
85
            );
86 3
    }
87
88
    /**
89
     * @throws InvalidOptionUsage
90
     */
91 3
    protected function execute(
92
        InputInterface $input,
93
        OutputInterface $output
94
    ) : int {
95 3
        $filterExpression = (string) $input->getOption('filter-expression');
96 3
        if ($filterExpression === '') {
97 2
            $filterExpression = null;
98
        }
99
100 3
        $formatted       = filter_var($input->getOption('formatted'), FILTER_VALIDATE_BOOLEAN);
101 3
        $lineLength      = (int) $input->getOption('line-length');
102 3
        $allowEmptyDiff  = $input->getOption('allow-empty-diff');
103 3
        $checkDbPlatform = filter_var($input->getOption('check-database-platform'), FILTER_VALIDATE_BOOLEAN);
104 3
        $namespace       = $input->getOption('namespace');
105 3
        if ($namespace === '') {
106
            $namespace = null;
107
        }
108
109 3
        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 3
        $configuration = $this->getDependencyFactory()->getConfiguration();
118
119 3
        $dirs = $configuration->getMigrationDirectories();
120 3
        if ($namespace === null) {
121 2
            $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 3
        assert(is_string($namespace));
127
128 3
        $statusCalculator              = $this->getDependencyFactory()->getMigrationStatusCalculator();
129 3
        $executedUnavailableMigrations = $statusCalculator->getExecutedUnavailableMigrations();
130 3
        $newMigrations                 = $statusCalculator->getNewMigrations();
131
132 3
        if (! $this->checkNewMigrationsOrExecutedUnavailable($newMigrations, $executedUnavailableMigrations, $input, $output)) {
133 2
            $this->io->error('Migration cancelled!');
134
135 2
            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 3
    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 3
        if (count($newMigrations) === 0 && count($executedUnavailableMigrations) === 0) {
185 1
            return true;
186
        }
187
188 2
        if (count($newMigrations) !== 0) {
189 2
            $this->io->warning(sprintf(
190 2
                'You have %d available migrations to execute.',
191 2
                count($newMigrations)
192
            ));
193
        }
194
195 2
        if (count($executedUnavailableMigrations) !== 0) {
196 1
            $this->io->warning(sprintf(
197 1
                'You have %d previously executed migrations in the database that are not registered migrations.',
198 1
                count($executedUnavailableMigrations)
199
            ));
200
        }
201
202 2
        return $this->canExecute('Are you sure you wish to continue?', $input);
203
    }
204
}
205