From f9853b253c6ecb9a77a9d1c9006c5f548cdfd04e Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Mon, 31 Mar 2014 20:00:44 +0200 Subject: Deduplicate connection handling code into \OC\DB\ConnectionFactory --- lib/private/db.php | 139 +++++++++++------------------------ lib/private/db/connectionfactory.php | 117 +++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 98 deletions(-) create mode 100644 lib/private/db/connectionfactory.php (limited to 'lib') diff --git a/lib/private/db.php b/lib/private/db.php index cfdac766bff..11532d9fa54 100644 --- a/lib/private/db.php +++ b/lib/private/db.php @@ -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); - - // 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(); + $factory = new \OC\DB\ConnectionFactory(); + if (!$factory->isValidType($type)) { + return false; + } + + 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, diff --git a/lib/private/db/connectionfactory.php b/lib/private/db/connectionfactory.php new file mode 100644 index 00000000000..14ffe1a4a56 --- /dev/null +++ b/lib/private/db/connectionfactory.php @@ -0,0 +1,117 @@ + + * 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]); + } +} -- cgit v1.2.3