mirror of
https://github.com/phpbb/phpbb.git
synced 2025-08-21 16:01:40 +02:00
[ticket/16741] Database tools to use Doctrine
PHPBB3-16741
This commit is contained in:
committed by
Tristan Darricau
parent
aee5e373bc
commit
98134abe20
55
phpBB/phpbb/db/doctrine/case_insensitive_string.php
Normal file
55
phpBB/phpbb/db/doctrine/case_insensitive_string.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?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\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
/**
|
||||
* Case-insensitive string type (only supported by Postgres).
|
||||
*/
|
||||
class case_insensitive_string extends Type
|
||||
{
|
||||
public const CASE_INSENSITIVE_STRING = 'string_ci';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
|
||||
{
|
||||
if ($platform->getName() === 'postgresql')
|
||||
{
|
||||
return 'varchar_ci';
|
||||
}
|
||||
|
||||
// This relies on our own oracle_platform implementation, and the fact that
|
||||
// we used 3 times larger capacity for strings on oracle for unicode strings
|
||||
// as on other platforms. This is not the case with varchar_ci, which uses
|
||||
// the same length as other platforms.
|
||||
if ($platform->getName() === 'oracle')
|
||||
{
|
||||
return $platform->getAsciiStringTypeDeclarationSQL($column);
|
||||
}
|
||||
|
||||
return $platform->getVarcharTypeDeclarationSQL($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return self::CASE_INSENSITIVE_STRING;
|
||||
}
|
||||
}
|
@@ -16,6 +16,7 @@ namespace phpbb\db\doctrine;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use InvalidArgumentException;
|
||||
use phpbb\config_php_file;
|
||||
use phpbb\exception\runtime_exception;
|
||||
@@ -25,8 +26,6 @@ use phpbb\exception\runtime_exception;
|
||||
*/
|
||||
class connection_factory
|
||||
{
|
||||
use driver_convertor;
|
||||
|
||||
/**
|
||||
* Creates a Doctrine DBAL connection from phpBB configuration.
|
||||
*
|
||||
@@ -37,7 +36,7 @@ class connection_factory
|
||||
* @throws runtime_exception If the database connection could not be established.
|
||||
* @throws InvalidArgumentException If the provided driver name is not a valid phpBB database driver.
|
||||
*/
|
||||
public static function get_connection(config_php_file $config) : Connection
|
||||
public static function get_connection(config_php_file $config): Connection
|
||||
{
|
||||
$driver = $config->get('dbms');
|
||||
$host = $config->get('dbhost');
|
||||
@@ -77,7 +76,7 @@ class connection_factory
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?string $name = null,
|
||||
?string $port = null) : Connection
|
||||
?string $port = null): Connection
|
||||
{
|
||||
$available_drivers = DriverManager::getAvailableDrivers();
|
||||
if (!in_array($driver, $available_drivers))
|
||||
@@ -97,7 +96,10 @@ class connection_factory
|
||||
|
||||
try
|
||||
{
|
||||
return DriverManager::getConnection($params);
|
||||
$connection = DriverManager::getConnection($params);
|
||||
Type::addType(case_insensitive_string::CASE_INSENSITIVE_STRING, case_insensitive_string::class);
|
||||
$connection->getDatabasePlatform()->registerDoctrineTypeMapping('varchar_ci', case_insensitive_string::CASE_INSENSITIVE_STRING);
|
||||
return $connection;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
@@ -105,6 +107,52 @@ class connection_factory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable constructor.
|
||||
*/
|
||||
|
@@ -151,6 +151,7 @@ class connection_parameter_factory
|
||||
],
|
||||
'oci8' => [
|
||||
'charset' => 'UTF8',
|
||||
'platform' => new oracle_platform(),
|
||||
],
|
||||
'pdo_pgsql' => [
|
||||
'charset' => 'UTF8',
|
||||
|
@@ -1,68 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
43
phpBB/phpbb/db/doctrine/oracle_platform.php
Normal file
43
phpBB/phpbb/db/doctrine/oracle_platform.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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\Platforms\OraclePlatform;
|
||||
|
||||
/**
|
||||
* Oracle specific schema restrictions for BC.
|
||||
*/
|
||||
class oracle_platform extends OraclePlatform
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getVarcharTypeDeclarationSQL(array $column): string
|
||||
{
|
||||
if (array_key_exists('length', $column) && is_int($column['length']))
|
||||
{
|
||||
$column['length'] *= 3;
|
||||
}
|
||||
|
||||
return parent::getVarcharTypeDeclarationSQL($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getAsciiStringTypeDeclarationSQL(array $column): string
|
||||
{
|
||||
return parent::getVarcharTypeDeclarationSQL($column);
|
||||
}
|
||||
}
|
122
phpBB/phpbb/db/doctrine/table_helper.php
Normal file
122
phpBB/phpbb/db/doctrine/table_helper.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?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;
|
||||
|
||||
class table_helper
|
||||
{
|
||||
/**
|
||||
* Converts phpBB's column representation to Doctrine's representation.
|
||||
*
|
||||
* @param array $column_data Column data.
|
||||
*
|
||||
* @return array<string, array> A pair of type and array of column options.
|
||||
*/
|
||||
public static function convert_column_data(array $column_data, string $dbms_layer): array
|
||||
{
|
||||
$options = self::resolve_dbms_specific_options($column_data, $dbms_layer);
|
||||
list($type, $opts) = type_converter::convert($column_data[0]);
|
||||
$options = array_merge($options, $opts);
|
||||
return [$type, $options];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve DBMS specific options in column data.
|
||||
*
|
||||
* @param array $column_data Original column data.
|
||||
* @param string $dbms_layer DBMS layer name.
|
||||
*
|
||||
* @return array Doctrine column options.
|
||||
*/
|
||||
private static function resolve_dbms_specific_options(array $column_data, string $dbms_layer): array
|
||||
{
|
||||
$doctrine_options = [];
|
||||
|
||||
if (is_array($column_data[1]))
|
||||
{
|
||||
$column_data[1] = self::get_default_column_option($column_data[1], $dbms_layer);
|
||||
}
|
||||
|
||||
if (!is_null($column_data[1]))
|
||||
{
|
||||
$doctrine_options['default'] = $column_data[1];
|
||||
$doctrine_options['notnull'] = true;
|
||||
}
|
||||
|
||||
$non_string_pattern = '/^[a-z]*(?:int|decimal|bool|timestamp)(?::[0-9]+)?$/';
|
||||
if ($dbms_layer === 'oracle' && !preg_match($non_string_pattern, strtolower($column_data[0]))
|
||||
&& array_key_exists('default', $doctrine_options[0]) && $doctrine_options[0]['default'] === '')
|
||||
{
|
||||
unset($doctrine_options['notnull']);
|
||||
}
|
||||
|
||||
if (isset($column_data[2]))
|
||||
{
|
||||
if ($column_data[2] === 'auto_increment')
|
||||
{
|
||||
$doctrine_options['autoincrement'] = true;
|
||||
}
|
||||
elseif ($dbms_layer === 'mysql' && $column_data[2] === 'true_sort')
|
||||
{
|
||||
$doctrine_options['platformoptions']['collation'] = 'utf8_unicode_ci';
|
||||
}
|
||||
}
|
||||
|
||||
return $doctrine_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DBMS specific default value for a column definition.
|
||||
*
|
||||
* @param array $default_options Database specific default value options.
|
||||
* @param string $dbms_layer Name of the DBMS layer.
|
||||
*
|
||||
* @return mixed Default value for the current DBMS.
|
||||
*
|
||||
* @throws InvalidArgumentException When `$schema_name` contains an invalid legacy DBMS name.
|
||||
*/
|
||||
private static function get_default_column_option(array $default_options, string $dbms_layer)
|
||||
{
|
||||
switch ($dbms_layer)
|
||||
{
|
||||
case 'mysql':
|
||||
return array_key_exists('mysql_41', $default_options)
|
||||
? $default_options['mysql_41']
|
||||
: $default_options['default'];
|
||||
case 'oracle':
|
||||
return array_key_exists('oracle', $default_options)
|
||||
? $default_options['oracle']
|
||||
: $default_options['default'];
|
||||
case 'postgresql':
|
||||
return array_key_exists('postgres', $default_options)
|
||||
? $default_options['postgres']
|
||||
: $default_options['default'];
|
||||
case 'mssql':
|
||||
return array_key_exists('mssqlnative', $default_options)
|
||||
? $default_options['mssqlnative']
|
||||
: (array_key_exists('mssql', $default_options) ? $default_options['mssql'] : $default_options['default']);
|
||||
case 'sqlite':
|
||||
return array_key_exists('sqlite3', $default_options)
|
||||
? $default_options['sqlite3']
|
||||
: $default_options['default'];
|
||||
default:
|
||||
throw new InvalidArgumentException('Invalid schema name.');
|
||||
}
|
||||
}
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
}
|
120
phpBB/phpbb/db/doctrine/type_converter.php
Normal file
120
phpBB/phpbb/db/doctrine/type_converter.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Map phpBB's database types to Doctrine's portable types.
|
||||
*/
|
||||
class type_converter
|
||||
{
|
||||
/**
|
||||
* Type map.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private const TYPE_MAP = [
|
||||
'BINT' => ['bigint', []],
|
||||
'ULINT' => ['integer', ['unsigned' => true]],
|
||||
'UINT' => ['integer', ['unsigned' => true]],
|
||||
'TINT' => ['smallint', []],
|
||||
'USINT' => ['smallint', ['unsigned' => true]],
|
||||
'BOOL' => ['boolean', ['unsigned' => true]],
|
||||
'VCHAR' => ['string', ['length' => 255]],
|
||||
'CHAR' => ['ascii_string', []],
|
||||
'XSTEXT' => ['ascii_string', ['length' => 1000]],
|
||||
'XSTEXT_UNI'=> ['string', ['length' => 100]],
|
||||
'STEXT' => ['ascii_string', ['length' => 3000]],
|
||||
'STEXT_UNI' => ['string', ['length' => 255]],
|
||||
'TEXT' => ['text', ['length' => ((1 << 16) - 1)]],
|
||||
'TEXT_UNI' => ['text', ['length' => ((1 << 16) - 1)]],
|
||||
'MTEXT' => ['text', ['length' => ((1 << 24) - 1)]],
|
||||
'MTEXT_UNI' => ['text', ['length' => ((1 << 24) - 1)]],
|
||||
'TIMESTAMP' => ['integer', ['unsigned' => true]],
|
||||
'DECIMAL' => ['integer', ['precision' => 5, 'scale' => 2]],
|
||||
'PDECIMAL' => ['integer', ['precision' => 6, 'scale' => 3]],
|
||||
'VCHAR_UNI' => ['string', ['length' => 255]],
|
||||
'VCHAR_CI' => ['string_ci', ['length' => 255]],
|
||||
'VARBINARY' => ['binary', ['length' => 255]],
|
||||
];
|
||||
|
||||
/**
|
||||
* Convert legacy type to Doctrine's type system.
|
||||
*
|
||||
* @param string $type Legacy type name
|
||||
*
|
||||
* @return array<string, array> Pair of type name and options.
|
||||
*/
|
||||
public static function convert(string $type): array
|
||||
{
|
||||
if (strpos($type, ':') !== false)
|
||||
{
|
||||
list($typename, $length) = explode(':', $type);
|
||||
return self::mapWithLength($typename, (int) $length);
|
||||
}
|
||||
|
||||
return self::mapType($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map legacy types with length attribute.
|
||||
*
|
||||
* @param string $type Legacy type name.
|
||||
* @param int $length Type length.
|
||||
*
|
||||
* @return array<string, array> Pair of type name and options.
|
||||
*/
|
||||
private static function mapWithLength(string $type, int $length): array
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case 'UINT':
|
||||
case 'INT':
|
||||
case 'TINT':
|
||||
return self::TYPE_MAP[$type];
|
||||
|
||||
case 'DECIMAL':
|
||||
case 'PDECIMAL':
|
||||
$pair = self::TYPE_MAP[$type];
|
||||
$pair[1]['precision'] = $length;
|
||||
return $pair;
|
||||
|
||||
case 'VCHAR':
|
||||
case 'CHAR':
|
||||
case 'VCHAR_UNI':
|
||||
$pair = self::TYPE_MAP[$type];
|
||||
$pair[1]['length'] = $length;
|
||||
return $pair;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Database type is undefined.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map phpBB's legacy database types to Doctrine types.
|
||||
*
|
||||
* @param string $type Type name.
|
||||
*
|
||||
* @return array<string, array> Pair of type name and an array of options.
|
||||
*/
|
||||
private static function mapType(string $type): array
|
||||
{
|
||||
if (!in_array($type, self::TYPE_MAP, true))
|
||||
{
|
||||
throw new \InvalidArgumentException("Database type is undefined.");
|
||||
}
|
||||
|
||||
return self::TYPE_MAP[$type];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user