Passed
Push — dbal ( e2fd69...784ce7 )
by Greg
10:28
created

DB::nchar()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 8
rs 10
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2023 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees;
21
22
use Doctrine\DBAL\Configuration;
23
use Doctrine\DBAL\Connection;
24
use Doctrine\DBAL\Driver as DBALDriver;
25
use Doctrine\DBAL\Query\Expression\ExpressionBuilder;
26
use Doctrine\DBAL\Query\QueryBuilder;
27
use DomainException;
28
use Fisharebest\Webtrees\DB\Column;
29
use Fisharebest\Webtrees\DB\ColumnType;
30
use Fisharebest\Webtrees\DB\Drivers\DriverInterface;
31
use Fisharebest\Webtrees\DB\Drivers\MySQLDriver;
32
use Fisharebest\Webtrees\DB\Drivers\PostgreSQLDriver;
33
use Fisharebest\Webtrees\DB\Drivers\SQLiteDriver;
34
use Fisharebest\Webtrees\DB\Drivers\SQLServerDriver;
35
use Fisharebest\Webtrees\DB\ForeignKey;
36
use Fisharebest\Webtrees\DB\Index;
37
use Fisharebest\Webtrees\DB\PrimaryKey;
38
use Fisharebest\Webtrees\DB\UniqueIndex;
39
use Illuminate\Database\Capsule\Manager;
40
use PDO;
41
42
use function array_key_first;
43
use function count;
44
use function str_starts_with;
45
46
/**
47
 * Static access to doctrine/dbal and laravel database
48
 */
49
class DB extends Manager
50
{
51
    private static Connection $connection;
52
53
    private static string $prefix;
54
55
    private static DBALDriver&DriverInterface $driver;
56
57
    public static function connect(PDO $pdo, string $prefix): void
58
    {
59
        $configuration = new Configuration();
60
        $configuration->setSchemaAssetsFilter(static fn (string $name): bool => str_starts_with($name, $prefix));
61
62
        $driver_name = $pdo->getAttribute(attribute: PDO::ATTR_DRIVER_NAME);
63
64
        self::$driver = match ($driver_name) {
65
            'mysql'    => new MySQLDriver(pdo: $pdo),
66
            'postgres' => new PostgreSQLDriver(pdo: $pdo),
67
            'sqlite'   => new SQLiteDriver(pdo: $pdo),
68
            'sqlsrv'   => new SQLServerDriver(pdo: $pdo),
69
            default    => throw new DomainException(message: 'No driver available for ' . $driver_name),
70
        };
71
72
        self::$connection = new Connection(params: [], driver: self::$driver, config: $configuration);
73
        self::$prefix     = $prefix;
74
    }
75
76
    /**
77
     * @todo - better function names are used by laravel, and we need them for the time being.
78
     */
79
    public static function getTheConnection()
80
    {
81
        return self::$connection;
82
    }
83
84
    public static function prefix(string $identifier = ''): string
85
    {
86
        return self::$prefix . $identifier;
87
    }
88
89
    public static function select(string ...$expressions): QueryBuilder
90
    {
91
        return self::$connection
92
            ->createQueryBuilder()
93
            ->select(...$expressions);
94
    }
95
96
    public static function update(string $table): QueryBuilder
97
    {
98
        return self::$connection->update(DB::prefix($table));
0 ignored issues
show
Bug introduced by
The call to Doctrine\DBAL\Connection::update() has too few arguments starting with data. ( Ignorable by Annotation )

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

98
        return self::$connection->/** @scrutinizer ignore-call */ update(DB::prefix($table));

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
99
    }
100
101
    /**
102
     * @param string                                                $table
103
     * @param array<array-key,array<string,int|float|string|null>>  $rows
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key,array<st...int|float|string|null>> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key,array<string,int|float|string|null>>.
Loading history...
104
     */
105
    public static function insert(string $table, array $rows): void
106
    {
107
        foreach ($rows as $row) {
108
            DB::getTheConnection()->insert(DB::prefix($table), $row);
109
        }
110
    }
111
112
    public static function delete(string ...$expressions): QueryBuilder
113
    {
114
        return self::$connection
115
            ->createQueryBuilder()
116
            ->delete(...$expressions);
0 ignored issues
show
Bug introduced by
$expressions is expanded, but the parameter $table of Doctrine\DBAL\Query\QueryBuilder::delete() does not expect variable arguments. ( Ignorable by Annotation )

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

116
            ->delete(/** @scrutinizer ignore-type */ ...$expressions);
Loading history...
117
    }
118
119
    public static function expression(): ExpressionBuilder
120
    {
121
        return self::$connection->createExpressionBuilder();
122
    }
123
124
125
    public static function char(string $name, int $length): Column
126
    {
127
        return new Column(
128
            name: $name,
129
            type: ColumnType::Char,
130
            length: $length,
131
            fixed: true,
132
            collation: self::$driver->collationASCII(),
133
        );
134
    }
135
136
    public static function varchar(string $name, int $length): Column
137
    {
138
        return new Column(
139
            name: $name,
140
            type: ColumnType::Char,
141
            length: $length,
142
            collation: self::$driver->collationASCII(),
143
        );
144
    }
145
146
    public static function nchar(string $name, int $length): Column
147
    {
148
        return new Column(
149
            name: $name,
150
            type: ColumnType::NChar,
151
            length: $length,
152
            fixed: true,
153
            collation: self::$driver->collationUTF8(),
154
        );
155
    }
156
157
    public static function nvarchar(string $name, int $length): Column
158
    {
159
        return new Column(
160
            name: $name,
161
            type: ColumnType::NVarChar,
162
            length: $length,
163
            collation: self::$driver->collationUTF8(),
164
        );
165
    }
166
167
    public static function integer(string $name): Column
168
    {
169
        return new Column(name: $name, type: ColumnType::Integer);
170
    }
171
172
    public static function float(string $name): Column
173
    {
174
        return new Column(name: $name, type: ColumnType::Float);
175
    }
176
177
    public static function text(string $name): Column
178
    {
179
        return new Column(
180
            name: $name,
181
            type: ColumnType::Text,
182
            collation: self::$driver->collationUTF8(),
183
        );
184
    }
185
186
    public static function timestamp(string $name, int $precision = 0): Column
187
    {
188
        return new Column(name: $name, type: ColumnType::Timestamp, precision: $precision);
189
    }
190
191
    /**
192
     * @param array<array-key,string> $columns
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key,string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key,string>.
Loading history...
193
     *
194
     * @return PrimaryKey
195
     */
196
    public static function primaryKey(array $columns): PrimaryKey
197
    {
198
        return new PrimaryKey(columns: $columns);
199
    }
200
201
    /**
202
     * @param array<array-key,string> $columns
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key,string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key,string>.
Loading history...
203
     *
204
     * @return Index
205
     */
206
    public static function index(array $columns): Index
207
    {
208
        return new Index(columns: $columns);
209
    }
210
211
    /**
212
     * @param array<array-key,string> $columns
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key,string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key,string>.
Loading history...
213
     *
214
     * @return UniqueIndex
215
     */
216
    public static function uniqueIndex(array $columns): UniqueIndex
217
    {
218
        return new UniqueIndex(columns: $columns);
219
    }
220
221
    /**
222
     * @param array<array-key,string> $local_columns
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key,string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key,string>.
Loading history...
223
     * @param string                  $foreign_table
224
     * @param array<array-key,string> $foreign_columns
225
     *
226
     * @return ForeignKey
227
     */
228
    public static function foreignKey(array $local_columns, string $foreign_table, array $foreign_columns = null): ForeignKey
229
    {
230
        return new ForeignKey(
231
            local_columns: $local_columns,
232
            foreign_table: $foreign_table,
233
            foreign_columns: $foreign_columns ?? $local_columns,
234
        );
235
    }
236
237
    /**
238
     * @internal
239
     */
240
    public static function caseInsensitiveLikeOperator(): string
241
    {
242
        if (DB::getTheConnection()->getDriverName() === 'pgsql') {
0 ignored issues
show
Bug introduced by
The method getDriverName() does not exist on Doctrine\DBAL\Connection. Did you maybe mean getDriver()? ( Ignorable by Annotation )

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

242
        if (DB::getTheConnection()->/** @scrutinizer ignore-call */ getDriverName() === 'pgsql') {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
243
            return 'ILIKE';
244
        }
245
246
        if (DB::getTheConnection()->getDriverName() === 'sqlsrv') {
247
            return 'COLLATE SQL_UTF8_General_CI_AI LIKE';
248
        }
249
250
        return 'LIKE';
251
    }
252
}
253