Completed
Push — master ( 599977...a7d112 )
by Thomas
10:10
created

ConnectionFactory::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 6
rs 9.4285
1
<?php
2
/**
3
 * @author Andreas Fischer <[email protected]>
4
 * @author Jörn Friedrich Dreyer <[email protected]>
5
 * @author Morris Jobke <[email protected]>
6
 * @author Robin Appelman <[email protected]>
7
 * @author Thomas Müller <[email protected]>
8
 *
9
 * @copyright Copyright (c) 2016, ownCloud GmbH.
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OC\DB;
27
use Doctrine\Common\EventManager;
28
use Doctrine\DBAL\Configuration;
29
use Doctrine\DBAL\DriverManager;
30
use Doctrine\DBAL\Event\Listeners\OracleSessionInit;
31
use Doctrine\DBAL\Event\Listeners\SQLSessionInit;
32
use OC\SystemConfig;
33
34
/**
35
* Takes care of creating and configuring Doctrine connections.
36
*/
37
class ConnectionFactory {
38
	/**
39
	* @var array
40
	*
41
	* Array mapping DBMS type to default connection parameters passed to
42
	* \Doctrine\DBAL\DriverManager::getConnection().
43
	*/
44
	protected $defaultConnectionParams = [
45
		'mysql' => [
46
			'adapter' => '\OC\DB\AdapterMySQL',
47
			'charset' => 'UTF8',
48
			'driver' => 'pdo_mysql',
49
			'wrapperClass' => 'OC\DB\Connection',
50
		],
51
		'oci' => [
52
			'adapter' => '\OC\DB\AdapterOCI8',
53
			'charset' => 'AL32UTF8',
54
			'driver' => 'oci8',
55
			'wrapperClass' => 'OC\DB\OracleConnection',
56
		],
57
		'pgsql' => [
58
			'adapter' => '\OC\DB\AdapterPgSql',
59
			'driver' => 'pdo_pgsql',
60
			'wrapperClass' => 'OC\DB\Connection',
61
		],
62
		'sqlite3' => [
63
			'adapter' => '\OC\DB\AdapterSqlite',
64
			'driver' => 'pdo_sqlite',
65
			'wrapperClass' => 'OC\DB\Connection',
66
		],
67
	];
68
	/** @var SystemConfig */
69
	private $config;
70
71
	/**
72
	 * ConnectionFactory constructor.
73
	 *
74
	 * @param SystemConfig $systemConfig
75
	 */
76
	public function __construct(SystemConfig $systemConfig) {
77
		$this->config = $systemConfig;
78
		if($this->config->getValue('mysql.utf8mb4', false)) {
79
			$this->defaultConnectionParams['mysql']['charset'] = 'utf8mb4';
80
		}
81
	}
82
83
	/**
84
	* @brief Get default connection parameters for a given DBMS.
85
	* @param string $type DBMS type
86
	* @throws \InvalidArgumentException If $type is invalid
87
	* @return array Default connection parameters.
88
	*/
89
	public function getDefaultConnectionParams($type) {
90
		$normalizedType = $this->normalizeType($type);
91
		if (!isset($this->defaultConnectionParams[$normalizedType])) {
92
			throw new \InvalidArgumentException("Unsupported type: $type");
93
		}
94
		$result = $this->defaultConnectionParams[$normalizedType];
95
		// \PDO::MYSQL_ATTR_FOUND_ROWS may not be defined, e.g. when the MySQL
96
		// driver is missing. In this case, we won't be able to connect anyway.
97
		if ($normalizedType === 'mysql' && defined('\PDO::MYSQL_ATTR_FOUND_ROWS')) {
98
			$result['driverOptions'] = [
99
				\PDO::MYSQL_ATTR_FOUND_ROWS => true,
100
			];
101
		}
102
103
		return $result;
104
	}
105
106
	/**
107
	* @brief Get default connection parameters for a given DBMS.
108
	* @param string $type DBMS type
109
	* @param array $additionalConnectionParams Additional connection parameters
110
	* @return \OC\DB\Connection
111
	*/
112
	public function getConnection($type, $additionalConnectionParams) {
113
		$normalizedType = $this->normalizeType($type);
114
		$eventManager = new EventManager();
115
		switch ($normalizedType) {
116
			case 'mysql':
117
				$eventManager->addEventSubscriber(
118
					new SQLSessionInit("SET SESSION AUTOCOMMIT=1"));
119
				break;
120
			case 'oci':
121
				$eventManager->addEventSubscriber(new OracleSessionInit);
122
				// the driverOptions are unused in dbal and need to be mapped to the parameters
123
				if (isset($additionalConnectionParams['driverOptions'])) {
124
					$additionalConnectionParams = array_merge($additionalConnectionParams, $additionalConnectionParams['driverOptions']);
125
				}
126
				break;
127
			case 'sqlite3':
128
				$journalMode = $additionalConnectionParams['sqlite.journal_mode'];
129
				$additionalConnectionParams['platform'] = new OCSqlitePlatform();
130
				$eventManager->addEventSubscriber(new SQLiteSessionInit(true, $journalMode));
131
				break;
132
		}
133
		/** @var Connection $connection */
134
		$connection = DriverManager::getConnection(
135
			array_merge($this->getDefaultConnectionParams($type), $additionalConnectionParams),
136
			new Configuration(),
137
			$eventManager
138
		);
139
		return $connection;
140
	}
141
142
	/**
143
	* @brief Normalize DBMS type
144
	* @param string $type DBMS type
145
	* @return string Normalized DBMS type
146
	*/
147
	public function normalizeType($type) {
148
		return $type === 'sqlite' ? 'sqlite3' : $type;
149
	}
150
151
	/**
152
	 * Checks whether the specified DBMS type is valid.
153
	 *
154
	 * @param string $type
155
	 * @return bool
156
	 */
157
	public function isValidType($type) {
158
		$normalizedType = $this->normalizeType($type);
159
		return isset($this->defaultConnectionParams[$normalizedType]);
160
	}
161
162
	/**
163
	 * Create the connection parameters for the config
164
	 *
165
	 * @return array
166
	 */
167
	public function createConnectionParams() {
168
		$type = $this->config->getValue('dbtype', 'sqlite');
169
170
		$connectionParams = [
171
			'user' => $this->config->getValue('dbuser', ''),
172
			'password' => $this->config->getValue('dbpassword', ''),
173
		];
174
		$name = $this->config->getValue('dbname', 'owncloud');
175
176
		if ($this->normalizeType($type) === 'sqlite3') {
177
			$dataDir = $this->config->getValue("datadirectory", \OC::$SERVERROOT . '/data');
178
			$connectionParams['path'] = $dataDir . '/' . $name . '.db';
179
		} else {
180
			$host = $this->config->getValue('dbhost', '');
181
			if (strpos($host, ':')) {
182
				// Host variable may carry a port or socket.
183
				list($host, $portOrSocket) = explode(':', $host, 2);
184
				if (ctype_digit($portOrSocket)) {
185
					$connectionParams['port'] = $portOrSocket;
186
				} else {
187
					$connectionParams['unix_socket'] = $portOrSocket;
188
				}
189
			}
190
			$connectionParams['host'] = $host;
191
			$connectionParams['dbname'] = $name;
192
		}
193
194
		$connectionParams['tablePrefix'] = $this->config->getValue('dbtableprefix', 'oc_');
195
		$connectionParams['sqlite.journal_mode'] = $this->config->getValue('sqlite.journal_mode', 'WAL');
196
197
		//additional driver options, eg. for mysql ssl
198
		$driverOptions = $this->config->getValue('dbdriveroptions', null);
199
		if ($driverOptions) {
200
			$connectionParams['driverOptions'] = $driverOptions;
201
		}
202
203
		// set default table creation options
204
		$connectionParams['defaultTableOptions'] = [
205
			'collate' => 'utf8_bin',
206
			'tablePrefix' => $connectionParams['tablePrefix']
207
		];
208
209
		if($this->config->getValue('mysql.utf8mb4', false)) {
210
			$connectionParams['defaultTableOptions'] = [
211
				'collate' => 'utf8mb4_bin',
212
				'charset' => 'utf8mb4',
213
				'row_format' => 'compressed',
214
				'tablePrefix' => $connectionParams['tablePrefix']
215
			];
216
		}
217
218
		return $connectionParams;
219
	}
220
}
221