Passed
Push — master ( b77a28...c613c8 )
by Christoph
30:00 queued 14:13
created
core/Command/Group/ListCommand.php 1 patch
Indentation   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -32,74 +32,74 @@
 block discarded – undo
32 32
 use Symfony\Component\Console\Output\OutputInterface;
33 33
 
34 34
 class ListCommand extends Base {
35
-	/** @var IGroupManager */
36
-	protected $groupManager;
35
+    /** @var IGroupManager */
36
+    protected $groupManager;
37 37
 
38
-	/**
39
-	 * @param IGroupManager $groupManager
40
-	 */
41
-	public function __construct(IGroupManager $groupManager) {
42
-		$this->groupManager = $groupManager;
43
-		parent::__construct();
44
-	}
38
+    /**
39
+     * @param IGroupManager $groupManager
40
+     */
41
+    public function __construct(IGroupManager $groupManager) {
42
+        $this->groupManager = $groupManager;
43
+        parent::__construct();
44
+    }
45 45
 
46
-	protected function configure() {
47
-		$this
48
-			->setName('group:list')
49
-			->setDescription('list configured groups')
50
-			->addOption(
51
-				'limit',
52
-				'l',
53
-				InputOption::VALUE_OPTIONAL,
54
-				'Number of groups to retrieve',
55
-				'500'
56
-			)->addOption(
57
-				'offset',
58
-				'o',
59
-				InputOption::VALUE_OPTIONAL,
60
-				'Offset for retrieving groups',
61
-				'0'
62
-			)->addOption(
63
-				'info',
64
-				'i',
65
-				InputOption::VALUE_NONE,
66
-				'Show additional info (backend)'
67
-			)->addOption(
68
-				'output',
69
-				null,
70
-				InputOption::VALUE_OPTIONAL,
71
-				'Output format (plain, json or json_pretty, default is plain)',
72
-				$this->defaultOutputFormat
73
-			);
74
-	}
46
+    protected function configure() {
47
+        $this
48
+            ->setName('group:list')
49
+            ->setDescription('list configured groups')
50
+            ->addOption(
51
+                'limit',
52
+                'l',
53
+                InputOption::VALUE_OPTIONAL,
54
+                'Number of groups to retrieve',
55
+                '500'
56
+            )->addOption(
57
+                'offset',
58
+                'o',
59
+                InputOption::VALUE_OPTIONAL,
60
+                'Offset for retrieving groups',
61
+                '0'
62
+            )->addOption(
63
+                'info',
64
+                'i',
65
+                InputOption::VALUE_NONE,
66
+                'Show additional info (backend)'
67
+            )->addOption(
68
+                'output',
69
+                null,
70
+                InputOption::VALUE_OPTIONAL,
71
+                'Output format (plain, json or json_pretty, default is plain)',
72
+                $this->defaultOutputFormat
73
+            );
74
+    }
75 75
 
76
-	protected function execute(InputInterface $input, OutputInterface $output): int {
77
-		$groups = $this->groupManager->search('', (int)$input->getOption('limit'), (int)$input->getOption('offset'));
78
-		$this->writeArrayInOutputFormat($input, $output, $this->formatGroups($groups, (bool)$input->getOption('info')));
79
-		return 0;
80
-	}
76
+    protected function execute(InputInterface $input, OutputInterface $output): int {
77
+        $groups = $this->groupManager->search('', (int)$input->getOption('limit'), (int)$input->getOption('offset'));
78
+        $this->writeArrayInOutputFormat($input, $output, $this->formatGroups($groups, (bool)$input->getOption('info')));
79
+        return 0;
80
+    }
81 81
 
82
-	/**
83
-	 * @param IGroup[] $groups
84
-	 * @return array
85
-	 */
86
-	private function formatGroups(array $groups, bool $addInfo = false) {
87
-		$keys = array_map(function (IGroup $group) {
88
-			return $group->getGID();
89
-		}, $groups);
82
+    /**
83
+     * @param IGroup[] $groups
84
+     * @return array
85
+     */
86
+    private function formatGroups(array $groups, bool $addInfo = false) {
87
+        $keys = array_map(function (IGroup $group) {
88
+            return $group->getGID();
89
+        }, $groups);
90 90
 
91
-		if ($addInfo) {
92
-			$values = array_map(function (IGroup $group) {
93
-				return [
94
-					'backends' => $group->getBackendNames(),
95
-					'users' => array_keys($group->getUsers()),
96
-				];
97
-			}, $groups);
98
-		} else {
99
-			$values = array_map(function (IGroup $group) {
100
-				return array_keys($group->getUsers());
101
-			}, $groups);
102
-		}
103
-		return array_combine($keys, $values);
104
-	}
91
+        if ($addInfo) {
92
+            $values = array_map(function (IGroup $group) {
93
+                return [
94
+                    'backends' => $group->getBackendNames(),
95
+                    'users' => array_keys($group->getUsers()),
96
+                ];
97
+            }, $groups);
98
+        } else {
99
+            $values = array_map(function (IGroup $group) {
100
+                return array_keys($group->getUsers());
101
+            }, $groups);
102
+        }
103
+        return array_combine($keys, $values);
104
+    }
105 105
 }
Please login to merge, or discard this patch.
core/Command/Db/ConvertType.php 2 patches
Indentation   +411 added lines, -411 removed lines patch added patch discarded remove patch
@@ -56,415 +56,415 @@
 block discarded – undo
56 56
 use function preg_quote;
57 57
 
58 58
 class ConvertType extends Command implements CompletionAwareInterface {
59
-	/**
60
-	 * @var \OCP\IConfig
61
-	 */
62
-	protected $config;
63
-
64
-	/**
65
-	 * @var \OC\DB\ConnectionFactory
66
-	 */
67
-	protected $connectionFactory;
68
-
69
-	/** @var array */
70
-	protected $columnTypes;
71
-
72
-	/**
73
-	 * @param \OCP\IConfig $config
74
-	 * @param \OC\DB\ConnectionFactory $connectionFactory
75
-	 */
76
-	public function __construct(IConfig $config, ConnectionFactory $connectionFactory) {
77
-		$this->config = $config;
78
-		$this->connectionFactory = $connectionFactory;
79
-		parent::__construct();
80
-	}
81
-
82
-	protected function configure() {
83
-		$this
84
-			->setName('db:convert-type')
85
-			->setDescription('Convert the Nextcloud database to the newly configured one')
86
-			->addArgument(
87
-				'type',
88
-				InputArgument::REQUIRED,
89
-				'the type of the database to convert to'
90
-			)
91
-			->addArgument(
92
-				'username',
93
-				InputArgument::REQUIRED,
94
-				'the username of the database to convert to'
95
-			)
96
-			->addArgument(
97
-				'hostname',
98
-				InputArgument::REQUIRED,
99
-				'the hostname of the database to convert to'
100
-			)
101
-			->addArgument(
102
-				'database',
103
-				InputArgument::REQUIRED,
104
-				'the name of the database to convert to'
105
-			)
106
-			->addOption(
107
-				'port',
108
-				null,
109
-				InputOption::VALUE_REQUIRED,
110
-				'the port of the database to convert to'
111
-			)
112
-			->addOption(
113
-				'password',
114
-				null,
115
-				InputOption::VALUE_REQUIRED,
116
-				'the password of the database to convert to. Will be asked when not specified. Can also be passed via stdin.'
117
-			)
118
-			->addOption(
119
-				'clear-schema',
120
-				null,
121
-				InputOption::VALUE_NONE,
122
-				'remove all tables from the destination database'
123
-			)
124
-			->addOption(
125
-				'all-apps',
126
-				null,
127
-				InputOption::VALUE_NONE,
128
-				'whether to create schema for all apps instead of only installed apps'
129
-			)
130
-			->addOption(
131
-				'chunk-size',
132
-				null,
133
-				InputOption::VALUE_REQUIRED,
134
-				'the maximum number of database rows to handle in a single query, bigger tables will be handled in chunks of this size. Lower this if the process runs out of memory during conversion.',
135
-				'1000'
136
-			)
137
-		;
138
-	}
139
-
140
-	protected function validateInput(InputInterface $input, OutputInterface $output) {
141
-		$type = $this->connectionFactory->normalizeType($input->getArgument('type'));
142
-		if ($type === 'sqlite3') {
143
-			throw new \InvalidArgumentException(
144
-				'Converting to SQLite (sqlite3) is currently not supported.'
145
-			);
146
-		}
147
-		if ($type === $this->config->getSystemValue('dbtype', '')) {
148
-			throw new \InvalidArgumentException(sprintf(
149
-				'Can not convert from %1$s to %1$s.',
150
-				$type
151
-			));
152
-		}
153
-		if ($type === 'oci' && $input->getOption('clear-schema')) {
154
-			// Doctrine unconditionally tries (at least in version 2.3)
155
-			// to drop sequence triggers when dropping a table, even though
156
-			// such triggers may not exist. This results in errors like
157
-			// "ORA-04080: trigger 'OC_STORAGES_AI_PK' does not exist".
158
-			throw new \InvalidArgumentException(
159
-				'The --clear-schema option is not supported when converting to Oracle (oci).'
160
-			);
161
-		}
162
-	}
163
-
164
-	protected function readPassword(InputInterface $input, OutputInterface $output) {
165
-		// Explicitly specified password
166
-		if ($input->getOption('password')) {
167
-			return;
168
-		}
169
-
170
-		// Read from stdin. stream_set_blocking is used to prevent blocking
171
-		// when nothing is passed via stdin.
172
-		stream_set_blocking(STDIN, 0);
173
-		$password = file_get_contents('php://stdin');
174
-		stream_set_blocking(STDIN, 1);
175
-		if (trim($password) !== '') {
176
-			$input->setOption('password', $password);
177
-			return;
178
-		}
179
-
180
-		// Read password by interacting
181
-		if ($input->isInteractive()) {
182
-			/** @var QuestionHelper $helper */
183
-			$helper = $this->getHelper('question');
184
-			$question = new Question('What is the database password?');
185
-			$question->setHidden(true);
186
-			$question->setHiddenFallback(false);
187
-			$password = $helper->ask($input, $output, $question);
188
-			$input->setOption('password', $password);
189
-			return;
190
-		}
191
-	}
192
-
193
-	protected function execute(InputInterface $input, OutputInterface $output): int {
194
-		$this->validateInput($input, $output);
195
-		$this->readPassword($input, $output);
196
-
197
-		/** @var Connection $fromDB */
198
-		$fromDB = \OC::$server->get(Connection::class);
199
-		$toDB = $this->getToDBConnection($input, $output);
200
-
201
-		if ($input->getOption('clear-schema')) {
202
-			$this->clearSchema($toDB, $input, $output);
203
-		}
204
-
205
-		$this->createSchema($fromDB, $toDB, $input, $output);
206
-
207
-		$toTables = $this->getTables($toDB);
208
-		$fromTables = $this->getTables($fromDB);
209
-
210
-		// warn/fail if there are more tables in 'from' database
211
-		$extraFromTables = array_diff($fromTables, $toTables);
212
-		if (!empty($extraFromTables)) {
213
-			$output->writeln('<comment>The following tables will not be converted:</comment>');
214
-			$output->writeln($extraFromTables);
215
-			if (!$input->getOption('all-apps')) {
216
-				$output->writeln('<comment>Please note that tables belonging to available but currently not installed apps</comment>');
217
-				$output->writeln('<comment>can be included by specifying the --all-apps option.</comment>');
218
-			}
219
-
220
-			$continueConversion = !$input->isInteractive(); // assume yes for --no-interaction and no otherwise.
221
-			$question = new ConfirmationQuestion('Continue with the conversion (y/n)? [n] ', $continueConversion);
222
-
223
-			/** @var QuestionHelper $helper */
224
-			$helper = $this->getHelper('question');
225
-
226
-			if (!$helper->ask($input, $output, $question)) {
227
-				return 1;
228
-			}
229
-		}
230
-		$intersectingTables = array_intersect($toTables, $fromTables);
231
-		$this->convertDB($fromDB, $toDB, $intersectingTables, $input, $output);
232
-		return 0;
233
-	}
234
-
235
-	protected function createSchema(Connection $fromDB, Connection $toDB, InputInterface $input, OutputInterface $output) {
236
-		$output->writeln('<info>Creating schema in new database</info>');
237
-
238
-		$fromMS = new MigrationService('core', $fromDB);
239
-		$currentMigration = $fromMS->getMigration('current');
240
-		if ($currentMigration !== '0') {
241
-			$toMS = new MigrationService('core', $toDB);
242
-			$toMS->migrate($currentMigration);
243
-		}
244
-
245
-		$apps = $input->getOption('all-apps') ? \OC_App::getAllApps() : \OC_App::getEnabledApps();
246
-		foreach ($apps as $app) {
247
-			$output->writeln('<info> - '.$app.'</info>');
248
-			// Make sure autoloading works...
249
-			\OC_App::loadApp($app);
250
-			$fromMS = new MigrationService($app, $fromDB);
251
-			$currentMigration = $fromMS->getMigration('current');
252
-			if ($currentMigration !== '0') {
253
-				$toMS = new MigrationService($app, $toDB);
254
-				$toMS->migrate($currentMigration, true);
255
-			}
256
-		}
257
-	}
258
-
259
-	protected function getToDBConnection(InputInterface $input, OutputInterface $output) {
260
-		$type = $input->getArgument('type');
261
-		$connectionParams = $this->connectionFactory->createConnectionParams();
262
-		$connectionParams = array_merge($connectionParams, [
263
-			'host' => $input->getArgument('hostname'),
264
-			'user' => $input->getArgument('username'),
265
-			'password' => $input->getOption('password'),
266
-			'dbname' => $input->getArgument('database'),
267
-		]);
268
-		if ($input->getOption('port')) {
269
-			$connectionParams['port'] = $input->getOption('port');
270
-		}
271
-		return $this->connectionFactory->getConnection($type, $connectionParams);
272
-	}
273
-
274
-	protected function clearSchema(Connection $db, InputInterface $input, OutputInterface $output) {
275
-		$toTables = $this->getTables($db);
276
-		if (!empty($toTables)) {
277
-			$output->writeln('<info>Clearing schema in new database</info>');
278
-		}
279
-		foreach ($toTables as $table) {
280
-			$db->getSchemaManager()->dropTable($table);
281
-		}
282
-	}
283
-
284
-	protected function getTables(Connection $db) {
285
-		$db->getConfiguration()->setSchemaAssetsFilter(function ($asset) {
286
-			/** @var string|AbstractAsset $asset */
287
-			$filterExpression = '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
288
-			if ($asset instanceof AbstractAsset) {
289
-				return preg_match($filterExpression, $asset->getName()) !== false;
290
-			}
291
-			return preg_match($filterExpression, $asset) !== false;
292
-		});
293
-		return $db->getSchemaManager()->listTableNames();
294
-	}
295
-
296
-	/**
297
-	 * @param Connection $fromDB
298
-	 * @param Connection $toDB
299
-	 * @param Table $table
300
-	 * @param InputInterface $input
301
-	 * @param OutputInterface $output
302
-	 */
303
-	protected function copyTable(Connection $fromDB, Connection $toDB, Table $table, InputInterface $input, OutputInterface $output) {
304
-		if ($table->getName() === $toDB->getPrefix() . 'migrations') {
305
-			$output->writeln('<comment>Skipping migrations table because it was already filled by running the migrations</comment>');
306
-			return;
307
-		}
308
-
309
-		$chunkSize = (int)$input->getOption('chunk-size');
310
-
311
-		$query = $fromDB->getQueryBuilder();
312
-		$query->automaticTablePrefix(false);
313
-		$query->select($query->func()->count('*', 'num_entries'))
314
-			->from($table->getName());
315
-		$result = $query->execute();
316
-		$count = $result->fetchOne();
317
-		$result->closeCursor();
318
-
319
-		$numChunks = ceil($count / $chunkSize);
320
-		if ($numChunks > 1) {
321
-			$output->writeln('chunked query, ' . $numChunks . ' chunks');
322
-		}
323
-
324
-		$progress = new ProgressBar($output, $count);
325
-		$progress->setFormat('very_verbose');
326
-		$progress->start();
327
-		$redraw = $count > $chunkSize ? 100 : ($count > 100 ? 5 : 1);
328
-		$progress->setRedrawFrequency($redraw);
329
-
330
-		$query = $fromDB->getQueryBuilder();
331
-		$query->automaticTablePrefix(false);
332
-		$query->select('*')
333
-			->from($table->getName())
334
-			->setMaxResults($chunkSize);
335
-
336
-		try {
337
-			$orderColumns = $table->getPrimaryKeyColumns();
338
-		} catch (Exception $e) {
339
-			$orderColumns = $table->getColumns();
340
-		}
341
-
342
-		foreach ($orderColumns as $column) {
343
-			$query->addOrderBy($column->getName());
344
-		}
345
-
346
-		$insertQuery = $toDB->getQueryBuilder();
347
-		$insertQuery->automaticTablePrefix(false);
348
-		$insertQuery->insert($table->getName());
349
-		$parametersCreated = false;
350
-
351
-		for ($chunk = 0; $chunk < $numChunks; $chunk++) {
352
-			$query->setFirstResult($chunk * $chunkSize);
353
-
354
-			$result = $query->execute();
355
-
356
-			while ($row = $result->fetch()) {
357
-				$progress->advance();
358
-				if (!$parametersCreated) {
359
-					foreach ($row as $key => $value) {
360
-						$insertQuery->setValue($key, $insertQuery->createParameter($key));
361
-					}
362
-					$parametersCreated = true;
363
-				}
364
-
365
-				foreach ($row as $key => $value) {
366
-					$type = $this->getColumnType($table, $key);
367
-					if ($type !== false) {
368
-						$insertQuery->setParameter($key, $value, $type);
369
-					} else {
370
-						$insertQuery->setParameter($key, $value);
371
-					}
372
-				}
373
-				$insertQuery->execute();
374
-			}
375
-			$result->closeCursor();
376
-		}
377
-		$progress->finish();
378
-		$output->writeln('');
379
-	}
380
-
381
-	protected function getColumnType(Table $table, $columnName) {
382
-		$tableName = $table->getName();
383
-		if (isset($this->columnTypes[$tableName][$columnName])) {
384
-			return $this->columnTypes[$tableName][$columnName];
385
-		}
386
-
387
-		$type = $table->getColumn($columnName)->getType()->getName();
388
-
389
-		switch ($type) {
390
-			case Types::BLOB:
391
-			case Types::TEXT:
392
-				$this->columnTypes[$tableName][$columnName] = IQueryBuilder::PARAM_LOB;
393
-				break;
394
-			case Types::BOOLEAN:
395
-				$this->columnTypes[$tableName][$columnName] = IQueryBuilder::PARAM_BOOL;
396
-				break;
397
-			default:
398
-				$this->columnTypes[$tableName][$columnName] = false;
399
-		}
400
-
401
-		return $this->columnTypes[$tableName][$columnName];
402
-	}
403
-
404
-	protected function convertDB(Connection $fromDB, Connection $toDB, array $tables, InputInterface $input, OutputInterface $output) {
405
-		$this->config->setSystemValue('maintenance', true);
406
-		$schema = $fromDB->createSchema();
407
-
408
-		try {
409
-			// copy table rows
410
-			foreach ($tables as $table) {
411
-				$output->writeln('<info> - '.$table.'</info>');
412
-				$this->copyTable($fromDB, $toDB, $schema->getTable($table), $input, $output);
413
-			}
414
-			if ($input->getArgument('type') === 'pgsql') {
415
-				$tools = new \OC\DB\PgSqlTools($this->config);
416
-				$tools->resynchronizeDatabaseSequences($toDB);
417
-			}
418
-			// save new database config
419
-			$this->saveDBInfo($input);
420
-		} catch (\Exception $e) {
421
-			$this->config->setSystemValue('maintenance', false);
422
-			throw $e;
423
-		}
424
-		$this->config->setSystemValue('maintenance', false);
425
-	}
426
-
427
-	protected function saveDBInfo(InputInterface $input) {
428
-		$type = $input->getArgument('type');
429
-		$username = $input->getArgument('username');
430
-		$dbHost = $input->getArgument('hostname');
431
-		$dbName = $input->getArgument('database');
432
-		$password = $input->getOption('password');
433
-		if ($input->getOption('port')) {
434
-			$dbHost .= ':'.$input->getOption('port');
435
-		}
436
-
437
-		$this->config->setSystemValues([
438
-			'dbtype' => $type,
439
-			'dbname' => $dbName,
440
-			'dbhost' => $dbHost,
441
-			'dbuser' => $username,
442
-			'dbpassword' => $password,
443
-		]);
444
-	}
445
-
446
-	/**
447
-	 * Return possible values for the named option
448
-	 *
449
-	 * @param string $optionName
450
-	 * @param CompletionContext $context
451
-	 * @return string[]
452
-	 */
453
-	public function completeOptionValues($optionName, CompletionContext $context) {
454
-		return [];
455
-	}
456
-
457
-	/**
458
-	 * Return possible values for the named argument
459
-	 *
460
-	 * @param string $argumentName
461
-	 * @param CompletionContext $context
462
-	 * @return string[]
463
-	 */
464
-	public function completeArgumentValues($argumentName, CompletionContext $context) {
465
-		if ($argumentName === 'type') {
466
-			return ['mysql', 'oci', 'pgsql'];
467
-		}
468
-		return [];
469
-	}
59
+    /**
60
+     * @var \OCP\IConfig
61
+     */
62
+    protected $config;
63
+
64
+    /**
65
+     * @var \OC\DB\ConnectionFactory
66
+     */
67
+    protected $connectionFactory;
68
+
69
+    /** @var array */
70
+    protected $columnTypes;
71
+
72
+    /**
73
+     * @param \OCP\IConfig $config
74
+     * @param \OC\DB\ConnectionFactory $connectionFactory
75
+     */
76
+    public function __construct(IConfig $config, ConnectionFactory $connectionFactory) {
77
+        $this->config = $config;
78
+        $this->connectionFactory = $connectionFactory;
79
+        parent::__construct();
80
+    }
81
+
82
+    protected function configure() {
83
+        $this
84
+            ->setName('db:convert-type')
85
+            ->setDescription('Convert the Nextcloud database to the newly configured one')
86
+            ->addArgument(
87
+                'type',
88
+                InputArgument::REQUIRED,
89
+                'the type of the database to convert to'
90
+            )
91
+            ->addArgument(
92
+                'username',
93
+                InputArgument::REQUIRED,
94
+                'the username of the database to convert to'
95
+            )
96
+            ->addArgument(
97
+                'hostname',
98
+                InputArgument::REQUIRED,
99
+                'the hostname of the database to convert to'
100
+            )
101
+            ->addArgument(
102
+                'database',
103
+                InputArgument::REQUIRED,
104
+                'the name of the database to convert to'
105
+            )
106
+            ->addOption(
107
+                'port',
108
+                null,
109
+                InputOption::VALUE_REQUIRED,
110
+                'the port of the database to convert to'
111
+            )
112
+            ->addOption(
113
+                'password',
114
+                null,
115
+                InputOption::VALUE_REQUIRED,
116
+                'the password of the database to convert to. Will be asked when not specified. Can also be passed via stdin.'
117
+            )
118
+            ->addOption(
119
+                'clear-schema',
120
+                null,
121
+                InputOption::VALUE_NONE,
122
+                'remove all tables from the destination database'
123
+            )
124
+            ->addOption(
125
+                'all-apps',
126
+                null,
127
+                InputOption::VALUE_NONE,
128
+                'whether to create schema for all apps instead of only installed apps'
129
+            )
130
+            ->addOption(
131
+                'chunk-size',
132
+                null,
133
+                InputOption::VALUE_REQUIRED,
134
+                'the maximum number of database rows to handle in a single query, bigger tables will be handled in chunks of this size. Lower this if the process runs out of memory during conversion.',
135
+                '1000'
136
+            )
137
+        ;
138
+    }
139
+
140
+    protected function validateInput(InputInterface $input, OutputInterface $output) {
141
+        $type = $this->connectionFactory->normalizeType($input->getArgument('type'));
142
+        if ($type === 'sqlite3') {
143
+            throw new \InvalidArgumentException(
144
+                'Converting to SQLite (sqlite3) is currently not supported.'
145
+            );
146
+        }
147
+        if ($type === $this->config->getSystemValue('dbtype', '')) {
148
+            throw new \InvalidArgumentException(sprintf(
149
+                'Can not convert from %1$s to %1$s.',
150
+                $type
151
+            ));
152
+        }
153
+        if ($type === 'oci' && $input->getOption('clear-schema')) {
154
+            // Doctrine unconditionally tries (at least in version 2.3)
155
+            // to drop sequence triggers when dropping a table, even though
156
+            // such triggers may not exist. This results in errors like
157
+            // "ORA-04080: trigger 'OC_STORAGES_AI_PK' does not exist".
158
+            throw new \InvalidArgumentException(
159
+                'The --clear-schema option is not supported when converting to Oracle (oci).'
160
+            );
161
+        }
162
+    }
163
+
164
+    protected function readPassword(InputInterface $input, OutputInterface $output) {
165
+        // Explicitly specified password
166
+        if ($input->getOption('password')) {
167
+            return;
168
+        }
169
+
170
+        // Read from stdin. stream_set_blocking is used to prevent blocking
171
+        // when nothing is passed via stdin.
172
+        stream_set_blocking(STDIN, 0);
173
+        $password = file_get_contents('php://stdin');
174
+        stream_set_blocking(STDIN, 1);
175
+        if (trim($password) !== '') {
176
+            $input->setOption('password', $password);
177
+            return;
178
+        }
179
+
180
+        // Read password by interacting
181
+        if ($input->isInteractive()) {
182
+            /** @var QuestionHelper $helper */
183
+            $helper = $this->getHelper('question');
184
+            $question = new Question('What is the database password?');
185
+            $question->setHidden(true);
186
+            $question->setHiddenFallback(false);
187
+            $password = $helper->ask($input, $output, $question);
188
+            $input->setOption('password', $password);
189
+            return;
190
+        }
191
+    }
192
+
193
+    protected function execute(InputInterface $input, OutputInterface $output): int {
194
+        $this->validateInput($input, $output);
195
+        $this->readPassword($input, $output);
196
+
197
+        /** @var Connection $fromDB */
198
+        $fromDB = \OC::$server->get(Connection::class);
199
+        $toDB = $this->getToDBConnection($input, $output);
200
+
201
+        if ($input->getOption('clear-schema')) {
202
+            $this->clearSchema($toDB, $input, $output);
203
+        }
204
+
205
+        $this->createSchema($fromDB, $toDB, $input, $output);
206
+
207
+        $toTables = $this->getTables($toDB);
208
+        $fromTables = $this->getTables($fromDB);
209
+
210
+        // warn/fail if there are more tables in 'from' database
211
+        $extraFromTables = array_diff($fromTables, $toTables);
212
+        if (!empty($extraFromTables)) {
213
+            $output->writeln('<comment>The following tables will not be converted:</comment>');
214
+            $output->writeln($extraFromTables);
215
+            if (!$input->getOption('all-apps')) {
216
+                $output->writeln('<comment>Please note that tables belonging to available but currently not installed apps</comment>');
217
+                $output->writeln('<comment>can be included by specifying the --all-apps option.</comment>');
218
+            }
219
+
220
+            $continueConversion = !$input->isInteractive(); // assume yes for --no-interaction and no otherwise.
221
+            $question = new ConfirmationQuestion('Continue with the conversion (y/n)? [n] ', $continueConversion);
222
+
223
+            /** @var QuestionHelper $helper */
224
+            $helper = $this->getHelper('question');
225
+
226
+            if (!$helper->ask($input, $output, $question)) {
227
+                return 1;
228
+            }
229
+        }
230
+        $intersectingTables = array_intersect($toTables, $fromTables);
231
+        $this->convertDB($fromDB, $toDB, $intersectingTables, $input, $output);
232
+        return 0;
233
+    }
234
+
235
+    protected function createSchema(Connection $fromDB, Connection $toDB, InputInterface $input, OutputInterface $output) {
236
+        $output->writeln('<info>Creating schema in new database</info>');
237
+
238
+        $fromMS = new MigrationService('core', $fromDB);
239
+        $currentMigration = $fromMS->getMigration('current');
240
+        if ($currentMigration !== '0') {
241
+            $toMS = new MigrationService('core', $toDB);
242
+            $toMS->migrate($currentMigration);
243
+        }
244
+
245
+        $apps = $input->getOption('all-apps') ? \OC_App::getAllApps() : \OC_App::getEnabledApps();
246
+        foreach ($apps as $app) {
247
+            $output->writeln('<info> - '.$app.'</info>');
248
+            // Make sure autoloading works...
249
+            \OC_App::loadApp($app);
250
+            $fromMS = new MigrationService($app, $fromDB);
251
+            $currentMigration = $fromMS->getMigration('current');
252
+            if ($currentMigration !== '0') {
253
+                $toMS = new MigrationService($app, $toDB);
254
+                $toMS->migrate($currentMigration, true);
255
+            }
256
+        }
257
+    }
258
+
259
+    protected function getToDBConnection(InputInterface $input, OutputInterface $output) {
260
+        $type = $input->getArgument('type');
261
+        $connectionParams = $this->connectionFactory->createConnectionParams();
262
+        $connectionParams = array_merge($connectionParams, [
263
+            'host' => $input->getArgument('hostname'),
264
+            'user' => $input->getArgument('username'),
265
+            'password' => $input->getOption('password'),
266
+            'dbname' => $input->getArgument('database'),
267
+        ]);
268
+        if ($input->getOption('port')) {
269
+            $connectionParams['port'] = $input->getOption('port');
270
+        }
271
+        return $this->connectionFactory->getConnection($type, $connectionParams);
272
+    }
273
+
274
+    protected function clearSchema(Connection $db, InputInterface $input, OutputInterface $output) {
275
+        $toTables = $this->getTables($db);
276
+        if (!empty($toTables)) {
277
+            $output->writeln('<info>Clearing schema in new database</info>');
278
+        }
279
+        foreach ($toTables as $table) {
280
+            $db->getSchemaManager()->dropTable($table);
281
+        }
282
+    }
283
+
284
+    protected function getTables(Connection $db) {
285
+        $db->getConfiguration()->setSchemaAssetsFilter(function ($asset) {
286
+            /** @var string|AbstractAsset $asset */
287
+            $filterExpression = '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
288
+            if ($asset instanceof AbstractAsset) {
289
+                return preg_match($filterExpression, $asset->getName()) !== false;
290
+            }
291
+            return preg_match($filterExpression, $asset) !== false;
292
+        });
293
+        return $db->getSchemaManager()->listTableNames();
294
+    }
295
+
296
+    /**
297
+     * @param Connection $fromDB
298
+     * @param Connection $toDB
299
+     * @param Table $table
300
+     * @param InputInterface $input
301
+     * @param OutputInterface $output
302
+     */
303
+    protected function copyTable(Connection $fromDB, Connection $toDB, Table $table, InputInterface $input, OutputInterface $output) {
304
+        if ($table->getName() === $toDB->getPrefix() . 'migrations') {
305
+            $output->writeln('<comment>Skipping migrations table because it was already filled by running the migrations</comment>');
306
+            return;
307
+        }
308
+
309
+        $chunkSize = (int)$input->getOption('chunk-size');
310
+
311
+        $query = $fromDB->getQueryBuilder();
312
+        $query->automaticTablePrefix(false);
313
+        $query->select($query->func()->count('*', 'num_entries'))
314
+            ->from($table->getName());
315
+        $result = $query->execute();
316
+        $count = $result->fetchOne();
317
+        $result->closeCursor();
318
+
319
+        $numChunks = ceil($count / $chunkSize);
320
+        if ($numChunks > 1) {
321
+            $output->writeln('chunked query, ' . $numChunks . ' chunks');
322
+        }
323
+
324
+        $progress = new ProgressBar($output, $count);
325
+        $progress->setFormat('very_verbose');
326
+        $progress->start();
327
+        $redraw = $count > $chunkSize ? 100 : ($count > 100 ? 5 : 1);
328
+        $progress->setRedrawFrequency($redraw);
329
+
330
+        $query = $fromDB->getQueryBuilder();
331
+        $query->automaticTablePrefix(false);
332
+        $query->select('*')
333
+            ->from($table->getName())
334
+            ->setMaxResults($chunkSize);
335
+
336
+        try {
337
+            $orderColumns = $table->getPrimaryKeyColumns();
338
+        } catch (Exception $e) {
339
+            $orderColumns = $table->getColumns();
340
+        }
341
+
342
+        foreach ($orderColumns as $column) {
343
+            $query->addOrderBy($column->getName());
344
+        }
345
+
346
+        $insertQuery = $toDB->getQueryBuilder();
347
+        $insertQuery->automaticTablePrefix(false);
348
+        $insertQuery->insert($table->getName());
349
+        $parametersCreated = false;
350
+
351
+        for ($chunk = 0; $chunk < $numChunks; $chunk++) {
352
+            $query->setFirstResult($chunk * $chunkSize);
353
+
354
+            $result = $query->execute();
355
+
356
+            while ($row = $result->fetch()) {
357
+                $progress->advance();
358
+                if (!$parametersCreated) {
359
+                    foreach ($row as $key => $value) {
360
+                        $insertQuery->setValue($key, $insertQuery->createParameter($key));
361
+                    }
362
+                    $parametersCreated = true;
363
+                }
364
+
365
+                foreach ($row as $key => $value) {
366
+                    $type = $this->getColumnType($table, $key);
367
+                    if ($type !== false) {
368
+                        $insertQuery->setParameter($key, $value, $type);
369
+                    } else {
370
+                        $insertQuery->setParameter($key, $value);
371
+                    }
372
+                }
373
+                $insertQuery->execute();
374
+            }
375
+            $result->closeCursor();
376
+        }
377
+        $progress->finish();
378
+        $output->writeln('');
379
+    }
380
+
381
+    protected function getColumnType(Table $table, $columnName) {
382
+        $tableName = $table->getName();
383
+        if (isset($this->columnTypes[$tableName][$columnName])) {
384
+            return $this->columnTypes[$tableName][$columnName];
385
+        }
386
+
387
+        $type = $table->getColumn($columnName)->getType()->getName();
388
+
389
+        switch ($type) {
390
+            case Types::BLOB:
391
+            case Types::TEXT:
392
+                $this->columnTypes[$tableName][$columnName] = IQueryBuilder::PARAM_LOB;
393
+                break;
394
+            case Types::BOOLEAN:
395
+                $this->columnTypes[$tableName][$columnName] = IQueryBuilder::PARAM_BOOL;
396
+                break;
397
+            default:
398
+                $this->columnTypes[$tableName][$columnName] = false;
399
+        }
400
+
401
+        return $this->columnTypes[$tableName][$columnName];
402
+    }
403
+
404
+    protected function convertDB(Connection $fromDB, Connection $toDB, array $tables, InputInterface $input, OutputInterface $output) {
405
+        $this->config->setSystemValue('maintenance', true);
406
+        $schema = $fromDB->createSchema();
407
+
408
+        try {
409
+            // copy table rows
410
+            foreach ($tables as $table) {
411
+                $output->writeln('<info> - '.$table.'</info>');
412
+                $this->copyTable($fromDB, $toDB, $schema->getTable($table), $input, $output);
413
+            }
414
+            if ($input->getArgument('type') === 'pgsql') {
415
+                $tools = new \OC\DB\PgSqlTools($this->config);
416
+                $tools->resynchronizeDatabaseSequences($toDB);
417
+            }
418
+            // save new database config
419
+            $this->saveDBInfo($input);
420
+        } catch (\Exception $e) {
421
+            $this->config->setSystemValue('maintenance', false);
422
+            throw $e;
423
+        }
424
+        $this->config->setSystemValue('maintenance', false);
425
+    }
426
+
427
+    protected function saveDBInfo(InputInterface $input) {
428
+        $type = $input->getArgument('type');
429
+        $username = $input->getArgument('username');
430
+        $dbHost = $input->getArgument('hostname');
431
+        $dbName = $input->getArgument('database');
432
+        $password = $input->getOption('password');
433
+        if ($input->getOption('port')) {
434
+            $dbHost .= ':'.$input->getOption('port');
435
+        }
436
+
437
+        $this->config->setSystemValues([
438
+            'dbtype' => $type,
439
+            'dbname' => $dbName,
440
+            'dbhost' => $dbHost,
441
+            'dbuser' => $username,
442
+            'dbpassword' => $password,
443
+        ]);
444
+    }
445
+
446
+    /**
447
+     * Return possible values for the named option
448
+     *
449
+     * @param string $optionName
450
+     * @param CompletionContext $context
451
+     * @return string[]
452
+     */
453
+    public function completeOptionValues($optionName, CompletionContext $context) {
454
+        return [];
455
+    }
456
+
457
+    /**
458
+     * Return possible values for the named argument
459
+     *
460
+     * @param string $argumentName
461
+     * @param CompletionContext $context
462
+     * @return string[]
463
+     */
464
+    public function completeArgumentValues($argumentName, CompletionContext $context) {
465
+        if ($argumentName === 'type') {
466
+            return ['mysql', 'oci', 'pgsql'];
467
+        }
468
+        return [];
469
+    }
470 470
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -282,9 +282,9 @@  discard block
 block discarded – undo
282 282
 	}
283 283
 
284 284
 	protected function getTables(Connection $db) {
285
-		$db->getConfiguration()->setSchemaAssetsFilter(function ($asset) {
285
+		$db->getConfiguration()->setSchemaAssetsFilter(function($asset) {
286 286
 			/** @var string|AbstractAsset $asset */
287
-			$filterExpression = '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
287
+			$filterExpression = '/^'.preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')).'/';
288 288
 			if ($asset instanceof AbstractAsset) {
289 289
 				return preg_match($filterExpression, $asset->getName()) !== false;
290 290
 			}
@@ -301,12 +301,12 @@  discard block
 block discarded – undo
301 301
 	 * @param OutputInterface $output
302 302
 	 */
303 303
 	protected function copyTable(Connection $fromDB, Connection $toDB, Table $table, InputInterface $input, OutputInterface $output) {
304
-		if ($table->getName() === $toDB->getPrefix() . 'migrations') {
304
+		if ($table->getName() === $toDB->getPrefix().'migrations') {
305 305
 			$output->writeln('<comment>Skipping migrations table because it was already filled by running the migrations</comment>');
306 306
 			return;
307 307
 		}
308 308
 
309
-		$chunkSize = (int)$input->getOption('chunk-size');
309
+		$chunkSize = (int) $input->getOption('chunk-size');
310 310
 
311 311
 		$query = $fromDB->getQueryBuilder();
312 312
 		$query->automaticTablePrefix(false);
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
 
319 319
 		$numChunks = ceil($count / $chunkSize);
320 320
 		if ($numChunks > 1) {
321
-			$output->writeln('chunked query, ' . $numChunks . ' chunks');
321
+			$output->writeln('chunked query, '.$numChunks.' chunks');
322 322
 		}
323 323
 
324 324
 		$progress = new ProgressBar($output, $count);
Please login to merge, or discard this patch.
core/Command/User/ListCommand.php 1 patch
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -34,88 +34,88 @@
 block discarded – undo
34 34
 
35 35
 class ListCommand extends Base {
36 36
 
37
-	/** @var IUserManager */
38
-	protected $userManager;
37
+    /** @var IUserManager */
38
+    protected $userManager;
39 39
 
40
-	/** @var IGroupManager */
41
-	protected $groupManager;
40
+    /** @var IGroupManager */
41
+    protected $groupManager;
42 42
 
43
-	/**
44
-	 * @param IUserManager $userManager
45
-	 * @param IGroupManager $groupManager
46
-	 */
47
-	public function __construct(IUserManager $userManager,
48
-								IGroupManager $groupManager) {
49
-		$this->userManager = $userManager;
50
-		$this->groupManager = $groupManager;
51
-		parent::__construct();
52
-	}
43
+    /**
44
+     * @param IUserManager $userManager
45
+     * @param IGroupManager $groupManager
46
+     */
47
+    public function __construct(IUserManager $userManager,
48
+                                IGroupManager $groupManager) {
49
+        $this->userManager = $userManager;
50
+        $this->groupManager = $groupManager;
51
+        parent::__construct();
52
+    }
53 53
 
54
-	protected function configure() {
55
-		$this
56
-			->setName('user:list')
57
-			->setDescription('list configured users')
58
-			->addOption(
59
-				'limit',
60
-				'l',
61
-				InputOption::VALUE_OPTIONAL,
62
-				'Number of users to retrieve',
63
-				'500'
64
-			)->addOption(
65
-				'offset',
66
-				'o',
67
-				InputOption::VALUE_OPTIONAL,
68
-				'Offset for retrieving users',
69
-				'0'
70
-			)->addOption(
71
-				'output',
72
-				null,
73
-				InputOption::VALUE_OPTIONAL,
74
-				'Output format (plain, json or json_pretty, default is plain)',
75
-				$this->defaultOutputFormat
76
-			)->addOption(
77
-				'info',
78
-				'i',
79
-				InputOption::VALUE_NONE,
80
-				'Show detailed info'
81
-			);
82
-	}
54
+    protected function configure() {
55
+        $this
56
+            ->setName('user:list')
57
+            ->setDescription('list configured users')
58
+            ->addOption(
59
+                'limit',
60
+                'l',
61
+                InputOption::VALUE_OPTIONAL,
62
+                'Number of users to retrieve',
63
+                '500'
64
+            )->addOption(
65
+                'offset',
66
+                'o',
67
+                InputOption::VALUE_OPTIONAL,
68
+                'Offset for retrieving users',
69
+                '0'
70
+            )->addOption(
71
+                'output',
72
+                null,
73
+                InputOption::VALUE_OPTIONAL,
74
+                'Output format (plain, json or json_pretty, default is plain)',
75
+                $this->defaultOutputFormat
76
+            )->addOption(
77
+                'info',
78
+                'i',
79
+                InputOption::VALUE_NONE,
80
+                'Show detailed info'
81
+            );
82
+    }
83 83
 
84
-	protected function execute(InputInterface $input, OutputInterface $output): int {
85
-		$users = $this->userManager->search('', (int) $input->getOption('limit'), (int) $input->getOption('offset'));
84
+    protected function execute(InputInterface $input, OutputInterface $output): int {
85
+        $users = $this->userManager->search('', (int) $input->getOption('limit'), (int) $input->getOption('offset'));
86 86
 
87
-		$this->writeArrayInOutputFormat($input, $output, $this->formatUsers($users, (bool)$input->getOption('info')));
88
-		return 0;
89
-	}
87
+        $this->writeArrayInOutputFormat($input, $output, $this->formatUsers($users, (bool)$input->getOption('info')));
88
+        return 0;
89
+    }
90 90
 
91
-	/**
92
-	 * @param IUser[] $users
93
-	 * @param bool [$detailed=false]
94
-	 * @return array
95
-	 */
96
-	private function formatUsers(array $users, bool $detailed = false) {
97
-		$keys = array_map(function (IUser $user) {
98
-			return $user->getUID();
99
-		}, $users);
91
+    /**
92
+     * @param IUser[] $users
93
+     * @param bool [$detailed=false]
94
+     * @return array
95
+     */
96
+    private function formatUsers(array $users, bool $detailed = false) {
97
+        $keys = array_map(function (IUser $user) {
98
+            return $user->getUID();
99
+        }, $users);
100 100
 
101
-		$values = array_map(function (IUser $user) use ($detailed) {
102
-			if ($detailed) {
103
-				$groups = $this->groupManager->getUserGroupIds($user);
104
-				return [
105
-					'user_id' => $user->getUID(),
106
-					'display_name' => $user->getDisplayName(),
107
-					'email' => $user->getEMailAddress() ? $user->getEMailAddress() : '',
108
-					'cloud_id' => $user->getCloudId(),
109
-					'enabled' => $user->isEnabled(),
110
-					'groups' => $groups,
111
-					'quota' => $user->getQuota(),
112
-					'last_seen' => date(\DateTime::ATOM, $user->getLastLogin()), // ISO-8601
113
-					'user_directory' => $user->getHome(),
114
-					'backend' => $user->getBackendClassName()
115
-				];
116
-			}
117
-			return $user->getDisplayName();
118
-		}, $users);
119
-		return array_combine($keys, $values);
120
-	}
101
+        $values = array_map(function (IUser $user) use ($detailed) {
102
+            if ($detailed) {
103
+                $groups = $this->groupManager->getUserGroupIds($user);
104
+                return [
105
+                    'user_id' => $user->getUID(),
106
+                    'display_name' => $user->getDisplayName(),
107
+                    'email' => $user->getEMailAddress() ? $user->getEMailAddress() : '',
108
+                    'cloud_id' => $user->getCloudId(),
109
+                    'enabled' => $user->isEnabled(),
110
+                    'groups' => $groups,
111
+                    'quota' => $user->getQuota(),
112
+                    'last_seen' => date(\DateTime::ATOM, $user->getLastLogin()), // ISO-8601
113
+                    'user_directory' => $user->getHome(),
114
+                    'backend' => $user->getBackendClassName()
115
+                ];
116
+            }
117
+            return $user->getDisplayName();
118
+        }, $users);
119
+        return array_combine($keys, $values);
120
+    }
121 121
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/Command/Search.php 1 patch
Indentation   +91 added lines, -91 removed lines patch added patch discarded remove patch
@@ -39,102 +39,102 @@
 block discarded – undo
39 39
 use Symfony\Component\Console\Output\OutputInterface;
40 40
 
41 41
 class Search extends Command {
42
-	/** @var \OCP\IConfig */
43
-	protected $ocConfig;
44
-	/** @var User_Proxy */
45
-	private $userProxy;
46
-	/** @var Group_Proxy */
47
-	private $groupProxy;
42
+    /** @var \OCP\IConfig */
43
+    protected $ocConfig;
44
+    /** @var User_Proxy */
45
+    private $userProxy;
46
+    /** @var Group_Proxy */
47
+    private $groupProxy;
48 48
 
49
-	public function __construct(IConfig $ocConfig, User_Proxy $userProxy, Group_Proxy $groupProxy) {
50
-		parent::__construct();
51
-		$this->ocConfig = $ocConfig;
52
-		$this->userProxy = $userProxy;
53
-		$this->groupProxy = $groupProxy;
54
-	}
49
+    public function __construct(IConfig $ocConfig, User_Proxy $userProxy, Group_Proxy $groupProxy) {
50
+        parent::__construct();
51
+        $this->ocConfig = $ocConfig;
52
+        $this->userProxy = $userProxy;
53
+        $this->groupProxy = $groupProxy;
54
+    }
55 55
 
56
-	protected function configure() {
57
-		$this
58
-			->setName('ldap:search')
59
-			->setDescription('executes a user or group search')
60
-			->addArgument(
61
-					'search',
62
-					InputArgument::REQUIRED,
63
-					'the search string (can be empty)'
64
-					 )
65
-			->addOption(
66
-					'group',
67
-					null,
68
-					InputOption::VALUE_NONE,
69
-					'searches groups instead of users'
70
-					 )
71
-			->addOption(
72
-					'offset',
73
-					null,
74
-					InputOption::VALUE_REQUIRED,
75
-					'The offset of the result set. Needs to be a multiple of limit. defaults to 0.',
76
-					'0'
77
-					 )
78
-			->addOption(
79
-					'limit',
80
-					null,
81
-					InputOption::VALUE_REQUIRED,
82
-					'limit the results. 0 means no limit, defaults to 15',
83
-					'15'
84
-					 )
85
-		;
86
-	}
56
+    protected function configure() {
57
+        $this
58
+            ->setName('ldap:search')
59
+            ->setDescription('executes a user or group search')
60
+            ->addArgument(
61
+                    'search',
62
+                    InputArgument::REQUIRED,
63
+                    'the search string (can be empty)'
64
+                        )
65
+            ->addOption(
66
+                    'group',
67
+                    null,
68
+                    InputOption::VALUE_NONE,
69
+                    'searches groups instead of users'
70
+                        )
71
+            ->addOption(
72
+                    'offset',
73
+                    null,
74
+                    InputOption::VALUE_REQUIRED,
75
+                    'The offset of the result set. Needs to be a multiple of limit. defaults to 0.',
76
+                    '0'
77
+                        )
78
+            ->addOption(
79
+                    'limit',
80
+                    null,
81
+                    InputOption::VALUE_REQUIRED,
82
+                    'limit the results. 0 means no limit, defaults to 15',
83
+                    '15'
84
+                        )
85
+        ;
86
+    }
87 87
 
88
-	/**
89
-	 * Tests whether the offset and limit options are valid
90
-	 * @param int $offset
91
-	 * @param int $limit
92
-	 * @throws \InvalidArgumentException
93
-	 */
94
-	protected function validateOffsetAndLimit($offset, $limit) {
95
-		if ($limit < 0) {
96
-			throw new \InvalidArgumentException('limit must be  0 or greater');
97
-		}
98
-		if ($offset < 0) {
99
-			throw new \InvalidArgumentException('offset must be 0 or greater');
100
-		}
101
-		if ($limit === 0 && $offset !== 0) {
102
-			throw new \InvalidArgumentException('offset must be 0 if limit is also set to 0');
103
-		}
104
-		if ($offset > 0 && ($offset % $limit !== 0)) {
105
-			throw new \InvalidArgumentException('offset must be a multiple of limit');
106
-		}
107
-	}
88
+    /**
89
+     * Tests whether the offset and limit options are valid
90
+     * @param int $offset
91
+     * @param int $limit
92
+     * @throws \InvalidArgumentException
93
+     */
94
+    protected function validateOffsetAndLimit($offset, $limit) {
95
+        if ($limit < 0) {
96
+            throw new \InvalidArgumentException('limit must be  0 or greater');
97
+        }
98
+        if ($offset < 0) {
99
+            throw new \InvalidArgumentException('offset must be 0 or greater');
100
+        }
101
+        if ($limit === 0 && $offset !== 0) {
102
+            throw new \InvalidArgumentException('offset must be 0 if limit is also set to 0');
103
+        }
104
+        if ($offset > 0 && ($offset % $limit !== 0)) {
105
+            throw new \InvalidArgumentException('offset must be a multiple of limit');
106
+        }
107
+    }
108 108
 
109
-	protected function execute(InputInterface $input, OutputInterface $output): int {
110
-		$helper = new Helper($this->ocConfig, \OC::$server->getDatabaseConnection());
111
-		$configPrefixes = $helper->getServerConfigurationPrefixes(true);
112
-		$ldapWrapper = new LDAP();
109
+    protected function execute(InputInterface $input, OutputInterface $output): int {
110
+        $helper = new Helper($this->ocConfig, \OC::$server->getDatabaseConnection());
111
+        $configPrefixes = $helper->getServerConfigurationPrefixes(true);
112
+        $ldapWrapper = new LDAP();
113 113
 
114
-		$offset = (int)$input->getOption('offset');
115
-		$limit = (int)$input->getOption('limit');
116
-		$this->validateOffsetAndLimit($offset, $limit);
114
+        $offset = (int)$input->getOption('offset');
115
+        $limit = (int)$input->getOption('limit');
116
+        $this->validateOffsetAndLimit($offset, $limit);
117 117
 
118
-		if ($input->getOption('group')) {
119
-			$proxy = $this->groupProxy;
120
-			$getMethod = 'getGroups';
121
-			$printID = false;
122
-			// convert the limit of groups to null. This will show all the groups available instead of
123
-			// nothing, and will match the same behaviour the search for users has.
124
-			if ($limit === 0) {
125
-				$limit = null;
126
-			}
127
-		} else {
128
-			$proxy = $this->userProxy;
129
-			$getMethod = 'getDisplayNames';
130
-			$printID = true;
131
-		}
118
+        if ($input->getOption('group')) {
119
+            $proxy = $this->groupProxy;
120
+            $getMethod = 'getGroups';
121
+            $printID = false;
122
+            // convert the limit of groups to null. This will show all the groups available instead of
123
+            // nothing, and will match the same behaviour the search for users has.
124
+            if ($limit === 0) {
125
+                $limit = null;
126
+            }
127
+        } else {
128
+            $proxy = $this->userProxy;
129
+            $getMethod = 'getDisplayNames';
130
+            $printID = true;
131
+        }
132 132
 
133
-		$result = $proxy->$getMethod($input->getArgument('search'), $limit, $offset);
134
-		foreach ($result as $id => $name) {
135
-			$line = $name . ($printID ? ' ('.$id.')' : '');
136
-			$output->writeln($line);
137
-		}
138
-		return 0;
139
-	}
133
+        $result = $proxy->$getMethod($input->getArgument('search'), $limit, $offset);
134
+        foreach ($result as $id => $name) {
135
+            $line = $name . ($printID ? ' ('.$id.')' : '');
136
+            $output->writeln($line);
137
+        }
138
+        return 0;
139
+    }
140 140
 }
Please login to merge, or discard this patch.