Passed
Push — master ( 2b8f81...145d48 )
by Gaetano
10:22 queued 05:19
created

MigrationCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 19
nc 1
nop 0
dl 0
loc 14
ccs 0
cts 13
cp 0
crap 2
rs 9.6333
c 0
b 0
f 0
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
use Symfony\Component\Console\Question\ConfirmationQuestion;
12
13
/**
14
 * Command to execute the available migration definitions.
15
 */
16
class MigrationCommand extends AbstractCommand
17
{
18
    /**
19
     * Set up the command.
20
     *
21
     * Define the name, options and help text.
22
     */
23
    protected function configure()
24
    {
25
        parent::configure();
26
27
        $this
28
            ->setName('kaliop:migration:migration')
29
            ->setDescription('Manually modify or get info about migrations in the database table.')
30
            ->addOption('delete', null, InputOption::VALUE_NONE, "Delete the specified migration.")
31
            ->addOption('info', null, InputOption::VALUE_NONE, "Get info about the specified migration.")
32
            ->addOption('add', null, InputOption::VALUE_NONE, "Add the specified migration definition.")
33
            ->addOption('skip', null, InputOption::VALUE_NONE, "Mark the specified migration as skipped.")
34
            ->addOption('no-interaction', 'n', InputOption::VALUE_NONE, "Do not ask any interactive question.")
35
            ->addArgument('migration', InputArgument::REQUIRED, 'The migration to add/skip (filename with full path) or detail/delete (plain migration name).', null)
36
            ->setHelp(<<<EOT
37
The <info>kaliop:migration:migration</info> command allows you to manually delete migrations versions from the migration table:
38
39
    <info>./ezpublish/console kaliop:migration:migration --delete migration_name</info>
40
41
As well as manually adding migrations to the migration table:
42
43
    <info>./ezpublish/console kaliop:migration:migration --add /path/to/migration_definition</info>
44
EOT
45
            );
46
    }
47
48
    /**
49
     * Execute the command.
50
     *
51
     * @param InputInterface $input
52
     * @param OutputInterface $output
53
     * @return null|int null or 0 if everything went fine, or an error code
54
     */
55
    protected function execute(InputInterface $input, OutputInterface $output)
56
    {
57
        $this->setOutput($output);
58
        $this->setVerbosity($output->getVerbosity());
59
60
        if (!$input->getOption('add') && !$input->getOption('delete') && !$input->getOption('skip') && !$input->getOption('info')) {
61
            throw new \InvalidArgumentException('You must specify whether you want to --add, --delete, --skip or --info the specified migration.');
62
        }
63
64
        $migrationService = $this->getMigrationService();
65
        $migrationNameOrPath = $input->getArgument('migration');
66
67
        if ($input->getOption('info')) {
68
            $output->writeln('');
69
70
            $migration = $migrationService->getMigration($migrationNameOrPath);
0 ignored issues
show
Bug introduced by
It seems like $migrationNameOrPath can also be of type string[]; however, parameter $migrationName of Kaliop\eZMigrationBundle...Service::getMigration() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

70
            $migration = $migrationService->getMigration(/** @scrutinizer ignore-type */ $migrationNameOrPath);
Loading history...
71
            if ($migration == null) {
72
                throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', $migrationNameOrPath));
0 ignored issues
show
Bug introduced by
It seems like $migrationNameOrPath can also be of type string[]; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

72
                throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', /** @scrutinizer ignore-type */ $migrationNameOrPath));
Loading history...
73
            }
74
75
            switch ($migration->status) {
76
                case Migration::STATUS_DONE:
77
                    $status = '<info>executed</info>';
78
                    break;
79
                case Migration::STATUS_STARTED:
80
                    $status = '<comment>execution started</comment>';
81
                    break;
82
                case Migration::STATUS_TODO:
83
                    // bold to-migrate!
84
                    $status = '<error>not executed</error>';
85
                    break;
86
                case Migration::STATUS_SKIPPED:
87
                    $status = '<comment>skipped</comment>';
88
                    break;
89
                case Migration::STATUS_PARTIALLY_DONE:
90
                    $status = '<comment>partially executed</comment>';
91
                    break;
92
                case Migration::STATUS_SUSPENDED:
93
                    $status = '<comment>suspended</comment>';
94
                    break;
95
                case Migration::STATUS_FAILED:
96
                    $status = '<error>failed</error>';
97
                    break;
98
            }
99
100
            $output->writeln('<info>Migration: ' . $migration->name . '</info>');
101
            $output->writeln('Status: ' . $status);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $status does not seem to be defined for all execution paths leading up to this point.
Loading history...
102
            $output->writeln('Executed on: <info>' . ($migration->executionDate != null ? date("Y-m-d H:i:s", $migration->executionDate) : '--'). '</info>');
103
            $output->writeln('Execution notes: <info>' . $migration->executionError . '</info>');
104
105
            if ($migration->status == Migration::STATUS_SUSPENDED) {
106
                /// @todo decode the suspension context: date, step, ...
107
            }
108
109
            $output->writeln('Definition path: <info>' . $migration->path . '</info>');
110
            $output->writeln('Definition md5: <info>' . $migration->md5 . '</info>');
111
112
            if ($migration->path != '') {
113
                // q: what if we have a loader which does not work with is_file? We could probably remove this check...
114
                if (is_file($migration->path)) {
115
                    try {
116
                        $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migration->path));
117
                        if (count($migrationDefinitionCollection)) {
118
                            $migrationDefinition = $migrationDefinitionCollection->reset();
119
                            $migrationDefinition = $migrationService->parseMigrationDefinition($migrationDefinition);
120
121
                            if ($migrationDefinition->status != MigrationDefinition::STATUS_PARSED) {
122
                                $output->writeln('Definition error: <error>' . $migrationDefinition->parsingError . '</error>');
123
                            }
124
125
                            if (md5($migrationDefinition->rawDefinition) != $migration->md5) {
126
                                $output->writeln('Notes: <comment>The migration definition file has now a different checksum</comment>');
127
                            }
128
                        } else {
129
                            $output->writeln('Definition error: <error>The migration definition file can not be loaded</error>');
130
                        }
131
                    } catch (\Exception $e) {
132
                        /// @todo one day we should be able to limit the kind of exceptions we have to catch here...
133
                        $output->writeln('Definition parsing error: <error>' . $e->getMessage() . '</error>');
134
                    }
135
                } else {
136
                    $output->writeln('Definition error: <error>The migration definition file can not be found any more</error>');
137
                }
138
            }
139
140
            $output->writeln('');
141
            return 0;
142
        }
143
144
        // ask user for confirmation to make changes
145
        if ($input->isInteractive() && !$input->getOption('no-interaction')) {
146
            $dialog = $this->getHelperSet()->get('question');
147
            if (!$dialog->ask(
0 ignored issues
show
Bug introduced by
The method ask() does not exist on Symfony\Component\Console\Helper\Helper. It seems like you code against a sub-type of Symfony\Component\Console\Helper\Helper such as Symfony\Component\Console\Helper\QuestionHelper or Symfony\Component\Console\Helper\DialogHelper. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

147
            if (!$dialog->/** @scrutinizer ignore-call */ ask(
Loading history...
148
                $input,
149
                $output,
150
                new ConfirmationQuestion('<question>Careful, the database will be modified. Do you want to continue Y/N ?</question>', false)
151
            )
152
            ) {
153
                $output->writeln('<error>Migration change cancelled!</error>');
154
                return 0;
155
            }
156
        }
157
158
        if ($input->getOption('add')) {
159
            // will throw if a file is passed and it is not found, but not if an empty dir is passed
160
            $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath));
161
162
            if (!count($migrationDefinitionCollection))
163
            {
164
                throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath));
165
            }
166
167
            foreach ($migrationDefinitionCollection as $migrationDefinition) {
168
                $migrationName = basename($migrationDefinition->path);
169
170
                $migration = $migrationService->getMigration($migrationNameOrPath);
171
                if ($migration != null) {
172
                    throw new \InvalidArgumentException(sprintf('The migration "%s" does already exist in the migrations table.', $migrationName));
173
                }
174
175
                $migrationService->addMigration($migrationDefinition);
176
                $output->writeln('<info>Added migration' . $migrationDefinition->path . '</info>');
177
            }
178
179
            return 0;
180
        }
181
182
        if ($input->getOption('delete')) {
183
            $migration = $migrationService->getMigration($migrationNameOrPath);
184
            if ($migration == null) {
185
                throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', $migrationNameOrPath));
186
            }
187
188
            $migrationService->deleteMigration($migration);
189
190
            return 0;
191
        }
192
193
        if ($input->getOption('skip')) {
194
            // will throw if a file is passed and it is not found, but not if an empty dir is passed
195
            $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath));
196
197
            if (!count($migrationDefinitionCollection))
198
            {
199
                throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath));
200
            }
201
202
            foreach ($migrationDefinitionCollection as $migrationDefinition) {
203
                $migrationService->skipMigration($migrationDefinition);
204
                $output->writeln('<info>Migration' . $migrationDefinition->path . ' marked as skipped</info>');
205
            }
206
207
            return 0;
208
        }
209
210
        throw new \InvalidArgumentException("Please specify one action to be taken on the given migration");
211
    }
212
}
213