Passed
Push — master ( 6e3b9e...b8bb1d )
by Joas
12:40
created

GenerateFromSchemaFileCommand::schemaToMigration()   F

Complexity

Conditions 15
Paths 329

Size

Total Lines 116
Code Lines 83

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 83
nc 329
nop 1
dl 0
loc 116
rs 3.1475
c 0
b 0
f 0

How to fix   Long Method    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) 2017 Joas Schilling <[email protected]>
4
 *
5
 * @author Joas Schilling <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OC\Core\Command\Db\Migrations;
25
26
27
use Doctrine\DBAL\Schema\Schema;
28
use OC\DB\MDB2SchemaReader;
29
use OC\DB\MigrationService;
30
use OC\Migration\ConsoleOutput;
31
use OCP\App\IAppManager;
32
use OCP\IConfig;
33
use OCP\IDBConnection;
34
use Symfony\Component\Console\Input\InputInterface;
35
use Symfony\Component\Console\Output\OutputInterface;
36
37
class GenerateFromSchemaFileCommand extends GenerateCommand {
38
39
	/** @var IConfig */
40
	protected $config;
41
42
	public function __construct(IConfig $config, IAppManager $appManager, IDBConnection $connection) {
43
		parent::__construct($connection, $appManager);
44
		$this->config = $config;
45
	}
46
47
48
	protected function configure() {
49
		parent::configure();
50
51
		$this->setName('migrations:generate-from-schema');
52
	}
53
54
	public function execute(InputInterface $input, OutputInterface $output) {
55
		$appName = $input->getArgument('app');
56
		$version = $input->getArgument('version');
57
58
		if (!preg_match('/^\d{1,16}$/',$version)) {
0 ignored issues
show
Bug introduced by
It seems like $version can also be of type string[]; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

58
		if (!preg_match('/^\d{1,16}$/',/** @scrutinizer ignore-type */ $version)) {
Loading history...
59
			$output->writeln('<error>The given version is invalid. Only 0-9 are allowed (max. 16 digits)</error>');
60
			return 1;
61
		}
62
63
		$schemaFile = $this->appManager->getAppPath($appName) . '/appinfo/database.xml';
0 ignored issues
show
Bug introduced by
It seems like $appName can also be of type string[]; however, parameter $appId of OCP\App\IAppManager::getAppPath() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
		$schemaFile = $this->appManager->getAppPath(/** @scrutinizer ignore-type */ $appName) . '/appinfo/database.xml';
Loading history...
64
		if (!file_exists($schemaFile)) {
65
			$output->writeln('<error>App ' . $appName . ' does not have a database.xml file</error>');
0 ignored issues
show
Bug introduced by
Are you sure $appName of type null|string|string[] can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

65
			$output->writeln('<error>App ' . /** @scrutinizer ignore-type */ $appName . ' does not have a database.xml file</error>');
Loading history...
66
			return 2;
67
		}
68
69
		$reader = new MDB2SchemaReader($this->config, $this->connection->getDatabasePlatform());
70
		$schema = new Schema();
71
		$reader->loadSchemaFromFile($schemaFile, $schema);
72
73
		$schemaBody = $this->schemaToMigration($schema);
74
75
		$ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output));
76
77
		$date = date('YmdHis');
78
		$path = $this->generateMigration($ms, 'Version' . $version . 'Date' . $date, $schemaBody);
0 ignored issues
show
Bug introduced by
Are you sure $version of type null|string|string[] can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
		$path = $this->generateMigration($ms, 'Version' . /** @scrutinizer ignore-type */ $version . 'Date' . $date, $schemaBody);
Loading history...
79
80
		$output->writeln("New migration class has been generated to <info>$path</info>");
81
		return 0;
82
	}
83
84
	/**
85
	 * @param Schema $schema
86
	 * @return string
87
	 */
88
	protected function schemaToMigration(Schema $schema) {
89
		$content = <<<'EOT'
90
		/** @var ISchemaWrapper $schema */
91
		$schema = $schemaClosure();
92
93
EOT;
94
95
		foreach ($schema->getTables() as $table) {
96
			$content .= str_replace('{{table-name}}', substr($table->getName(), 3), <<<'EOT'
97
98
		if (!$schema->hasTable('{{table-name}}')) {
99
			$table = $schema->createTable('{{table-name}}');
100
101
EOT
102
			);
103
104
			foreach ($table->getColumns() as $column) {
105
				$content .= str_replace(['{{name}}', '{{type}}'], [$column->getName(), $column->getType()->getName()], <<<'EOT'
106
			$table->addColumn('{{name}}', '{{type}}', [
107
108
EOT
109
				);
110
				if ($column->getAutoincrement()) {
111
					$content .= <<<'EOT'
112
				'autoincrement' => true,
113
114
EOT;
115
				}
116
				$content .= str_replace('{{notnull}}', $column->getNotnull() ? 'true' : 'false', <<<'EOT'
117
				'notnull' => {{notnull}},
118
119
EOT
120
				);
121
				if ($column->getLength() !== null) {
122
					$content .= str_replace('{{length}}', $column->getLength(), <<<'EOT'
123
				'length' => {{length}},
124
125
EOT
126
					);
127
				}
128
				$default = $column->getDefault();
129
				if ($default !== null) {
130
					if (is_string($default)) {
131
						$default = "'$default'";
132
					} else if (is_bool($default)) {
133
						$default = ($default === true) ? 'true' : 'false';
134
					}
135
					$content .= str_replace('{{default}}', $default, <<<'EOT'
136
				'default' => {{default}},
137
138
EOT
139
					);
140
				}
141
				if ($column->getUnsigned()) {
142
					$content .= <<<'EOT'
143
				'unsigned' => true,
144
145
EOT;
146
				}
147
148
				$content .= <<<'EOT'
149
			]);
150
151
EOT;
152
			}
153
154
			$content .= <<<'EOT'
155
156
EOT;
157
158
			$primaryKey = $table->getPrimaryKey();
159
			if ($primaryKey !== null) {
160
				$content .= str_replace('{{columns}}', implode('\', \'', $primaryKey->getUnquotedColumns()), <<<'EOT'
161
			$table->setPrimaryKey(['{{columns}}']);
162
163
EOT
164
				);
165
			}
166
167
			foreach ($table->getIndexes() as $index) {
168
				if ($index->isPrimary()) {
169
					continue;
170
				}
171
172
				if ($index->isUnique()) {
173
					$content .= str_replace(
174
						['{{columns}}', '{{name}}'],
175
						[implode('\', \'', $index->getUnquotedColumns()), $index->getName()],
176
						<<<'EOT'
177
			$table->addUniqueIndex(['{{columns}}'], '{{name}}');
178
179
EOT
180
					);
181
				} else {
182
					$content .= str_replace(
183
						['{{columns}}', '{{name}}'],
184
						[implode('\', \'', $index->getUnquotedColumns()), $index->getName()],
185
						<<<'EOT'
186
			$table->addIndex(['{{columns}}'], '{{name}}');
187
188
EOT
189
					);
190
				}
191
			}
192
193
			$content .= <<<'EOT'
194
		}
195
196
EOT;
197
		}
198
199
		$content .= <<<'EOT'
200
		return $schema;
201
EOT;
202
203
		return $content;
204
	}
205
}
206