Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
33 / 33
70.83% covered (warning)
70.83%
17 / 24
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
Runner
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
33 / 33
70.83% covered (warning)
70.83%
17 / 24
100.00% covered (success)
100.00%
4 / 4
29.92
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 run
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
13 / 13
42.86% covered (danger)
42.86%
3 / 7
100.00% covered (success)
100.00%
1 / 1
24.11
 finish
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
16 / 16
78.57% covered (warning)
78.57%
11 / 14
100.00% covered (success)
100.00%
1 / 1
8.63
 begin
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Celema\Quma\Migrations;
6
7use Celema\Console\Io;
8use Celema\Quma\Database;
9use Celema\Quma\Environment;
10
11final readonly class Runner
12{
13    // Internal wiring, constructed by the Migrations command only.
14    // @mago-expect lint:excessive-parameter-list
15    public function __construct(
16        private Environment $env,
17        private DriverPolicy $driverPolicy,
18        private Planner $planner,
19        private Log $log,
20        private Executor $executor,
21        private Io $io,
22    ) {}
23
24    /** @param list<string> $migrations */
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
32            $result = ($options->createMigrationsTable)();
33
34            // @codeCoverageIgnoreStart
35            if ($result !== 0) {
36                if ($this->driverPolicy->supportsTransactions()) {
37                    $db->rollback();
38                }
39
40                return $result;
41            } // @codeCoverageIgnoreEnd
42        }
43
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }
74
75    public function finish(
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
85            if ($result === Executor::ERROR) {
86                $db->rollback();
87                $io->echolnErr("\nDue to errors no migrations applied");
88
89                return 1;
90            }
91
92            if ($numApplied === 0) {
93                $db->rollback();
94                $io->echoln("\nNo migrations applied");
95
96                return 0;
97            }
98
99            if ($apply) {
100                $db->commit();
101                $io->echoln("\n{$numApplied} migration{$plural} successfully applied");
102
103                return 0;
104            }
105            $io->echoln("\n<bright-red>Notice</bright-red>: Test run only");
106            $io->echo("Rolled back {$numApplied} migration{$plural}");
107            $io->echoln('Use --apply to commit them');
108            $db->rollback();
109
110            return 0;
111        }
112
113        if ($result === Executor::ERROR) {
114            $io->echolnErr("\n{$numApplied} migration{$plural} applied until the error occured");
115
116            return 1;
117        }
118
119        if ($numApplied > 0) {
120            $io->echoln("\n{$numApplied} migration{$plural} successfully applied");
121
122            return 0;
123        }
124
125        $io->echoln("\nNo migrations applied");
126
127        return 0;
128    }
129
130    private function begin(Database $db): void
131    {
132        if ($this->driverPolicy->supportsTransactions()) {
133            $db->begin();
134        }
135    }
136}

Paths

Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once. Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

Runner->__construct
16        private Environment $env,
17        private DriverPolicy $driverPolicy,
18        private Planner $planner,
19        private Log $log,
20        private Executor $executor,
21        private Io $io,
22    ) {}
Runner->begin
130    private function begin(Database $db): void
131    {
132        if ($this->driverPolicy->supportsTransactions()) {
 
133            $db->begin();
134        }
135    }
 
135    }
130    private function begin(Database $db): void
131    {
132        if ($this->driverPolicy->supportsTransactions()) {
 
135    }
Runner->finish
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
86                $db->rollback();
87                $io->echolnErr("\nDue to errors no migrations applied");
88
89                return 1;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
92            if ($numApplied === 0) {
 
93                $db->rollback();
94                $io->echoln("\nNo migrations applied");
95
96                return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
92            if ($numApplied === 0) {
 
99            if ($apply) {
 
100                $db->commit();
101                $io->echoln("\n{$numApplied} migration{$plural} successfully applied");
102
103                return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
92            if ($numApplied === 0) {
 
99            if ($apply) {
 
105            $io->echoln("\n<bright-red>Notice</bright-red>: Test run only");
106            $io->echo("Rolled back {$numApplied} migration{$plural}");
107            $io->echoln('Use --apply to commit them');
108            $db->rollback();
109
110            return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
113        if ($result === Executor::ERROR) {
 
114            $io->echolnErr("\n{$numApplied} migration{$plural} applied until the error occured");
115
116            return 1;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
113        if ($result === Executor::ERROR) {
 
119        if ($numApplied > 0) {
 
120            $io->echoln("\n{$numApplied} migration{$plural} successfully applied");
121
122            return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
113        if ($result === Executor::ERROR) {
 
119        if ($numApplied > 0) {
 
125        $io->echoln("\nNo migrations applied");
126
127        return 0;
128    }
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
86                $db->rollback();
87                $io->echolnErr("\nDue to errors no migrations applied");
88
89                return 1;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
92            if ($numApplied === 0) {
 
93                $db->rollback();
94                $io->echoln("\nNo migrations applied");
95
96                return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
92            if ($numApplied === 0) {
 
99            if ($apply) {
 
100                $db->commit();
101                $io->echoln("\n{$numApplied} migration{$plural} successfully applied");
102
103                return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
85            if ($result === Executor::ERROR) {
 
92            if ($numApplied === 0) {
 
99            if ($apply) {
 
105            $io->echoln("\n<bright-red>Notice</bright-red>: Test run only");
106            $io->echo("Rolled back {$numApplied} migration{$plural}");
107            $io->echoln('Use --apply to commit them');
108            $db->rollback();
109
110            return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
113        if ($result === Executor::ERROR) {
 
114            $io->echolnErr("\n{$numApplied} migration{$plural} applied until the error occured");
115
116            return 1;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
113        if ($result === Executor::ERROR) {
 
119        if ($numApplied > 0) {
 
120            $io->echoln("\n{$numApplied} migration{$plural} successfully applied");
121
122            return 0;
76        Database $db,
77        string $result,
78        bool $apply,
79        int $numApplied,
80    ): int {
81        $io = $this->io;
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
 
82        $plural = $numApplied > 1 ? 's' : '';
83
84        if ($this->driverPolicy->supportsTransactions()) {
 
113        if ($result === Executor::ERROR) {
 
119        if ($numApplied > 0) {
 
125        $io->echoln("\nNo migrations applied");
126
127        return 0;
128    }
Runner->run
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
 
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
 
54                continue;
 
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
 
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
 
57            if (!$this->driverPolicy->supportsMigration($migration)) {
 
58                continue;
 
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
 
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
 
57            if (!$this->driverPolicy->supportsMigration($migration)) {
 
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
 
64                break;
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
 
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
 
57            if (!$this->driverPolicy->supportsMigration($migration)) {
 
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
 
67            if ($result === Executor::SUCCESS) {
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
 
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
 
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
 
57            if (!$this->driverPolicy->supportsMigration($migration)) {
 
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
 
67            if ($result === Executor::SUCCESS) {
 
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
 
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }
25    public function run(string $namespace, array $migrations, RunOptions $options): int
26    {
27        $db = $this->env->db;
28
29        $this->begin($db);
30
31        if (!$options->tableExists) {
 
44        $appliedMigrations = $this->log->applied($db);
45        $result = Executor::STARTED;
46        $numApplied = 0;
47
48        foreach ($migrations as $migration) {
 
48        foreach ($migrations as $migration) {
49            assert($migration !== '', 'Migration path must be a non-empty string.');
50
51            $migrationId = $this->planner->migrationId($namespace, $migration);
52
53            if (in_array($migrationId, $appliedMigrations, strict: true)) {
54                continue;
55            }
56
57            if (!$this->driverPolicy->supportsMigration($migration)) {
58                continue;
59            }
60
61            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
62
63            if ($result === Executor::ERROR) {
64                break;
65            }
66
67            if ($result === Executor::SUCCESS) {
68                $numApplied++;
69            }
70        }
71
72        return $this->finish($db, $result, $options->apply, $numApplied);
73    }