Completed
Push — master ( 0854ed...7daeea )
by Jonathan
01:35 queued 01:34
created

VersionCommand::mark()   C

Complexity

Conditions 12
Paths 32

Size

Total Lines 62
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 12.032

Importance

Changes 0
Metric Value
cc 12
eloc 35
nc 32
nop 4
dl 0
loc 62
ccs 31
cts 33
cp 0.9394
crap 12.032
rs 6.9666
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\Exception\UnknownMigrationVersion;
8
use Doctrine\Migrations\Tools\Console\Exception\InvalidOptionUsage;
9
use Doctrine\Migrations\Tools\Console\Exception\VersionAlreadyExists;
10
use Doctrine\Migrations\Tools\Console\Exception\VersionDoesNotExist;
11
use Symfony\Component\Console\Input\InputArgument;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Input\InputOption;
14
use Symfony\Component\Console\Output\OutputInterface;
15
use function sprintf;
16
17
/**
18
 * The VersionCommand class is responsible for manually adding and deleting migration versions from the tracking table.
19
 */
20
class VersionCommand extends AbstractCommand
21
{
22
    /** @var bool */
23
    private $markMigrated;
24
25 23
    protected function configure() : void
26
    {
27
        $this
28 23
            ->setName('migrations:version')
29 23
            ->setAliases(['version'])
30 23
            ->setDescription('Manually add and delete migration versions from the version table.')
31 23
            ->addArgument(
32 23
                'version',
33 23
                InputArgument::OPTIONAL,
34 23
                'The version to add or delete.',
35 23
                null
36
            )
37 23
            ->addOption(
38 23
                'add',
39 23
                null,
40 23
                InputOption::VALUE_NONE,
41 23
                'Add the specified version.'
42
            )
43 23
            ->addOption(
44 23
                'delete',
45 23
                null,
46 23
                InputOption::VALUE_NONE,
47 23
                'Delete the specified version.'
48
            )
49 23
            ->addOption(
50 23
                'all',
51 23
                null,
52 23
                InputOption::VALUE_NONE,
53 23
                'Apply to all the versions.'
54
            )
55 23
            ->addOption(
56 23
                'range-from',
57 23
                null,
58 23
                InputOption::VALUE_OPTIONAL,
59 23
                'Apply from specified version.'
60
            )
61 23
            ->addOption(
62 23
                'range-to',
63 23
                null,
64 23
                InputOption::VALUE_OPTIONAL,
65 23
                'Apply to specified version.'
66
            )
67 23
            ->setHelp(<<<EOT
68 23
The <info>%command.name%</info> command allows you to manually add, delete or synchronize migration versions from the version table:
69
70
    <info>%command.full_name% YYYYMMDDHHMMSS --add</info>
71
72
If you want to delete a version you can use the <comment>--delete</comment> option:
73
74
    <info>%command.full_name% YYYYMMDDHHMMSS --delete</info>
75
76
If you want to synchronize by adding or deleting all migration versions available in the version table you can use the <comment>--all</comment> option:
77
78
    <info>%command.full_name% --add --all</info>
79
    <info>%command.full_name% --delete --all</info>
80
81
If you want to synchronize by adding or deleting some range of migration versions available in the version table you can use the <comment>--range-from/--range-to</comment> option:
82
83
    <info>%command.full_name% --add --range-from=YYYYMMDDHHMMSS --range-to=YYYYMMDDHHMMSS</info>
84
    <info>%command.full_name% --delete --range-from=YYYYMMDDHHMMSS --range-to=YYYYMMDDHHMMSS</info>
85
86
You can also execute this command without a warning message which you need to interact with:
87
88
    <info>%command.full_name% --no-interaction</info>
89
EOT
90
            );
91
92 23
        parent::configure();
93 23
    }
94
95
    /**
96
     * @throws InvalidOptionUsage
97
     */
98 13
    public function execute(InputInterface $input, OutputInterface $output) : ?int
99
    {
100 13
        if ($input->getOption('add') === false && $input->getOption('delete') === false) {
101
            throw InvalidOptionUsage::new('You must specify whether you want to --add or --delete the specified version.');
102
        }
103
104 13
        $this->markMigrated = (bool) $input->getOption('add');
105
106 13
        if ($input->isInteractive()) {
107
            $question = 'WARNING! You are about to add, delete or synchronize migration versions from the version table that could result in data lost. Are you sure you wish to continue? (y/n)';
108
109
            $confirmation = $this->askConfirmation($question, $input, $output);
110
111
            if ($confirmation) {
112
                $this->markVersions($input, $output);
113
            } else {
114
                $output->writeln('<error>Migration cancelled!</error>');
115
            }
116
        } else {
117 13
            $this->markVersions($input, $output);
118
        }
119
120 7
        return 0;
121
    }
122
123
    /**
124
     * @throws InvalidOptionUsage
125
     */
126 13
    private function markVersions(InputInterface $input, OutputInterface $output) : void
127
    {
128 13
        $affectedVersion = $input->getArgument('version');
129 13
        $allOption       = $input->getOption('all');
130 13
        $rangeFromOption = $input->getOption('range-from');
131 13
        $rangeToOption   = $input->getOption('range-to');
132
133 13
        if ($allOption === true && ($rangeFromOption !== null || $rangeToOption !== null)) {
134 2
            throw InvalidOptionUsage::new(
135 2
                'Options --all and --range-to/--range-from both used. You should use only one of them.'
136
            );
137
        }
138
139 11
        if ($rangeFromOption !== null xor $rangeToOption !== null) {
140 2
            throw InvalidOptionUsage::new(
141 2
                'Options --range-to and --range-from should be used together.'
142
            );
143
        }
144
145 9
        if ($allOption === true) {
146 2
            $availableVersions = $this->migrationRepository->getAvailableVersions();
147
148 2
            foreach ($availableVersions as $version) {
149 2
                $this->mark($input, $output, $version, true);
150
            }
151 7
        } elseif ($rangeFromOption !== null && $rangeToOption !== null) {
152 2
            $availableVersions = $this->migrationRepository->getAvailableVersions();
153
154 2
            foreach ($availableVersions as $version) {
155 2
                if ($version < $rangeFromOption || $version > $rangeToOption) {
156 2
                    continue;
157
                }
158
159 2
                $this->mark($input, $output, $version, true);
160
            }
161
        } else {
162 5
            $this->mark($input, $output, $affectedVersion);
163
        }
164 7
    }
165
166
    /**
167
     * @throws VersionAlreadyExists
168
     * @throws VersionDoesNotExist
169
     * @throws UnknownMigrationVersion
170
     */
171 9
    private function mark(InputInterface $input, OutputInterface $output, string $version, bool $all = false) : void
172
    {
173 9
        if (! $this->migrationRepository->hasVersion($version)) {
174 1
            if ((bool) $input->getOption('delete') === false) {
175
                throw UnknownMigrationVersion::new($version);
176
            }
177
178
            $question =
179
                'WARNING! You are about to delete a migration version from the version table that has no corresponding migration file.' .
180 1
                'Do you want to delete this migration from the migrations table? (y/n)';
181
182 1
            $confirmation = $this->askConfirmation($question, $input, $output);
183
184 1
            if ($confirmation) {
185 1
                $this->migrationRepository->removeMigrationVersionFromDatabase($version);
186
187 1
                $output->writeln(sprintf(
188 1
                    '<info>%s</info> deleted from the version table.',
189 1
                    $version
190
                ));
191
192 1
                return;
193
            }
194
        }
195
196 8
        $version = $this->migrationRepository->getVersion($version);
197
198 8
        $marked = false;
199
200 8
        if ($this->markMigrated && $this->migrationRepository->hasVersionMigrated($version)) {
201 1
            if (! $all) {
202 1
                throw VersionAlreadyExists::new($version);
203
            }
204
205
            $marked = true;
206
        }
207
208 7
        if (! $this->markMigrated && ! $this->migrationRepository->hasVersionMigrated($version)) {
209 3
            if (! $all) {
210 1
                throw VersionDoesNotExist::new($version);
211
            }
212
213 2
            $marked = true;
214
        }
215
216 6
        if ($marked === true) {
217 2
            return;
218
        }
219
220 6
        if ($this->markMigrated) {
221 3
            $version->markMigrated();
222
223 3
            $output->writeln(sprintf(
224 3
                '<info>%s</info> added to the version table.',
225 3
                $version->getVersion()
226
            ));
227
        } else {
228 3
            $version->markNotMigrated();
229
230 3
            $output->writeln(sprintf(
231 3
                '<info>%s</info> deleted from the version table.',
232 3
                $version->getVersion()
233
            ));
234
        }
235 6
    }
236
}
237