Deduplicate connection handling code into \OC\DB\ConnectionFactory

This commit is contained in:
Andreas Fischer 2014-03-31 20:00:44 +02:00
parent a585cec530
commit f9853b253c
4 changed files with 173 additions and 130 deletions

View file

@ -22,10 +22,17 @@ class ConvertType extends Command {
protected $config;
/**
* @param \OC\Config $config
* @var \OC\DB\ConnectionFactory
*/
public function __construct($config) {
protected $connectionFactory;
/**
* @param \OC\Config $config
* @param \OC\DB\ConnectionFactory $connectionFactory
*/
public function __construct($config, $connectionFactory) {
$this->config = $config;
$this->connectionFactory = $connectionFactory;
parent::__construct();
}
@ -87,12 +94,6 @@ class ConvertType extends Command {
;
}
private static $type2driver = array(
'mysql' => 'pdo_mysql',
'pgsql' => 'pdo_pgsql',
'oci' => 'oci8',
'mssql' => 'pdo_sqlsrv',
);
protected function execute(InputInterface $input, OutputInterface $output) {
$fromDB = \OC_DB::getConnection();
$toDB = $this->getToDBConnection($input, $output);
@ -140,35 +141,17 @@ class ConvertType extends Command {
private function getToDBConnection($input, $output) {
$type = $input->getArgument('type');
$username = $input->getArgument('username');
$hostname = $input->getArgument('hostname');
$dbname = $input->getArgument('database');
$password = $input->getOption('password');
if (!isset(self::$type2driver[$type])) {
throw new \InvalidArgumentException('Unknown type: '.$type);
}
$connectionParams = array(
'driver' => self::$type2driver[$type],
'user' => $username,
'password' => $password,
'host' => $hostname,
'dbname' => $dbname,
'host' => $input->getArgument('hostname'),
'user' => $input->getArgument('username'),
'password' => $input->getOption('password'),
'dbname' => $input->getArgument('database'),
'tablePrefix' => $this->config->getValue('dbtableprefix', 'oc_'),
);
if ($input->getOption('port')) {
$connectionParams['port'] = $input->getOption('port');
}
switch ($type) {
case 'mysql':
case 'mssql':
$connectionParams['charset'] = 'UTF8';
break;
case 'oci':
$connectionParams['charset'] = 'AL32UTF8';
break;
}
return \Doctrine\DBAL\DriverManager::getConnection($connectionParams);
return $this->connectionFactory->getConnection($type, $connectionParams);
}
private function getTables($db) {

View file

@ -9,7 +9,7 @@
/** @var $application Symfony\Component\Console\Application */
$application->add(new OC\Core\Command\Status);
$application->add(new OC\Core\Command\Db\GenerateChangeScript());
$application->add(new OC\Core\Command\Db\ConvertType(OC_Config::getObject()));
$application->add(new OC\Core\Command\Db\ConvertType(OC_Config::getObject(), new \OC\DB\ConnectionFactory()));
$application->add(new OC\Core\Command\Upgrade());
$application->add(new OC\Core\Command\Maintenance\SingleUser());
$application->add(new OC\Core\Command\App\Disable());

View file

@ -72,102 +72,45 @@ class OC_DB {
$port=false;
}
// do nothing if the connection already has been established
if (!self::$connection) {
$config = new \Doctrine\DBAL\Configuration();
$eventManager = new \Doctrine\Common\EventManager();
switch($type) {
case 'sqlite':
case 'sqlite3':
$datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
$connectionParams = array(
'user' => $user,
'password' => $pass,
'path' => $datadir.'/'.$name.'.db',
'driver' => 'pdo_sqlite',
);
$connectionParams['adapter'] = '\OC\DB\AdapterSqlite';
$connectionParams['wrapperClass'] = 'OC\DB\Connection';
break;
case 'mysql':
$connectionParams = array(
'user' => $user,
'password' => $pass,
'host' => $host,
'port' => $port,
'dbname' => $name,
'charset' => 'UTF8',
'driver' => 'pdo_mysql',
);
$connectionParams['adapter'] = '\OC\DB\Adapter';
$connectionParams['wrapperClass'] = 'OC\DB\Connection';
// Send "SET NAMES utf8". Only required on PHP 5.3 below 5.3.6.
// See http://stackoverflow.com/questions/4361459/php-pdo-charset-set-names#4361485
$eventManager->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\MysqlSessionInit);
break;
case 'pgsql':
$connectionParams = array(
'user' => $user,
'password' => $pass,
'host' => $host,
'port' => $port,
'dbname' => $name,
'driver' => 'pdo_pgsql',
);
$connectionParams['adapter'] = '\OC\DB\AdapterPgSql';
$connectionParams['wrapperClass'] = 'OC\DB\Connection';
break;
case 'oci':
$connectionParams = array(
'user' => $user,
'password' => $pass,
'host' => $host,
'dbname' => $name,
'charset' => 'AL32UTF8',
'driver' => 'oci8',
);
if (!empty($port)) {
$connectionParams['port'] = $port;
}
$connectionParams['adapter'] = '\OC\DB\AdapterOCI8';
$connectionParams['wrapperClass'] = 'OC\DB\OracleConnection';
$eventManager->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\OracleSessionInit);
break;
case 'mssql':
$connectionParams = array(
'user' => $user,
'password' => $pass,
'host' => $host,
'port' => $port,
'dbname' => $name,
'charset' => 'UTF8',
'driver' => 'pdo_sqlsrv',
);
$connectionParams['adapter'] = '\OC\DB\AdapterSQLSrv';
$connectionParams['wrapperClass'] = 'OC\DB\Connection';
break;
default:
return false;
}
$connectionParams['tablePrefix'] = OC_Config::getValue('dbtableprefix', 'oc_' );
try {
self::$connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config, $eventManager);
if ($type === 'sqlite' || $type === 'sqlite3') {
// Sqlite doesn't handle query caching and schema changes
// TODO: find a better way to handle this
self::$connection->disableQueryStatementCaching();
}
} catch(\Doctrine\DBAL\DBALException $e) {
OC_Log::write('core', $e->getMessage(), OC_Log::FATAL);
OC_User::setUserId(null);
$factory = new \OC\DB\ConnectionFactory();
if (!$factory->isValidType($type)) {
return false;
}
// send http status 503
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
OC_Template::printErrorPage('Failed to connect to database');
die();
if ($factory->normalizeType($type) === 'sqlite3') {
$datadir = OC_Config::getValue("datadirectory", OC::$SERVERROOT.'/data');
$connectionParams = array(
'user' => $user,
'password' => $pass,
'path' => $datadir.'/'.$name.'.db',
);
} else {
$connectionParams = array(
'user' => $user,
'password' => $pass,
'host' => $host,
'dbname' => $name,
);
if (!empty($port)) {
$connectionParams['port'] = $port;
}
}
$connectionParams['tablePrefix'] = OC_Config::getValue('dbtableprefix', 'oc_');
try {
self::$connection = $factory->getConnection($type, $connectionParams);
} catch(\Doctrine\DBAL\DBALException $e) {
OC_Log::write('core', $e->getMessage(), OC_Log::FATAL);
OC_User::setUserId(null);
// send http status 503
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
OC_Template::printErrorPage('Failed to connect to database');
die();
}
return true;
}
@ -202,12 +145,12 @@ class OC_DB {
*/
static public function prepare( $query , $limit = null, $offset = null, $isManipulation = null) {
self::connect();
if ($isManipulation === null) {
//try to guess, so we return the number of rows on manipulations
$isManipulation = self::isManipulation($query);
}
// return the result
try {
$result = self::$connection->prepare($query, $limit, $offset);
@ -222,7 +165,7 @@ class OC_DB {
/**
* tries to guess the type of statement based on the first 10 characters
* the current check allows some whitespace but does not work with IF EXISTS or other more complex statements
*
*
* @param string $sql
* @return bool
*/
@ -245,7 +188,7 @@ class OC_DB {
}
return false;
}
/**
* @brief execute a prepared statement, on error write log and throw exception
* @param mixed $stmt OC_DB_StatementWrapper,

View file

@ -0,0 +1,117 @@
<?php
/**
* Copyright (c) 2014 Andreas Fischer <bantu@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\DB;
/**
* Takes care of creating and configurating Doctrine connections.
*/
class ConnectionFactory {
/**
* @var array
*
* Array mapping DBMS type to default connection parameters passed to
* \Doctrine\DBAL\DriverManager::getConnection().
*/
protected $defaultConnectionParams = array(
'mssql' => array(
'adapter' => '\OC\DB\AdapterSQLSrv',
'charset' => 'UTF8',
'driver' => 'pdo_sqlsrv',
'wrapperClass' => 'OC\DB\Connection',
),
'mysql' => array(
'adapter' => '\OC\DB\Adapter',
'charset' => 'UTF8',
'driver' => 'pdo_mysql',
'wrapperClass' => 'OC\DB\Connection',
),
'oci' => array(
'adapter' => '\OC\DB\AdapterOCI8',
'charset' => 'AL32UTF8',
'driver' => 'oci8',
'wrapperClass' => 'OC\DB\OracleConnection',
),
'pgsql' => array(
'adapter' => '\OC\DB\AdapterPgSql',
'driver' => 'pdo_pgsql',
'wrapperClass' => 'OC\DB\Connection',
),
'sqlite3' => array(
'adapter' => '\OC\DB\AdapterSqlite',
'driver' => 'pdo_sqlite',
'wrapperClass' => 'OC\DB\Connection',
),
);
/**
* @brief Get default connection parameters for a given DBMS.
* @param string $type DBMS type
* @throws \InvalidArgumentException If $type is invalid
* @return array Default connection parameters.
*/
public function getDefaultConnectionParams($type) {
$normalizedType = $this->normalizeType($type);
if (!isset($this->defaultConnectionParams[$normalizedType])) {
throw new \InvalidArgumentException("Unsupported type: $type");
}
return $this->defaultConnectionParams[$normalizedType];
}
/**
* @brief Get default connection parameters for a given DBMS.
* @param string $type DBMS type
* @param array $additionalConnectionParams Additional connection parameters
* @return \OC\DB\Connection
*/
public function getConnection($type, $additionalConnectionParams) {
$normalizedType = $this->normalizeType($type);
$eventManager = new \Doctrine\Common\EventManager();
switch ($normalizedType) {
case 'mysql':
// Send "SET NAMES utf8". Only required on PHP 5.3 below 5.3.6.
// See http://stackoverflow.com/questions/4361459/php-pdo-charset-set-names#4361485
$eventManager->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\MysqlSessionInit);
break;
case 'oci':
$eventManager->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\OracleSessionInit);
break;
}
$connection = \Doctrine\DBAL\DriverManager::getConnection(
array_merge($this->getDefaultConnectionParams($type), $additionalConnectionParams),
new \Doctrine\DBAL\Configuration(),
$eventManager
);
switch ($normalizedType) {
case 'sqlite3':
// Sqlite doesn't handle query caching and schema changes
// TODO: find a better way to handle this
$connection->disableQueryStatementCaching();
break;
}
return $connection;
}
/**
* @brief Normalize DBMS type
* @param string $type DBMS type
* @return string Normalized DBMS type
*/
public function normalizeType($type) {
return $type === 'sqlite' ? 'sqlite3' : $type;
}
/**
* @brief Checks whether the specififed DBMS type is valid.
* @return bool
*/
public function isValidType($type) {
$normalizedType = $this->normalizeType($type);
return isset($this->defaultConnectionParams[$normalizedType]);
}
}