Commit 4a5e2c86 authored by Morton Jonuschat's avatar Morton Jonuschat Committed by Christian Kuhn
Browse files

[!!!][FEATURE] Introduce Doctrine DBAL database connections

The Doctrine DBAL library is added as a composer dependency
as a foundation to replace the current DatabaseConnection class,
EXT:dbal and EXT:adodb.

Doctrine DBAL is encapsulated within a ConnectionPool class that
manages the connections to all defined database connections.

The main parts of the patch consist of the connection management,
convenience methods for simple SQL queries, a QueryBuilder to build
complex queries in a database platform independent way and a
QueryRestriction Builder that aims to replace deleteClause and
BEenableFields in the backend context as well as enableFields in
frontend context.

Documentation and an example implementation of using the API will
follow in separate patches.

Releases: master
Resolves: #75454
Change-Id: I47837d9e77331132807bbb7fb956c359031b4f16
Reviewed-on: https://review.typo3.org/47111

Reviewed-by: Frank Nägler's avatarFrank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Nägler's avatarFrank Naegler <frank.naegler@typo3.org>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 5ab7fd5e
......@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "8d5c9b829baf959723f0331b902a6950",
"content-hash": "6223c70de09731f9587fc3bd4c52e970",
"hash": "475c61a0b0d33a16dac25dd9a288c75f",
"content-hash": "aa3d371cb5c714497024983e989e7062",
"packages": [
{
"name": "cogpowered/finediff",
......@@ -58,6 +58,421 @@
],
"time": "2014-05-19 10:25:02"
},
{
"name": "doctrine/annotations",
"version": "v1.2.7",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535",
"reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"php": ">=5.3.2"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "4.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Annotations\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"docblock",
"parser"
],
"time": "2015-08-31 12:32:49"
},
{
"name": "doctrine/cache",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6",
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6",
"shasum": ""
},
"require": {
"php": "~5.5|~7.0"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.0",
"predis/predis": "~1.0",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Caching library offering an object-oriented API for many cache backends",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
],
"time": "2015-12-31 16:37:02"
},
{
"name": "doctrine/collections",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Collections\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Collections Abstraction library",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"array",
"collections",
"iterator"
],
"time": "2015-04-14 22:21:58"
},
{
"name": "doctrine/common",
"version": "v2.6.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "a579557bc689580c19fee4e27487a67fe60defc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0",
"reference": "a579557bc689580c19fee4e27487a67fe60defc0",
"shasum": ""
},
"require": {
"doctrine/annotations": "1.*",
"doctrine/cache": "1.*",
"doctrine/collections": "1.*",
"doctrine/inflector": "1.*",
"doctrine/lexer": "1.*",
"php": "~5.5|~7.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common Library for Doctrine projects",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"collections",
"eventmanager",
"persistence",
"spl"
],
"time": "2015-12-25 13:18:31"
},
{
"name": "doctrine/dbal",
"version": "v2.5.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/abbdfd1cff43a7b99d027af3be709bc8fc7d4769",
"reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769",
"shasum": ""
},
"require": {
"doctrine/common": ">=2.4,<2.7-dev",
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*",
"symfony/console": "2.*"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\DBAL\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Database Abstraction Layer",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"database",
"dbal",
"persistence",
"queryobject"
],
"time": "2016-01-05 22:11:12"
},
{
"name": "doctrine/inflector",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "90b2128806bfde671b6952ab8bea493942c1fdae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae",
"reference": "90b2128806bfde671b6952ab8bea493942c1fdae",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Inflector\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"inflection",
"pluralize",
"singularize",
"string"
],
"time": "2015-11-06 14:35:42"
},
{
"name": "doctrine/instantiator",
"version": "1.0.5",
......@@ -112,6 +527,60 @@
],
"time": "2015-06-14 21:17:01"
},
{
"name": "doctrine/lexer",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"lexer",
"parser"
],
"time": "2014-09-09 13:34:57"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.2.0",
......
......@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus;
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Core\Bootstrap;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Page\PageRenderer;
......@@ -168,7 +169,9 @@ class SystemInformationToolbarItem implements ToolbarItemInterface
{
$this->systemInformation[] = array(
'title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.database')),
'value' => $this->getDatabaseConnection()->getServerVersion(),
'value' => GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME)
->getServerVersion(),
'icon' => $this->iconFactory->getIcon('sysinfo-database', Icon::SIZE_SMALL)->render()
);
}
......
......@@ -398,7 +398,6 @@ class Bootstrap
$this->initializeCachingFramework()
->initializePackageManagement($packageManagerClassName)
->initializeRuntimeActivatedPackagesFromConfiguration()
->defineDatabaseConstants()
->defineUserAgentConstant()
->registerExtDirectComponents()
->setCacheHashOptions()
......@@ -514,20 +513,6 @@ class Bootstrap
return $this;
}
/**
* Define database constants
*
* @return \TYPO3\CMS\Core\Core\Bootstrap
*/
protected function defineDatabaseConstants()
{
define('TYPO3_db', $GLOBALS['TYPO3_CONF_VARS']['DB']['database']);
define('TYPO3_db_username', $GLOBALS['TYPO3_CONF_VARS']['DB']['username']);
define('TYPO3_db_password', $GLOBALS['TYPO3_CONF_VARS']['DB']['password']);
define('TYPO3_db_host', $GLOBALS['TYPO3_CONF_VARS']['DB']['host']);
return $this;
}
/**
* Define user agent constant
*
......@@ -809,45 +794,55 @@ class Bootstrap
{
/** @var $databaseConnection \TYPO3\CMS\Core\Database\DatabaseConnection */
$databaseConnection = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\DatabaseConnection::class);
$databaseConnection->setDatabaseName(TYPO3_db);
$databaseConnection->setDatabaseUsername(TYPO3_db_username);
$databaseConnection->setDatabasePassword(TYPO3_db_password);
$databaseConnection->setDatabaseName(
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['dbname'] ?? ''
);
$databaseConnection->setDatabaseUsername(
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['user'] ?? ''
);
$databaseConnection->setDatabasePassword(
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['password'] ?? ''
);
$databaseHost = TYPO3_db_host;
if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['port'])) {
$databaseConnection->setDatabasePort($GLOBALS['TYPO3_CONF_VARS']['DB']['port']);
$databaseHost = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['host'] ?? '';
if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['port'])) {
$databaseConnection->setDatabasePort($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['port']);
} elseif (strpos($databaseHost, ':') > 0) {
// @TODO: Find a way to handle this case in the install tool and drop this
list($databaseHost, $databasePort) = explode(':', $databaseHost);
$databaseConnection->setDatabasePort($databasePort);
}
if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['socket'])) {
$databaseConnection->setDatabaseSocket($GLOBALS['TYPO3_CONF_VARS']['DB']['socket']);
if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['unix_socket'])) {
$databaseConnection->setDatabaseSocket(
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['unix_socket']
);
}
$databaseConnection->setDatabaseHost($databaseHost);
$databaseConnection->debugOutput = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sqlDebug'];
if (
isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'])
&& !$GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']
if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['persistentConnection'])
&& $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['persistentConnection']
) {
$databaseConnection->setPersistentDatabaseConnection(true);
}
$isDatabaseHostLocalHost = $databaseHost === 'localhost' || $databaseHost === '127.0.0.1' || $databaseHost === '::1';
if (
isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress'])
&& $GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress']
$isDatabaseHostLocalHost = in_array($databaseHost, ['localhost', '127.0.0.1', '::1'], true);
if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driverOptions'])
&& $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driverOptions'] & MYSQLI_CLIENT_COMPRESS
&& !$isDatabaseHostLocalHost
) {
$databaseConnection->setConnectionCompression(true);
}
if (!empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'])) {
if (!empty($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['initCommands'])) {
$commandsAfterConnect = GeneralUtility::trimExplode(
LF,
str_replace('\' . LF . \'', LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']),
str_replace(
'\' . LF . \'',
LF,
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['initCommands']
),
true
);
$databaseConnection->setInitializeCommandsAfterConnect($commandsAfterConnect);
......
<?php
declare (strict_types=1);
namespace TYPO3\CMS\Core\Database;
/*
* This file is part of the TYPO3 CMS project.
*