• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 18389505594

09 Oct 2025 09:21PM UTC coverage: 84.39% (+0.03%) from 84.362%
18389505594

Pull #9751

github

web-flow
Merge 3d707799b into d945236b2
Pull Request #9751: refactor(app): Standardize subdomain detection logic

16 of 16 new or added lines in 3 files covered. (100.0%)

43 existing lines in 6 files now uncovered.

21236 of 25164 relevant lines covered (84.39%)

195.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.0
/system/Database/Database.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\Database;
15

16
use CodeIgniter\Exceptions\ConfigException;
17
use CodeIgniter\Exceptions\CriticalError;
18
use CodeIgniter\Exceptions\InvalidArgumentException;
19

20
/**
21
 * Database Connection Factory
22
 *
23
 * Creates and returns an instance of the appropriate Database Connection.
24
 */
25
class Database
26
{
27
    /**
28
     * Maintains an array of the instances of all connections that have
29
     * been created.
30
     *
31
     * Helps to keep track of all open connections for performance
32
     * monitoring, logging, etc.
33
     *
34
     * @var array
35
     */
36
    protected $connections = [];
37

38
    /**
39
     * Parses the connection binds and creates a Database Connection instance.
40
     *
41
     * @return BaseConnection
42
     *
43
     * @throws InvalidArgumentException
44
     */
45
    public function load(array $params = [], string $alias = '')
46
    {
47
        if ($alias === '') {
57✔
48
            throw new InvalidArgumentException('You must supply the parameter: alias.');
×
49
        }
50

51
        if (! empty($params['DSN']) && str_contains($params['DSN'], '://')) {
57✔
52
            $params = $this->parseDSN($params);
2✔
53
        }
54

55
        if (empty($params['DBDriver'])) {
57✔
56
            throw new InvalidArgumentException('You have not selected a database type to connect to.');
×
57
        }
58

59
        assert($this->checkDbExtension($params['DBDriver']));
60

61
        $this->connections[$alias] = $this->initDriver($params['DBDriver'], 'Connection', $params);
57✔
62

63
        return $this->connections[$alias];
57✔
64
    }
65

66
    /**
67
     * Creates a Forge instance for the current database type.
68
     *
69
     * @param BaseConnection $db
70
     */
71
    public function loadForge(ConnectionInterface $db): Forge
72
    {
73
        if (! $db->connID) {
734✔
74
            $db->initialize();
5✔
75
        }
76

77
        return $this->initDriver($db->DBDriver, 'Forge', $db);
734✔
78
    }
79

80
    /**
81
     * Creates an instance of Utils for the current database type.
82
     *
83
     * @param BaseConnection $db
84
     */
85
    public function loadUtils(ConnectionInterface $db): BaseUtils
86
    {
87
        if (! $db->connID) {
15✔
88
            $db->initialize();
1✔
89
        }
90

91
        return $this->initDriver($db->DBDriver, 'Utils', $db);
15✔
92
    }
93

94
    /**
95
     * Parses universal DSN string
96
     *
97
     * @throws InvalidArgumentException
98
     */
99
    protected function parseDSN(array $params): array
100
    {
101
        $dsn = parse_url($params['DSN']);
2✔
102

103
        if (in_array($dsn, [0, '', '0', [], false, null], true)) {
2✔
104
            throw new InvalidArgumentException('Your DSN connection string is invalid.');
×
105
        }
106

107
        $dsnParams = [
2✔
108
            'DSN'      => '',
2✔
109
            'DBDriver' => $dsn['scheme'],
2✔
110
            'hostname' => isset($dsn['host']) ? rawurldecode($dsn['host']) : '',
2✔
111
            'port'     => isset($dsn['port']) ? rawurldecode((string) $dsn['port']) : '',
2✔
112
            'username' => isset($dsn['user']) ? rawurldecode($dsn['user']) : '',
2✔
113
            'password' => isset($dsn['pass']) ? rawurldecode($dsn['pass']) : '',
2✔
114
            'database' => isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : '',
2✔
115
        ];
2✔
116

117
        if (isset($dsn['query']) && ($dsn['query'] !== '')) {
2✔
118
            parse_str($dsn['query'], $extra);
2✔
119

120
            foreach ($extra as $key => $val) {
2✔
121
                if (is_string($val) && in_array(strtolower($val), ['true', 'false', 'null'], true)) {
2✔
122
                    $val = $val === 'null' ? null : filter_var($val, FILTER_VALIDATE_BOOLEAN);
1✔
123
                }
124

125
                $dsnParams[$key] = $val;
2✔
126
            }
127
        }
128

129
        return array_merge($params, $dsnParams);
2✔
130
    }
131

132
    /**
133
     * Creates a database object.
134
     *
135
     * @param string                    $driver   Driver name. FQCN can be used.
136
     * @param string                    $class    'Connection'|'Forge'|'Utils'
137
     * @param array|ConnectionInterface $argument The constructor parameter or DB connection
138
     *
139
     * @return BaseConnection|BaseUtils|Forge
140
     */
141
    protected function initDriver(string $driver, string $class, $argument): object
142
    {
143
        $classname = str_contains($driver, '\\')
756✔
UNCOV
144
            ? $driver . '\\' . $class
×
145
            : "CodeIgniter\\Database\\{$driver}\\{$class}";
756✔
146

147
        return new $classname($argument);
756✔
148
    }
149

150
    /**
151
     * Check the PHP database extension is loaded.
152
     *
153
     * @param string $driver DB driver or FQCN for custom driver
154
     */
155
    private function checkDbExtension(string $driver): bool
156
    {
157
        if (str_contains($driver, '\\')) {
×
158
            // Cannot check a fully qualified classname for a custom driver.
159
            return true;
×
160
        }
161

162
        $extensionMap = [
×
163
            // DBDriver => PHP extension
164
            'MySQLi'  => 'mysqli',
×
165
            'SQLite3' => 'sqlite3',
×
166
            'Postgre' => 'pgsql',
×
167
            'SQLSRV'  => 'sqlsrv',
×
168
            'OCI8'    => 'oci8',
×
169
        ];
×
170

171
        $extension = $extensionMap[$driver] ?? '';
×
172

173
        if ($extension === '') {
×
174
            $message = 'Invalid DBDriver name: "' . $driver . '"';
×
175

176
            throw new ConfigException($message);
×
177
        }
178

179
        if (extension_loaded($extension)) {
×
180
            return true;
×
181
        }
182

183
        $message = 'The required PHP extension "' . $extension . '" is not loaded.'
×
184
            . ' Install and enable it to use "' . $driver . '" driver.';
×
185

186
        throw new CriticalError($message);
×
187
    }
188
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc