Failed Conditions
Pull Request — master (#632)
by Michael
02:44
created

VersionCommand::mark()   D

Complexity

Conditions 10
Paths 16

Size

Total Lines 38
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 10.1

Importance

Changes 0
Metric Value
cc 10
eloc 20
nc 16
nop 2
dl 0
loc 38
ccs 18
cts 20
cp 0.9
crap 10.1
rs 4.8196
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\Configuration\Configuration;
8
use Doctrine\Migrations\MigrationException;
9
use InvalidArgumentException;
10
use Symfony\Component\Console\Input\InputArgument;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputOption;
13
use Symfony\Component\Console\Output\OutputInterface;
14
use function sprintf;
15
16
class VersionCommand extends AbstractCommand
17
{
18
    /** @var Configuration */
19
    private $configuration;
20
21
    /** @var bool */
22
    private $markMigrated;
23
24 20
    protected function configure() : void
25
    {
26
        $this
27 20
            ->setName('migrations:version')
28 20
            ->setDescription('Manually add and delete migration versions from the version table.')
29 20
            ->addArgument(
30 20
                'version',
31 20
                InputArgument::OPTIONAL,
32 20
                'The version to add or delete.',
33 20
                null
34
            )
35 20
            ->addOption(
36 20
                'add',
37 20
                null,
38 20
                InputOption::VALUE_NONE,
39 20
                'Add the specified version.'
40
            )
41 20
            ->addOption(
42 20
                'delete',
43 20
                null,
44 20
                InputOption::VALUE_NONE,
45 20
                'Delete the specified version.'
46
            )
47 20
            ->addOption(
48 20
                'all',
49 20
                null,
50 20
                InputOption::VALUE_NONE,
51 20
                'Apply to all the versions.'
52
            )
53 20
            ->addOption(
54 20
                'range-from',
55 20
                null,
56 20
                InputOption::VALUE_OPTIONAL,
57 20
                'Apply from specified version.'
58
            )
59 20
            ->addOption(
60 20
                'range-to',
61 20
                null,
62 20
                InputOption::VALUE_OPTIONAL,
63 20
                'Apply to specified version.'
64
            )
65 20
            ->setHelp(<<<EOT
66 20
The <info>%command.name%</info> command allows you to manually add, delete or synchronize migration versions from the version table:
67
68
    <info>%command.full_name% YYYYMMDDHHMMSS --add</info>
69
70
If you want to delete a version you can use the <comment>--delete</comment> option:
71
72
    <info>%command.full_name% YYYYMMDDHHMMSS --delete</info>
73
74
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:
75
76
    <info>%command.full_name% --add --all</info>
77
    <info>%command.full_name% --delete --all</info>
78
79
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:
80
81
    <info>%command.full_name% --add --range-from=YYYYMMDDHHMMSS --range-to=YYYYMMDDHHMMSS</info>
82
    <info>%command.full_name% --delete --range-from=YYYYMMDDHHMMSS --range-to=YYYYMMDDHHMMSS</info>
83
84
You can also execute this command without a warning message which you need to interact with:
85
86
    <info>%command.full_name% --no-interaction</info>
87
EOT
88
            );
89
90 20
        parent::configure();
91 20
    }
92
93 12
    public function execute(InputInterface $input, OutputInterface $output) : void
94
    {
95 12
        $this->configuration = $this->getMigrationConfiguration($input, $output);
96
97 12
        if (! $input->getOption('add') && ! $input->getOption('delete')) {
98
            throw new InvalidArgumentException(
99
                'You must specify whether you want to --add or --delete the specified version.'
100
            );
101
        }
102
103 12
        $this->markMigrated = (bool) $input->getOption('add');
104
105 12
        if ($input->isInteractive()) {
106
            $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)';
107
108
            $confirmation = $this->askConfirmation($question, $input, $output);
109
110
            if ($confirmation) {
111
                $this->markVersions($input);
112
            } else {
113
                $output->writeln('<error>Migration cancelled!</error>');
114
            }
115
        } else {
116 12
            $this->markVersions($input);
117
        }
118 6
    }
119
120
    /**
121
     * @throws InvalidArgumentException
122
     * @throws MigrationException
123
     */
124 12
    private function markVersions(InputInterface $input) : void
125
    {
126 12
        $affectedVersion = $input->getArgument('version');
127
128 12
        $allOption       = $input->getOption('all');
129 12
        $rangeFromOption = $input->getOption('range-from');
130 12
        $rangeToOption   = $input->getOption('range-to');
131
132 12
        if ($allOption && ($rangeFromOption !== null || $rangeToOption !== null)) {
133 2
            throw new InvalidArgumentException(
134 2
                'Options --all and --range-to/--range-from both used. You should use only one of them.'
135
            );
136
        }
137
138 10
        if ($rangeFromOption !== null ^ $rangeToOption !== null) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: ($rangeFromOption !== nu...$rangeToOption !== null, Probably Intended Meaning: $rangeFromOption !== (nu...rangeToOption !== null)

When comparing the result of a bit operation, we suggest to add explicit parenthesis and not to rely on PHP?s built-in operator precedence to ensure the code behaves as intended and to make it more readable.

Let?s take a look at these examples:

// Returns always int(0).
return 0 === $foo & 4;
return (0 === $foo) & 4;

// More likely intended return: true/false
return 0 === ($foo & 4);
Loading history...
139 2
            throw new InvalidArgumentException(
140 2
                'Options --range-to and --range-from should be used together.'
141
            );
142
        }
143
144 8
        if ($allOption === true) {
145 2
            $availableVersions = $this->configuration->getAvailableVersions();
146
147 2
            foreach ($availableVersions as $version) {
148 2
                $this->mark($version, true);
149
            }
150 6
        } elseif ($rangeFromOption !== null && $rangeToOption !== null) {
151 2
            $availableVersions = $this->configuration->getAvailableVersions();
152
153 2
            foreach ($availableVersions as $version) {
154 2
                if ($version < $rangeFromOption || $version > $rangeToOption) {
155 2
                    continue;
156
                }
157
158 2
                $this->mark($version, true);
159
            }
160
        } else {
161 4
            $this->mark($affectedVersion);
162
        }
163 6
    }
164
165
    /**
166
     * @throws InvalidArgumentException
167
     * @throws MigrationException
168
     */
169 8
    private function mark(string $version, bool $all = false) : void
170
    {
171 8
        if (! $this->configuration->hasVersion($version)) {
172
            throw MigrationException::unknownMigrationVersion($version);
173
        }
174
175 8
        $version = $this->configuration->getVersion($version);
176
177 8
        $marked = false;
178
179 8
        if ($this->markMigrated && $this->configuration->hasVersionMigrated($version)) {
180 1
            if (! $all) {
181 1
                throw new InvalidArgumentException(
182 1
                    sprintf('The version "%s" already exists in the version table.', $version)
183
                );
184
            }
185
186
            $marked = true;
187
        }
188
189 7
        if (! $this->markMigrated && ! $this->configuration->hasVersionMigrated($version)) {
190 3
            if (! $all) {
191 1
                throw new InvalidArgumentException(
192 1
                    sprintf('The version "%s" does not exist in the version table.', $version)
193
                );
194
            }
195
196 2
            $marked = true;
197
        }
198
199 6
        if ($marked === true) {
200 2
            return;
201
        }
202
203 6
        if ($this->markMigrated) {
204 3
            $version->markMigrated();
205
        } else {
206 3
            $version->markNotMigrated();
207
        }
208 6
    }
209
}
210