GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#5)
by Robert
20:32 queued 18:20
created

MigrationsCommand   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 11

Test Coverage

Coverage 93.81%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 26
c 3
b 0
f 1
lcom 0
cbo 11
dl 0
loc 189
ccs 106
cts 113
cp 0.9381
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
B configure() 0 32 1
F execute() 0 147 25
1
<?php declare(strict_types=1);
2
3
namespace Gruberro\MongoDbMigrations\Console\Command;
4
5
use Gruberro\MongoDbMigrations;
6
use MongoDB;
7
use Symfony\Component\Console;
8
9
class MigrationsCommand extends Console\Command\Command
10
{
11
    /**
12
     * {@inheritdoc}
13
     */
14 6
    protected function configure()
15
    {
16
        $this
17 6
            ->setName('php-mongodb-migrations:migrate')
18 6
            ->setDescription('Execute all open migrations')
19 6
            ->addOption(
20 6
                'server',
21 6
                's',
22 6
                Console\Input\InputOption::VALUE_REQUIRED,
23 6
                'The connection string (e.g. mongodb://[username:password@]host1[:port1][,host2[:port2:],...]/db)',
24 6
                'mongodb://localhost:27017'
25
            )
26 6
            ->addOption(
27 6
                'contexts',
28 6
                'c',
29 6
                Console\Input\InputOption::VALUE_IS_ARRAY | Console\Input\InputOption::VALUE_REQUIRED,
30 6
                'A list of contexts evaluated with each migration of type ContextualMigrationInterface',
31 6
                []
32
            )
33 6
            ->addArgument(
34 6
                'database',
35 6
                Console\Input\InputArgument::REQUIRED,
36 6
                'The database to connect to'
37
            )
38 6
            ->addArgument(
39 6
                'migration-directories',
40 6
                Console\Input\InputArgument::IS_ARRAY,
41 6
                'List of directories containing migration classes',
42 6
                []
43
            )
44
        ;
45 6
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 7
    protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
51
    {
52 7
        $client = new MongoDB\Client($input->getOption('server'));
53 7
        $db = $client->selectDatabase($input->getArgument('database'));
54 7
        $output->writeln("<info>✓ Successfully established database connection</info>", $output::VERBOSITY_VERBOSE);
55
56 7
        $directories = $input->getArgument('migration-directories');
57 7
        foreach ($directories as $directory) {
58 7
            if (! is_dir($directory)) {
59 1
                throw new Console\Exception\InvalidArgumentException("'{$directory}' is no valid directory");
60
            }
61
62 7
            $output->writeln("<comment>Iterating '{$directory}' for potential migrations classes</comment>", $output::VERBOSITY_DEBUG);
63 7
            $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory), \RecursiveIteratorIterator::LEAVES_ONLY);
64
65
            /** @var \SplFileInfo $file */
66 7
            foreach ($iterator as $file) {
67 7
                if ($file->getBasename('.php') === $file->getBasename()) {
68 7
                    continue;
69
                }
70
71 7
                require_once $file->getRealPath();
72
73 7
                $output->writeln("<comment>Loaded potential migration '{$file->getRealPath()}'</comment>", $output::VERBOSITY_DEBUG);
74
            }
75
        }
76
77
        /** @var MongoDbMigrations\MigrationInterface[] $migrations */
78 6
        $migrations = [];
79 6
        foreach (get_declared_classes() as $className) {
80 6
            $reflectionClass = new \ReflectionClass($className);
81
82 6
            if ($reflectionClass->implementsInterface(MongoDbMigrations\MigrationInterface::class)) {
83
                /** @var MongoDbMigrations\MigrationInterface $newInstance */
84 6
                $newInstance = $reflectionClass->newInstance();
85 6
                $id = md5($newInstance->getId());
86
87 6
                if (isset($migrations[$id])) {
88 1
                    $existingMigrationClass = get_class($migrations[$id]);
89 1
                    throw new Console\Exception\RuntimeException("Found a non unique migration id '{$newInstance->getId()}' in '{$reflectionClass->getName()}', already defined by migration class '{$existingMigrationClass}'");
90
                }
91
92 6
                $migrations[$id] = $newInstance;
93
94 6
                $output->writeln("<comment>Found valid migration class '{$reflectionClass->getName()}'</comment>", $output::VERBOSITY_DEBUG);
95
            }
96
        }
97
98 5
        $migrationClassesCount = count($migrations);
99 5
        $output->writeln("<info>✓ Found {$migrationClassesCount} valid migration classes</info>", $output::VERBOSITY_VERBOSE);
100
101 5
        uasort($migrations, function (MongoDbMigrations\MigrationInterface $a, MongoDbMigrations\MigrationInterface $b) {
102 5
            if ($a->getCreateDate() === $b->getCreateDate()) {
103
                return 0;
104
            }
105
106 5
            return $a->getCreateDate() < $b->getCreateDate() ? -1 : 1;
107 5
        });
108
109 5
        $output->writeln("<info>✓ Reordered all migration classes according to their create date</info>", $output::VERBOSITY_VERBOSE);
110
111 5
        $databaseMigrationsLockCollection = $db->selectCollection('DATABASE_MIGRATIONS_LOCK');
112 5
        if (count($databaseMigrationsLockCollection->listIndexes()) <= 1) {
113 5
            $databaseMigrationsLockCollection->createIndex(['locked' => 1]);
114
        }
115
116 5
        $currentLock = $databaseMigrationsLockCollection->findOneAndReplace(['locked' => ['$exists' => true]], ['locked' => true, 'last_locked_date' => new MongoDB\BSON\UTCDatetime((new \DateTime())->getTimestamp() * 1000)], ['upsert' => true]);
117 5
        if ($currentLock !== null && $currentLock->locked === true) {
118 1
            throw new Console\Exception\RuntimeException('Concurrent migrations are not allowed');
119
        }
120
121
        try {
122 4
            $output->writeln("<info>✓ Successfully acquired migration lock</info>", $output::VERBOSITY_VERBOSE);
123
124 4
            $databaseMigrationsCollection = $db->selectCollection('DATABASE_MIGRATIONS');
125
126 4
            if (count($databaseMigrationsCollection->listIndexes()) <= 1) {
127 4
                $databaseMigrationsCollection->createIndex(['migration_id' => 1], ['unique' => true, 'background' => false]);
128
            }
129
130 4
            $progress = new Console\Helper\ProgressBar($output, count($migrations));
131
132 4
            switch ($output->getVerbosity()) {
133 4
                case $output::VERBOSITY_VERBOSE:
134
                    $format = 'verbose';
135
                    break;
136 4
                case $output::VERBOSITY_VERY_VERBOSE:
137
                    $format = 'very_verbose';
138
                    break;
139 4
                case $output::VERBOSITY_DEBUG:
140
                    $format = 'debug';
141
                    break;
142
                default:
143 4
                    $format = 'normal';
144
            }
145
146 4
            $progress->setFormat($format);
147 4
            $progress->start();
148 4
            $executedMigrations = 0;
149
150 4
            foreach ($migrations as $id => $migration) {
151 4
                $progress->advance();
152
153 4
                if ($migration instanceof MongoDbMigrations\ContextualMigrationInterface && $input->getOption('contexts') !== []) {
154 3
                    if (array_intersect($migration->getContexts(), $input->getOption('contexts')) === []) {
155 1
                        continue;
156
                    }
157
                }
158
159 4
                if (!$migration instanceof MongoDbMigrations\RunAlwaysMigrationInterface) {
160 4
                    if ($databaseMigrationsCollection->count(['migration_id' => $id]) > 0) {
161 1
                        continue;
162
                    }
163
                }
164
165 4
                $migration->execute($db);
166 4
                $executedMigrations++;
167
168
                $migrationInfo = [
169 4
                    'migration_id' => $id,
170 4
                    'migration_class' => get_class($migration),
171 4
                    'last_execution_date' => new MongoDB\BSON\UTCDatetime((new \DateTime())->getTimestamp() * 1000),
172 4
                    'run_always' => $migration instanceof MongoDbMigrations\RunAlwaysMigrationInterface,
173
                ];
174
175 4
                if ($migration instanceof MongoDbMigrations\ContextualMigrationInterface) {
176 2
                    $migrationInfo['contexts'] = $migration->getContexts();
177
                }
178
179 4
                $databaseMigrationsCollection->updateOne(
180 4
                    ['migration_id' => $id],
181 4
                    ['$set' => $migrationInfo],
182 4
                    ['upsert' => true]
183
                );
184
            }
185
186 3
            $progress->finish();
187 3
            $output->writeln('');
188
189 3
            $output->writeln("<info>✓ Successfully executed {$executedMigrations} migrations</info>");
190 1
        } catch (\Exception $e) {
191 1
            throw new Console\Exception\RuntimeException('Error while executing migrations', $e->getCode(), $e);
192 3
        } finally {
193 4
            $databaseMigrationsLockCollection->updateOne(['locked' => true], ['$set' => ['locked' => false]]);
194 4
            $output->writeln("<info>✓ Successfully released migration lock</info>", $output::VERBOSITY_VERBOSE);
195
        }
196 3
    }
197
}
198