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
![]() |
|||||||
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
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
![]() 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
![]() |
|||||||
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 |