Passed
Pull Request — master (#739)
by Michael
02:38
created

VersionCommand::mark()   B

Complexity

Conditions 10
Paths 16

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 10.0578

Importance

Changes 0
Metric Value
cc 10
nc 16
nop 3
dl 0
loc 43
ccs 22
cts 24
cp 0.9167
crap 10.0578
rs 7.6666
c 0
b 0
f 0

How to fix   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 22
    protected function configure() : void
26
    {
27
        $this
28 22
            ->setName('migrations:version')
29 22
            ->setAliases(['version'])
30 22
            ->setDescription('Manually add and delete migration versions from the version table.')
31 22
            ->addArgument(
32 22
                'version',
33 22
                InputArgument::OPTIONAL,
34 22
                'The version to add or delete.',
35 22
                null
36
            )
37 22
            ->addOption(
38 22
                'add',
39 22
                null,
40 22
                InputOption::VALUE_NONE,
41 22
                'Add the specified version.'
42
            )
43 22
            ->addOption(
44 22
                'delete',
45 22
                null,
46 22
                InputOption::VALUE_NONE,
47 22
                'Delete the specified version.'
48
            )
49 22
            ->addOption(
50 22
                'all',
51 22
                null,
52 22
                InputOption::VALUE_NONE,
53 22
                'Apply to all the versions.'
54
            )
55 22
            ->addOption(
56 22
                'range-from',
57 22
                null,
58 22
                InputOption::VALUE_OPTIONAL,
59 22
                'Apply from specified version.'
60
            )
61 22
            ->addOption(
62 22
                'range-to',
63 22
                null,
64 22
                InputOption::VALUE_OPTIONAL,
65 22
                'Apply to specified version.'
66
            )
67 22
            ->setHelp(<<<EOT
68 22
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 22
        parent::configure();
93 22
    }
94
95
    /**
96
     * @throws InvalidOptionUsage
97
     */
98 12
    public function execute(InputInterface $input, OutputInterface $output) : ?int
99
    {
100 12
        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 12
        $this->markMigrated = (bool) $input->getOption('add');
105
106 12
        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 12
            $this->markVersions($input, $output);
118
        }
119
120 6
        return 0;
121
    }
122
123
    /**
124
     * @throws InvalidOptionUsage
125
     */
126 12
    private function markVersions(InputInterface $input, OutputInterface $output) : void
127
    {
128 12
        $affectedVersion = $input->getArgument('version');
129 12
        $allOption       = $input->getOption('all');
130 12
        $rangeFromOption = $input->getOption('range-from');
131 12
        $rangeToOption   = $input->getOption('range-to');
132
133 12
        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 10
        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 8
        if ($allOption === true) {
146 2
            $availableVersions = $this->migrationRepository->getAvailableVersions();
147
148 2
            foreach ($availableVersions as $version) {
149 2
                $this->mark($output, $version, true);
150
            }
151 6
        } 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($output, $version, true);
160
            }
161
        } else {
162 4
            $this->mark($output, $affectedVersion);
163
        }
164 6
    }
165
166
    /**
167
     * @throws VersionAlreadyExists
168
     * @throws VersionDoesNotExist
169
     * @throws UnknownMigrationVersion
170
     */
171 8
    private function mark(OutputInterface $output, string $version, bool $all = false) : void
172
    {
173 8
        if (! $this->migrationRepository->hasVersion($version)) {
174
            throw UnknownMigrationVersion::new($version);
175
        }
176
177 8
        $version = $this->migrationRepository->getVersion($version);
178
179 8
        $marked = false;
180
181 8
        if ($this->markMigrated && $this->migrationRepository->hasVersionMigrated($version)) {
182 1
            if (! $all) {
183 1
                throw VersionAlreadyExists::new($version);
184
            }
185
186
            $marked = true;
187
        }
188
189 7
        if (! $this->markMigrated && ! $this->migrationRepository->hasVersionMigrated($version)) {
190 3
            if (! $all) {
191 1
                throw VersionDoesNotExist::new($version);
192
            }
193
194 2
            $marked = true;
195
        }
196
197 6
        if ($marked === true) {
198 2
            return;
199
        }
200
201 6
        if ($this->markMigrated) {
202 3
            $version->markMigrated();
203
204 3
            $output->writeln(sprintf(
205 3
                '<info>%s</info> added to the version table.',
206 3
                $version->getVersion()
207
            ));
208
        } else {
209 3
            $version->markNotMigrated();
210
211 3
            $output->writeln(sprintf(
212 3
                '<info>%s</info> deleted from the version table.',
213 3
                $version->getVersion()
214
            ));
215
        }
216 6
    }
217
}
218