Completed
Pull Request — master (#665)
by Jonathan
02:09
created

VersionCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 67
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 57
nc 1
nop 0
dl 0
loc 67
ccs 36
cts 36
cp 1
crap 1
rs 9.2815
c 0
b 0
f 0

How to fix   Long Method   

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