本教程爲整個數據庫表進行建立遷移,彌補之前未作的工做,且僅適合於Migrations(2.0.8)版本用戶及以上。php
你們都知道Migrations是一個在開發和維護數據庫驅動的應用過程當中,數據庫的結構與源代碼的開發同步更新。例如,在應用開發的過程當中,新建了一張表,在應用部署到生產環境後,發現須要爲這張表建立一個索引以提高查詢性能,等等。由於數據庫結構改變後須要源代碼隨之而改變,Yii支持此類數據庫遷移特徵,這樣你就能夠用數據庫遷移的形式追蹤數據庫的變化,也就是與源代碼同步的版本控制。mysql
那麼我如今數據表有接近300多張,因此不可能每張表進行命令建立遷移,這樣太浪費時間且項目也不止一個,因此我想到一個思路,就是使用命令讓程序批量將每張表建立遷移文件,那麼原生的Migrations據我瞭解是沒辦法實現將表裏每一個字段都輸出到遷移代碼裏面,因此咱們須要稍微改動一下。web
咱們先找到一個核心文件:/vendor/yiisoft/yii2/console/controllers/BaseMigrateController.php
建立遷移的視圖文件:/vendor/yiisoft/yii2/views/createTableMigration.phpsql
咱們先打開核心文件(BaseMigrateController.php)方法:actionCreate
行數大概在:493行。數據庫
使用Migrations命令建立遷移的時候,命令會詢問咱們是否須要建立,填寫y 或 n,那麼咱們既然要批量建立,確定是不能容許這種阻止程序的事情發生,在502行,有個if判斷$this->confirm("Create new migration '$file'?")
,這句代碼就是在咱們操做Migrations不管建立或其餘操做的時候都會詢問,那麼咱們在if判斷裏面添加一個或者條件preg_match('/^create_(.+)$/', $name, $matches)
意思就是若是我是建立我就不須要通過詢問(固然後期若是有相似需求,能夠直接將這個if判斷詢問幹掉)。windows
在if判斷裏面有作了六件事,咱們此次僅針對於建立的時候修改,找到else if的preg_match('/^create_(.+)$/', $name, $matches)
這個條件裏面,如下是個人代碼:數組
$this->addDefaultPrimaryKey(); $primaryKeyArray = $createIndexArray = array(); $tableInfo = Yii::$app->getDb()->getSchema()->getTableSchema($matches[1]); foreach($tableInfo->columns as $key => $value): if($value->isPrimaryKey == 1 && !$value->autoIncrement): $primaryKeyArray[] = $value->name; endif; endforeach; $fieldsIndex = Yii::$app->db->createCommand("SHOW index FROM {$matches[1]} WHERE Key_name<>'PRIMARY'")->queryAll(); foreach($fieldsIndex as $key => $value): $createIndexArray[$key]['Key_name'] = $value['Key_name']; $createIndexArray[$key]['Column_name'] = $value['Column_name']; $createIndexArray[$key]['Index_cat'] = $value['Non_unique'] < 1 ? 'Unique' : 'Normal'; $createIndexArray[$key]['Index_type'] = $value['Index_type']; endforeach; $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['create_table']), [ 'className' => $className, 'table' => mb_strtolower($matches[1], Yii::$app->charset), 'fields' => $this->fields, 'tableInfo' => $tableInfo, 'primaryKeyArray' => $primaryKeyArray, 'createIndexArray' => $createIndexArray ]);
思路是,先用Yii::$app->getDb()->getSchema()->getTableSchema(表名)
方法獲取到表字段數據,而後咱們循環字段,判斷isPrimaryKey是否爲1 且 autoIncrement是否不存在(由於有的表可能不須要自增而須要主鍵,這個循環判斷就是爲了幹這件事),而後咱們會發現Yii::$app->getDb()->getSchema()->getTableSchema(表名)
方法並不能獲取到個人索引字段,那麼咱們就不要侷限於Schema,咱們改用mysql語句來查詢:Yii::$app->db->createCommand("SHOW index FROM {$matches[1]} WHERE Key_name<>'PRIMARY'")->queryAll()
。yii2
這裏爲何要新增條件 WHERE Key_name<>'PRIMARY'
,由於當你有個自增主鍵的時候,他也會輸出出來,但這個自增主鍵並非咱們想要的索引字段,因此咱們使用條件將他幹掉。app
下面foreach循環就是爲了等下輸出的時候方便(Non_unique在做者這裏原覺得用Migrations新增索引的時候能該類型,因此就寫上去了,誰知道後面發現索引類型,已經寫死了,必須爲unique類型,createIndex方法代碼在:/vendor/yiisoft/yii2/db/Migration.php 468行)yii
數據表有用到外鍵的朋友,代碼大家可能要本身手寫一小段了,做者項目中未遇到外鍵因此代碼沒寫,在Yii::$app->getDb()->getSchema()->getTableSchema(表名)
方法中,已經查出了表的外鍵,大家能夠利用。
接着往下代碼就是渲染視圖模板,模板路徑在上面剛剛已經說了,這個時候,咱們把剛剛查出來的三個數組傳進去。
如今開始到視圖模板(/vendor/yiisoft/yii2/views/createTableMigration.php):咱們修改up
方法裏面的代碼,這裏能看到只有一個自增ID。
$this->createTable('<?= $table ?>', [ <?php foreach ($tableInfo->columns as $key => $value): ?> '<?= $key ?>' => $this-><?php if($value->isPrimaryKey == 1 && $value->autoIncrement == 1): ?>primaryKey()<?php else: ?><?php if($value->type == 'smallint'): ?>smallinteger<?php elseif($value->type == 'bigint'): ?>biginteger<?php else: ?><?= $value->type ?><?php endif; ?>(<?php if(isset($value->scale)): ?><?= $value->size ?>, <?= $value->scale ?><?php else: ?><?= $value->size ?><?php endif; ?>)<?php if(!$value->allowNull): ?>->notNull()<?php endif; ?><?php if(isset($value->defaultValue) && $value->defaultValue != 'CURRENT_TIMESTAMP' && $value->defaultValue != '' && $value->defaultValue != '\'\''): ?>->defaultValue('<?= $value->defaultValue ?>')<?php endif; ?><?php if(isset($value->comment) && $value->comment != ''): ?>->comment('<?= $value->comment ?>')<?php endif; ?><?php endif; ?><?= ",\n" ?> <?php endforeach; ?> ]); <?php if(count($primaryKeyArray) > 0 && !empty($primaryKeyArray)): ?> $this->addPrimaryKey('<?= $table ?>', '<?= $table ?>', '<?= implode(",", $primaryKeyArray) ?>'); <?php endif; ?> <?php if(count($createIndexArray) > 0 && !empty($createIndexArray)): ?> <?php foreach($createIndexArray as $key => $value): ?> $this->createIndex('<?= $value['Key_name'] ?>', '<?= $table ?>', '<?= $value['Column_name'] ?>', true); <?php endforeach; ?> <?php endif; ?>
以上代碼就是將剛剛查到的數據字段進行循環,而後拼接成字段名
=> 字段自增->字段類型(字段大小)->是否爲空->字段默認值->字段註釋
(Migrations2.0.8版本才支持註釋2.0.8版本如下不支持字段註釋)。
好,上面的代碼我能知足百分之80以上的字段,除了一些個別特殊的字段,什麼是特殊的字段呢?例如,在mysql類型中是:smallint
但我在Migrations中必須是 smallinteger
包括 bigint
也要改成 biginteger
,目前我就發現這兩個不同,其餘的暫時還沒遇到。
而後咱們開始輸出主鍵字段(並非自增的哦~自增的若是存在就已經在上面輸出了,這裏的代碼只處理主鍵字段)咱們先判斷數組是否存在且數組個數大於0,這裏不能使用foreach
來循環主鍵數組,由於$this->addPrimaryKey('name', 'tableName', 'columns')
方法只能存在一個,因此咱們使用PHP的 implode()
方法進行拆分數組。
主鍵的解決了,還差一個新增索引的,新增索引方法爲 $this->createIndex('name', 'tableName', 'Column_name')
,這個方法容許存在多個,那麼咱們就先判斷數組是否存在且個數是否大於0,而後再使用 foreach
方法,Key_name
是新增索引時的名字,table
就是你新增索引到哪一個表,Column_name
就是字段名。
以上步驟都完成之後,咱們就開始新建console命令啦~
做者建立的控制器是:TimerController.php,若是大家有控制器能夠直接使用,再新建一個Model文件,而且將引入Model關鍵詞
代碼:
<?php namespace console\controllers; use Yii; use yii\console\Controller; use console\models\MigrationDb; /** * 定時任務 * @author mo * */ class TimerController extends Controller { public function actionMigrationdb() { $Migrate = new MigrationDb(); // 獲取遷移目錄路徑 console/migrations/ $dirName = Yii::getAlias('@console').'/migrations'; // 先刪除該路徑下已生成的全部文件 $Migrate->deleteFile($dirName); // 獲取全部表名 開始循環獲取表字段信息,建立遷移 $db = Yii::$app->getDb(); $tablesName = $db->getSchema()->getTableNames(); foreach($tablesName as $key => $value) { $tablesInfo = $db->getSchema()->getTableSchema($value); exec("yii migrate/create create_".$value, $info); } } }
咱們先實例化模型文件,而後獲取到存放遷移文件的路徑,先將遷移路徑下的全部遷移文件刪除掉(避免重複),而後咱們就使用:Yii::$app->getDb()->getSchema()->getTableNames()
獲取全部的表名,接着就 foreach
循環全部的表,key
爲鍵值 value
爲表名,而後咱們使用php的 exec
函數執行命令,這命令的意思是,建立遷移文件,文件名是以:create_表名
形式拼接好的,$info
能夠輸出打印調試結果,執行成功將會返回 New migration created successfully.
。
好了咱們最後開始寫Model文件了
代碼:
<?php namespace console\models; use yii\base\Model; class MigrationDb extends Model { /** * 刪除該目錄下的全部文件及文件夾 * @dirName 路徑名 */ public static function deleteFile($dirName) { if($handle = opendir($dirName)) { while(false != ($item = readdir($handle))) { if($item != '.' && $item != '..') { if(is_dir($dirName."/".$item)) { self::deleteFile($dirName."/".$item); }else { unlink($dirName.'/'.$item); } } } closedir($handle); } } }
這裏就是找到指定目錄將其目錄下的全部文件及文件夾刪除掉(若是不知足大家需求能夠進行更改)。
到了最後緊張又刺激的時刻了,咱們的工做已經完成,就差運行命令調試。
咱們先將全部表備份一份並導出到本地(以防萬一,我不捨得大家跑路啊),確保全部表都在的時候,咱們就是用命令執行console任務。
(先進入到你的程序根目錄,有yii.bat的那裏)
windows的DOC命令:/你的文件夾路徑/yii timer(控制器名)/migrationdb(方法名)。
Linux命令:老子不會。
這個時候:console/migrations/ 目錄下會建立遷移文件,成功建立完遷移文件以後,咱們將全部表刪除掉(刪除以前記得備份!備份!!備份!!!),而後咱們打開命令執行:yii migrate,這個時候有多少個遷移文件會告訴你,還會問你是否執行,咱們輸入y
肯定執行,這個時候就開始往數據庫導入表了,若有報錯可發截圖並詢問我或者百度。
若是報表已存在的錯誤的話,那麼就是你沒有將表刪完,Migrations建立遷移 跟 其餘操做的時候,會自動新增一張爲 migrtions的表,這張表是記錄的。
Detect languageAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu |
|
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu |
|
|
|
|
|