Completed
Push — master ( 05902f...9e6322 )
by mark
01:41 queued 11s
created

Rollback::execute()   B

Complexity

Conditions 8
Paths 66

Size

Total Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 8.0093

Importance

Changes 0
Metric Value
dl 0
loc 63
ccs 36
cts 38
cp 0.9474
rs 7.5628
c 0
b 0
f 0
cc 8
nc 66
nop 2
crap 8.0093

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
/**
4
 * MIT License
5
 * For full license information, please view the LICENSE file that was distributed with this source code.
6
 */
7
8
namespace Phinx\Console\Command;
9
10
use DateTime;
11
use InvalidArgumentException;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Input\InputOption;
14
use Symfony\Component\Console\Output\OutputInterface;
15
16
class Rollback extends AbstractCommand
17
{
18
    /**
19
     * @var string
20
     */
21
    protected static $defaultName = 'rollback';
22
23
    /**
24
     * {@inheritDoc}
25
     *
26
     * @return void
27
     */
28
    protected function configure()
29
    {
30
        parent::configure();
31
32
        $this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
33
34
        $this->setDescription('Rollback the last or to a specific migration')
35
            ->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to rollback to')
36
            ->addOption('--date', '-d', InputOption::VALUE_REQUIRED, 'The date to rollback to')
37
            ->addOption('--force', '-f', InputOption::VALUE_NONE, 'Force rollback to ignore breakpoints')
38
            ->addOption('--dry-run', '-x', InputOption::VALUE_NONE, 'Dump query to standard output instead of executing it')
39
            ->addOption('--fake', null, InputOption::VALUE_NONE, "Mark any rollbacks selected as run, but don't actually execute them")
40
            ->setHelp(
41 44
                <<<EOT
42
The <info>rollback</info> command reverts the last migration, or optionally up to a specific version
43 44
44
<info>phinx rollback -e development</info>
45 44
<info>phinx rollback -e development -t 20111018185412</info>
46
<info>phinx rollback -e development -d 20111018</info>
47 44
<info>phinx rollback -e development -v</info>
48 44
<info>phinx rollback -e development -t 20111018185412 -f</info>
49 44
50 44
If you have a breakpoint set, then you can rollback to target 0 and the rollbacks will stop at the breakpoint.
51 44
<info>phinx rollback -e development -t 0 </info>
52 44
53 44
The <info>version_order</info> configuration option is used to determine the order of the migrations when rolling back.
54
This can be used to allow the rolling back of the last executed migration instead of the last created one, or combined
55
with the <info>-d|--date</info> option to rollback to a certain date using the migration start times to order them.
56
57
EOT
58
            );
59
    }
60
61
    /**
62
     * Rollback the migration.
63
     *
64
     * @param \Symfony\Component\Console\Input\InputInterface $input Input
65
     * @param \Symfony\Component\Console\Output\OutputInterface $output Output
66
     *
67
     * @return int integer 0 on success, or an error code.
68
     */
69
    protected function execute(InputInterface $input, OutputInterface $output)
70
    {
71 44
        $this->bootstrap($input, $output);
72 44
73
        $environment = $input->getOption('environment');
74
        $version = $input->getOption('target');
75
        $date = $input->getOption('date');
76
        $force = (bool)$input->getOption('force');
77
        $fake = (bool)$input->getOption('fake');
78
79
        $config = $this->getConfig();
80
81 6
        if ($environment === null) {
82
            $environment = $config->getDefaultEnvironment();
83 6
            $output->writeln('<comment>warning</comment> no environment specified, defaulting to: ' . $environment);
84
        } else {
85 6
            $output->writeln('<info>using environment</info> ' . $environment);
86 6
        }
87 6
88 6
        if (!$this->getConfig()->hasEnvironment($environment)) {
89
            $output->writeln(sprintf('<error>The environment "%s" does not exist</error>', $environment));
90 6
91
            return self::CODE_ERROR;
92 6
        }
93 5
94 5
        $envOptions = $config->getEnvironment($environment);
95 5
        if (isset($envOptions['adapter'])) {
96 1
            $output->writeln('<info>using adapter</info> ' . $envOptions['adapter']);
97
        }
98
99 6
        if (isset($envOptions['wrapper'])) {
100 6
            $output->writeln('<info>using wrapper</info> ' . $envOptions['wrapper']);
101 5
        }
102 5
103
        if (isset($envOptions['name'])) {
104 6
            $output->writeln('<info>using database</info> ' . $envOptions['name']);
105
        }
106
107
        $versionOrder = $this->getConfig()->getVersionOrder();
108 6
        $output->writeln('<info>ordering by</info> ' . $versionOrder . ' time');
109 5
110 5
        if ($fake) {
111
            $output->writeln('<comment>warning</comment> performing fake rollbacks');
112 6
        }
113 6
114
        // rollback the specified environment
115
        if ($date === null) {
116 6
            $targetMustMatchVersion = true;
117 4
            $target = $version;
118 4
        } else {
119 4
            $targetMustMatchVersion = false;
120 2
            $target = $this->getTargetFromDate($date);
121 2
        }
122
123
        $start = microtime(true);
124 6
        $this->getManager()->rollback($environment, $target, $force, $targetMustMatchVersion, $fake);
125 6
        $end = microtime(true);
126 6
127
        $output->writeln('');
128 6
        $output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
129 6
130 6
        return self::CODE_SUCCESS;
131
    }
132
133
    /**
134
     * Get Target from Date
135
     *
136
     * @param string $date The date to convert to a target.
137
     *
138 10
     * @throws \InvalidArgumentException
139
     *
140 10
     * @return string The target
141 3
     */
142
    public function getTargetFromDate($date)
143
    {
144
        if (!preg_match('/^\d{4,14}$/', $date)) {
145
            throw new InvalidArgumentException('Invalid date. Format is YYYY[MM[DD[HH[II[SS]]]]].');
146 7
        }
147 7
148 7
        // what we need to append to the date according to the possible date string lengths
149 7
        $dateStrlenToAppend = [
150 7
            14 => '',
151 7
            12 => '00',
152 7
            10 => '0000',
153
            8 => '000000',
154 7
            6 => '01000000',
155
            4 => '0101000000',
156
        ];
157
158 7
        if (!isset($dateStrlenToAppend[strlen($date)])) {
159
            throw new InvalidArgumentException('Invalid date. Format is YYYY[MM[DD[HH[II[SS]]]]].');
160 7
        }
161
162 7
        $target = $date . $dateStrlenToAppend[strlen($date)];
163
164
        $dateTime = DateTime::createFromFormat('YmdHis', $target);
165
166 7
        if ($dateTime === false) {
167
            throw new InvalidArgumentException('Invalid date. Format is YYYY[MM[DD[HH[II[SS]]]]].');
168
        }
169
170
        return $dateTime->format('YmdHis');
171
    }
172
}
173