Passed
Push — main ( 9c95cc...5952b6 )
by Thomas
01:49
created

Connection::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 8
dl 0
loc 14
ccs 5
cts 5
cp 1
crap 1
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Conia\Quma;
6
7
use Conia\Quma\Util;
8
use PDO;
9
use RuntimeException;
10
use ValueError;
11
12
/**
13
 * @psalm-type MigrationDirs = list<non-empty-string>
14
 * @psalm-type SqlDirs = list<non-empty-string>
15
 * @psalm-type SqlAssoc = array<non-empty-string, non-empty-string>
16
 * @psalm-type SqlMixed = list<non-empty-string|SqlAssoc>
17
 * @psalm-type SqlConfig = non-empty-string|SqlAssoc|SqlMixed
18
 */
19
class Connection
20
{
21
    use GetsSetsPrint;
22
23
    /** @var non-empty-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
24
    public readonly string $driver;
25
26
    /** @var SqlDirs */
0 ignored issues
show
Bug introduced by
The type Conia\Quma\SqlDirs was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
    protected array $sql;
28
29
    /** @var MigrationDirs */
0 ignored issues
show
Bug introduced by
The type Conia\Quma\MigrationDirs was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
    protected array $migrations;
31
32
    protected string $migrationsTable = 'migrations';
33
    protected string $migrationsColumnMigration = 'migration';
34
    protected string $migrationsColumnApplied = 'applied';
35
36
    /**
37
     * @psalm-param SqlConfig $sql
38
     * @psalm-param MigrationDirs $migrations
39
     * */
40 82
    public function __construct(
41
        public readonly string $dsn,
42
        string|array $sql,
43
        string|array $migrations = null,
44
        public readonly ?string $username = null,
45
        public readonly ?string $password = null,
46
        public readonly array $options = [],
47
        public readonly int $fetchMode = PDO::FETCH_BOTH,
48
        bool $print = false
49
    ) {
50 82
        $this->driver = $this->readDriver($this->dsn);
1 ignored issue
show
Bug introduced by
The property driver is declared read-only in Conia\Quma\Connection.
Loading history...
51 81
        $this->sql = $this->readDirs($sql);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->readDirs($sql) of type array or string[] is incompatible with the declared type Conia\Quma\SqlDirs of property $sql.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
52 80
        $this->migrations = $this->readDirs($migrations ?? []);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->readDirs($migrations ?? array()) of type array or string[] is incompatible with the declared type Conia\Quma\MigrationDirs of property $migrations.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
53 79
        $this->print = $print;
54
    }
55
56 71
    public function setMigrationsTable(string $table): void
57
    {
58 71
        $this->migrationsTable = $table;
59
    }
60
61 2
    public function setMigrationsColumnMigration(string $column): void
62
    {
63 2
        $this->migrationsColumnMigration = $column;
64
    }
65
66 2
    public function setMigrationsColumnApplied(string $column): void
67
    {
68 2
        $this->migrationsColumnApplied = $column;
69
    }
70
71 40
    public function migrationsTable(): string
72
    {
73 40
        if ($this->driver === 'pgsql') {
74
            // PostgreSQL table names can contain a schema
75 9
            if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $this->migrationsTable)) {
76 9
                return $this->migrationsTable;
77
            }
78
        } else {
79 31
            if (preg_match('/^[a-zA-Z0-9_]+$/', $this->migrationsTable)) {
80 30
                return $this->migrationsTable;
81
            }
82
        }
83
84 1
        throw new ValueError('Invalid migrations table name: ' . $this->migrationsTable);
85
    }
86
87 40
    public function migrationsColumnMigration(): string
88
    {
89 40
        return $this->getColumnName($this->migrationsColumnMigration);
90
    }
91
92 40
    public function migrationsColumnApplied(): string
93
    {
94 40
        return $this->getColumnName($this->migrationsColumnApplied);
95
    }
96
97
    /** @psalm-param non-empty-string $migrations */
98 1
    public function addMigrationDir(string $migrations): void
99
    {
100 1
        $migrations = $this->readDirs($migrations);
101 1
        $this->migrations = array_merge($migrations, $this->migrations);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($migrations, $this->migrations) of type array is incompatible with the declared type Conia\Quma\MigrationDirs of property $migrations.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
102
    }
103
104
    /** @psalm-return MigrationDirs */
105 28
    public function migrations(): array
106
    {
107 28
        return $this->migrations;
108
    }
109
110
    /** @psalm-param SqlConfig $sql */
111 1
    public function addSqlDirs(array|string $sql): void
112
    {
113 1
        $sql = $this->readDirs($sql);
114 1
        $this->sql = array_merge($sql, $this->sql);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($sql, $this->sql) of type array is incompatible with the declared type Conia\Quma\SqlDirs of property $sql.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
115
    }
116
117 30
    public function sql(): array
118
    {
119 30
        return $this->sql;
120
    }
121
122
    /** @return non-empty-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
123 81
    protected function preparePath(string $path): string
124
    {
125 81
        $result = realpath($path);
126
127 81
        if ($result) {
128 81
            return $result;
129
        }
130
131 1
        throw new ValueError("Path does not exist: {$path}");
132
    }
133
134
    /** @return non-empty-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
135 82
    protected function readDriver(string $dsn): string
136
    {
137 82
        $driver = explode(':', $dsn)[0];
138
139 82
        if (in_array($driver, PDO::getAvailableDrivers())) {
140
            assert(!empty($driver));
141
142 81
            return $driver;
143
        }
144
145 1
        throw new RuntimeException('PDO driver not supported: ' . $driver);
146
    }
147
148
    /**
149
     * @psalm-param SqlAssoc $entry
150
     *
151
     * @psalm-return MigrationDirs
152
     */
153 7
    protected function prepareDirs(array $entry): array
154
    {
155
        /** @var MigrationDirs */
156 7
        $dirs = [];
157
158
        // Add sql scripts for the current pdo driver.
159
        // Should be the first in the list as they
160
        // may have platform specific queries.
161 7
        if (array_key_exists($this->driver, $entry)) {
162 7
            $dirs[] = $this->preparePath($entry[$this->driver]);
163
        }
164
165
        // Add sql scripts for all platforms
166 7
        if (array_key_exists('all', $entry)) {
167 6
            $dirs[] = $this->preparePath($entry['all']);
168
        }
169
170 7
        return $dirs;
171
    }
172
173
    /**
174
     * Adds the sql script paths from configuration.
175
     *
176
     * Script paths are ordered last in first out (LIFO).
177
     * Which means the last path added is the first one searched
178
     * for a SQL script.
179
     *
180
     * @psalm-param SqlConfig $sql
181
     *
182
     * @return MigrationDirs
183
     */
184 81
    protected function readDirs(string|array $sql): array
185
    {
186 81
        if (is_string($sql)) {
0 ignored issues
show
introduced by
The condition is_string($sql) is always false.
Loading history...
187
            /** @var MigrationDirs */
188 78
            return [$this->preparePath($sql)];
189
        }
190
191 16
        if (Util::isAssoc($sql)) {
192
            /** @var SqlAssoc $sql */
193 2
            return $this->prepareDirs($sql);
0 ignored issues
show
Bug introduced by
$sql of type Conia\Quma\SqlAssoc is incompatible with the type array expected by parameter $entry of Conia\Quma\Connection::prepareDirs(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

193
            return $this->prepareDirs(/** @scrutinizer ignore-type */ $sql);
Loading history...
Bug Best Practice introduced by
The expression return $this->prepareDirs($sql) returns the type array|string[] which is incompatible with the documented return type Conia\Quma\MigrationDirs.
Loading history...
194
        }
195
196
        /** @var MigrationDirs */
197 16
        $dirs = [];
198
199 16
        foreach ($sql as $entry) {
200 7
            if (is_string($entry)) {
201 7
                array_unshift($dirs, $this->preparePath($entry));
202
203 7
                continue;
204
            }
205
206 6
            if (Util::isAssoc($entry)) {
207 5
                $dirs = array_merge($this->prepareDirs($entry), $dirs);
208
209 5
                continue;
210
            }
211
212 1
            throw new ValueError(
213 1
                "A single 'sql' item must be either a string or an associative array"
214 1
            );
215
        }
216
217 15
        return $dirs;
218
    }
219
220 41
    protected function getColumnName(string $column): string
221
    {
222 41
        if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) {
223 39
            return $column;
224
        }
225
226 2
        throw new ValueError('Invalid migrations table column name: ' . $column);
227
    }
228
}
229