DefaultController.php 8.9 KB

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