Completed
Push — master ( 178c75...b82d68 )
by Luís
11s
created

VersionCommand   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 144
Duplicated Lines 34.72 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 87.3%

Importance

Changes 0
Metric Value
wmc 28
lcom 2
cbo 6
dl 50
loc 144
ccs 55
cts 63
cp 0.873
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B configure() 38 38 1
C markVersions() 0 32 12
B execute() 0 25 5
D mark() 12 29 10

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
21
22
use Doctrine\DBAL\Migrations\MigrationException;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\Console\Input\InputArgument;
26
use Symfony\Component\Console\Input\InputOption;
27
28
/**
29
 * Command for manually adding and deleting migration versions from the version table.
30
 *
31
 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
32
 * @link    www.doctrine-project.org
33
 * @since   2.0
34
 * @author  Jonathan Wage <[email protected]>
35
 */
36
class VersionCommand extends AbstractCommand
37
{
38
    /**
39
     * The Migrations Configuration instance
40
     *
41
     * @var \Doctrine\DBAL\Migrations\Configuration\Configuration
42
     */
43
    private $configuration;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
44
45
    /**
46
     * Whether or not the versions have to be marked as migrated or not
47
     *
48
     * @var boolean
49
     */
50
    private $markMigrated;
51
52 20 View Code Duplication
    protected function configure()
53
    {
54
        $this
55 20
            ->setName('migrations:version')
56 20
            ->setDescription('Manually add and delete migration versions from the version table.')
57 20
            ->addArgument('version', InputArgument::OPTIONAL, 'The version to add or delete.', null)
58 20
            ->addOption('add', null, InputOption::VALUE_NONE, 'Add the specified version.')
59 20
            ->addOption('delete', null, InputOption::VALUE_NONE, 'Delete the specified version.')
60 20
            ->addOption('all', null, InputOption::VALUE_NONE, 'Apply to all the versions.')
61 20
            ->addOption('range-from', null, InputOption::VALUE_OPTIONAL, 'Apply from specified version.')
62 20
            ->addOption('range-to', null, InputOption::VALUE_OPTIONAL, 'Apply to specified version.')
63 20
            ->setHelp(<<<EOT
64 20
The <info>%command.name%</info> command allows you to manually add, delete or synchronize migration versions from the version table:
65
66
    <info>%command.full_name% YYYYMMDDHHMMSS --add</info>
67
68
If you want to delete a version you can use the <comment>--delete</comment> option:
69
70
    <info>%command.full_name% YYYYMMDDHHMMSS --delete</info>
71
72
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:
73
74
    <info>%command.full_name% --add --all</info>
75
    <info>%command.full_name% --delete --all</info>
76
77
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:
78
79
    <info>%command.full_name% --add --range-from=YYYYMMDDHHMMSS --range-to=YYYYMMDDHHMMSS</info>
80
    <info>%command.full_name% --delete --range-from=YYYYMMDDHHMMSS --range-to=YYYYMMDDHHMMSS</info>
81
82
You can also execute this command without a warning message which you need to interact with:
83
84
    <info>%command.full_name% --no-interaction</info>
85
EOT
86
            );
87
88 20
        parent::configure();
89 20
    }
90
91 12
    public function execute(InputInterface $input, OutputInterface $output)
92
    {
93 12
        $this->configuration = $this->getMigrationConfiguration($input, $output);
94
95 12
        if ( ! $input->getOption('add') && ! $input->getOption('delete')) {
96
            throw new \InvalidArgumentException('You must specify whether you want to --add or --delete the specified version.');
97
        }
98
99 12
        $this->markMigrated = (boolean) $input->getOption('add');
100
101 12
        if ($input->isInteractive()) {
102
            $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)';
103
104
            $confirmation = $this->askConfirmation($question, $input, $output);
105
106
            if ($confirmation) {
107
                $this->markVersions($input);
108
            } else {
109
                $output->writeln('<error>Migration cancelled!</error>');
110
            }
111
        } else {
112 12
            $this->markVersions($input);
113
        }
114
115 6
    }
116
117 12
    private function markVersions(InputInterface $input)
118
    {
119 12
        $affectedVersion = $input->getArgument('version');
120
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 && ($rangeFromOption !== null || $rangeToOption !== null)) {
126 2
            throw new \InvalidArgumentException('Options --all and --range-to/--range-from both used. You should use only one of them.');
127
        }
128
129 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...
130 2
            throw new \InvalidArgumentException('Options --range-to and --range-from should be used together.');
131
        }
132
133 8
        if ($allOption === true) {
134 2
            $availableVersions = $this->configuration->getAvailableVersions();
135 2
            foreach ($availableVersions as $version) {
136 2
                $this->mark($version, true);
137
            }
138 6
        } elseif ($rangeFromOption !== null && $rangeToOption !== null) {
139 2
            $availableVersions = $this->configuration->getAvailableVersions();
140 2
            foreach ($availableVersions as $version) {
141 2
                if ($version >= $rangeFromOption && $version <= $rangeToOption) {
142 2
                    $this->mark($version, true);
143
                }
144
            }
145
        } else {
146 4
            $this->mark($affectedVersion);
147
        }
148 6
    }
149
150 8
    private function mark($version, $all = false)
151
    {
152 8
        if ( ! $this->configuration->hasVersion($version)) {
153
            throw MigrationException::unknownMigrationVersion($version);
154
        }
155
156 8
        $version = $this->configuration->getVersion($version);
157 8 View Code Duplication
        if ($this->markMigrated && $this->configuration->hasVersionMigrated($version)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
158 1
            if (! $all) {
159 1
                throw new \InvalidArgumentException(sprintf('The version "%s" already exists in the version table.', $version));
160
            }
161
            $marked = true;
162
        }
163
164 7 View Code Duplication
        if ( ! $this->markMigrated && ! $this->configuration->hasVersionMigrated($version)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165 3
            if (! $all) {
166 1
                throw new \InvalidArgumentException(sprintf('The version "%s" does not exists in the version table.', $version));
167
            }
168 2
            $marked = false;
169
        }
170
171 6
        if ( ! isset($marked)) {
172 6
            if ($this->markMigrated) {
173 3
                $version->markMigrated();
174
            } else {
175 3
                $version->markNotMigrated();
176
            }
177
        }
178 6
    }
179
}
180