‪TYPO3CMS  ‪main
Connection.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\ArrayParameterType;
21 use Doctrine\DBAL\Configuration;
22 use Doctrine\DBAL\Driver;
23 use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
24 use Doctrine\DBAL\Exception as DbalException;
25 use Doctrine\DBAL\ParameterType;
26 use Doctrine\DBAL\Platforms\MariaDBPlatform as DoctrineMariaDBPlatform;
27 use Doctrine\DBAL\Platforms\MySQLPlatform as DoctrineMySQLPlatform;
28 use Doctrine\DBAL\Platforms\PostgreSQLPlatform as DoctrinePostgreSQLPlatform;
29 use Doctrine\DBAL\Result;
30 use Doctrine\DBAL\Types\Type;
31 use Psr\Log\LoggerAwareInterface;
32 use Psr\Log\LoggerAwareTrait;
36 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
39 
40 class ‪Connection extends \Doctrine\DBAL\Connection implements LoggerAwareInterface
41 {
42  use LoggerAwareTrait;
43 
47  public const ‪PARAM_NULL = ParameterType::NULL;
48 
52  public const ‪PARAM_INT = ParameterType::INTEGER;
53 
57  public const ‪PARAM_STR = ParameterType::STRING;
58 
62  public const ‪PARAM_LOB = ParameterType::LARGE_OBJECT;
63 
67  public const ‪PARAM_BOOL = ParameterType::BOOLEAN;
68 
72  public const ‪PARAM_INT_ARRAY = ArrayParameterType::INTEGER;
73 
77  public const ‪PARAM_STR_ARRAY = ArrayParameterType::STRING;
78 
80  private array ‪$prepareConnectionCommands = [];
81 
89  public function ‪__construct(array $params, Driver $driver, Configuration $config = null)
90  {
91  parent::__construct($params, $driver, $config);
92  $this->expressionBuilder = GeneralUtility::makeInstance(ExpressionBuilder::class, $this);
93  }
94 
98  protected function ‪connect(): ConnectionInterface
99  {
100  if ($this->_conn !== null) {
101  return $this->_conn;
102  }
103  // Early return if the connection is already open and custom setup has been done.
104  $connection = parent::connect();
105  foreach ($this->prepareConnectionCommands as $command) {
106  $this->executeStatement($command);
107  }
108  return $connection;
109  }
110 
114  public function ‪createQueryBuilder(): QueryBuilder
115  {
116  return GeneralUtility::makeInstance(QueryBuilder::class, $this);
117  }
118 
129  public function ‪quoteIdentifier(string ‪$identifier): string
130  {
131  if (‪$identifier === '*') {
132  return ‪$identifier;
133  }
134  return parent::quoteIdentifier(‪$identifier);
135  }
136 
141  public function ‪quoteIdentifiers(array $input): array
142  {
143  return array_map($this->‪quoteIdentifier(...), $input);
144  }
145 
151  public function ‪quoteColumnValuePairs(array $input): array
152  {
153  return array_combine($this->‪quoteIdentifiers(array_keys($input)), array_values($input));
154  }
155 
161  protected function ‪quoteColumnTypes(array $input): array
162  {
163  if (!is_string(key($input))) {
164  return $input;
165  }
166  return $this->‪quoteColumnValuePairs($input);
167  }
168 
175  public function ‪escapeLikeWildcards(string $value): string
176  {
177  return addcslashes($value, '_%');
178  }
179 
190  public function ‪insert(string $tableName, array $data, array $types = []): int
191  {
192  $this->‪ensureDatabaseValueTypes($tableName, $data, $types);
193  return parent::insert(
194  $this->‪quoteIdentifier($tableName),
195  $this->‪quoteColumnValuePairs($data),
196  $this->‪quoteColumnTypes($types)
197  );
198  }
199 
210  public function ‪bulkInsert(string $tableName, array $data, array $columns = [], array $types = []): int
211  {
212  $query = GeneralUtility::makeInstance(BulkInsertQuery::class, $this, $tableName, $columns);
213  foreach ($data as $values) {
214  $this->‪ensureDatabaseValueTypes($tableName, $values, $types);
215  $query->addValues($values, $types);
216  }
217  return $query->execute();
218  }
219 
233  public function ‪select(
234  array $columns,
235  string $tableName,
236  array $identifiers = [],
237  array $groupBy = [],
238  array $orderBy = [],
239  int $limit = 0,
240  int $offset = 0
241  ) {
242  $query = $this->‪createQueryBuilder();
243  $query->select(...$columns)->from($tableName);
244  foreach ($identifiers as ‪$identifier => $value) {
245  $query->andWhere($query->expr()->eq(‪$identifier, $query->createNamedParameter($value)));
246  }
247  foreach ($orderBy as $fieldName => $order) {
248  $query->addOrderBy($fieldName, $order);
249  }
250  if (!empty($groupBy)) {
251  $query->groupBy(...$groupBy);
252  }
253  if ($limit > 0) {
254  $query->setMaxResults($limit);
255  $query->setFirstResult($offset);
256  }
257  return $query->executeQuery();
258  }
259 
270  public function ‪update(string $tableName, array $data, array ‪$identifier = [], array $types = []): int
271  {
272  $this->‪ensureDatabaseValueTypes($tableName, $data, $types);
273  return parent::update(
274  $this->‪quoteIdentifier($tableName),
275  $this->‪quoteColumnValuePairs($data),
277  $this->‪quoteColumnTypes($types)
278  );
279  }
280 
290  public function delete(string $tableName, array ‪$identifier = [], array $types = []): int
291  {
292  return parent::delete(
293  $this->‪quoteIdentifier($tableName),
294  $this->‪quoteColumnValuePairs($identifier),
295  $this->‪quoteColumnTypes($types)
296  );
297  }
298 
307  public function ‪truncate(string $tableName, bool $cascade = false): int
308  {
309  return $this->executeStatement(
310  $this->getDatabasePlatform()->getTruncateTableSQL(
311  $this->‪quoteIdentifier($tableName),
312  $cascade
313  )
314  );
315  }
316 
325  public function ‪count(string $item, string $tableName, array $identifiers): int
326  {
327  $query = $this->‪createQueryBuilder();
328  $query->count($item)->from($tableName);
329  foreach ($identifiers as ‪$identifier => $value) {
330  $query->andWhere($query->expr()->eq(‪$identifier, $query->createNamedParameter($value)));
331  }
332  return (int)$query->executeQuery()->fetchOne();
333  }
334 
343  public function ‪getServerVersion(): string
344  {
345  try {
346  return parent::getServerVersion();
347  } catch (DbalException) {
348  }
349  // Return empty server version due to database connection error.
350  return '';
351  }
352 
361  public function ‪getPlatformServerVersion(): string
362  {
363  $platform = $this->getDatabasePlatform();
364  $version = trim($this->‪getServerVersion());
365  if ($version !== '') {
366  $version = ' ' . $version;
367  }
368  return match (true) {
369  // @todo Check if we should use 'MariaDB' now directly instead of MySQL as an alias.
370  $platform instanceof DoctrineMariaDBPlatform => 'MySQL' . $version,
371  $platform instanceof DoctrineMySQLPlatform => 'MySQL' . $version,
372  $platform instanceof DoctrinePostgreSQLPlatform => 'PostgreSQL' . $version,
373  default => (str_replace('Platform', '', array_reverse(explode('\\', $platform::class))[0] ?? '')) . $version,
374  };
375  }
376 
380  public function ‪prepareConnection(string $commands): void
381  {
382  if (empty($commands)) {
383  return;
384  }
385  $this->prepareConnectionCommands = ‪GeneralUtility::trimExplode(
386  LF,
387  str_replace(
388  '\' . LF . \'',
389  LF,
390  $commands
391  ),
392  true
393  );
394  }
395 
402  public function ‪lastInsertId(): string
403  {
404  return (string)parent::lastInsertId();
405  }
406 
411  {
413  }
414 
422  protected function ‪ensureDatabaseValueTypes(string $tableName, array &$data, array &$types): void
423  {
424  // If types are incoming already (meaning they're hand over to insert() for instance), don't auto-set them.
425  $setAllTypes = $types === [];
426  $tableDetails = $this->‪getSchemaInformation()->introspectTable($tableName);
427  $databasePlatform = $this->getDatabasePlatform();
428  array_walk($data, function (mixed &$value, string $key) use ($tableDetails, $setAllTypes, &$types, $databasePlatform): void {
429  $typeName = ($types[$key] ?? '');
430  if (!$setAllTypes && is_string($typeName) && $typeName !== '' && Type::hasType($typeName)) {
431  $types[$key] = Type::getType($typeName)->getBindingType();
432  } elseif ($typeName instanceof Type) {
433  $types[$key] = $typeName->getBindingType();
434  }
435  if ($tableDetails->hasColumn($key)) {
436  $type = $tableDetails->getColumn($key)->getType();
437  if ($setAllTypes) {
438  $types[$key] = $type->getBindingType();
439  }
440  $value = $type->convertToDatabaseValue($value, $databasePlatform);
441  }
442  });
443  }
444 
449  {
450  return new ‪SchemaInformation(
451  $this,
452  GeneralUtility::makeInstance(CacheManager::class)->getCache('database_schema')
453  );
454  }
455 }
‪TYPO3\CMS\Core\Database\Connection\truncate
‪int truncate(string $tableName, bool $cascade=false)
Definition: Connection.php:307
‪TYPO3\CMS\Core\Database\Connection\PARAM_BOOL
‪const PARAM_BOOL
Definition: Connection.php:67
‪TYPO3\CMS\Core\Database\Connection\ensureDatabaseValueTypes
‪ensureDatabaseValueTypes(string $tableName, array &$data, array &$types)
Definition: Connection.php:422
‪TYPO3\CMS\Core\Database\Connection\quoteColumnValuePairs
‪quoteColumnValuePairs(array $input)
Definition: Connection.php:151
‪TYPO3\CMS\Core\Database\Connection\escapeLikeWildcards
‪string escapeLikeWildcards(string $value)
Definition: Connection.php:175
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:40
‪TYPO3\CMS\Core\Database\Connection\bulkInsert
‪int bulkInsert(string $tableName, array $data, array $columns=[], array $types=[])
Definition: Connection.php:210
‪TYPO3\CMS\Core\Database\Connection\getServerVersion
‪getServerVersion()
Definition: Connection.php:343
‪TYPO3\CMS\Core\Database\Connection\getExpressionBuilder
‪getExpressionBuilder()
Definition: Connection.php:410
‪TYPO3\CMS\Core\Database\Connection\quoteIdentifiers
‪quoteIdentifiers(array $input)
Definition: Connection.php:141
‪TYPO3\CMS\Core\Database\Schema\SchemaInformation
Definition: SchemaInformation.php:32
‪TYPO3\CMS\Core\Database\Connection\$expressionBuilder
‪ExpressionBuilder $expressionBuilder
Definition: Connection.php:79
‪TYPO3\CMS\Core\Database\Connection\PARAM_STR
‪const PARAM_STR
Definition: Connection.php:57
‪TYPO3\CMS\Core\Database\Connection\getSchemaInformation
‪getSchemaInformation()
Definition: Connection.php:448
‪TYPO3\CMS\Core\Database\Connection\select
‪Result select(array $columns, string $tableName, array $identifiers=[], array $groupBy=[], array $orderBy=[], int $limit=0, int $offset=0)
Definition: Connection.php:233
‪TYPO3\CMS\Core\Database\Connection\PARAM_STR_ARRAY
‪const PARAM_STR_ARRAY
Definition: Connection.php:77
‪TYPO3\CMS\Core\Database\Connection\createQueryBuilder
‪createQueryBuilder()
Definition: Connection.php:114
‪TYPO3\CMS\Core\Database\Connection\quoteIdentifier
‪string quoteIdentifier(string $identifier)
Definition: Connection.php:129
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Database\Connection\count
‪int count(string $item, string $tableName, array $identifiers)
Definition: Connection.php:325
‪TYPO3\CMS\Core\Database\Connection\insert
‪int insert(string $tableName, array $data, array $types=[])
Definition: Connection.php:190
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Core\Database\Connection\prepareConnection
‪prepareConnection(string $commands)
Definition: Connection.php:380
‪TYPO3\CMS\Core\Database\Connection\getPlatformServerVersion
‪getPlatformServerVersion()
Definition: Connection.php:361
‪TYPO3\CMS\Core\Database\Connection\connect
‪connect()
Definition: Connection.php:98
‪TYPO3\CMS\Core\Database\Query\BulkInsertQuery
Definition: BulkInsertQuery.php:36
‪TYPO3\CMS\Core\Database\Connection\PARAM_NULL
‪const PARAM_NULL
Definition: Connection.php:47
‪TYPO3\CMS\Core\Database\Connection\lastInsertId
‪numeric string lastInsertId()
Definition: Connection.php:402
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Database\Connection\__construct
‪__construct(array $params, Driver $driver, Configuration $config=null)
Definition: Connection.php:89
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT_ARRAY
‪const PARAM_INT_ARRAY
Definition: Connection.php:72
‪TYPO3\CMS\Core\Database\Connection\quoteColumnTypes
‪quoteColumnTypes(array $input)
Definition: Connection.php:161
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Core\Database\Connection\update
‪int update(string $tableName, array $data, array $identifier=[], array $types=[])
Definition: Connection.php:270
‪TYPO3\CMS\Core\Database
Definition: Connection.php:18
‪TYPO3\CMS\Core\Database\Connection\$prepareConnectionCommands
‪array $prepareConnectionCommands
Definition: Connection.php:80
‪TYPO3\CMS\Core\Database\Connection\PARAM_LOB
‪const PARAM_LOB
Definition: Connection.php:62