Completed
Push — master ( 58d53e...73f4ae )
by Lukas
13:40
created

MDB2SchemaReader::loadTable()   D

Complexity

Conditions 10
Paths 9

Size

Total Lines 38
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 28
nc 9
nop 2
dl 0
loc 38
rs 4.8196
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bart Visscher <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Jörn Friedrich Dreyer <[email protected]>
8
 * @author Morris Jobke <[email protected]>
9
 * @author Oliver Gasser <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Robin McCorkell <[email protected]>
12
 * @author Thomas Müller <[email protected]>
13
 * @author Victor Dubiniuk <[email protected]>
14
 * @author Vincent Petry <[email protected]>
15
 *
16
 * @license AGPL-3.0
17
 *
18
 * This code is free software: you can redistribute it and/or modify
19
 * it under the terms of the GNU Affero General Public License, version 3,
20
 * as published by the Free Software Foundation.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public License, version 3,
28
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
29
 *
30
 */
31
32
namespace OC\DB;
33
34
use Doctrine\DBAL\Platforms\AbstractPlatform;
35
use Doctrine\DBAL\Schema\SchemaConfig;
36
use Doctrine\DBAL\Platforms\MySqlPlatform;
37
use OCP\IConfig;
38
39
class MDB2SchemaReader {
40
	/**
41
	 * @var string $DBNAME
42
	 */
43
	protected $DBNAME;
44
45
	/**
46
	 * @var string $DBTABLEPREFIX
47
	 */
48
	protected $DBTABLEPREFIX;
49
50
	/**
51
	 * @var \Doctrine\DBAL\Platforms\AbstractPlatform $platform
52
	 */
53
	protected $platform;
54
55
	/** @var \Doctrine\DBAL\Schema\SchemaConfig $schemaConfig */
56
	protected $schemaConfig;
57
58
	/** @var IConfig */
59
	protected $config;
60
61
	/**
62
	 * @param \OCP\IConfig $config
63
	 * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
64
	 */
65
	public function __construct(IConfig $config, AbstractPlatform $platform) {
66
		$this->platform = $platform;
67
		$this->config = $config;
68
		$this->DBNAME = $config->getSystemValue('dbname', 'owncloud');
69
		$this->DBTABLEPREFIX = $config->getSystemValue('dbtableprefix', 'oc_');
70
71
		// Oracle does not support longer index names then 30 characters.
72
		// We use this limit for all DBs to make sure it does not cause a
73
		// problem.
74
		$this->schemaConfig = new SchemaConfig();
75
		$this->schemaConfig->setMaxIdentifierLength(30);
76
	}
77
78
	/**
79
	 * @param string $file
80
	 * @return \Doctrine\DBAL\Schema\Schema
81
	 * @throws \DomainException
82
	 */
83
	public function loadSchemaFromFile($file) {
84
		$schema = new \Doctrine\DBAL\Schema\Schema();
85
		$loadEntities = libxml_disable_entity_loader(false);
86
		$xml = simplexml_load_file($file);
87
		libxml_disable_entity_loader($loadEntities);
88
		foreach ($xml->children() as $child) {
89
			/**
90
			 * @var \SimpleXMLElement $child
91
			 */
92
			switch ($child->getName()) {
93
				case 'name':
94
				case 'create':
95
				case 'overwrite':
96
				case 'charset':
97
					break;
98
				case 'table':
99
					$this->loadTable($schema, $child);
100
					break;
101
				default:
102
					throw new \DomainException('Unknown element: ' . $child->getName());
103
104
			}
105
		}
106
		return $schema;
107
	}
108
109
	/**
110
	 * @param \Doctrine\DBAL\Schema\Schema $schema
111
	 * @param \SimpleXMLElement $xml
112
	 * @throws \DomainException
113
	 */
114
	private function loadTable($schema, $xml) {
115
		$table = null;
116
		foreach ($xml->children() as $child) {
117
			/**
118
			 * @var \SimpleXMLElement $child
119
			 */
120
			switch ($child->getName()) {
121
				case 'name':
122
					$name = (string)$child;
123
					$name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name);
124
					$name = $this->platform->quoteIdentifier($name);
125
					$table = $schema->createTable($name);
126
					$table->setSchemaConfig($this->schemaConfig);
127
128
					if($this->platform instanceof MySqlPlatform && $this->config->getSystemValue('mysql.utf8mb4', false)) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\Platforms\MySqlPlatform does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
129
						$table->addOption('charset', 'utf8mb4');
130
						$table->addOption('collate', 'utf8mb4_bin');
131
						$table->addOption('row_format', 'compressed');
132
					} else {
133
						$table->addOption('collate', 'utf8_bin');
134
					}
135
					break;
136
				case 'create':
137
				case 'overwrite':
138
				case 'charset':
139
					break;
140
				case 'declaration':
141
					if (is_null($table)) {
142
						throw new \DomainException('Table declaration before table name');
143
					}
144
					$this->loadDeclaration($table, $child);
145
					break;
146
				default:
147
					throw new \DomainException('Unknown element: ' . $child->getName());
148
149
			}
150
		}
151
	}
152
153
	/**
154
	 * @param \Doctrine\DBAL\Schema\Table $table
155
	 * @param \SimpleXMLElement $xml
156
	 * @throws \DomainException
157
	 */
158
	private function loadDeclaration($table, $xml) {
159
		foreach ($xml->children() as $child) {
160
			/**
161
			 * @var \SimpleXMLElement $child
162
			 */
163
			switch ($child->getName()) {
164
				case 'field':
165
					$this->loadField($table, $child);
166
					break;
167
				case 'index':
168
					$this->loadIndex($table, $child);
169
					break;
170
				default:
171
					throw new \DomainException('Unknown element: ' . $child->getName());
172
173
			}
174
		}
175
	}
176
177
	/**
178
	 * @param \Doctrine\DBAL\Schema\Table $table
179
	 * @param \SimpleXMLElement $xml
180
	 * @throws \DomainException
181
	 */
182
	private function loadField($table, $xml) {
183
		$options = array( 'notnull' => false );
184
		foreach ($xml->children() as $child) {
185
			/**
186
			 * @var \SimpleXMLElement $child
187
			 */
188
			switch ($child->getName()) {
189
				case 'name':
190
					$name = (string)$child;
191
					$name = $this->platform->quoteIdentifier($name);
192
					break;
193
				case 'type':
194
					$type = (string)$child;
195
					switch ($type) {
196
						case 'text':
197
							$type = 'string';
198
							break;
199
						case 'clob':
200
							$type = 'text';
201
							break;
202
						case 'timestamp':
203
							$type = 'datetime';
204
							break;
205
						case 'numeric':
206
							$type = 'decimal';
207
							break;
208
					}
209
					break;
210
				case 'length':
211
					$length = (string)$child;
212
					$options['length'] = $length;
213
					break;
214
				case 'unsigned':
215
					$unsigned = $this->asBool($child);
216
					$options['unsigned'] = $unsigned;
217
					break;
218
				case 'notnull':
219
					$notnull = $this->asBool($child);
220
					$options['notnull'] = $notnull;
221
					break;
222
				case 'autoincrement':
223
					$autoincrement = $this->asBool($child);
224
					$options['autoincrement'] = $autoincrement;
225
					break;
226
				case 'default':
227
					$default = (string)$child;
228
					$options['default'] = $default;
229
					break;
230
				case 'comments':
231
					$comment = (string)$child;
232
					$options['comment'] = $comment;
233
					break;
234
				case 'primary':
235
					$primary = $this->asBool($child);
236
					$options['primary'] = $primary;
237
					break;
238
				case 'precision':
239
					$precision = (string)$child;
240
					$options['precision'] = $precision;
241
					break;
242
				case 'scale':
243
					$scale = (string)$child;
244
					$options['scale'] = $scale;
245
					break;
246
				default:
247
					throw new \DomainException('Unknown element: ' . $child->getName());
248
249
			}
250
		}
251
		if (isset($name) && isset($type)) {
252
			if (isset($options['default']) && empty($options['default'])) {
253
				if (empty($options['notnull']) || !$options['notnull']) {
254
					unset($options['default']);
255
					$options['notnull'] = false;
256
				} else {
257
					$options['default'] = '';
258
				}
259
				if ($type == 'integer' || $type == 'decimal') {
260
					$options['default'] = 0;
261
				} elseif ($type == 'boolean') {
262
					$options['default'] = false;
263
				}
264
				if (!empty($options['autoincrement']) && $options['autoincrement']) {
265
					unset($options['default']);
266
				}
267
			}
268
			if ($type === 'integer' && isset($options['default'])) {
269
				$options['default'] = (int)$options['default'];
270
			}
271
			if ($type === 'integer' && isset($options['length'])) {
272
				$length = $options['length'];
273
				if ($length < 4) {
274
					$type = 'smallint';
275
				} else if ($length > 4) {
276
					$type = 'bigint';
277
				}
278
			}
279
			if ($type === 'boolean' && isset($options['default'])) {
280
				$options['default'] = $this->asBool($options['default']);
281
			}
282
			if (!empty($options['autoincrement'])
283
				&& !empty($options['notnull'])
284
			) {
285
				$options['primary'] = true;
286
			}
287
			$table->addColumn($name, $type, $options);
288
			if (!empty($options['primary']) && $options['primary']) {
289
				$table->setPrimaryKey(array($name));
290
			}
291
		}
292
	}
293
294
	/**
295
	 * @param \Doctrine\DBAL\Schema\Table $table
296
	 * @param \SimpleXMLElement $xml
297
	 * @throws \DomainException
298
	 */
299
	private function loadIndex($table, $xml) {
300
		$name = null;
301
		$fields = array();
302
		foreach ($xml->children() as $child) {
303
			/**
304
			 * @var \SimpleXMLElement $child
305
			 */
306
			switch ($child->getName()) {
307
				case 'name':
308
					$name = (string)$child;
309
					break;
310
				case 'primary':
311
					$primary = $this->asBool($child);
312
					break;
313
				case 'unique':
314
					$unique = $this->asBool($child);
315
					break;
316
				case 'field':
317
					foreach ($child->children() as $field) {
318
						/**
319
						 * @var \SimpleXMLElement $field
320
						 */
321
						switch ($field->getName()) {
322
							case 'name':
323
								$field_name = (string)$field;
324
								$field_name = $this->platform->quoteIdentifier($field_name);
325
								$fields[] = $field_name;
326
								break;
327
							case 'sorting':
328
								break;
329
							default:
330
								throw new \DomainException('Unknown element: ' . $field->getName());
331
332
						}
333
					}
334
					break;
335
				default:
336
					throw new \DomainException('Unknown element: ' . $child->getName());
337
338
			}
339
		}
340
		if (!empty($fields)) {
341
			if (isset($primary) && $primary) {
342
				if ($table->hasPrimaryKey()) {
343
					return;
344
				}
345
				$table->setPrimaryKey($fields, $name);
346
			} else {
347
				if (isset($unique) && $unique) {
348
					$table->addUniqueIndex($fields, $name);
349
				} else {
350
					$table->addIndex($fields, $name);
351
				}
352
			}
353
		} else {
354
			throw new \DomainException('Empty index definition: ' . $name . ' options:' . print_r($fields, true));
355
		}
356
	}
357
358
	/**
359
	 * @param \SimpleXMLElement|string $xml
360
	 * @return bool
361
	 */
362
	private function asBool($xml) {
363
		$result = (string)$xml;
364
		if ($result == 'true') {
365
			$result = true;
366
		} elseif ($result == 'false') {
367
			$result = false;
368
		}
369
		return (bool)$result;
370
	}
371
372
}
373