mirror of
https://github.com/phpbb/phpbb.git
synced 2025-08-25 17:41:25 +02:00
[ticket/16643] Add Doctrine DBAL to phpBB
PHPBB3-16643
This commit is contained in:
@@ -121,7 +121,7 @@ class config_php_file
|
||||
* @return string driver class
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function convert_30_dbms_to_31($dbms)
|
||||
public static function convert_30_dbms_to_31($dbms)
|
||||
{
|
||||
// Note: this check is done first because mysqli extension
|
||||
// supplies a mysqli class, and class_exists($dbms) would return
|
||||
|
114
phpBB/phpbb/db/doctrine/connection_factory.php
Normal file
114
phpBB/phpbb/db/doctrine/connection_factory.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\doctrine;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\Exception;
|
||||
use InvalidArgumentException;
|
||||
use phpbb\config_php_file;
|
||||
use phpbb\exception\runtime_exception;
|
||||
|
||||
/**
|
||||
* Doctrine DBAL connection factory.
|
||||
*/
|
||||
class connection_factory
|
||||
{
|
||||
use driver_convertor;
|
||||
|
||||
/**
|
||||
* Creates a Doctrine DBAL connection from phpBB configuration.
|
||||
*
|
||||
* @param config_php_file $config Config PHP file wrapper.
|
||||
*
|
||||
* @return Connection Doctrine DBAL connection.
|
||||
*
|
||||
* @throws runtime_exception If the database connection could not be established.
|
||||
* @throws InvalidArgumentException If $driver_name is not a valid phpBB database driver.
|
||||
*/
|
||||
public static function get_connection(config_php_file $config) : Connection
|
||||
{
|
||||
$driver = $config->get('dbms');
|
||||
$host = $config->get('dbhost');
|
||||
$user = $config->get('dbuser');
|
||||
$pass = $config->get('dbpasswd');
|
||||
$name = $config->get('dbname');
|
||||
$port = $config->get('dbport');
|
||||
|
||||
return self::get_connection_from_params(
|
||||
$driver,
|
||||
$host,
|
||||
$user,
|
||||
$pass,
|
||||
$name,
|
||||
$port
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a database connection from the specified parameters.
|
||||
*
|
||||
* @param string $driver Driver name.
|
||||
* @param string $host Hostname.
|
||||
* @param string|null $user Username.
|
||||
* @param string|null $password Password.
|
||||
* @param string|null $name Database name.
|
||||
* @param string|null $port Database port.
|
||||
*
|
||||
* @return Connection Doctrine DBAL connection.
|
||||
*
|
||||
* @throws runtime_exception If the database connection could not be established.
|
||||
* @throws InvalidArgumentException If $driver_name is not a valid phpBB database driver.
|
||||
*/
|
||||
public static function get_connection_from_params(
|
||||
string $driver,
|
||||
string $host,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?string $name = null,
|
||||
?string $port = null) : Connection
|
||||
{
|
||||
$available_drivers = DriverManager::getAvailableDrivers();
|
||||
if (!in_array($driver, $available_drivers))
|
||||
{
|
||||
$driver = config_php_file::convert_30_dbms_to_31($driver);
|
||||
$driver = self::to_doctrine_driver($driver);
|
||||
}
|
||||
|
||||
$params = connection_parameter_factory::get_configuration(
|
||||
$driver,
|
||||
$host,
|
||||
$user,
|
||||
$password,
|
||||
$name,
|
||||
$port
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
return DriverManager::getConnection($params);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new runtime_exception('DB_CONNECTION_FAILED');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable constructor.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
}
|
180
phpBB/phpbb/db/doctrine/connection_parameter_factory.php
Normal file
180
phpBB/phpbb/db/doctrine/connection_parameter_factory.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\doctrine;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Helper class to generate Doctrine DBAL configuration.
|
||||
*/
|
||||
class connection_parameter_factory
|
||||
{
|
||||
/**
|
||||
* Returns configuration options for Doctrine DBAL.
|
||||
*
|
||||
* @param string $driver Driver name.
|
||||
* @param string $host Hostname.
|
||||
* @param string|null $user Username.
|
||||
* @param string|null $password Password.
|
||||
* @param string|null $name Database name.
|
||||
* @param string|null $port Database port.
|
||||
*
|
||||
* @return array Doctrine DBAL connection parameters.
|
||||
*
|
||||
* @throws InvalidArgumentException If a required parameter is empty or null.
|
||||
*/
|
||||
public static function get_configuration(
|
||||
string $driver,
|
||||
string $host,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?string $name = null,
|
||||
?string $port = null) : array
|
||||
{
|
||||
$params = [
|
||||
'driver' => $driver,
|
||||
];
|
||||
|
||||
return self::build_connection_parameters(
|
||||
$params,
|
||||
$host,
|
||||
$user,
|
||||
$password,
|
||||
$name,
|
||||
$port
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Doctrine configuration array.
|
||||
*
|
||||
* @param array $params Parameter array.
|
||||
* @param string $host Database hostname.
|
||||
* @param string|null $user Username.
|
||||
* @param string|null $password Password.
|
||||
* @param string|null $name Database name.
|
||||
* @param string|null $port Database port.
|
||||
*
|
||||
* @return array Doctrine's DBAL configuration for SQLite.
|
||||
*
|
||||
* @throws InvalidArgumentException If a required parameter is empty or null.
|
||||
*/
|
||||
private static function build_connection_parameters(
|
||||
array $params,
|
||||
string $host,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?string $name = null,
|
||||
?string $port = null) : array
|
||||
{
|
||||
if ($params['driver'] === 'pdo_sqlite')
|
||||
{
|
||||
return self::enrich_parameters(
|
||||
self::build_sqlite_parameters($params, $host, $user, $password)
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($host) || empty($user) || empty($name))
|
||||
{
|
||||
throw new InvalidArgumentException('Required database parameter is not set.');
|
||||
}
|
||||
|
||||
$params = array_merge($params, [
|
||||
'host' => $host,
|
||||
'user' => $user,
|
||||
'dbname' => $name,
|
||||
]);
|
||||
|
||||
if (!empty($password))
|
||||
{
|
||||
$params['password'] = $password;
|
||||
}
|
||||
|
||||
if (!empty($port))
|
||||
{
|
||||
$params['port'] = (int) $port;
|
||||
}
|
||||
|
||||
return self::enrich_parameters($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build configuration array for SQLite.
|
||||
*
|
||||
* @param array $params Parameter array.
|
||||
* @param string $path Path to the database.
|
||||
* @param string|null $user Username.
|
||||
* @param string|null $password Password.
|
||||
*
|
||||
* @return array Doctrine's DBAL configuration for SQLite.
|
||||
*/
|
||||
private static function build_sqlite_parameters(array $params, string $path, ?string $user, ?string $password) : array
|
||||
{
|
||||
$params['path'] = $path;
|
||||
|
||||
if (!empty($user))
|
||||
{
|
||||
$params['user'] = $user;
|
||||
}
|
||||
|
||||
if (!empty($password))
|
||||
{
|
||||
$params['password'] = $password;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional configuration options to the parameter list.
|
||||
*
|
||||
* @param array $params The parameter list to enrich.
|
||||
*
|
||||
* @return array The enriched parameter list.
|
||||
*/
|
||||
private static function enrich_parameters(array $params) : array
|
||||
{
|
||||
$enrichment_tags = [
|
||||
'pdo_mysql' => [
|
||||
'charset' => 'UTF8',
|
||||
],
|
||||
'oci8' => [
|
||||
'charset' => 'UTF8',
|
||||
],
|
||||
'pdo_pgsql' => [
|
||||
'charset' => 'UTF8',
|
||||
],
|
||||
];
|
||||
|
||||
if ($params['driver'] === 'pdo_mysql')
|
||||
{
|
||||
$enrichment_tags['pdo_mysql'][\PDO::MYSQL_ATTR_FOUND_ROWS] = true;
|
||||
}
|
||||
|
||||
$driver = $params['driver'];
|
||||
if (!array_key_exists($driver, $enrichment_tags))
|
||||
{
|
||||
return $params;
|
||||
}
|
||||
|
||||
return array_merge($params, $enrichment_tags[$driver]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable constructing this class.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
}
|
68
phpBB/phpbb/db/doctrine/driver_convertor.php
Normal file
68
phpBB/phpbb/db/doctrine/driver_convertor.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\doctrine;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Driver convertor utility for Doctrine DBAL.
|
||||
*/
|
||||
trait driver_convertor
|
||||
{
|
||||
/**
|
||||
* Converts phpBB driver names to Doctrine's equivalent.
|
||||
*
|
||||
* @param string $driver_name phpBB database driver name.
|
||||
*
|
||||
* @return string Doctrine DBAL's driver name.
|
||||
*
|
||||
* @throws InvalidArgumentException If $driver_name is not a valid phpBB database driver.
|
||||
*/
|
||||
public static function to_doctrine_driver(string $driver_name) : string
|
||||
{
|
||||
// Normalize driver name.
|
||||
$name = str_replace('phpbb\db\driver', '', $driver_name);
|
||||
$name = preg_replace('/mysql$/i', 'mysqli', $name);
|
||||
$name = trim($name, '\\');
|
||||
|
||||
switch ($name)
|
||||
{
|
||||
case 'mssql_odbc':
|
||||
case 'mssqlnative':
|
||||
$name = 'pdo_sqlsrv';
|
||||
break;
|
||||
|
||||
case 'mysqli':
|
||||
$name = 'pdo_mysql';
|
||||
break;
|
||||
|
||||
case 'oracle':
|
||||
$name = 'oci8';
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
$name = 'pdo_pgsql';
|
||||
break;
|
||||
|
||||
case 'sqlite3':
|
||||
$name = 'pdo_sqlite';
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Invalid phpBB database driver provided: ' . $driver_name);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
@@ -572,7 +572,7 @@ class container_builder
|
||||
{
|
||||
if ($this->dbal_connection === null)
|
||||
{
|
||||
$dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms'));
|
||||
$dbal_driver_class = \phpbb\config_php_file::convert_30_dbms_to_31($this->config_php_file->get('dbms'));
|
||||
/** @var \phpbb\db\driver\driver_interface $dbal_connection */
|
||||
$this->dbal_connection = new $dbal_driver_class();
|
||||
$this->dbal_connection->sql_connect(
|
||||
|
167
phpBB/phpbb/install/database_task.php
Normal file
167
phpBB/phpbb/install/database_task.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\install;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver\Exception as DriverException;
|
||||
use Doctrine\DBAL\Driver\Statement as DriverStmt;
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\DBAL\Statement;
|
||||
use phpbb\db\doctrine\connection_factory;
|
||||
use phpbb\install\helper\config;
|
||||
use phpbb\install\helper\database;
|
||||
use phpbb\install\helper\iohandler\iohandler_interface;
|
||||
|
||||
/**
|
||||
* Abstract base class for common database manipulation tasks.
|
||||
*/
|
||||
abstract class database_task extends task_base
|
||||
{
|
||||
/**
|
||||
* @var Connection
|
||||
*/
|
||||
private $conn;
|
||||
|
||||
/**
|
||||
* @var iohandler_interface
|
||||
*/
|
||||
private $io;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Connection $connection Doctrine DBAL connection.
|
||||
* @param iohandler_interface $io IO handler to use.
|
||||
* @param bool $essential Whether the task is essential.
|
||||
*/
|
||||
public function __construct(Connection $connection, iohandler_interface $io, bool $essential = true)
|
||||
{
|
||||
$this->conn = $connection;
|
||||
$this->io = $io;
|
||||
|
||||
parent::__construct($essential);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL query.
|
||||
*
|
||||
* @param string $sql The SQL to execute.
|
||||
*/
|
||||
protected function exec_sql(string $sql)
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->conn->executeStatement($sql);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$this->report_error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a prepared statement.
|
||||
*
|
||||
* @param string $sql The SQL.
|
||||
*
|
||||
* @return DriverStmt|Statement The prepared statement object.
|
||||
*/
|
||||
protected function create_prepared_stmt(string $sql)
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->conn->prepare($sql);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$this->report_error($e->getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and execute a prepared statement.
|
||||
*
|
||||
* @param string $sql The SQL to create the statement from.
|
||||
* @param array $params The parameters to bind to it.
|
||||
*/
|
||||
protected function create_and_execute_prepared_stmt(string $sql, array $params)
|
||||
{
|
||||
try
|
||||
{
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$this->exec_prepared_stmt($stmt, $params);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$this->report_error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind values and execute a prepared statement.
|
||||
*
|
||||
* @param Statement|DriverStmt $stmt Prepared statement.
|
||||
* @param array $params Parameters.
|
||||
*/
|
||||
protected function exec_prepared_stmt($stmt, array $params)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach ($params as $name => $val)
|
||||
{
|
||||
$stmt->bindValue($name, $val);
|
||||
}
|
||||
$stmt->execute();
|
||||
}
|
||||
catch (DriverException $e)
|
||||
{
|
||||
$this->report_error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a database error.
|
||||
*
|
||||
* @param string $message The error message.
|
||||
*/
|
||||
private function report_error(string $message)
|
||||
{
|
||||
$this->io->add_error_message('INST_ERR_DB', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Doctrine connection in the installer context.
|
||||
*
|
||||
* @param database $db_helper Database helper.
|
||||
* @param config $config Config options.
|
||||
*
|
||||
* @return Connection Doctrine DBAL connection object.
|
||||
*/
|
||||
protected static function get_doctrine_connection(database $db_helper, config $config) : Connection
|
||||
{
|
||||
$dbms = $db_helper->get_available_dbms($config->get('dbms'));
|
||||
$dbms = $dbms[$config->get('dbms')]['DRIVER'];
|
||||
|
||||
return connection_factory::get_connection_from_params(
|
||||
$dbms,
|
||||
$config->get('dbhost'),
|
||||
$config->get('dbuser'),
|
||||
$config->get('dbpasswd'),
|
||||
$config->get('dbname'),
|
||||
$config->get('dbport')
|
||||
);
|
||||
}
|
||||
}
|
@@ -41,6 +41,7 @@ class database
|
||||
'LABEL' => 'MySQL with MySQLi Extension',
|
||||
'SCHEMA' => 'mysql_41',
|
||||
'MODULE' => 'mysqli',
|
||||
'DOCTRINE' => ['pdo_mysql'],
|
||||
'DELIM' => ';',
|
||||
'DRIVER' => 'phpbb\db\driver\mysqli',
|
||||
'AVAILABLE' => true,
|
||||
@@ -50,6 +51,7 @@ class database
|
||||
'LABEL' => 'MS SQL Server [ ODBC ]',
|
||||
'SCHEMA' => 'mssql',
|
||||
'MODULE' => 'odbc',
|
||||
'DOCTRINE' => ['pdo_sqlsrv'],
|
||||
'DELIM' => ';',
|
||||
'DRIVER' => 'phpbb\db\driver\mssql_odbc',
|
||||
'AVAILABLE' => true,
|
||||
@@ -59,6 +61,7 @@ class database
|
||||
'LABEL' => 'MS SQL Server 2005+ [ Native ]',
|
||||
'SCHEMA' => 'mssql',
|
||||
'MODULE' => 'sqlsrv',
|
||||
'DOCTRINE' => ['pdo_sqlsrv'],
|
||||
'DELIM' => ';',
|
||||
'DRIVER' => 'phpbb\db\driver\mssqlnative',
|
||||
'AVAILABLE' => true,
|
||||
@@ -77,6 +80,7 @@ class database
|
||||
'LABEL' => 'PostgreSQL 8.3+',
|
||||
'SCHEMA' => 'postgres',
|
||||
'MODULE' => 'pgsql',
|
||||
'DOCTRINE' => ['pdo_pgsql'],
|
||||
'DELIM' => ';',
|
||||
'DRIVER' => 'phpbb\db\driver\postgres',
|
||||
'AVAILABLE' => true,
|
||||
@@ -86,6 +90,7 @@ class database
|
||||
'LABEL' => 'SQLite3',
|
||||
'SCHEMA' => 'sqlite',
|
||||
'MODULE' => 'sqlite3',
|
||||
'DOCTRINE' => ['pdo_sqlite'],
|
||||
'DELIM' => ';',
|
||||
'DRIVER' => 'phpbb\db\driver\sqlite3',
|
||||
'AVAILABLE' => true,
|
||||
@@ -166,6 +171,33 @@ class database
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists('DOCTRINE', $db_array))
|
||||
{
|
||||
$available = false;
|
||||
foreach ($db_array['DOCTRINE'] as $dll)
|
||||
{
|
||||
if (@extension_loaded($dll))
|
||||
{
|
||||
$available = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$available)
|
||||
{
|
||||
if ($return_unavailable)
|
||||
{
|
||||
$available_dbms[$db_name]['AVAILABLE'] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($available_dbms[$db_name]);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$any_dbms_available = true;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user