Completed
Push — master ( ead074...fd19fe )
by Jonathan
12s
created

VersionCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 68
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 1

Importance

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