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