Completed
Push — master ( ac3b8b...3c857d )
by Gaetano
18:21
created

MigrationCommand::configure()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 24
c 0
b 0
f 0
rs 8.9713
ccs 10
cts 10
cp 1
cc 1
eloc 14
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Command;
4
5
use Symfony\Component\Console\Input\InputInterface;
6
use Symfony\Component\Console\Output\OutputInterface;
7
use Symfony\Component\Console\Input\InputOption;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Kaliop\eZMigrationBundle\API\Value\Migration;
10
use Kaliop\eZMigrationBundle\API\Value\MigrationDefinition;
11
12
/**
13
 * Command to execute the available migration definitions.
14
 */
15
class MigrationCommand extends AbstractCommand
16
{
17
    /**
18
     * Set up the command.
19 20
     *
20
     * Define the name, options and help text.
21 20
     */
22
    protected function configure()
23 20
    {
24 20
        parent::configure();
25 20
26 20
        $this
27 20
            ->setName('kaliop:migration:migration')
28 20
            ->setDescription('Manually delete migrations from the database table.')
29 20
            ->addOption('delete', null, InputOption::VALUE_NONE, "Delete the specified migration.")
30 20
            ->addOption('info', null, InputOption::VALUE_NONE, "Get info about the specified migration.")
31
            ->addOption('add', null, InputOption::VALUE_NONE, "Add the specified migration definition.")
32
            ->addOption('skip', null, InputOption::VALUE_NONE, "Mark the specified migration as skipped.")
33
            ->addOption('no-interaction', 'n', InputOption::VALUE_NONE, "Do not ask any interactive question.")
34
            ->addArgument('migration', InputArgument::REQUIRED, 'The migration to add/skip (filename with full path) or detail/delete (plain migration name).', null)
35
            ->setHelp(<<<EOT
36
The <info>kaliop:migration:migration</info> command allows you to manually delete migrations versions from the migration table:
37
38
    <info>./ezpublish/console kaliop:migration:migration --delete migration_name</info>
39
40 20
As well as manually adding migrations to the migration table:
41 20
42
    <info>./ezpublish/console kaliop:migration:migration --add /path/to/migration_definition</info>
43
EOT
44
            );
45
    }
46
47
    /**
48
     * Execute the command.
49
     *
50 19
     * @param InputInterface $input
51
     * @param OutputInterface $output
52 19
     * @return null|int null or 0 if everything went fine, or an error code
53
     */
54
    protected function execute(InputInterface $input, OutputInterface $output)
55
    {
56 19
        if (!$input->getOption('add') && !$input->getOption('delete') && !$input->getOption('skip') && !$input->getOption('info')) {
57 19
            throw new \InvalidArgumentException('You must specify whether you want to --add, --delete, --skip or --info the specified migration.');
58
        }
59
60 19
        $migrationService = $this->getMigrationService();
61
        $migrationNameOrPath = $input->getArgument('migration');
62
63
        if ($input->getOption('info')) {
64
            $output->writeln('');
65
66
            $migration = $migrationService->getMigration($migrationNameOrPath);
67
            if ($migration == null) {
68
                throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', $migrationNameOrPath));
69
            }
70
71 View Code Duplication
            switch ($migration->status) {
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...
72
                case Migration::STATUS_DONE:
73 19
                    $status = '<info>executed</info>';
74
                    break;
75 19
                case Migration::STATUS_STARTED:
76
                    $status = '<comment>execution started</comment>';
77 19
                    break;
78 19
                case Migration::STATUS_TODO:
79
                    // bold to-migrate!
80
                    $status = '<error>not executed</error>';
81
                    break;
82 19
                case Migration::STATUS_SKIPPED:
83 19
                    $status = '<comment>skipped</comment>';
84
                    break;
85 19
                case Migration::STATUS_PARTIALLY_DONE:
86 19
                    $status = '<comment>partially executed</comment>';
87
                    break;
88
                case Migration::STATUS_SUSPENDED:
89
                    $status = '<comment>suspended</comment>';
90 19
                    break;
91 19
                case Migration::STATUS_FAILED:
92 19
                    $status = '<error>failed</error>';
93
                    break;
94 19
            }
95
96
            $output->writeln('<info>Migration: ' . $migration->name . '</info>');
97 19
            $output->writeln('Status: ' . $status);
0 ignored issues
show
Bug introduced by
The variable $status does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
98 19
            $output->writeln('Executed on: <info>' . ($migration->executionDate != null ? date("Y-m-d H:i:s", $migration->executionDate) : '--'). '</info>');
99 19
            $output->writeln('Execution notes: <info>' . $migration->executionError . '</info>');
100 19
101
            if ($migration->status == Migration::STATUS_SUSPENDED) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
102
                /// @todo decode the suspension context: date, step, ...
103 19
            }
104 19
105 19
            $output->writeln('Definition path: <info>' . $migration->path . '</info>');
106
            $output->writeln('Definition md5: <info>' . $migration->md5 . '</info>');
107
108
            if ($migration->path != '') {
109
                // q: what if we have a loader which does not work with is_file? We could probably remove this check...
110
                if (is_file($migration->path)) {
111
                    try {
112
                        $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migration->path));
113
                        if (count($migrationDefinitionCollection)) {
114
                            $migrationDefinition = reset($migrationDefinitionCollection);
115
                            $migrationDefinition = $migrationService->parseMigrationDefinition($migrationDefinition);
116
117
                            if ($migrationDefinition->status != MigrationDefinition::STATUS_PARSED) {
118
                                $output->writeln('Definition error: <error>' . $migrationDefinition->parsingError . '</error>');
119
                            }
120
121
                            if (md5($migrationDefinition->rawDefinition) != $migration->md5) {
122
                                $output->writeln('Notes: <comment>The migration definition file has now a different checksum</comment>');
123
                            }
124
                        } else {
125
                            $output->writeln('Definition error: <error>The migration definition file can not be loaded</error>');
126
                        }
127
                    } catch (\Exception $e) {
128
                        /// @todo one day we should be able to limit the kind of exceptions we have to catch here...
129
                        $output->writeln('Definition parsing error: <error>' . $e->getMessage() . '</error>');
130
                    }
131
                } else {
132
                    $output->writeln('Definition error: <error>The migration definition file can not be found any more</error>');
133
                }
134
            }
135
136
            $output->writeln('');
137
            return;
138
        }
139
140
        // ask user for confirmation to make changes
141 View Code Duplication
        if ($input->isInteractive() && !$input->getOption('no-interaction')) {
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...
142
            $dialog = $this->getHelperSet()->get('dialog');
143
            if (!$dialog->askConfirmation(
144
                $output,
145
                '<question>Careful, the database will be modified. Do you want to continue Y/N ?</question>',
146
                false
147
            )
148
            ) {
149
                $output->writeln('<error>Migration change cancelled!</error>');
150
                return 0;
151
            }
152
        }
153
154
        if ($input->getOption('add')) {
155
            // will throw if a file is passed and it is not found, but not if an empty dir is passed
156
            $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath));
157
158
            if (!count($migrationDefinitionCollection))
159
            {
160
                throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath));
161
            }
162
163
            foreach ($migrationDefinitionCollection as $migrationDefinition) {
164
                $migrationName = basename($migrationDefinition->path);
165
166
                $migration = $migrationService->getMigration($migrationNameOrPath);
167
                if ($migration != null) {
168
                    throw new \InvalidArgumentException(sprintf('The migration "%s" does already exist in the migrations table.', $migrationName));
169
                }
170
171
                $migrationService->addMigration($migrationDefinition);
172
                $output->writeln('<info>Added migration' . $migrationDefinition->path . '</info>');
173
            }
174
175
            return;
176
        }
177
178
        if ($input->getOption('delete')) {
179
            $migration = $migrationService->getMigration($migrationNameOrPath);
180
            if ($migration == null) {
181
                throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', $migrationNameOrPath));
182
            }
183
184
            $migrationService->deleteMigration($migration);
185
186
            return;
187
        }
188
189
        if ($input->getOption('skip')) {
190
            // will throw if a file is passed and it is not found, but not if an empty dir is passed
191
            $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath));
192
193
            if (!count($migrationDefinitionCollection))
194
            {
195
                throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath));
196
            }
197
198
            foreach ($migrationDefinitionCollection as $migrationDefinition) {
199
                $migrationService->skipMigration($migrationDefinition);
200
                $output->writeln('<info>Migration' . $migrationDefinition->path . ' marked as skipped</info>');
201
            }
202
203
            return;
204
        }
205
    }
206
}
207