Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow options to be provided to Doctrine #40449

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions config/config.sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,34 @@
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET wait_timeout = 28800'
],

/**
* Allows defining custom DB types and options as well as the ability to override
* the default connection parameters as defined by
* OC\DB\ConnectionFactory::defaultConnectionParams.
*/
'dbconnectionparams' => [
'dbtype' => [
'adapter' => AdapterMySQL::class,
'charset' => 'UTF8',
'driver' => 'pdo_dbtype',
'wrapperClass' => Doctrine\DBAL\Connection::class,
],
],

/**
* Allows additional configuration options to be provided for the database
* connection as defined by Doctrine\DBAL\Configuration::class. This is useful
* for specifying a custom logger, middlewares, etc.
*/
'dbconfigurationparams' => [
"sqllogger" => 'Doctrine\DBAL\Logging\SQLLogger',
"resultcache" => 'Psr\Cache\CacheItemPoolInterface',
"schemaassetsfilter" => 'callable',
"autocommit" => true,
"middlewares" => array(
'Doctrine\DBAL\Driver\Middleware',
),
],
/**
* sqlite3 journal mode can be specified using this configuration parameter -
* can be 'WAL' or 'DELETE' see for more details https://www.sqlite.org/wal.html
Expand Down
51 changes: 47 additions & 4 deletions lib/private/AppFramework/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,15 @@
use OC\AppFramework\DependencyInjection\DIContainer;
use OC\AppFramework\Http\Dispatcher;
use OC\AppFramework\Http\Request;
use OCP\App\IAppManager;
use OCP\Profiler\IProfiler;
use OC\Profiler\RoutingDataCollector;
use OCP\AppFramework\QueryException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\ICallbackResponse;
use OCP\AppFramework\Http\IOutput;
use OCP\AppFramework\QueryException;
use OCP\Diagnostics\IEventLogger;
use OCP\HintException;
use OCP\IRequest;
use OCP\Profiler\IProfiler;

/**
* Entry point for every request in your app. You can consider this as your
Expand All @@ -69,7 +68,7 @@ public static function buildAppNamespace(string $appId, string $topNamespace = '
return $topNamespace . self::$nameSpaceCache[$appId];
}

$appInfo = \OCP\Server::get(IAppManager::class)->getAppInfo($appId);
$appInfo = self::getAppInfo($appId);
if (isset($appInfo['namespace'])) {
self::$nameSpaceCache[$appId] = trim($appInfo['namespace']);
} else {
Expand All @@ -91,11 +90,42 @@ public static function buildAppNamespace(string $appId, string $topNamespace = '
return $topNamespace . self::$nameSpaceCache[$appId];
}

public static function getAppInfo(string $appId, bool $path = false, $lang = null) {
if ($path) {
$file = $appId;
} else {
$dir = \OC_App::findAppInDirectories($appId);

if ($dir === false) {
return null;
}

$appPath = $dir['path'] . '/' . $appId;
$file = $appPath . '/appinfo/info.xml';
}

$parser = new \OC\App\InfoParser();
$data = $parser->parse($file);

if (is_array($data)) {
$data = \OC_App::parseAppInfo($data, $lang);
}

return $data;
}

public static function getAppIdForClass(string $className, string $topNamespace = 'OCA\\'): ?string {
if (!str_starts_with($className, $topNamespace)) {
return null;
}

if (str_starts_with($className, $topNamespace)) {
$classNoTopNamespace = substr($className, strlen($topNamespace));
$appNameParts = explode('\\', $classNoTopNamespace, 2);
$appName = reset($appNameParts);
return strtolower($appName);
}

foreach (self::$nameSpaceCache as $appId => $namespace) {
if (str_starts_with($className, $topNamespace . $namespace . '\\')) {
return $appId;
Expand All @@ -105,6 +135,19 @@ public static function getAppIdForClass(string $className, string $topNamespace
return null;
}

public static function registerAppClass(string $className): void {
$classParts = explode('\\', $className, 2);
$topNamespace = reset($classParts) . '\\';
$appId = self::getAppIdForClass($className, $topNamespace);
$dir = \OC_App::findAppInDirectories($appId);

if ($dir === false) {
throw new \OCP\App\AppPathNotFoundException('App not found in any app directory');
}

$appPath = $dir['path'] . '/' . $appId;
\OC_App::registerAutoloading($appId, $appPath);
}

/**
* Shortcut for calling a controller method and printing the result
Expand Down
49 changes: 48 additions & 1 deletion lib/private/DB/ConnectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Event\Listeners\OracleSessionInit;
use Doctrine\DBAL\Event\Listeners\SQLSessionInit;
use OC\AppFramework\App;
use OC\SystemConfig;

/**
Expand Down Expand Up @@ -93,6 +94,21 @@
if ($collationOverride) {
$this->defaultConnectionParams['mysql']['collation'] = $collationOverride;
}

$connectionParams = $this->config->getValue('dbconnectionparams', array()) ?: array();

foreach ($connectionParams as $type) {
foreach ($type as $key => $param) {
switch ($key) {
case 'adapter':
case 'wrapperClass':
\OC::$server->get(App::class)::registerAppClass($param);
break;
}
}
}

$this->defaultConnectionParams = array_replace_recursive($this->defaultConnectionParams, $connectionParams);
}

/**
Expand Down Expand Up @@ -121,7 +137,7 @@
* @brief Get default connection parameters for a given DBMS.
* @param string $type DBMS type
* @param array $additionalConnectionParams Additional connection parameters
* @return \OC\DB\Connection

Check failure on line 140 in lib/private/DB/ConnectionFactory.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MoreSpecificReturnType

lib/private/DB/ConnectionFactory.php:140:13: MoreSpecificReturnType: The declared return type 'OC\DB\Connection' for OC\DB\ConnectionFactory::getConnection is more specific than the inferred return type 'Doctrine\DBAL\Connection' (see https://psalm.dev/070)
*/
public function getConnection($type, $additionalConnectionParams) {
$normalizedType = $this->normalizeType($type);
Expand Down Expand Up @@ -158,12 +174,43 @@
break;
}
/** @var Connection $connection */
$configuration = new Configuration();

foreach ($this->config->getValue('dbconfigurationparams', array()) as $param => $value) {
switch ($param) {
case "sqllogger":
\OC::$server->get(App::class)::registerAppClass($value);
$configuration->setSQLLogger(new $value());

Check failure

Code scanning / Psalm

TaintedCallable Error

Detected tainted text

Check failure

Code scanning / Psalm

TaintedCallable Error

Detected tainted text
break;
case "resultcache":
\OC::$server->get(App::class)::registerAppClass($value);
$configuration->setResultCache(new $value());

Check failure

Code scanning / Psalm

TaintedCallable Error

Detected tainted text

Check failure

Code scanning / Psalm

TaintedCallable Error

Detected tainted text
break;
case "schemaassetsfilter":
$configuration->setSchemaAssetsFilter($value);
break;
case "autocommit":
$configuration->setAutoCommit($value);
break;
case "middlewares":
$middlewares = array();

foreach ($value as $middleware) {
\OC::$server->get(App::class)::registerAppClass($middleware);
array_push($middlewares, new $middleware());

Check failure

Code scanning / Psalm

TaintedCallable Error

Detected tainted text
}

$configuration->setMiddlewares($value);
break;
}
}

$connection = DriverManager::getConnection(
array_merge($this->getDefaultConnectionParams($type), $additionalConnectionParams),
new Configuration(),
$configuration,
$eventManager
);
return $connection;

Check failure on line 213 in lib/private/DB/ConnectionFactory.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

LessSpecificReturnStatement

lib/private/DB/ConnectionFactory.php:213:10: LessSpecificReturnStatement: The type 'Doctrine\DBAL\Connection' is more general than the declared return type 'OC\DB\Connection' for OC\DB\ConnectionFactory::getConnection (see https://psalm.dev/129)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/private/legacy/OC_App.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ public static function getInstallPath() {
*
* @param string $appId
* @param bool $ignoreCache ignore cache and rebuild it
* @return false|string
* @return false|array
*/
public static function findAppInDirectories(string $appId, bool $ignoreCache = false) {
$sanitizedAppId = self::cleanAppId($appId);
Expand Down
Loading