Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
PdoConfig
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
6 / 6
7
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
n/a
0 / 0
n/a
0 / 0
100.00% covered (success)
100.00%
1 / 1
1
 credentials
100.00% covered (success)
100.00%
1 / 1
n/a
0 / 0
n/a
0 / 0
100.00% covered (success)
100.00%
1 / 1
1
 options
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
 option
100.00% covered (success)
100.00%
2 / 2
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
 fetch
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
 effectiveOptions
100.00% covered (success)
100.00%
4 / 4
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 Celema\Quma;
6
7use PDO;
8
9/** @api */
10final class PdoConfig
11{
12    private const array DEFAULT_OPTIONS = [
13        PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
14        PDO::ATTR_EMULATE_PREPARES => true,
15        PDO::ATTR_CASE => PDO::CASE_NATURAL,
16    ];
17    private const array REQUIRED_OPTIONS = [
18        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
19    ];
20    /** For SQLite, PDO::ATTR_TIMEOUT limits waiting for a locked database instead of connecting. */
21    private const array CONNECT_TIMEOUT_DRIVERS = ['mysql', 'pgsql'];
22    private const int CONNECT_TIMEOUT = 5;
23
24    /** @param array<array-key, mixed> $options */
25    public function __construct(
26        public readonly ?string $username = null,
27        #[\SensitiveParameter]
28        public readonly ?string $password = null,
29        public readonly array $options = [],
30        public readonly int $fetchMode = PDO::FETCH_ASSOC,
31    ) {}
32
33    public function credentials(
34        string $username,
35        #[\SensitiveParameter]
36        ?string $password = null,
37    ): self {
38        return new self($username, $password, $this->options, $this->fetchMode);
39    }
40
41    /** @param array<array-key, mixed> $options */
42    public function options(array $options): self
43    {
44        return new self($this->username, $this->password, $options, $this->fetchMode);
45    }
46
47    public function option(int $attribute, mixed $value): self
48    {
49        $options = array_replace($this->options, [$attribute => $value]);
50
51        return new self($this->username, $this->password, $options, $this->fetchMode);
52    }
53
54    public function fetch(int $fetchMode): self
55    {
56        return new self($this->username, $this->password, $this->options, $fetchMode);
57    }
58
59    /** @return array<array-key, mixed> */
60    public function effectiveOptions(string $driver): array
61    {
62        $defaults = self::DEFAULT_OPTIONS;
63
64        if (in_array($driver, self::CONNECT_TIMEOUT_DRIVERS, strict: true)) {
65            $defaults[PDO::ATTR_TIMEOUT] = self::CONNECT_TIMEOUT;
66        }
67
68        return array_replace($defaults, $this->options, self::REQUIRED_OPTIONS);
69    }
70}