checkNewMigrationsOrExecutedUnavailable()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 12
cts 12
cp 1
rs 9.1928
c 0
b 0
f 0
cc 5
nc 5
nop 4
crap 5
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\ExecutedMigrationsList;
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
35 3 View Code Duplication
    protected function configure() : void
36
    {
37 3
        parent::configure();
38
39
        $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 3
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
            )
49 3
            ->addOption(
50 3
                'namespace',
51 3
                null,
52 3
                InputOption::VALUE_REQUIRED,
53 3
                'The namespace to use for the migration (must be in the list of configured namespaces)'
54
            )
55 3
            ->addOption(
56 3
                'filter-expression',
57 3
                null,
58 3
                InputOption::VALUE_REQUIRED,
59 3
                'Tables which are filtered by Regular Expression.'
60
            )
61 3
            ->addOption(
62 3
                'formatted',
63 3
                null,
64 3
                InputOption::VALUE_NONE,
65 3
                'Format the generated SQL.'
66
            )
67 3
            ->addOption(
68 3
                'line-length',
69 3
                null,
70 3
                InputOption::VALUE_REQUIRED,
71 3
                'Max line length of unformatted lines.',
72 3
                120
73
            )
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 3
                false
80
            )
81 3
            ->addOption(
82 3
                'allow-empty-diff',
83 3
                null,
84 3
                InputOption::VALUE_NONE,
85 3
                'Do not throw an exception when no changes are detected.'
86
            );
87 3
    }
88
89
    /**
90
     * @throws InvalidOptionUsage
91
     */
92 3
    protected function execute(
93
        InputInterface $input,
94
        OutputInterface $output
95
    ) : int {
96 3
        $filterExpression = (string) $input->getOption('filter-expression');
97 3
        if ($filterExpression === '') {
98 2
            $filterExpression = null;
99
        }
100
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 3
        if ($namespace === '') {
107
            $namespace = null;
108
        }
109
110 3
        if ($formatted) {
111 1
            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
118 3
        $configuration = $this->getDependencyFactory()->getConfiguration();
119
120 3
        $dirs = $configuration->getMigrationDirectories();
121 3 View Code Duplication
        if ($namespace === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
122 2
            $namespace = key($dirs);
123 1
        } elseif (! isset($dirs[$namespace])) {
124
            throw new OutOfBoundsException(sprintf('Path not defined for the namespace %s', $namespace));
125
        }
126
127 3
        assert(is_string($namespace));
128
129 3
        $statusCalculator              = $this->getDependencyFactory()->getMigrationStatusCalculator();
130 3
        $executedUnavailableMigrations = $statusCalculator->getExecutedUnavailableMigrations();
131 3
        $newMigrations                 = $statusCalculator->getNewMigrations();
132
133 3
        if (! $this->checkNewMigrationsOrExecutedUnavailable($newMigrations, $executedUnavailableMigrations, $input, $output)) {
134 2
            $this->io->error('Migration cancelled!');
135
136 2
            return 3;
137
        }
138
139 1
        $fqcn = $this->getDependencyFactory()->getClassNameGenerator()->generateClassName($namespace);
140
141 1
        $diffGenerator = $this->getDependencyFactory()->getDiffGenerator();
142
143
        try {
144 1
            $path = $diffGenerator->generate(
145 1
                $fqcn,
146 1
                $filterExpression,
147 1
                $formatted,
148 1
                $lineLength,
149 1
                $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
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 1
                addslashes($fqcn)
167
            ),
168 1
            '',
169 1
            sprintf(
170 1
                'To revert the migration you can use <info>migrations:execute --down \'%s\'</info>',
171 1
                addslashes($fqcn)
172
            ),
173 1
            '',
174
        ]);
175
176 1
        return 0;
177
    }
178
179 3
    private function checkNewMigrationsOrExecutedUnavailable(
180
        AvailableMigrationsList $newMigrations,
181
        ExecutedMigrationsList $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.

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

Loading history...
184
    ) : bool {
185 3
        if (count($newMigrations) === 0 && count($executedUnavailableMigrations) === 0) {
186 1
            return true;
187
        }
188
189 2
        if (count($newMigrations) !== 0) {
190 2
            $this->io->warning(sprintf(
191 2
                'You have %d available migrations to execute.',
192 2
                count($newMigrations)
193
            ));
194
        }
195
196 2
        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 1
                count($executedUnavailableMigrations)
200
            ));
201
        }
202
203 2
        return $this->canExecute('Are you sure you wish to continue?', $input);
204
    }
205
}
206