* SPL autoload
*/
public static function autoload($className) {
- if(array_key_exists($className, OC::$CLASSPATH)) {
+ if (array_key_exists($className, OC::$CLASSPATH)) {
$path = OC::$CLASSPATH[$className];
/** @TODO: Remove this when necessary
- Remove "apps/" from inclusion path for smooth migration to mutli app dir
- */
- if (strpos($path, 'apps/')===0) {
- OC_Log::write('core', 'include path for class "'.$className.'" starts with "apps/"', OC_Log::DEBUG);
+ Remove "apps/" from inclusion path for smooth migration to mutli app dir
+ */
+ if (strpos($path, 'apps/') === 0) {
+ OC_Log::write('core', 'include path for class "' . $className . '" starts with "apps/"', OC_Log::DEBUG);
$path = str_replace('apps/', '', $path);
}
- }
- elseif(strpos($className, 'OC_')===0) {
+ } elseif (strpos($className, 'OC_') === 0) {
$path = strtolower(str_replace('_', '/', substr($className, 3)) . '.php');
- }
- elseif(strpos($className, 'OCP\\')===0) {
- $path = 'public/'.strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- }
- elseif(strpos($className, 'OCA\\')===0) {
- $path = 'apps/'.strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- }
- elseif(strpos($className, 'Sabre_')===0) {
- $path = str_replace('_', '/', $className) . '.php';
- }
- elseif(strpos($className, 'Doctrine\\Common')===0) {
+ } elseif (strpos($className, 'OC\\') === 0) {
+ $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
+ } elseif (strpos($className, 'OCP\\') === 0) {
+ $path = 'public/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
+ } elseif (strpos($className, 'OCA\\') === 0) {
+ foreach (self::$APPSROOTS as $appDir) {
+ $path = $appDir['path'] . '/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
+ $fullPath = stream_resolve_include_path($path);
+ if (file_exists($fullPath)) {
+ require_once $fullPath;
+ return false;
+ }
+ }
+ } elseif (strpos($className, 'Sabre_') === 0) {
+ $path = str_replace('_', '/', $className) . '.php';
++ } elseif(strpos($className, 'Doctrine\\Common')===0) {
+ $path = 'doctrine/common/lib/'.str_replace('\\', '/', $className) . '.php';
- }
- elseif(strpos($className, 'Doctrine\\DBAL')===0) {
++ } elseif(strpos($className, 'Doctrine\\DBAL')===0) {
+ $path = 'doctrine/dbal/lib/'.str_replace('\\', '/', $className) . '.php';
- }
- elseif(strpos($className, 'Symfony\\Component\\Routing\\')===0) {
- $path = 'symfony/routing/'.str_replace('\\', '/', $className) . '.php';
- }
- elseif(strpos($className, 'Sabre\\VObject')===0) {
+ } elseif (strpos($className, 'Symfony\\Component\\Routing\\') === 0) {
+ $path = 'symfony/routing/' . str_replace('\\', '/', $className) . '.php';
+ } elseif (strpos($className, 'Sabre\\VObject') === 0) {
$path = str_replace('\\', '/', $className) . '.php';
- }
- elseif(strpos($className, 'Test_')===0) {
- $path = 'tests/lib/'.strtolower(str_replace('_', '/', substr($className, 5)) . '.php');
- }else{
+ } elseif (strpos($className, 'Test_') === 0) {
+ $path = 'tests/lib/' . strtolower(str_replace('_', '/', substr($className, 5)) . '.php');
+ } elseif (strpos($className, 'Test\\') === 0) {
+ $path = 'tests/lib/' . strtolower(str_replace('\\', '/', substr($className, 5)) . '.php');
+ } else {
return false;
}
*
*/
+define('MDB2_SCHEMA_DUMP_STRUCTURE', '1');
++
+ class DatabaseException extends Exception{
+ private $query;
+
+ public function __construct($message, $query){
+ parent::__construct($message);
+ $this->query = $query;
+ }
+
+ public function getQuery(){
+ return $this->query;
+ }
+ }
+
/**
* This class manages the access to the database. It basically is a wrapper for
- * MDB2 with some adaptions.
+ * Doctrine with some adaptions.
*/
class OC_DB {
- const BACKEND_PDO=0;
- const BACKEND_MDB2=1;
+ const BACKEND_DOCTRINE=2;
+ static private $preparedQueries = array();
+
/**
- * @var MDB2_Driver_Common
+ * @var \Doctrine\DBAL\Connection
*/
- static private $connection; //the prefered connection to use, either PDO or MDB2
+ static private $connection; //the prefered connection to use, only Doctrine
static private $backend=null;
/**
- * @var MDB2_Driver_Common
- */
- static private $MDB2=null;
- /**
- * @var PDO
- */
- static private $PDO=null;
- /**
- * @var MDB2_Schema
+ * @var Doctrine
*/
- static private $schema=null;
+ static private $DOCTRINE=null;
+
static private $inTransaction=false;
static private $prefix=null;
static private $type=null;
default:
return false;
}
- self::$DOCTRINE = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
-
- // Try to establish connection
- self::$MDB2 = MDB2::factory( $dsn, $options );
-
- // Die if we could not connect
- if( PEAR::isError( self::$MDB2 )) {
- OC_Log::write('core', self::$MDB2->getUserInfo(), OC_Log::FATAL);
- OC_Log::write('core', self::$MDB2->getMessage(), OC_Log::FATAL);
++ try {
++ self::$DOCTRINE = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
++ } 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();
+ }
-
- // We always, really always want associative arrays
- self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
}
-
- // we are done. great!
return true;
}
static public function prepare( $query , $limit=null, $offset=null ) {
if (!is_null($limit) && $limit != -1) {
- if (self::$backend == self::BACKEND_MDB2) {
- //MDB2 uses or emulates limits & offset internally
- self::$MDB2->setLimit($limit, $offset);
+ //PDO does not handle limit and offset.
+ //FIXME: check limit notation for other dbs
+ //the following sql thus might needs to take into account db ways of representing it
+ //(oracle has no LIMIT / OFFSET)
+ $limit = (int)$limit;
+ $limitsql = ' LIMIT ' . $limit;
+ if (!is_null($offset)) {
+ $offset = (int)$offset;
+ $limitsql .= ' OFFSET ' . $offset;
+ }
+ //insert limitsql
+ if (substr($query, -1) == ';') { //if query ends with ;
+ $query = substr($query, 0, -1) . $limitsql . ';';
} else {
- //PDO does not handle limit and offset.
- //FIXME: check limit notation for other dbs
- //the following sql thus might needs to take into account db ways of representing it
- //(oracle has no LIMIT / OFFSET)
- $limit = (int)$limit;
- $limitsql = ' LIMIT ' . $limit;
- if (!is_null($offset)) {
- $offset = (int)$offset;
- $limitsql .= ' OFFSET ' . $offset;
- }
- //insert limitsql
- if (substr($query, -1) == ';') { //if query ends with ;
- $query = substr($query, 0, -1) . $limitsql . ';';
- } else {
- $query.=$limitsql;
- }
+ $query.=$limitsql;
}
+ } else {
+ if (isset(self::$preparedQueries[$query])) {
+ return self::$preparedQueries[$query];
+ }
}
+ $rawQuery = $query;
// Optimize the query
$query = self::processQuery( $query );
try{
$result=self::$connection->prepare($query);
}catch(PDOException $e) {
- $entry = 'DB Error: "'.$e->getMessage().'"<br />';
- $entry .= 'Offending command was: '.htmlentities($query).'<br />';
- OC_Log::write('core', $entry, OC_Log::FATAL);
- error_log('DB error: '.$entry);
- OC_Template::printErrorPage( $entry );
+ throw new DatabaseException($e->getMessage(), $query);
}
- $result=new PDOStatementWrapper($result);
+ $result=new DoctrineStatementWrapper($result);
}
+ if (is_null($limit) || $limit == -1) {
+ self::$preparedQueries[$rawQuery] = $result;
+ }
return $result;
}
* http://www.sqlite.org/lang_createtable.html
* http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm
*/
- if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't
- $content = str_replace( '<default>0000-00-00 00:00:00</default>', '<default>CURRENT_TIMESTAMP</default>', $content );
- }
+ if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't
+ $content = str_replace( '<default>0000-00-00 00:00:00</default>',
+ '<default>CURRENT_TIMESTAMP</default>', $content );
+ }
-
- file_put_contents( $file2, $content );
-
- // Try to create tables
- $definition = self::$schema->parseDatabaseDefinitionFile( $file2 );
-
- //clean up memory
- unlink( $file2 );
-
- // Die in case something went wrong
- if( $definition instanceof MDB2_Schema_Error ) {
- OC_Template::printErrorPage( $definition->getMessage().': '.$definition->getUserInfo() );
- }
- if(OC_Config::getValue('dbtype', 'sqlite')==='oci') {
- unset($definition['charset']); //or MDB2 tries SHUTDOWN IMMEDIATE
- $oldname = $definition['name'];
- $definition['name']=OC_Config::getValue( "dbuser", $oldname );
- }
-
- // we should never drop a database
- $definition['overwrite'] = false;
-
- $ret=self::$schema->createDatabase( $definition );
-
- // Die in case something went wrong
- if( $ret instanceof MDB2_Error ) {
- OC_Template::printErrorPage( self::$MDB2->getDebugOutput().' '.$ret->getMessage() . ': '
- . $ret->getUserInfo() );
- }
-
- return true;
}
/**
* @return bool
*/
public static function updateDbFromStructure($file) {
- $CONFIG_DBTABLEPREFIX = OC_Config::getValue( "dbtableprefix", "oc_" );
- $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" );
-
- self::connectScheme();
-
- // read file
- $content = file_get_contents( $file );
-
- $previousSchema = self::$schema->getDefinitionFromDatabase();
- if (PEAR::isError($previousSchema)) {
- $error = $previousSchema->getMessage();
- $detail = $previousSchema->getDebugInfo();
- $message = 'Failed to get existing database structure for updating ('.$error.', '.$detail.')';
- OC_Log::write('core', $message, OC_Log::FATAL);
- throw new Exception($message);
+ self::connectDoctrine();
+ try {
+ $result = OC_DB_Schema::updateDbFromStructure(self::$connection, $file);
+ } catch (Exception $e) {
+ OC_Log::write('core', 'Failed to update database structure ('.$e.')', OC_Log::FATAL);
- return false;
++ throw $e;
}
-
- // Make changes and save them to an in-memory file
- $file2 = 'static://db_scheme';
- $content = str_replace( '*dbname*', $previousSchema['name'], $content );
- $content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content );
+ return $result;
/* FIXME: use CURRENT_TIMESTAMP for all databases. mysql supports it as a default for DATETIME since 5.6.5 [1]
* as a fallback we could use <default>0000-01-01 00:00:00</default> everywhere
* [1] http://bugs.mysql.com/bug.php?id=27645
* http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm
*/
if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't
- $content = str_replace( '<default>0000-00-00 00:00:00</default>', '<default>CURRENT_TIMESTAMP</default>', $content );
+ $content = str_replace( '<default>0000-00-00 00:00:00</default>',
+ '<default>CURRENT_TIMESTAMP</default>', $content );
}
- file_put_contents( $file2, $content );
- $op = self::$schema->updateDatabase($file2, $previousSchema, array(), false);
-
- //clean up memory
- unlink( $file2 );
-
- if (PEAR::isError($op)) {
- $error = $op->getMessage();
- $detail = $op->getDebugInfo();
- $message = 'Failed to update database structure ('.$error.', '.$detail.')';
- OC_Log::write('core', $message, OC_Log::FATAL);
- throw new Exception($message);
- }
- return true;
- }
-
- /**
- * @brief connects to a MDB2 database scheme
- * @returns bool
- *
- * Connects to a MDB2 database scheme
- */
- private static function connectScheme() {
- // We need a mdb2 database connection
- self::connectMDB2();
- self::$MDB2->loadModule('Manager');
- self::$MDB2->loadModule('Reverse');
-
- // Connect if this did not happen before
- if(!self::$schema) {
- require_once 'MDB2/Schema.php';
- self::$schema=MDB2_Schema::factory(self::$MDB2);
- }
-
- return true;
}
/**