Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
82 / 82
90.91% covered (success)
90.91%
40 / 44
60.00% covered (warning)
60.00%
18 / 30
62.50% covered (warning)
62.50%
5 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
Executor
100.00% covered (success)
100.00%
82 / 82
90.91% covered (success)
90.91%
40 / 44
60.00% covered (warning)
60.00%
18 / 30
100.00% covered (success)
100.00%
8 / 8
49.22
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
 migrate
100.00% covered (success)
100.00%
12 / 12
84.62% covered (warning)
84.62%
11 / 13
45.45% covered (danger)
45.45%
5 / 11
100.00% covered (success)
100.00%
1 / 1
11.84
 migrateSQL
100.00% covered (success)
100.00%
5 / 5
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
 migrateCompiledSQL
100.00% covered (success)
100.00%
8 / 8
83.33% covered (warning)
83.33%
5 / 6
50.00% covered (danger)
50.00%
2 / 4
100.00% covered (success)
100.00%
1 / 1
2.50
 migrateTPQL
100.00% covered (success)
100.00%
28 / 28
91.67% covered (success)
91.67%
11 / 12
33.33% covered (danger)
33.33%
2 / 6
100.00% covered (success)
100.00%
1 / 1
8.74
 migratePHP
100.00% covered (success)
100.00%
8 / 8
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
 showEmptyMessage
100.00% covered (success)
100.00%
5 / 5
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
 showMessage
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Quma\Migrations;
6
7use Celemas\Quma\Environment;
8use RuntimeException;
9use Throwable;
10
11final readonly class Executor
12{
13    public const string STARTED = 'start';
14    public const string ERROR = 'error';
15    public const string WARNING = 'warning';
16    public const string SUCCESS = 'success';
17
18    public function __construct(
19        private Environment $env,
20        private Log $log,
21        private PhpLoader $phpLoader,
22    ) {}
23
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
29            $this->showMessage($migration, new RuntimeException('Could not read migration file'));
30
31            return self::ERROR;
32        }
33
34        if (trim($script) === '') {
35            $this->showEmptyMessage($migration);
36
37            return self::WARNING;
38        }
39
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
41            'sql' => $this->migrateSQL($namespace, $migration, $script, $showStacktrace),
42            'tpql' => $this->migrateTPQL($namespace, $migration, $showStacktrace),
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
44        };
45    }
46
47    private function migrateSQL(
48        string $namespace,
49        string $migration,
50        string $script,
51        bool $showStacktrace,
52    ): string {
53        try {
54            $script = $this->env->conn->config->placeholders?->compileSql($script, $migration) ?? $script;
55
56            return $this->migrateCompiledSQL($namespace, $migration, $script);
57        } catch (Throwable $e) {
58            $this->showMessage($migration, $e, $showStacktrace);
59
60            return self::ERROR;
61        }
62    }
63
64    private function migrateCompiledSQL(
65        string $namespace,
66        string $migration,
67        string $script,
68    ): string {
69        if (trim($script) === '') {
70            $this->showEmptyMessage($migration);
71
72            return self::WARNING;
73        }
74
75        $db = $this->env->db;
76        $db->execute($script)->run();
77        $this->log->record($db, $namespace, $migration);
78        $this->showMessage($migration);
79
80        return self::SUCCESS;
81    }
82
83    private function migrateTPQL(
84        string $namespace,
85        string $migration,
86        bool $showStacktrace,
87    ): string {
88        try {
89            $db = $this->env->db;
90            $conn = $this->env->conn;
91            $context = [
92                'driver' => $db->getPdoDriver(),
93                'db' => $db,
94                'conn' => $conn,
95            ];
96
97            $executeTemplate = static function (
98                string $templatePath,
99                array $context,
100            ): void {
101                extract($context, EXTR_SKIP);
102
103                /** @psalm-suppress UnresolvableInclude */
104                require $templatePath;
105            };
106
107            ob_start();
108            $script = '';
109
110            try {
111                $executeTemplate($migration, $context);
112                $script = ob_get_contents();
113            } finally {
114                ob_end_clean();
115            }
116
117            if (!is_string($script)) {
118                // Defensive guard for an impossible false from ob_get_contents() after ob_start().
119                $script = ''; // @codeCoverageIgnore
120            }
121
122            $script = $conn->config->placeholders?->compileSql($script, $migration) ?? $script;
123
124            if (trim($script) === '') {
125                $this->showEmptyMessage($migration);
126
127                return self::WARNING;
128            }
129
130            return $this->migrateCompiledSQL($namespace, $migration, $script);
131        } catch (Throwable $e) {
132            $this->showMessage($migration, $e, $showStacktrace);
133
134            return self::ERROR;
135        }
136    }
137
138    private function migratePHP(
139        string $namespace,
140        string $migration,
141        bool $showStacktrace,
142    ): string {
143        try {
144            $migrationObject = $this->phpLoader->load($migration);
145            $migrationObject->run($this->env);
146            $this->log->record($this->env->db, $namespace, $migration);
147            $this->showMessage($migration);
148
149            return self::SUCCESS;
150        } catch (Throwable $e) {
151            $this->showMessage($migration, $e, $showStacktrace);
152
153            return self::ERROR;
154        }
155    }
156
157    private function showEmptyMessage(string $migration): void
158    {
159        echo
160            "\033[33mWarning\033[0m: Migration '\033[1;33m"
161                . basename($migration)
162                . "'\033[0m is empty. Skipped\n"
163        ;
164    }
165
166    private function showMessage(
167        string $migration,
168        ?Throwable $e = null,
169        bool $showStacktrace = false,
170    ): void {
171        if ($e) {
172            echo
173                "\033[1;31mError\033[0m: while working on migration '\033[1;33m"
174                    . basename($migration)
175                    . "\033[0m'\n"
176            ;
177            echo $e->getMessage() . "\n";
178
179            if ($showStacktrace) {
180                echo $e->getTraceAsString() . "\n";
181            }
182
183            return;
184        }
185
186        echo
187            "\033[1;32mSuccess\033[0m: Migration '\033[1;33m"
188                . basename($migration)
189                . "\033[0m' successfully applied\n"
190        ;
191    }
192}

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.

Executor->__construct
19        private Environment $env,
20        private Log $log,
21        private PhpLoader $phpLoader,
22    ) {}
Executor->migrate
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
29            $this->showMessage($migration, new RuntimeException('Could not read migration file'));
30
31            return self::ERROR;
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
35            $this->showEmptyMessage($migration);
36
37            return self::WARNING;
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
41            'sql' => $this->migrateSQL($namespace, $migration, $script, $showStacktrace),
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
44        };
45    }
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
42            'tpql' => $this->migrateTPQL($namespace, $migration, $showStacktrace),
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
44        };
45    }
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
44        };
45    }
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
35            $this->showEmptyMessage($migration);
36
37            return self::WARNING;
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
41            'sql' => $this->migrateSQL($namespace, $migration, $script, $showStacktrace),
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
44        };
45    }
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
42            'tpql' => $this->migrateTPQL($namespace, $migration, $showStacktrace),
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
44        };
45    }
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
 
43            'php' => $this->migratePHP($namespace, $migration, $showStacktrace),
44        };
45    }
24    public function migrate(string $namespace, string $migration, bool $showStacktrace): string
25    {
26        $script = file_get_contents($migration);
27
28        if ($script === false) {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
34        if (trim($script) === '') {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
 
40        return match (pathinfo($migration, PATHINFO_EXTENSION)) {
Executor->migrateCompiledSQL
65        string $namespace,
66        string $migration,
67        string $script,
68    ): string {
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
70            $this->showEmptyMessage($migration);
71
72            return self::WARNING;
65        string $namespace,
66        string $migration,
67        string $script,
68    ): string {
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
75        $db = $this->env->db;
76        $db->execute($script)->run();
77        $this->log->record($db, $namespace, $migration);
78        $this->showMessage($migration);
79
80        return self::SUCCESS;
81    }
65        string $namespace,
66        string $migration,
67        string $script,
68    ): string {
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
70            $this->showEmptyMessage($migration);
71
72            return self::WARNING;
65        string $namespace,
66        string $migration,
67        string $script,
68    ): string {
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
69        if (trim($script) === '') {
 
75        $db = $this->env->db;
76        $db->execute($script)->run();
77        $this->log->record($db, $namespace, $migration);
78        $this->showMessage($migration);
79
80        return self::SUCCESS;
81    }
Executor->migratePHP
139        string $namespace,
140        string $migration,
141        bool $showStacktrace,
142    ): string {
143        try {
144            $migrationObject = $this->phpLoader->load($migration);
145            $migrationObject->run($this->env);
146            $this->log->record($this->env->db, $namespace, $migration);
147            $this->showMessage($migration);
148
149            return self::SUCCESS;
150        } catch (Throwable $e) {
 
151            $this->showMessage($migration, $e, $showStacktrace);
152
153            return self::ERROR;
154        }
155    }
Executor->migrateSQL
48        string $namespace,
49        string $migration,
50        string $script,
51        bool $showStacktrace,
52    ): string {
53        try {
54            $script = $this->env->conn->config->placeholders?->compileSql($script, $migration) ?? $script;
55
56            return $this->migrateCompiledSQL($namespace, $migration, $script);
57        } catch (Throwable $e) {
 
58            $this->showMessage($migration, $e, $showStacktrace);
59
60            return self::ERROR;
61        }
62    }
Executor->migrateTPQL
84        string $namespace,
85        string $migration,
86        bool $showStacktrace,
87    ): string {
88        try {
89            $db = $this->env->db;
90            $conn = $this->env->conn;
91            $context = [
92                'driver' => $db->getPdoDriver(),
93                'db' => $db,
94                'conn' => $conn,
95            ];
96
97            $executeTemplate = static function (
98                string $templatePath,
99                array $context,
100            ): void {
101                extract($context, EXTR_SKIP);
102
103                /** @psalm-suppress UnresolvableInclude */
104                require $templatePath;
105            };
106
107            ob_start();
108            $script = '';
109
110            try {
111                $executeTemplate($migration, $context);
112                $script = ob_get_contents();
113            } finally {
 
114                ob_end_clean();
84        string $namespace,
85        string $migration,
86        bool $showStacktrace,
87    ): string {
88        try {
89            $db = $this->env->db;
90            $conn = $this->env->conn;
91            $context = [
92                'driver' => $db->getPdoDriver(),
93                'db' => $db,
94                'conn' => $conn,
95            ];
96
97            $executeTemplate = static function (
98                string $templatePath,
99                array $context,
100            ): void {
101                extract($context, EXTR_SKIP);
102
103                /** @psalm-suppress UnresolvableInclude */
104                require $templatePath;
105            };
106
107            ob_start();
108            $script = '';
109
110            try {
111                $executeTemplate($migration, $context);
112                $script = ob_get_contents();
113            } finally {
 
113            } finally {
 
117            if (!is_string($script)) {
 
122            $script = $conn->config->placeholders?->compileSql($script, $migration) ?? $script;
123
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
125                $this->showEmptyMessage($migration);
126
127                return self::WARNING;
84        string $namespace,
85        string $migration,
86        bool $showStacktrace,
87    ): string {
88        try {
89            $db = $this->env->db;
90            $conn = $this->env->conn;
91            $context = [
92                'driver' => $db->getPdoDriver(),
93                'db' => $db,
94                'conn' => $conn,
95            ];
96
97            $executeTemplate = static function (
98                string $templatePath,
99                array $context,
100            ): void {
101                extract($context, EXTR_SKIP);
102
103                /** @psalm-suppress UnresolvableInclude */
104                require $templatePath;
105            };
106
107            ob_start();
108            $script = '';
109
110            try {
111                $executeTemplate($migration, $context);
112                $script = ob_get_contents();
113            } finally {
 
113            } finally {
 
117            if (!is_string($script)) {
 
122            $script = $conn->config->placeholders?->compileSql($script, $migration) ?? $script;
123
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
130            return $this->migrateCompiledSQL($namespace, $migration, $script);
84        string $namespace,
85        string $migration,
86        bool $showStacktrace,
87    ): string {
88        try {
89            $db = $this->env->db;
90            $conn = $this->env->conn;
91            $context = [
92                'driver' => $db->getPdoDriver(),
93                'db' => $db,
94                'conn' => $conn,
95            ];
96
97            $executeTemplate = static function (
98                string $templatePath,
99                array $context,
100            ): void {
101                extract($context, EXTR_SKIP);
102
103                /** @psalm-suppress UnresolvableInclude */
104                require $templatePath;
105            };
106
107            ob_start();
108            $script = '';
109
110            try {
111                $executeTemplate($migration, $context);
112                $script = ob_get_contents();
113            } finally {
 
113            } finally {
 
117            if (!is_string($script)) {
 
122            $script = $conn->config->placeholders?->compileSql($script, $migration) ?? $script;
123
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
125                $this->showEmptyMessage($migration);
126
127                return self::WARNING;
84        string $namespace,
85        string $migration,
86        bool $showStacktrace,
87    ): string {
88        try {
89            $db = $this->env->db;
90            $conn = $this->env->conn;
91            $context = [
92                'driver' => $db->getPdoDriver(),
93                'db' => $db,
94                'conn' => $conn,
95            ];
96
97            $executeTemplate = static function (
98                string $templatePath,
99                array $context,
100            ): void {
101                extract($context, EXTR_SKIP);
102
103                /** @psalm-suppress UnresolvableInclude */
104                require $templatePath;
105            };
106
107            ob_start();
108            $script = '';
109
110            try {
111                $executeTemplate($migration, $context);
112                $script = ob_get_contents();
113            } finally {
 
113            } finally {
 
117            if (!is_string($script)) {
 
122            $script = $conn->config->placeholders?->compileSql($script, $migration) ?? $script;
123
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
124            if (trim($script) === '') {
 
130            return $this->migrateCompiledSQL($namespace, $migration, $script);
131        } catch (Throwable $e) {
 
132            $this->showMessage($migration, $e, $showStacktrace);
133
134            return self::ERROR;
135        }
136    }
Executor->showEmptyMessage
157    private function showEmptyMessage(string $migration): void
158    {
159        echo
160            "\033[33mWarning\033[0m: Migration '\033[1;33m"
161                . basename($migration)
162                . "'\033[0m is empty. Skipped\n"
163        ;
164    }
Executor->showMessage
167        string $migration,
168        ?Throwable $e = null,
169        bool $showStacktrace = false,
170    ): void {
171        if ($e) {
 
174                    . basename($migration)
175                    . "\033[0m'\n"
176            ;
177            echo $e->getMessage() . "\n";
178
179            if ($showStacktrace) {
 
180                echo $e->getTraceAsString() . "\n";
181            }
182
183            return;
 
183            return;
167        string $migration,
168        ?Throwable $e = null,
169        bool $showStacktrace = false,
170    ): void {
171        if ($e) {
 
174                    . basename($migration)
175                    . "\033[0m'\n"
176            ;
177            echo $e->getMessage() . "\n";
178
179            if ($showStacktrace) {
 
183            return;
167        string $migration,
168        ?Throwable $e = null,
169        bool $showStacktrace = false,
170    ): void {
171        if ($e) {
 
188                . basename($migration)
189                . "\033[0m' successfully applied\n"
190        ;
191    }
{closure:/workspace/celemas/quma/src/Migrations/Executor.php:97-105}
98                string $templatePath,
99                array $context,
100            ): void {
101                extract($context, EXTR_SKIP);
102
103                /** @psalm-suppress UnresolvableInclude */
104                require $templatePath;
105            };