1 | <?php |
||
2 | |||
3 | namespace Bdf\Prime\Connection; |
||
4 | |||
5 | use Bdf\Dsn\Dsn; |
||
6 | use Bdf\Prime\Connection\Configuration\ConfigurationResolver; |
||
7 | use Bdf\Prime\Connection\Configuration\ConfigurationResolverInterface; |
||
8 | use Bdf\Prime\Connection\Factory\ConnectionFactory; |
||
9 | use Bdf\Prime\Connection\Factory\ConnectionFactoryInterface; |
||
10 | use Bdf\Prime\ConnectionRegistryInterface; |
||
11 | use Bdf\Prime\Exception\DBALException; |
||
12 | |||
13 | /** |
||
14 | * ConnectionRegistry |
||
15 | */ |
||
16 | class ConnectionRegistry implements ConnectionRegistryInterface |
||
17 | { |
||
18 | /** |
||
19 | * The connection factory |
||
20 | * |
||
21 | * @var ConnectionFactoryInterface |
||
22 | */ |
||
23 | private $connectionFactory; |
||
24 | |||
25 | /** |
||
26 | * The configuration resolver |
||
27 | * |
||
28 | * @var ConfigurationResolverInterface |
||
29 | */ |
||
30 | private $configResolver; |
||
31 | |||
32 | /** |
||
33 | * The configuration map |
||
34 | * Contains configuration of some connections |
||
35 | * |
||
36 | * @var array |
||
37 | */ |
||
38 | private $parametersMap; |
||
39 | |||
40 | /** |
||
41 | * The drive name alias |
||
42 | * |
||
43 | * @var array |
||
44 | */ |
||
45 | private static $driverSchemeAliases = [ |
||
46 | 'db2' => 'ibm_db2', |
||
47 | 'mssql' => 'pdo_sqlsrv', |
||
48 | 'mysql' => 'pdo_mysql', |
||
49 | 'mysql2' => 'pdo_mysql', // Amazon RDS, for some weird reason |
||
50 | 'postgres' => 'pdo_pgsql', |
||
51 | 'postgresql' => 'pdo_pgsql', |
||
52 | 'pgsql' => 'pdo_pgsql', |
||
53 | 'sqlite' => 'pdo_sqlite', |
||
54 | 'sqlite3' => 'pdo_sqlite', |
||
55 | ]; |
||
56 | |||
57 | /** |
||
58 | * Set default configuration |
||
59 | * |
||
60 | * @param array $parametersMap |
||
61 | * @param ConnectionFactoryInterface|null $connectionFactory |
||
62 | * @param ConfigurationResolverInterface|null $configResolver |
||
63 | */ |
||
64 | 476 | public function __construct(array $parametersMap = [], ConnectionFactoryInterface $connectionFactory = null, ConfigurationResolverInterface $configResolver = null) |
|
65 | { |
||
66 | 476 | $this->parametersMap = $parametersMap; |
|
67 | 476 | $this->connectionFactory = $connectionFactory ?? new ConnectionFactory(); |
|
68 | 476 | $this->configResolver = $configResolver ?? new ConfigurationResolver(); |
|
69 | } |
||
70 | |||
71 | /** |
||
72 | * {@inheritDoc} |
||
73 | */ |
||
74 | 404 | public function getConnection(string $name): ConnectionInterface |
|
75 | { |
||
76 | 404 | return $this->connectionFactory->create($name, $this->getConnectionParameters($name), $this->configResolver->getConfiguration($name)); |
|
77 | } |
||
78 | |||
79 | /** |
||
80 | * Associate configuration to connection |
||
81 | * |
||
82 | * @param string $connectionName |
||
83 | * @param string|array $parameters |
||
84 | * |
||
85 | * @return void |
||
86 | */ |
||
87 | 59 | public function declareConnection(string $connectionName, $parameters): void |
|
88 | { |
||
89 | 59 | $this->parametersMap[$connectionName] = $parameters; |
|
90 | } |
||
91 | |||
92 | /** |
||
93 | * {@inheritDoc} |
||
94 | */ |
||
95 | 5 | public function getConnectionNames(): array |
|
96 | { |
||
97 | 5 | return array_keys($this->parametersMap); |
|
98 | } |
||
99 | |||
100 | /** |
||
101 | * Create the doctrine config for the connection |
||
102 | * |
||
103 | * @param string $connectionName |
||
104 | * |
||
105 | * @return array |
||
106 | */ |
||
107 | 404 | private function getConnectionParameters(string $connectionName): array |
|
108 | { |
||
109 | 404 | if (!isset($this->parametersMap[$connectionName])) { |
|
110 | 2 | throw new DBALException('Connection name "' . $connectionName . '" is not set'); |
|
111 | } |
||
112 | |||
113 | 402 | $parameters = $this->parametersMap[$connectionName]; |
|
114 | |||
115 | // Manage string configuration as dsn |
||
116 | 402 | if (is_string($parameters)) { |
|
117 | 29 | $parameters = ['url' => $parameters]; |
|
118 | } |
||
119 | |||
120 | //@todo move in factory ? Allows shard / slave to use url as parameter. Otherwise doctrine will evaluate the url |
||
121 | // Url key describe a dsn. Extract item from dsn and merge info the current config |
||
122 | 402 | if (isset($parameters['url'])) { |
|
123 | 32 | $parameters = array_merge($parameters, $this->parseDsn($parameters['url'])); |
|
124 | // Remove url: don't let doctrine parse the url |
||
125 | 32 | unset($parameters['url']); |
|
126 | } |
||
127 | |||
128 | 402 | return $parameters; |
|
129 | } |
||
130 | |||
131 | /** |
||
132 | * Parse the dsn string |
||
133 | * |
||
134 | * @param string $dsn |
||
135 | * |
||
136 | * @return array |
||
137 | */ |
||
138 | 32 | private function parseDsn(string $dsn): array |
|
139 | { |
||
140 | 32 | $request = Dsn::parse($dsn); |
|
141 | |||
142 | 32 | $parameters = $request->getQuery() + [ |
|
143 | 32 | 'host' => $request->getHost(), |
|
144 | 32 | 'port' => $request->getPort(), |
|
145 | 32 | 'user' => $request->getUser(), |
|
146 | 32 | 'password' => $request->getPassword(), |
|
147 | 32 | ]; |
|
148 | |||
149 | // Get drive from alias or manage synthax 'pdo+mysql' because '_' are not allowed in scheme |
||
150 | 32 | $parameters['driver'] = self::$driverSchemeAliases[$request->getScheme()] ?? str_replace('+', '_', $request->getScheme()); |
|
151 | |||
152 | // SQLite option: dont create dbname key use by many drivers |
||
153 | // Sqlite drive needs memory or path key |
||
154 | // Remove the 'path' if not used by sqlite |
||
155 | 32 | if (strpos($parameters['driver'], 'sqlite') !== false) { |
|
156 | 26 | if ($request->getPath() === ':memory:') { |
|
157 | 24 | $parameters['memory'] = true; |
|
158 | } else { |
||
159 | 26 | $parameters['path'] = $request->getPath(); |
|
160 | } |
||
161 | 6 | } elseif (!isset($parameters['dbname'])) { |
|
162 | 2 | $parameters['dbname'] = trim($request->getPath(), '/'); |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
163 | } |
||
164 | |||
165 | 32 | return $parameters; |
|
166 | } |
||
167 | } |
||
168 |