‪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\Common\EventManager;
21 use Doctrine\DBAL\Configuration;
22 use Doctrine\DBAL\Driver;
23 use Doctrine\DBAL\Platforms\MariaDBPlatform as DoctrineMariaDBPlatform;
24 use Doctrine\DBAL\Platforms\MySQLPlatform as DoctrineMySQLPlatform;
25 use Doctrine\DBAL\Platforms\OraclePlatform as DoctrineOraclePlatform;
26 use Doctrine\DBAL\Platforms\PostgreSQLPlatform as DoctrinePostgreSqlPlatform;
27 use Doctrine\DBAL\Result;
28 use Doctrine\DBAL\Types\Type;
29 use Psr\Log\LoggerAwareInterface;
30 use Psr\Log\LoggerAwareTrait;
34 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
37 
38 class ‪Connection extends \Doctrine\DBAL\Connection implements LoggerAwareInterface
39 {
40  use LoggerAwareTrait;
41 
45  public const ‪PARAM_NULL = \PDO::PARAM_NULL; // 0
46 
50  public const ‪PARAM_INT = \PDO::PARAM_INT; // 1
51 
55  public const ‪PARAM_STR = \PDO::PARAM_STR; // 2
56 
60  public const ‪PARAM_LOB = \PDO::PARAM_LOB; // 3
61 
65  public const ‪PARAM_STMT = \PDO::PARAM_STMT; // 4
66 
70  public const ‪PARAM_BOOL = \PDO::PARAM_BOOL; // 5
71 
73  protected ‪$_expr;
74 
78  private ‪$prepareConnectionCommands = [];
79 
90  public function ‪__construct(array $params, Driver $driver, Configuration $config = null, EventManager $em = null)
91  {
92  parent::__construct($params, $driver, $config, $em);
93  $this->_expr = GeneralUtility::makeInstance(ExpressionBuilder::class, $this);
94  }
95 
99  public function ‪connect(): bool
100  {
101  // Early return if the connection is already open and custom setup has been done.
102  if (!parent::connect()) {
103  return false;
104  }
105 
106  foreach ($this->prepareConnectionCommands as $command) {
107  $this->executeStatement($command);
108  }
109 
110  return true;
111  }
112 
116  public function ‪createQueryBuilder(): QueryBuilder
117  {
118  return GeneralUtility::makeInstance(QueryBuilder::class, $this);
119  }
120 
132  public function ‪quoteIdentifier(‪$identifier): string
133  {
134  if (‪$identifier === '*') {
135  return ‪$identifier;
136  }
137 
138  return parent::quoteIdentifier(‪$identifier);
139  }
140 
148  public function ‪quoteIdentifiers(array $input): array
149  {
150  return array_map($this->‪quoteIdentifier(...), $input);
151  }
152 
161  public function ‪quoteColumnValuePairs(array $input): array
162  {
163  return array_combine($this->‪quoteIdentifiers(array_keys($input)), array_values($input));
164  }
165 
171  protected function ‪quoteColumnTypes(array $input): array
172  {
173  if (!is_string(key($input))) {
174  return $input;
175  }
176 
177  return $this->‪quoteColumnValuePairs($input);
178  }
179 
187  public function ‪escapeLikeWildcards(string $value): string
188  {
189  return addcslashes($value, '_%');
190  }
191 
203  public function ‪insert($tableName, array $data, array $types = []): int
204  {
205  $this->‪ensureDatabaseValueTypes($tableName, $data, $types);
206  return parent::insert(
207  $this->‪quoteIdentifier($tableName),
208  $this->‪quoteColumnValuePairs($data),
209  $this->‪quoteColumnTypes($types)
210  );
211  }
212 
225  public function ‪bulkInsert(string $tableName, array $data, array $columns = [], array $types = []): int
226  {
227  $query = GeneralUtility::makeInstance(BulkInsertQuery::class, $this, $tableName, $columns);
228  foreach ($data as $values) {
229  $this->‪ensureDatabaseValueTypes($tableName, $values, $types);
230  $query->addValues($values, $types);
231  }
232 
233  return $query->execute();
234  }
235 
251  public function ‪select(
252  array $columns,
253  string $tableName,
254  array $identifiers = [],
255  array $groupBy = [],
256  array $orderBy = [],
257  int $limit = 0,
258  int $offset = 0
259  ) {
260  $query = $this->‪createQueryBuilder();
261  $query->select(...$columns)
262  ->from($tableName);
263 
264  foreach ($identifiers as ‪$identifier => $value) {
265  $query->andWhere($query->expr()->eq(‪$identifier, $query->createNamedParameter($value)));
266  }
267 
268  foreach ($orderBy as $fieldName => $order) {
269  $query->addOrderBy($fieldName, $order);
270  }
271 
272  if (!empty($groupBy)) {
273  $query->groupBy(...$groupBy);
274  }
275 
276  if ($limit > 0) {
277  $query->setMaxResults($limit);
278  $query->setFirstResult($offset);
279  }
280 
281  return $query->executeQuery();
282  }
283 
296  public function ‪update($tableName, array $data, array ‪$identifier, array $types = []): int
297  {
298  $this->‪ensureDatabaseValueTypes($tableName, $data, $types);
299  return parent::update(
300  $this->‪quoteIdentifier($tableName),
301  $this->‪quoteColumnValuePairs($data),
302  $this->‪quoteColumnValuePairs($identifier),
303  $this->‪quoteColumnTypes($types)
304  );
305  }
306 
318  public function delete($tableName, array ‪$identifier, array $types = []): int
319  {
320  return parent::delete(
321  $this->‪quoteIdentifier($tableName),
322  $this->‪quoteColumnValuePairs($identifier),
323  $this->‪quoteColumnTypes($types)
324  );
325  }
326 
337  public function ‪truncate(string $tableName, bool $cascade = false): int
338  {
339  return $this->executeStatement(
340  $this->getDatabasePlatform()->getTruncateTableSQL(
341  $this->‪quoteIdentifier($tableName),
342  $cascade
343  )
344  );
345  }
346 
356  public function ‪count(string $item, string $tableName, array $identifiers): int
357  {
358  $query = $this->‪createQueryBuilder();
359  $query->count($item)
360  ->from($tableName);
361 
362  foreach ($identifiers as ‪$identifier => $value) {
363  $query->andWhere($query->expr()->eq(‪$identifier, $query->createNamedParameter($value)));
364  }
365 
366  return (int)$query->executeQuery()->fetchOne();
367  }
368 
377  public function ‪getServerVersion(): string
378  {
379  $connection = $this->getWrappedConnection();
380  if (method_exists($connection, 'getServerVersion')) {
381  return $connection->getServerVersion();
382  }
383 
384  // Return empty server version due to database connection error.
385  return '';
386  }
387 
396  public function ‪getPlatformServerVersion(): string
397  {
398  $platform = $this->getDatabasePlatform();
399  $version = trim($this->‪getServerVersion());
400  if ($version !== '') {
401  $version = ' ' . $version;
402  }
403  return match (true) {
404  // @todo Check if we should use 'MariaDB' now directly instead of MySQL as an alias.
405  $platform instanceof DoctrineMariaDBPlatform => 'MySQL' . $version,
406  $platform instanceof DoctrineMySQLPlatform => 'MySQL' . $version,
407  $platform instanceof DoctrinePostgreSQLPlatform => 'PostgreSQL' . $version,
408  $platform instanceof DoctrineOraclePlatform => 'Oracle' . $version,
409  default => (str_replace('Platform', '', array_reverse(explode('\\', $platform::class))[0] ?? '')) . $version,
410  };
411  }
412 
416  public function ‪prepareConnection(string $commands)
417  {
418  if (empty($commands)) {
419  return;
420  }
421 
422  $this->prepareConnectionCommands = GeneralUtility::trimExplode(
423  LF,
424  str_replace(
425  '\' . LF . \'',
426  LF,
427  $commands
428  ),
429  true
430  );
431  }
432 
441  public function ‪lastInsertId($tableName = null, string $fieldName = 'uid'): string
442  {
443  $databasePlatform = $this->getDatabasePlatform();
444  if ($databasePlatform instanceof DoctrinePostgreSqlPlatform) {
445  return parent::lastInsertId(trim(implode('_', [$tableName, $fieldName, 'seq']), '_'));
446  }
447  return (string)parent::lastInsertId($tableName);
448  }
449 
455  public function ‪getExpressionBuilder()
456  {
457  return ‪$this->_expr;
458  }
459 
467  protected function ‪ensureDatabaseValueTypes(string $tableName, array &$data, array &$types): void
468  {
469  // If types are incoming already (meaning they're hand over to insert() for instance), don't auto-set them.
470  $setAllTypes = $types === [];
471  $tableDetails = $this->‪getSchemaInformation()->introspectTable($tableName);
472  array_walk($data, function (mixed &$value, string $key) use ($tableDetails, $setAllTypes, &$types): void {
473  if ($tableDetails->hasColumn($key)) {
474  $type = $tableDetails->getColumn($key)->getType();
475  if ($setAllTypes) {
476  $types[$key] = $type->getBindingType();
477  }
478  $value = $this->convertToDatabaseValue($value, $type);
479  }
480  });
481  }
482 
494  public function convertToDatabaseValue($value, $type)
495  {
496  if (is_string($type)) {
497  $type = Type::getType($type);
498  }
499  return $type->convertToDatabaseValue($value, $this->getDatabasePlatform());
500  }
501 
505  public function getSchemaInformation(): SchemaInformation
506  {
507  return new SchemaInformation(
508  $this,
509  GeneralUtility::makeInstance(CacheManager::class)->getCache('database_schema')
510  );
511  }
512 }
‪TYPO3\CMS\Core\Database\Connection\truncate
‪int truncate(string $tableName, bool $cascade=false)
Definition: Connection.php:335
‪TYPO3\CMS\Core\Database\Connection\PARAM_BOOL
‪const PARAM_BOOL
Definition: Connection.php:70
‪TYPO3\CMS\Core\Database\Connection\ensureDatabaseValueTypes
‪ensureDatabaseValueTypes(string $tableName, array &$data, array &$types)
Definition: Connection.php:465
‪TYPO3\CMS\Core\Database\Connection\quoteColumnValuePairs
‪quoteColumnValuePairs(array $input)
Definition: Connection.php:159
‪TYPO3\CMS\Core\Database\Connection\escapeLikeWildcards
‪string escapeLikeWildcards(string $value)
Definition: Connection.php:185
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:50
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:40
‪TYPO3\CMS\Core\Database\Connection\$_expr
‪ExpressionBuilder $_expr
Definition: Connection.php:72
‪TYPO3\CMS\Core\Database\Connection\bulkInsert
‪int bulkInsert(string $tableName, array $data, array $columns=[], array $types=[])
Definition: Connection.php:223
‪TYPO3\CMS\Core\Database\Connection\getServerVersion
‪getServerVersion()
Definition: Connection.php:375
‪TYPO3\CMS\Core\Database\Connection\insert
‪int insert($tableName, array $data, array $types=[])
Definition: Connection.php:201
‪TYPO3\CMS\Core\Database\Connection\quoteIdentifiers
‪quoteIdentifiers(array $input)
Definition: Connection.php:146
‪TYPO3\CMS\Core\Database\Schema\SchemaInformation
Definition: SchemaInformation.php:32
‪TYPO3\CMS\Core\Database\Connection\quoteIdentifier
‪string quoteIdentifier($identifier)
Definition: Connection.php:130
‪TYPO3\CMS\Core\Database\Connection\PARAM_STR
‪const PARAM_STR
Definition: Connection.php:55
‪TYPO3\CMS\Core\Database\Connection\update
‪int update($tableName, array $data, array $identifier, array $types=[])
Definition: Connection.php:294
‪TYPO3\CMS\Core\Database\Connection\getSchemaInformation
‪getSchemaInformation()
Definition: Connection.php:503
‪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:249
‪TYPO3\CMS\Core\Database\Connection\PARAM_STMT
‪const PARAM_STMT
Definition: Connection.php:65
‪TYPO3\CMS\Core\Database\Connection\getExpressionBuilder
‪ExpressionBuilder getExpressionBuilder()
Definition: Connection.php:453
‪TYPO3\CMS\Core\Database\Connection\createQueryBuilder
‪createQueryBuilder()
Definition: Connection.php:114
‪TYPO3\CMS\Core\Database\Connection\lastInsertId
‪lastInsertId($tableName=null, string $fieldName='uid')
Definition: Connection.php:439
‪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:354
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:39
‪TYPO3\CMS\Core\Database\Connection\prepareConnection
‪prepareConnection(string $commands)
Definition: Connection.php:414
‪TYPO3\CMS\Core\Database\Connection\getPlatformServerVersion
‪getPlatformServerVersion()
Definition: Connection.php:394
‪TYPO3\CMS\Core\Database\Connection\connect
‪connect()
Definition: Connection.php:97
‪TYPO3\CMS\Core\Database\Query\BulkInsertQuery
Definition: BulkInsertQuery.php:36
‪TYPO3\CMS\Core\Database\Connection\PARAM_NULL
‪const PARAM_NULL
Definition: Connection.php:45
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Database\Connection\__construct
‪__construct(array $params, Driver $driver, Configuration $config=null, EventManager $em=null)
Definition: Connection.php:88
‪TYPO3\CMS\Core\Database\Connection\quoteColumnTypes
‪quoteColumnTypes(array $input)
Definition: Connection.php:169
‪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\Connection\$prepareConnectionCommands
‪array $prepareConnectionCommands
Definition: Connection.php:76
‪TYPO3\CMS\Core\Database\Connection\PARAM_LOB
‪const PARAM_LOB
Definition: Connection.php:60
‪TYPO3\CMS\Core\Database\Connection\convertToDatabaseValue
‪mixed convertToDatabaseValue($value, $type)
Definition: Connection.php:492