MigrateController.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * Author: ljt
  5. * DateTime: 2016/11/25 11:30
  6. * Description:
  7. */
  8. namespace migration\console;
  9. use migration\models\MigrationUtility;
  10. use Yii;
  11. use yii\base\BaseObject;
  12. use yii\helpers\Console;
  13. use yii\helpers\FileHelper;
  14. use migration\AppUtility;
  15. class MigrateController extends \yii\console\controllers\MigrateController
  16. {
  17. public $useTablePrefix = true;
  18. public $migrationPath = '@database/migrations';
  19. /**
  20. * dump migrate file
  21. *
  22. * @return string
  23. */
  24. public function actionDump()
  25. {
  26. set_time_limit(0);
  27. $model = new MigrationUtility();
  28. $upStr = new OutputString();
  29. $downStr = new OutputString();
  30. $data = [
  31. 'tableSchemas' => array_keys(MigrationUtility::getTableNames()),
  32. 'tableDatas' => array_keys(MigrationUtility::getTableNames()),
  33. 'migrationPath' => $this->migrationPath
  34. ];
  35. if ($model->load($data, '')) {
  36. if (!empty($model->tableSchemas)) {
  37. list ($up, $down) = $this->generalTableSchemas($model->tableSchemas, $model->tableOption);
  38. $upStr->outputStringArray = array_merge($upStr->outputStringArray, $up->outputStringArray);
  39. $downStr->outputStringArray = array_merge($downStr->outputStringArray, $down->outputStringArray);
  40. }
  41. if (! empty($model->tableDatas)) {
  42. list ($up, $down) = $this->generalTableDatas($model->tableDatas);
  43. $upStr->outputStringArray = array_merge($upStr->outputStringArray, $up->outputStringArray);
  44. $downStr->outputStringArray = array_merge($downStr->outputStringArray, $down->outputStringArray);
  45. }
  46. $path = Yii::getAlias($model->migrationPath);
  47. if (!is_dir($path)) {
  48. FileHelper::createDirectory($path);
  49. }
  50. $name = 'm' . gmdate('ymd_His') . '_' . $model->migrationName;
  51. $file = $path . DIRECTORY_SEPARATOR . $name . '.php';
  52. $content = $this->renderFile(Yii::getAlias("@backend/modules/migration/views/migration.php"), [
  53. 'className' => $name,
  54. 'up' => $upStr->output(),
  55. 'down' => $downStr->output()
  56. ]);
  57. file_put_contents($file, $content);
  58. $this->stdout('成功生成迁移文件 ' . $file, Console::FG_GREEN);
  59. }
  60. }
  61. public function getTableName($name)
  62. {
  63. $prefix = \Yii::$app->db->tablePrefix;
  64. return str_replace($prefix, '', $name);
  65. }
  66. public function generalTableSchemas($tables, $tableOption)
  67. {
  68. $initialTabLevel = 0;
  69. $upStr = new OutputString([
  70. 'tabLevel' => $initialTabLevel
  71. ]);
  72. $upStr->addStr('$this->execute(\'SET foreign_key_checks = 0\');');
  73. $upStr->addStr(' ');
  74. foreach ($tables as $table) {
  75. $upStr->tabLevel = $initialTabLevel;
  76. $tablePrepared = $this->getTableName($table);
  77. // 添加表结构
  78. $upStr->addStr('$this->createTable(\'{{%' . $tablePrepared . '}}\', [');
  79. $upStr->tabLevel ++;
  80. $tableSchema = \Yii::$app->db->getTableSchema($table);
  81. foreach ($tableSchema->columns as $column) {
  82. $appUtility = new AppUtility($column);
  83. $upStr->addStr($appUtility->string . "',");
  84. }
  85. if (! empty($tableSchema->primaryKey)) {
  86. $upStr->addStr("'PRIMARY KEY (`" . implode("`,`", $tableSchema->primaryKey) . "`)'");
  87. }
  88. $upStr->tabLevel --;
  89. $upStr->addStr('], "' . $tableOption . '");');
  90. // 添加索引
  91. $tableIndexes = Yii::$app->db->createCommand('SHOW INDEX FROM `' . $table . '`')->queryAll();
  92. $indexs = [];
  93. foreach ($tableIndexes as $item) {
  94. if ($item['Key_name'] == 'PRIMARY') {
  95. continue;
  96. }
  97. if (! isset($indexs[$item["Key_name"]])) {
  98. $indexs[$item["Key_name"]] = [];
  99. $indexs[$item["Key_name"]]["unique"] = ($item['Non_unique']) ? 0 : 1;
  100. }
  101. $indexs[$item["Key_name"]]["columns"][] = $item['Column_name'];
  102. }
  103. if (! empty($indexs)) {
  104. $upStr->addStr(' ');
  105. }
  106. foreach ($indexs as $index => $item) {
  107. $str = '$this->createIndex(\'' . $index . '\',\'{{%' . $tablePrepared . '}}\',\'' . implode(', ', $item['columns']) . '\',' . $item['unique'] . ');';
  108. $upStr->addStr($str);
  109. }
  110. $upStr->addStr(' ');
  111. }
  112. //添加外键
  113. $sql = "SELECT tb1.CONSTRAINT_NAME, tb1.TABLE_NAME, tb1.COLUMN_NAME,
  114. tb1.REFERENCED_TABLE_NAME, tb1.REFERENCED_COLUMN_NAME, tb2.MATCH_OPTION,
  115. tb2.UPDATE_RULE, tb2.DELETE_RULE
  116. FROM information_schema.KEY_COLUMN_USAGE AS tb1
  117. INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS tb2 ON
  118. tb1.CONSTRAINT_NAME = tb2.CONSTRAINT_NAME AND tb1.CONSTRAINT_SCHEMA = tb2.CONSTRAINT_SCHEMA
  119. WHERE TABLE_SCHEMA = DATABASE()
  120. AND REFERENCED_TABLE_SCHEMA = DATABASE() AND REFERENCED_COLUMN_NAME IS NOT NULL";
  121. $foreignKeys = Yii::$app->db->createCommand($sql)->queryAll();
  122. foreach ($foreignKeys as $fk)
  123. {
  124. $str = '$this->addForeignKey(';
  125. $str .= '\'' . $fk['CONSTRAINT_NAME'] . '\', ';
  126. $str .= '\'{{%' . $this->getTableName($fk['TABLE_NAME']) . '}}\', ';
  127. $str .= '\'' . $fk['COLUMN_NAME'] . '\', ';
  128. $str .= '\'{{%' . $this->getTableName($fk['REFERENCED_TABLE_NAME']) . '}}\', ';
  129. $str .= '\'' . $fk['REFERENCED_COLUMN_NAME'] . '\', ';
  130. $str .= '\'' . $fk['DELETE_RULE'] . '\', ';
  131. $str .= '\'' . $fk['UPDATE_RULE'] . '\' ';
  132. $str .= ');';
  133. $upStr->addStr($str);
  134. }
  135. $upStr->addStr(' ');
  136. $upStr->addStr('$this->execute(\'SET foreign_key_checks = 1;\');');
  137. $downStr = new OutputString();
  138. /* DROP TABLE */
  139. $downStr->addStr('$this->execute(\'SET foreign_key_checks = 0\');');
  140. foreach ($tables as $table) {
  141. if (! empty($table)) {
  142. $downStr->addStr('$this->dropTable(\'{{%' . $tablePrepared . '}}\');');
  143. }
  144. }
  145. $downStr->addStr('$this->execute(\'SET foreign_key_checks = 1;\');');
  146. return [
  147. $upStr,
  148. $downStr
  149. ];
  150. }
  151. public function generalTableDatas($tables)
  152. {
  153. $initialTabLevel = 0;
  154. $upStr = new OutputString([
  155. 'tabLevel' => $initialTabLevel
  156. ]);
  157. $upStr->addStr('$this->execute(\'SET foreign_key_checks = 0\');');
  158. $upStr->addStr(' ');
  159. foreach ($tables as $table) {
  160. $tablePrepared = $this->getTableName($table);
  161. $upStr->addStr('/* Table ' . $table . ' */');
  162. $tableSchema = \Yii::$app->db->getTableSchema($table);
  163. $data = Yii::$app->db->createCommand('SELECT * FROM `' . $table . '`')->queryAll();
  164. $out = '$this->batchInsert(\'{{%' . $tablePrepared . '}}\',[';
  165. foreach ($tableSchema->columns as $column) {
  166. $out .= "'" . $column->name . "',";
  167. }
  168. $out = rtrim($out, ',') . '],[';
  169. foreach ($data as $row) {
  170. $out .= '[';
  171. foreach ($row as $field) {
  172. if ($field === null) {
  173. $out .= "null,";
  174. } else {
  175. $out .= "'" . addcslashes($field, "'") . "',";
  176. }
  177. }
  178. $out = rtrim($out, ',') . "],\n";
  179. }
  180. $out = rtrim($out, ',') . ']);';
  181. $upStr->addStr($out);
  182. $upStr->addStr(' ');
  183. }
  184. $upStr->addStr('$this->execute(\'SET foreign_key_checks = 1;\');');
  185. $downStr = new OutputString();
  186. return [
  187. $upStr,
  188. $downStr
  189. ];
  190. }
  191. }
  192. /**
  193. * Class OutputString
  194. *
  195. * @author Nils Lindentals <nils@dfworks.lv>
  196. *
  197. * @package c006\utility\migration\controllers
  198. */
  199. class OutputString extends BaseObject
  200. {
  201. /**
  202. *
  203. * @var string
  204. */
  205. public $nw = "\n";
  206. /**
  207. *
  208. * @var string
  209. */
  210. public $tab = "\t";
  211. /**
  212. *
  213. * @var string
  214. */
  215. public $outputStringArray = array();
  216. /**
  217. *
  218. * @var int
  219. */
  220. public $tabLevel = 0;
  221. /**
  222. * Adds string to output string array with "tab" prefix
  223. *
  224. * @var string $str
  225. */
  226. public function addStr($str)
  227. {
  228. $str = str_replace($this->tab, '', $str);
  229. $this->outputStringArray[] = str_repeat($this->tab, $this->tabLevel) . $str;
  230. }
  231. /**
  232. * Returns string output
  233. */
  234. public function output()
  235. {
  236. return implode($this->nw, $this->outputStringArray);
  237. }
  238. }