PDOConnectionConfig   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 76
Duplicated Lines 0 %

Test Coverage

Coverage 90%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 21
dl 0
loc 76
ccs 18
cts 20
cp 0.9
rs 10
c 1
b 0
f 0
wmc 8

4 Methods

Rating   Name   Duplication   Size   Complexity  
A dsnValueToString() 0 8 2
A __construct() 0 8 1
A getOptions() 0 3 1
A dsn() 0 15 4
1
<?php
2
3
/**
4
 * This file is part of Cycle Database package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Database\Config;
13
14
/**
15
 * List of connection examples:
16
 *  - MS SQL   - dblib:host=localhost:3007;dbname=dbname
17
 *  - MS SQL   - sqlsrv:Server=localhost,1521;Database=dbname
18
 *  - CUBRID   - cubrid:dbname=dbname;host=localhost;port=33000
19
 *  - MySQL    - mysql:host=localhost;port=3307;dbname=dbname
20
 *  - MySQL    - mysql:unix_socket=/tmp/mysql.sock;dbname=dbname
21
 *  - Firebird - firebird:dbname=localhost:/path/to/file.eu3
22
 *  - Firebird - firebird:dbname=localhost:example;charset=utf8;
23
 *  - IBM      - ibm:DRIVER={IBM DB2 ODBC DRIVER};DATABASE=dbname;HOSTNAME=localhost;
24
 *               PORT=56789;PROTOCOL=TCPIP;UID=user;PWD=pass
25
 *  - Informix - informix:host=localhost;service=9800;database=dbname;server=ids_server;
26
 *               protocol=onsoctcp;EnableScrollableCursors=1
27
 *  - Oracle   - oci:dbname=//localhost:1521/dbname
28
 *  - Oracle   - oci:dbname=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))
29
 *               (CONNECT_DATA=(SERVICE_NAME=ORCL)(SID=ORCL)))
30
 *  - ODBC/DB2 - odbc:DRIVER={IBM DB2 ODBC DRIVER};HOSTNAME=localhost;PORT=50000;DATABASE=dbname;
31
 *               PROTOCOL=TCPIP;UID=db2inst1;PWD=ibmdb2;
32
 *  - Postgres - pgsql:host=localhost;port=5432;dbname=dbname;user=login;password=pass
33
 *  - SQLite   - sqlite:/path/to/database.db
34
 *  - SQLite   - sqlite::memory:
35
 *  - SQLite   - sqlite:
36
 *
37
 * @psalm-type PDOFlag = \PDO::ATTR_*
38
 */
39
abstract class PDOConnectionConfig extends ConnectionConfig
40
{
41
    /**
42
     * General driver specific PDO options.
43
     *
44
     * @var array<PDOFlag, mixed>
45
     */
46
    protected const DEFAULT_PDO_OPTIONS = [
47
        \PDO::ATTR_CASE => \PDO::CASE_NATURAL,
48
        \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
49
        \PDO::ATTR_EMULATE_PREPARES => false,
50
    ];
51
52
    /**
53
     * @param non-empty-string|null $user
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string|null at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string|null.
Loading history...
54
     * @param non-empty-string|null $password
55
     * @param array<PDOFlag, mixed> $options
56
     */
57 60
    public function __construct(
58
        ?string $user = null,
59
        ?string $password = null,
60
        public array $options = [],
61
    ) {
62 60
        parent::__construct($user, $password);
63
64 60
        $this->options = \array_replace(static::DEFAULT_PDO_OPTIONS, $this->options);
65 60
    }
66
67
    /**
68
     * @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...
69
     */
70
    abstract public function getName(): string;
71
72
    /**
73
     * @return array<PDOFlag, mixed>
74
     */
75 62
    public function getOptions(): array
76
    {
77 62
        return $this->options;
78
    }
79
80
    /**
81
     * Returns PDO data source name.
82
     *
83
     */
84
    abstract public function getDsn(): string;
85 54
86
    /**
87 54
     * @param iterable<int, mixed|non-empty-string> ...$fields
88
     *
89 54
     */
90 54
    protected function dsn(iterable $fields): string
91 14
    {
92
        $result = [];
93
94 54
        foreach ($fields as $key => $value) {
95 54
            if ($value === null) {
96
                continue;
97
            }
98
99 54
            $result[] = \is_string($key)
100
                ? \sprintf('%s=%s', $key, $this->dsnValueToString($value))
101
                : $this->dsnValueToString($value);
102
        }
103
104
        return \implode(';', $result);
105
    }
106
107 54
    private function dsnValueToString(mixed $value): string
108
    {
109
        return match (true) {
110 54
            \is_bool($value) => $value ? '1' : '0',
111
            // TODO Think about escaping special chars in strings
112 54
            \is_scalar($value), $value instanceof \Stringable => (string) $value,
113
            default => throw new \InvalidArgumentException(
114 54
                \sprintf('Can not convert config value of type "%s" to string', \get_debug_type($value)),
115
            ),
116
        };
117
    }
118
}
119