‪TYPO3CMS  ‪main
ConnectionPool.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Doctrine\DBAL\Configuration;
21 use Doctrine\DBAL\Driver\Middleware as DriverMiddleware;
22 use Doctrine\DBAL\DriverManager;
23 use Doctrine\DBAL\Types\Type;
24 use Doctrine\DBAL\Types\Types;
28 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
36 
48 {
52  public const ‪DEFAULT_CONNECTION_NAME = 'Default';
53 
57  protected static ‪$connections = [];
58 
62  protected array ‪$customDoctrineTypes = [
63  ‪EnumType::TYPE => EnumType::class,
64  ‪SetType::TYPE => SetType::class,
65  ];
66 
70  protected array ‪$overrideDoctrineTypes = [
71  Types::DATE_MUTABLE => DateType::class,
72  Types::DATETIME_MUTABLE => DateTimeType::class,
73  Types::DATETIME_IMMUTABLE => DateTimeType::class,
74  Types::TIME_MUTABLE => TimeType::class,
75  ];
76 
82  protected static ‪$driverMap = [
83  'pdo_mysql' => PDOMySqlDriver::class,
84  'pdo_sqlite' => PDOSqliteDriver::class,
85  'pdo_pgsql' => PDOPgSqlDriver::class,
86  ];
87 
96  public function ‪getConnectionForTable(string $tableName): ‪Connection
97  {
98  if (empty($tableName)) {
99  throw new \UnexpectedValueException(
100  'ConnectionPool->getConnectionForTable() requires a table name to be provided.',
101  1459421719
102  );
103  }
104 
105  $connectionName = ‪self::DEFAULT_CONNECTION_NAME;
106  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'][$tableName])) {
107  $connectionName = (string)‪$GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'][$tableName];
108  }
109 
110  return $this->‪getConnectionByName($connectionName);
111  }
112 
122  public function ‪getConnectionByName(string $connectionName): ‪Connection
123  {
124  if (empty($connectionName)) {
125  throw new \UnexpectedValueException(
126  'ConnectionPool->getConnectionByName() requires a connection name to be provided.',
127  1459422125
128  );
129  }
130 
131  if (isset(static::$connections[$connectionName])) {
132  return static::$connections[$connectionName];
133  }
134 
135  $connectionParams = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][$connectionName] ?? [];
136  if (empty($connectionParams)) {
137  throw new \RuntimeException(
138  'The requested database connection named "' . $connectionName . '" has not been configured.',
139  1459422492
140  );
141  }
142 
143  if (empty($connectionParams['wrapperClass'])) {
144  $connectionParams['wrapperClass'] = Connection::class;
145  }
146 
147  if (!is_a($connectionParams['wrapperClass'], Connection::class, true)) {
148  throw new \UnexpectedValueException(
149  'The "wrapperClass" for the connection name "' . $connectionName .
150  '" needs to be a subclass of "' . Connection::class . '".',
151  1459422968
152  );
153  }
154 
155  // Transform TYPO3 `tableoptions` to valid `doctrine/dbal` connection param option `defaultTableOptions`
156  // @todo TYPO3 database configuration should be changed to directly write defaultTableOptions instead,
157  // with proper upgrade migration. Along with that, default table options for MySQL in
158  // testing-framework and core should be adjusted.
159  if (isset($connectionParams['tableoptions'])) {
160  $connectionParams['defaultTableOptions'] = array_replace(
161  $connectionParams['defaultTableOptions'] ?? [],
162  $connectionParams['tableoptions']
163  );
164  unset($connectionParams['tableoptions']);
165  }
166 
167  static::$connections[$connectionName] = $this->‪getDatabaseConnection($connectionParams);
168 
169  return static::$connections[$connectionName];
170  }
171 
177  protected function ‪mapCustomDriver(array $connectionParams): array
178  {
179  // if no custom driver is provided, map TYPO3 specific drivers
180  if (!isset($connectionParams['driverClass']) && isset(static::$driverMap[$connectionParams['driver']])) {
181  $connectionParams['driverClass'] = static::$driverMap[$connectionParams['driver']];
182  }
183 
184  return $connectionParams;
185  }
186 
192  protected function ‪getDriverMiddlewares(array $connectionParams): array
193  {
195  $driverMiddlewares = array_replace(
196  ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['globalDriverMiddlewares'] ?? [],
197  $connectionParams['driverMiddlewares'] ?? []
198  );
199  $middlewares = [];
200 
201  foreach ($driverMiddlewares as ‪$identifier => $className) {
202  // Using a empty classname for an identifier disables the middleware. This can be used to disable a
203  // global driver middleware for a specific connection.
204  if ($className === '') {
205  continue;
206  }
207  if (!in_array(DriverMiddleware::class, class_implements($className) ?: [], true)) {
208  throw new \UnexpectedValueException(
209  sprintf(
210  'Doctrine Driver Middleware "%s" must implement \Doctrine\DBAL\Driver\Middleware',
211  $className
212  ),
213  1677958727
214  );
215  }
216  $middlewares[] = GeneralUtility::makeInstance($className);
217  }
218 
219  return $middlewares;
220  }
221 
225  protected function ‪getDatabaseConnection(array $connectionParams): Connection
226  {
227  $this->‪registerDoctrineTypes();
228 
229  // Default to UTF-8 connection charset
230  if (empty($connectionParams['charset'])) {
231  $connectionParams['charset'] = 'utf8';
232  }
233 
234  $connectionParams = $this->‪mapCustomDriver($connectionParams);
235  $middlewares = $this->‪getDriverMiddlewares($connectionParams);
236  $configuration = (new Configuration())
237  ->setMiddlewares($middlewares)
238  // @link https://github.com/doctrine/dbal/blob/3.7.x/UPGRADE.md#deprecated-not-setting-a-schema-manager-factory
239  ->setSchemaManagerFactory(GeneralUtility::makeInstance(CoreSchemaManagerFactory::class));
240 
242  $conn = DriverManager::getConnection($connectionParams, $configuration);
243  $conn->prepareConnection($connectionParams['initCommands'] ?? '');
244 
245  // Register all custom data types in the type mapping
246  foreach ($this->customDoctrineTypes as $type => $className) {
247  $conn->getDatabasePlatform()->registerDoctrineTypeMapping($type, $type);
248  }
249 
250  // Register all override data types in the type mapping
251  foreach ($this->overrideDoctrineTypes as $type => $className) {
252  $conn->getDatabasePlatform()->registerDoctrineTypeMapping($type, $type);
253  }
254 
255  return $conn;
256  }
257 
262  public function ‪getQueryBuilderForTable(string $tableName): QueryBuilder
263  {
264  if (empty($tableName)) {
265  throw new \UnexpectedValueException(
266  'ConnectionPool->getQueryBuilderForTable() requires a connection name to be provided.',
267  1459423448
268  );
269  }
270 
271  return $this->‪getConnectionForTable($tableName)->createQueryBuilder();
272  }
273 
282  public function ‪getConnectionNames(): array
283  {
284  return array_keys(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']);
285  }
286 
295  public function ‪registerDoctrineTypes(): void
296  {
297  // Register custom data types
298  foreach ($this->customDoctrineTypes as $type => $className) {
299  if (!Type::hasType($type)) {
300  Type::addType($type, $className);
301  }
302  }
303  // Override data types
304  foreach ($this->overrideDoctrineTypes as $type => $className) {
305  if (!Type::hasType($type)) {
306  Type::addType($type, $className);
307  continue;
308  }
309  Type::overrideType($type, $className);
310  }
311  }
312 
318  public function ‪resetConnections(): void
319  {
320  static::$connections = [];
321  }
322 }
‪TYPO3\CMS\Core\Database\Schema\Types\DateTimeType
Definition: DateTimeType.php:31
‪TYPO3\CMS\Core\Database\Driver\PDOPgSql\Driver
Definition: Driver.php:32
‪TYPO3\CMS\Core\Database\Driver\PDOMySql\Driver
Definition: Driver.php:32
‪TYPO3\CMS\Core\Database\ConnectionPool\registerDoctrineTypes
‪registerDoctrineTypes()
Definition: ConnectionPool.php:293
‪TYPO3\CMS\Core\Database\ConnectionPool\mapCustomDriver
‪mapCustomDriver(array $connectionParams)
Definition: ConnectionPool.php:175
‪TYPO3\CMS\Core\Database\Schema\Types\SetType
Definition: SetType.php:29
‪TYPO3\CMS\Core\Database\ConnectionPool\getConnectionNames
‪getConnectionNames()
Definition: ConnectionPool.php:280
‪TYPO3\CMS\Core\Database\Schema\Types\EnumType
Definition: EnumType.php:29
‪TYPO3\CMS\Core\Database\ConnectionPool\$driverMap
‪static string[] $driverMap
Definition: ConnectionPool.php:80
‪TYPO3\CMS\Core\Database\Schema\Types\DateType
Definition: DateType.php:31
‪TYPO3\CMS\Core\Database\Driver\PDOSqlite\Driver
Definition: Driver.php:33
‪TYPO3\CMS\Core\Database\Schema\Types\EnumType\TYPE
‪const TYPE
Definition: EnumType.php:30
‪TYPO3\CMS\Core\Database\ConnectionPool\DEFAULT_CONNECTION_NAME
‪const DEFAULT_CONNECTION_NAME
Definition: ConnectionPool.php:52
‪TYPO3\CMS\Core\Database\ConnectionPool\$customDoctrineTypes
‪array $customDoctrineTypes
Definition: ConnectionPool.php:61
‪TYPO3\CMS\Core\Database\Schema\SchemaManager\CoreSchemaManagerFactory
Definition: CoreSchemaManagerFactory.php:42
‪TYPO3\CMS\Core\Database\ConnectionPool\$connections
‪static Connection[] $connections
Definition: ConnectionPool.php:56
‪TYPO3\CMS\Core\Database\ConnectionPool\getConnectionByName
‪getConnectionByName(string $connectionName)
Definition: ConnectionPool.php:120
‪TYPO3\CMS\Core\Database\ConnectionPool\getQueryBuilderForTable
‪getQueryBuilderForTable(string $tableName)
Definition: ConnectionPool.php:260
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:39
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\Schema\Types\TimeType
Definition: TimeType.php:31
‪TYPO3\CMS\Core\Database\ConnectionPool\getConnectionForTable
‪getConnectionForTable(string $tableName)
Definition: ConnectionPool.php:94
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:48
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Database\ConnectionPool\getDriverMiddlewares
‪getDriverMiddlewares(array $connectionParams)
Definition: ConnectionPool.php:190
‪TYPO3\CMS\Core\Database\Schema\Types\SetType\TYPE
‪const TYPE
Definition: SetType.php:30
‪TYPO3\CMS\Core\Database\ConnectionPool\resetConnections
‪resetConnections()
Definition: ConnectionPool.php:316
‪TYPO3\CMS\Core\Database\ConnectionPool\getDatabaseConnection
‪getDatabaseConnection(array $connectionParams)
Definition: ConnectionPool.php:223
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Core\Database
Definition: Connection.php:18
‪TYPO3\CMS\Core\Database\ConnectionPool\$overrideDoctrineTypes
‪array $overrideDoctrineTypes
Definition: ConnectionPool.php:69