Database::getDrivers()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 16
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Biurad opensource projects.
7
 *
8
 * PHP version 7.2 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Biurad\Cycle;
19
20
use Biurad\DependencyInjection\FactoryInterface;
21
use Closure;
22
use Psr\Container\ContainerExceptionInterface;
23
use Psr\Log\LoggerAwareInterface;
24
use Psr\Log\LoggerAwareTrait;
25
use Psr\Log\NullLogger;
26
use Spiral\Core\Container\Autowire;
27
use Spiral\Database\Config\DatabaseConfig;
28
use Spiral\Database\Config\DatabasePartial;
29
use Spiral\Database\Database as SpiralDatabase;
30
use Spiral\Database\DatabaseInterface;
31
use Spiral\Database\DatabaseProviderInterface;
32
use Spiral\Database\Driver\DriverInterface;
33
use Spiral\Database\Exception\DBALException;
34
35
/**
36
 * Automatic factory and configurator for Drivers and Databases.
37
 *
38
 * Example:
39
 * $config = [
40
 *  'default'     => 'default',
41
 *  'aliases'     => [
42
 *      'default'  => 'primary',
43
 *      'database' => 'primary',
44
 *      'db'       => 'primary',
45
 *  ],
46
 *  'databases'   => [
47
 *      'primary'   => [
48
 *          'connection'  => 'mysql',
49
 *          'tablePrefix' => 'db_'
50
 *      ],
51
 *      'secondary' => [
52
 *          'connection'  => 'postgres',
53
 *          'tablePrefix' => '',
54
 *      ],
55
 *  ],
56
 *  'connections' => [
57
 *      'mysql'     => [
58
 *          'driver'     => Driver\MySQL\MySQLDriver::class,
59
 *          'options' => [
60
 *              'connection' => 'mysql:host=127.0.0.1;dbname=database',
61
 *              'username'   => 'mysql',
62
 *              'password'   => 'mysql',
63
 *           ],
64
 *      ],
65
 *      'postgres'  => [
66
 *          'driver'     => Driver\Postgres\PostgresDriver::class,
67
 *          'options' => [
68
 *              'connection' => 'pgsql:host=127.0.0.1;dbname=database',
69
 *              'username'   => 'postgres',
70
 *              'password'   => 'postgres',
71
 *           ],
72
 *      ],
73
 *      'runtime'   => [
74
 *          'driver'     => Driver\SQLite\SQLiteDriver::class,
75
 *          'options' => [
76
 *              'connection' => 'sqlite:' . directory('runtime') . 'runtime.db',
77
 *              'username'   => 'sqlite',
78
 *           ],
79
 *      ],
80
 *      'sqlServer' => [
81
 *          'driver'     => Driver\SQLServer\SQLServerDriver::class,
82
 *          'options' => [
83
 *              'connection' => 'sqlsrv:Server=OWNER;Database=DATABASE',
84
 *              'username'   => 'sqlServer',
85
 *              'password'   => 'sqlServer',
86
 *           ],
87
 *      ],
88
 *   ]
89
 * ];
90
 *
91
 * $manager = new DatabaseManager(new DatabaseConfig($config));
92
 *
93
 * echo $manager->database('runtime')->select()->from('users')->count();
94
 */
95
final class Database implements DatabaseProviderInterface
96
{
97
    use LoggerAwareTrait;
98
99
    /** @var DatabaseConfig */
100
    private $config;
101
102
    /** @var FactoryInterface */
103
    private $factory;
104
105
    /** @var SpiralDatabase[] */
106
    private $databases = [];
107
108
    /** @var DriverInterface[] */
109
    private $drivers = [];
110
111
    /**
112
     * @param DatabaseConfig   $config
113
     * @param FactoryInterface $factory
114
     */
115
    public function __construct(DatabaseConfig $config, FactoryInterface $factory)
116
    {
117
        $this->config  = $config;
118
        $this->factory = $factory;
119
    }
120
121
    /**
122
     * Get all databases.
123
     *
124
     * @throws DatabaseException
125
     *
126
     * @return DatabaseInterface[]
127
     */
128
    public function getDatabases(): array
129
    {
130
        $names = \array_unique(
131
            \array_merge(
132
                \array_keys($this->databases),
133
                \array_keys($this->config->getDatabases())
134
            )
135
        );
136
137
        $result = [];
138
139
        foreach ($names as $name) {
140
            $result[] = $this->database($name);
141
        }
142
143
        return $result;
144
    }
145
146
    /**
147
     * Get Database associated with a given database alias or automatically created one.
148
     *
149
     * @param null|string $database
150
     *
151
     * @throws DBALException
152
     *
153
     * @return DatabaseInterface
154
     */
155
    public function database(string $database = null): DatabaseInterface
156
    {
157
        if ($database === null) {
158
            $database = $this->config->getDefaultDatabase();
159
        }
160
161
        //Spiral support ability to link multiple virtual databases together using aliases
162
        $database = $this->config->resolveAlias($database);
163
164
        if (isset($this->databases[$database])) {
165
            return $this->databases[$database];
166
        }
167
168
        if (!$this->config->hasDatabase($database)) {
169
            throw new DBALException(
170
                "Unable to create Database, no presets for '{$database}' found"
171
            );
172
        }
173
174
        return $this->databases[$database] = $this->makeDatabase(
175
            $this->config->getDatabase($database)
176
        );
177
    }
178
179
    /**
180
     * Add new database.
181
     *
182
     * @param SpiralDatabase $database
183
     *
184
     * @throws DBALException
185
     */
186
    public function addDatabase(SpiralDatabase $database): void
187
    {
188
        if (isset($this->databases[$database->getName()])) {
189
            throw new DBALException("Database '{$database->getName()}' already exists");
190
        }
191
192
        $this->databases[$database->getName()] = $database;
193
    }
194
195
    /**
196
     * Get instance of every available driver/connection.
197
     *
198
     * @throws DBALException
199
     *
200
     * @return DriverInterface[]
201
     */
202
    public function getDrivers(): array
203
    {
204
        $names = \array_unique(
205
            \array_merge(
206
                \array_keys($this->drivers),
207
                \array_keys($this->config->getDrivers())
208
            )
209
        );
210
211
        $result = [];
212
213
        foreach ($names as $name) {
214
            $result[] = $this->driver($name);
215
        }
216
217
        return $result;
218
    }
219
220
    /**
221
     * Get driver instance by it's name or automatically create one.
222
     *
223
     * @param string $driver
224
     *
225
     * @throws DBALException
226
     *
227
     * @return DriverInterface
228
     */
229
    public function driver(string $driver): DriverInterface
230
    {
231
        if (isset($this->drivers[$driver])) {
232
            return $this->drivers[$driver];
233
        }
234
235
        $factory = clone $this->factory;
236
237
        try {
238
            $driverObject = Closure::bind(
239
                static function (Autowire $autowire) use ($factory): DriverInterface {
240
                    return $factory->createInstance($autowire->alias, $autowire->parameters);
0 ignored issues
show
Bug introduced by
The property parameters is declared private in Spiral\Core\Container\Autowire and cannot be accessed from this context.
Loading history...
Bug introduced by
The property alias is declared private in Spiral\Core\Container\Autowire and cannot be accessed from this context.
Loading history...
241
                },
242
                null,
243
                Autowire::class
244
            );
245
            $driverObject = $driverObject($this->config->getDriver($driver));
246
247
            $this->drivers[$driver] = $driverObject;
248
249
            if ($driverObject instanceof LoggerAwareInterface) {
250
                if (!$this->logger instanceof NullLogger) {
251
                    $driverObject->setLogger($this->logger);
252
                }
253
            }
254
255
            return $this->drivers[$driver];
256
        } catch (ContainerExceptionInterface $e) {
257
            throw new DBALException($e->getMessage(), $e->getCode(), $e);
0 ignored issues
show
Bug introduced by
The method getMessage() does not exist on Psr\Container\ContainerExceptionInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Psr\Container\NotFoundExceptionInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

257
            throw new DBALException($e->/** @scrutinizer ignore-call */ getMessage(), $e->getCode(), $e);
Loading history...
Bug introduced by
The method getCode() does not exist on Psr\Container\ContainerExceptionInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Psr\Container\NotFoundExceptionInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

257
            throw new DBALException($e->getMessage(), $e->/** @scrutinizer ignore-call */ getCode(), $e);
Loading history...
258
        }
259
    }
260
261
    /**
262
     * Manually set connection instance.
263
     *
264
     * @param string          $name
265
     * @param DriverInterface $driver
266
     *
267
     * @throws DBALException
268
     *
269
     * @return self
270
     */
271
    public function addDriver(string $name, DriverInterface $driver): Database
272
    {
273
        if (isset($this->drivers[$name])) {
274
            throw new DBALException("Connection '{$name}' already exists");
275
        }
276
277
        $this->drivers[$name] = $driver;
278
279
        return $this;
280
    }
281
282
    /**
283
     * @param DatabasePartial $database
284
     *
285
     * @throws DBALException
286
     *
287
     * @return SpiralDatabase
288
     */
289
    protected function makeDatabase(DatabasePartial $database): SpiralDatabase
290
    {
291
        return new SpiralDatabase(
292
            $database->getName(),
293
            $database->getPrefix(),
294
            $this->driver($database->getDriver()),
295
            $database->getReadDriver() ? $this->driver($database->getReadDriver()) : null
296
        );
297
    }
298
}
299