GenerateFromSchemaFileCommand.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
  4. *
  5. * @author Joas Schilling <coding@schilljs.com>
  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. namespace OC\Core\Command\Db\Migrations;
  24. use Doctrine\DBAL\Schema\Schema;
  25. use OC\DB\MDB2SchemaReader;
  26. use OC\DB\MigrationService;
  27. use OC\Migration\ConsoleOutput;
  28. use OCP\App\IAppManager;
  29. use OCP\IConfig;
  30. use OCP\IDBConnection;
  31. use Symfony\Component\Console\Input\InputInterface;
  32. use Symfony\Component\Console\Output\OutputInterface;
  33. class GenerateFromSchemaFileCommand extends GenerateCommand {
  34. /** @var IConfig */
  35. protected $config;
  36. /** @var IAppManager */
  37. protected $appManager;
  38. public function __construct(IConfig $config, IAppManager $appManager, IDBConnection $connection) {
  39. parent::__construct($connection);
  40. $this->config = $config;
  41. $this->appManager = $appManager;
  42. }
  43. protected function configure() {
  44. parent::configure();
  45. $this->setName('migrations:generate-from-schema');
  46. }
  47. public function execute(InputInterface $input, OutputInterface $output) {
  48. $appName = $input->getArgument('app');
  49. $version = $input->getArgument('version');
  50. if (!preg_match('/^\d{1,16}$/',$version)) {
  51. $output->writeln('<error>The given version is invalid. Only 0-9 are allowed (max. 16 digits)</error>');
  52. return 1;
  53. }
  54. $schemaFile = $this->appManager->getAppPath($appName) . '/appinfo/database.xml';
  55. if (!file_exists($schemaFile)) {
  56. $output->writeln('<error>App ' . $appName . ' does not have a database.xml file</error>');
  57. return 2;
  58. }
  59. $reader = new MDB2SchemaReader($this->config, $this->connection->getDatabasePlatform());
  60. $schema = new Schema();
  61. $reader->loadSchemaFromFile($schemaFile, $schema);
  62. $schemaBody = $this->schemaToMigration($schema);
  63. $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output));
  64. $date = date('YmdHis');
  65. $path = $this->generateMigration($ms, 'Version' . $version . 'Date' . $date, $schemaBody);
  66. $output->writeln("New migration class has been generated to <info>$path</info>");
  67. return 0;
  68. }
  69. /**
  70. * @param Schema $schema
  71. * @return string
  72. */
  73. protected function schemaToMigration(Schema $schema) {
  74. $content = <<<'EOT'
  75. /** @var ISchemaWrapper $schema */
  76. $schema = $schemaClosure();
  77. EOT;
  78. foreach ($schema->getTables() as $table) {
  79. $content .= str_replace('{{table-name}}', substr($table->getName(), 3), <<<'EOT'
  80. if (!$schema->hasTable('{{table-name}}')) {
  81. $table = $schema->createTable('{{table-name}}');
  82. EOT
  83. );
  84. foreach ($table->getColumns() as $column) {
  85. $content .= str_replace(['{{name}}', '{{type}}'], [$column->getName(), $column->getType()->getName()], <<<'EOT'
  86. $table->addColumn('{{name}}', '{{type}}', [
  87. EOT
  88. );
  89. if ($column->getAutoincrement()) {
  90. $content .= <<<'EOT'
  91. 'autoincrement' => true,
  92. EOT;
  93. }
  94. $content .= str_replace('{{notnull}}', $column->getNotnull() ? 'true' : 'false', <<<'EOT'
  95. 'notnull' => {{notnull}},
  96. EOT
  97. );
  98. if ($column->getLength() !== null) {
  99. $content .= str_replace('{{length}}', $column->getLength(), <<<'EOT'
  100. 'length' => {{length}},
  101. EOT
  102. );
  103. }
  104. $default = $column->getDefault();
  105. if ($default !== null) {
  106. $default = is_numeric($default) ? $default : "'$default'";
  107. $content .= str_replace('{{default}}', $default, <<<'EOT'
  108. 'default' => {{default}},
  109. EOT
  110. );
  111. }
  112. if ($column->getUnsigned()) {
  113. $content .= <<<'EOT'
  114. 'unsigned' => true,
  115. EOT;
  116. }
  117. $content .= <<<'EOT'
  118. ]);
  119. EOT;
  120. }
  121. $content .= <<<'EOT'
  122. EOT;
  123. $primaryKey = $table->getPrimaryKey();
  124. if ($primaryKey !== null) {
  125. $content .= str_replace('{{columns}}', implode('\', \'', $primaryKey->getUnquotedColumns()), <<<'EOT'
  126. $table->setPrimaryKey(['{{columns}}']);
  127. EOT
  128. );
  129. }
  130. foreach ($table->getIndexes() as $index) {
  131. if ($index->isPrimary()) {
  132. continue;
  133. }
  134. if ($index->isUnique()) {
  135. $content .= str_replace(
  136. ['{{columns}}', '{{name}}'],
  137. [implode('\', \'', $index->getUnquotedColumns()), $index->getName()],
  138. <<<'EOT'
  139. $table->addUniqueIndex(['{{columns}}'], '{{name}}');
  140. EOT
  141. );
  142. } else {
  143. $content .= str_replace(
  144. ['{{columns}}', '{{name}}'],
  145. [implode('\', \'', $index->getUnquotedColumns()), $index->getName()],
  146. <<<'EOT'
  147. $table->addIndex(['{{columns}}'], '{{name}}');
  148. EOT
  149. );
  150. }
  151. }
  152. $content .= <<<'EOT'
  153. }
  154. EOT;
  155. }
  156. $content .= <<<'EOT'
  157. return $schema;
  158. EOT;
  159. return $content;
  160. }
  161. }