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}

Branches

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

Runner->__construct
13        private Environment $env,
14        private DriverPolicy $driverPolicy,
15        private Planner $planner,
16        private Log $log,
17        private Executor $executor,
18    ) {}
Runner->begin
125    private function begin(Database $db): void
126    {
127        if ($this->driverPolicy->supportsTransactions()) {
128            $db->begin();
129        }
130    }
130    }
Runner->finish
72        Database $db,
73        string $result,
74        bool $apply,
75        int $numApplied,
76    ): int {
77        $plural = $numApplied > 1 ? 's' : '';
77        $plural = $numApplied > 1 ? 's' : '';
77        $plural = $numApplied > 1 ? 's' : '';
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;
87            if ($numApplied === 0) {
88                $db->rollback();
89                echo "\nNo migrations applied\n";
90
91                return 0;
94            if ($apply) {
95                $db->commit();
96                echo "\n{$numApplied} migration{$plural} successfully applied\n";
97
98                return 0;
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;
108        if ($result === Executor::ERROR) {
109            echo "\n{$numApplied} migration{$plural} applied until the error occured\n";
110
111            return 1;
114        if ($numApplied > 0) {
115            echo "\n{$numApplied} migration{$plural} successfully applied\n";
116
117            return 0;
120        echo "\nNo migrations applied\n";
121
122        return 0;
123    }
Runner->run
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) {
40        $appliedMigrations = $this->log->applied($db);
41        $result = Executor::STARTED;
42        $numApplied = 0;
43
44        foreach ($migrations as $migration) {
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;
53            if (!$this->driverPolicy->supportsMigration($migration)) {
54                continue;
57            $result = $this->executor->migrate($namespace, $migration, $options->showStacktrace);
58
59            if ($result === Executor::ERROR) {
60                break;
63            if ($result === Executor::SUCCESS) {
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++;
44        foreach ($migrations as $migration) {
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    }