ResumeCommand   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Test Coverage

Coverage 65.15%

Importance

Changes 0
Metric Value
eloc 72
dl 0
loc 131
ccs 43
cts 66
cp 0.6515
rs 10
c 0
b 0
f 0
wmc 17

2 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 13 1
C execute() 0 98 16
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Command;
4
5
use Kaliop\eZMigrationBundle\API\Value\Migration;
6
use Symfony\Component\Console\Input\InputInterface;
7
use Symfony\Component\Console\Output\OutputInterface;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Question\ConfirmationQuestion;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Consol...on\ConfirmationQuestion was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
11
/**
12
 * Command to resume suspended migrations.
13
 *
14
 * @todo add support for resuming a set based on path
15
 * @todo add support for the separate-process cli switch, as well as clear-cache, default-language, force-sigchild-enabled, survive-disconnected-tty
16
 */
17
class ResumeCommand extends AbstractCommand
18
{
19
    /**
20
     * Set up the command.
21
     *
22
     * Define the name, options and help text.
23
     */
24
    protected function configure()
25 148
    {
26
        parent::configure();
27 148
28
        $this
29
            ->setName('kaliop:migration:resume')
30 148
            ->setDescription('Restarts any suspended migrations.')
31 148
            ->addOption('ignore-failures', 'i', InputOption::VALUE_NONE, "Keep resuming migrations even if one fails")
32 148
            ->addOption('no-interaction', 'n', InputOption::VALUE_NONE, "Do not ask any interactive question.")
33 148
            ->addOption('no-transactions', 'u', InputOption::VALUE_NONE, "Do not use a repository transaction to wrap each migration. Unsafe, but needed for legacy slot handlers")
34 148
            ->addOption('migration', 'm', InputOption::VALUE_REQUIRED, 'A single migration to resume (plain migration name).', null)
35 148
            ->addOption('set-reference', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, "Inject references into the migrations. Format: --set-reference refname:value --set-reference ref2name:value2")
36 148
            ->setHelp(<<<EOT
37 148
The <info>kaliop:migration:resume</info> command allows you to resume any suspended migration
38 148
EOT
39
            );
40
    }
41 148
42
    /**
43
     * Execute the command.
44
     *
45
     * @param InputInterface $input
46
     * @param OutputInterface $output
47
     * @return null|int null or 0 if everything went fine, or an error code
48
     * @throws \Exception
49
     */
50
    protected function execute(InputInterface $input, OutputInterface $output)
51 1
    {
52
        $start = microtime(true);
53 1
54
        $this->setOutput($output);
55 1
        $this->setVerbosity($output->getVerbosity());
56 1
57
        $this->getContainer()->get('ez_migration_bundle.step_executed_listener.tracing')->setOutput($output);
58 1
59
        $migrationService = $this->getMigrationService();
60 1
        $migrationService->setOutput($output);
61 1
62
        $migrationName = $input->getOption('migration');
63 1
        if ($migrationName != null) {
64 1
            $suspendedMigration = $migrationService->getMigration($migrationName);
65
            if (!$suspendedMigration) {
66
                throw new \RuntimeException("Migration '$migrationName' not found");
67
            }
68
            if ($suspendedMigration->status != Migration::STATUS_SUSPENDED) {
69
                throw new \RuntimeException("Migration '$migrationName' is not suspended, can not resume it");
70
            }
71
72
            $suspendedMigrations = array($suspendedMigration);
73
        } else {
74
            $suspendedMigrations = $migrationService->getMigrationsByStatus(Migration::STATUS_SUSPENDED);
75 1
        };
76
77
        $output->writeln('<info>Found ' . count($suspendedMigrations) . ' suspended migrations</info>');
78 1
79
        if (!count($suspendedMigrations)) {
80 1
            $output->writeln('Nothing to do');
81
            return 0;
82
        }
83
84
        // ask user for confirmation to make changes
85
        if ($input->isInteractive() && !$input->getOption('no-interaction')) {
86 1
            $dialog = $this->getHelperSet()->get('question');
87
            if (!$dialog->ask(
0 ignored issues
show
Bug introduced by
The method ask() does not exist on Symfony\Component\Console\Helper\HelperInterface. It seems like you code against a sub-type of Symfony\Component\Console\Helper\HelperInterface such as 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

87
            if (!$dialog->/** @scrutinizer ignore-call */ ask(
Loading history...
88
                $input,
89
                $output,
90
                new ConfirmationQuestion('<question>Careful, the database will be modified. Do you want to continue Y/N ?</question>', false)
91
            )
92
            ) {
93
                $output->writeln('<error>Migration resuming cancelled!</error>');
94
                return 0;
95
            }
96
        }
97
98
        $forcedRefs = array();
99 1
        if ($input->getOption('set-reference') /*&& !$input->getOption('separate-process')*/) {
100 1
            foreach ($input->getOption('set-reference') as $refSpec) {
101 1
                $ref = explode(':', $refSpec, 2);
102 1
                if (count($ref) < 2 || $ref[0] === '') {
103 1
                    throw new \InvalidArgumentException("Invalid reference specification: '$refSpec'");
104 1
                }
105
                $forcedRefs[$ref[0]] = $ref[1];
106
            }
107 1
        }
108
109
        $executed = 0;
110
        $failed = 0;
111 1
112 1
        $migrationContext = array(
113
            'useTransaction' => !$input->getOption('no-transactions'),
114 1
            'forcedReferences' => $forcedRefs,
115 1
        );
116
117
        foreach ($suspendedMigrations as $suspendedMigration) {
118 1
            $output->writeln("<info>Resuming {$suspendedMigration->name}</info>");
119
120 1
            try {
121
                $migrationService->resumeMigration($suspendedMigration, $migrationContext);
122
123
                $executed++;
124
            } catch (\Exception $e) {
125
                if ($input->getOption('ignore-failures')) {
126
                    $this->errOutput->writeln("\n<error>Migration failed! Reason: " . $e->getMessage() . "</error>\n");
127
                    $failed++;
128
                    continue;
129
                }
130
                $this->errOutput->writeln("\n<error>Migration aborted! Reason: " . $e->getMessage() . "</error>");
131
                return 1;
132 1
            }
133 1
134 1
            // in case we are resuming many migrations, and the 1st one changes values to the injected refs, we do not
135
            // inject them any more from the 2nd onwards
136 1
            $migrationContext['forcedReferences'] = array();
137
        }
138
139
        $time = microtime(true) - $start;
140 1
        $output->writeln("Resumed $executed migrations, failed $failed");
141
        $output->writeln("Time taken: ".sprintf('%.3f', $time)." secs, memory: ".sprintf('%.2f', (memory_get_peak_usage(true) / 1000000)). ' MB');
142
143
        if ($failed) {
144
            return 2;
145
        }
146
147
        return 0;
148
    }
149
}
150