摘要:看下兩個方法的源碼同樣是使用了對象來添加命令和。
說明:本文主要學習Schema Builder和Migration System的使用及相關原理。傳統上在設計database時需要寫大量的SQL語句,但Laravel提供了Schema Builder這個神器使得在設計database時使用面向對象方法來做,不需要寫一行SQL,并且還提供了另一個神器Migration System,可以對database做版本控制,包括回滾上一次的遷移操作。本小系列主要分為上中下三篇。本篇主要學習使用Schema Builder來creating,dropping,updating tables;adding,removing,renaming columns;simple index,unique index,foreign keys,同時也會學習相關源碼來進一步了解Schema Builder。
開發環境: Laravel5.3 + PHP7
表的操作-tables在設計database時需要創建、刪除和更新表,Schema Builder類提供了一些methods來面向對象的執行這些操作,而不需要寫一行SQL。在寫Laravel程序時,也經常使用類似命令php artisan make:migration create_accounts_table --create=accounts來做一個遷移類創建數據表,會在database/migrations文件夾下得到類似如下的代碼類:
use IlluminateSupportFacadesSchema; use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateAccountsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create("accounts", function (Blueprint $table) { $table->increments("id"); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists("accounts"); } }(1)creating tables
在執行php artisan migrate命令時操作的是up()方法中語句。在創建的遷移類CreateAccountsTable中,Schema::create()就是創建表的語句,并且第一個參數就是表的名字,第二個參數是個閉包,是操作columns的語句,并且參數是個Blueprint對象。為什么有這么奇怪的寫法呢?
看下Schema Facade中getFacadeAccessor的源碼:
/** * Get a schema builder instance for the default connection. * * @return IlluminateDatabaseSchemaBuilder */ protected static function getFacadeAccessor() { // 這里"db"服務是在DatabaseServiceProvider中定義的,是DatabaseManager對象,且laravel默認connection是mysql // 則返回的是MysqlBuilder,也就是IlluminateDatabaseSchemaBuilder的子類 return static::$app["db"]->connection()->getSchemaBuilder(); }
根據注釋就知道Schema::create就是等同于MysqlBuilder::create(),看下源碼:
// IlluminateDatabaseSchemaBuilder /** * Create a new table on the schema. * * @param string $table * @param Closure $callback * @return IlluminateDatabaseSchemaBlueprint */ public function create($table, Closure $callback) { /** @var IlluminateDatabaseSchemaBlueprint $blueprint */ $blueprint = $this->createBlueprint($table); // 添加"create"命令 $blueprint->create(); // 執行閉包里的操作,也就是操作columns $callback($blueprint); $this->build($blueprint); } protected function createBlueprint($table, Closure $callback = null) { if (isset($this->resolver)) { return call_user_func($this->resolver, $table, $callback); } return new Blueprint($table, $callback); } // IlluminateDatabaseSchemaBlueprint public function create() { return $this->addCommand("create"); } protected function build(Blueprint $blueprint) { $blueprint->build($this->connection, $this->grammar); }
create()中的$callback($blueprint);語句執行了閉包操作,并且閉包參數還是個Blueprint對象。最關鍵的方法時Blueprint對象的build()方法,下文再聊具體細節。
當然,Schema Builder是可以在任意模塊中使用的,如在路由中使用,執行https://localhost:8888/create_accounts就可以創建一個accounts表了:
Route::get("create_accounts", function () { IlluminateSupportFacadesSchema::create("accounts", function(IlluminateDatabaseSchemaBlueprint $table) { $table->increments("id"); $table->string("name"); $table->string("number"); $table->tinyInteger("status"); $table->enum("source", ["bank account", "credit card", "investment account"]); $table->timestamps(); }); });(2)dropping tables
Schema Builder提供了兩個方法來刪除表:drop(string $table)和dropIfExists(string $table),參數是表名,dropIfExists()表示只有在表存在才刪除,所以dropIfExists()比drop()更優雅。看下兩個方法的源碼:
/** * Drop a table from the schema. * * @param string $table * @return IlluminateDatabaseSchemaBlueprint */ public function drop($table) { $blueprint = $this->createBlueprint($table); $blueprint->drop(); $this->build($blueprint); } /** * Drop a table from the schema if it exists. * * @param string $table * @return IlluminateDatabaseSchemaBlueprint */ public function dropIfExists($table) { $blueprint = $this->createBlueprint($table); $blueprint->dropIfExists(); $this->build($blueprint); } // IlluminateDatabaseSchemaBlueprint public function drop() { return $this->addCommand("drop"); } public function dropIfExists() { return $this->addCommand("dropIfExists"); }
同樣是使用了Blueprint對象來添加命令drop和dropIfExists。在路由中刪除accounts表:
Route::get("delete_accounts", function () { IlluminateSupportFacadesSchema::dropIfExists("accounts"); // IlluminateSupportFacadesSchema::drop("accounts"); });(3)updating tables
更新表的操作包括更新表名和更新表字段。
使用Schema::rename($from, $to)方法來更新表名:
Route::get("rename_bank_accounts", function () { IlluminateSupportFacadesSchema::rename("accounts", "bank_accounts"); });
看下Schema的rename()源碼,同樣是使用Blueprint對象添加rename命令:
public function rename($from, $to) { $blueprint = $this->createBlueprint($from); $blueprint->rename($to); $this->build($blueprint); } // IlluminateDatabaseSchemaBlueprint public function rename($to) { return $this->addCommand("rename", compact("to")); }
使用Schema::table()方法來更新表字段值,如更新accounts的number字段,,不過如果該表中有字段類型為enum就不支持修改:
Route::get("update_accounts", function () { IlluminateSupportFacadesSchema::table("accounts", function(IlluminateDatabaseSchemaBlueprint $table) { $table->string("number", 50)->change(); }); });
同時,Schema還提供了幾個有用的方法,如hasTable($table),hasColumn($table, $column),hasColumns($table, array $column),getColumnListing($table):
Route::get("get_column_listing", function () { // if (IlluminateSupportFacadesSchema::hasTable("accounts")) // if (IlluminateSupportFacadesSchema::hasColumn("accounts", "name")) if (IlluminateSupportFacadesSchema::hasColumns("accounts", ["name"])) { // ["id", "name", "number", "status", "source", "created_at", "updated_at"] return IlluminateSupportFacadesSchema::getColumnListing("accounts"); } });字段的操作-column (1)adding columns
設計database時需要添加columns,上文說過這段邏輯是在Schema::create(),Schema::table()的閉包里執行的,利用Blueprint對象來依次添加每一個column字段屬性和Mysql中數據類型對應,如:
IlluminateSupportFacadesSchema::create("accounts", function(IlluminateDatabaseSchemaBlueprint $table) { $table->string("name"); // => $this->addColumn("string", $column, compact("length")); });
常用的Schema字段類型函數表如下:
Schema Column Type | MySQL Column Type |
---|---|
bigIncrements("id") | id UNSIGNED BIGINT |
bigInteger("number") | number BIGINT |
binary("data") | data BLOB |
boolean("is_viewed") | is_viewed BOOLEAN |
char("title", 50) | title CHAR(50) |
date("created_at") | created_at DATE |
dateTime("updated_at") | updated_at DATETIME |
decimal("amount", 2, 2) | amount DECIMAL(2,2) |
double("length", 10, 10) | length DOUBLE(10, 10) |
enum("source", ["fund", "equity"]) | source ENUM("fund", "equity") |
float("width", 5, 5) | width FLOAT(5, 5) |
json("options") | options JSON |
string("content") | content VARCHAR(255) |
text("description") | description TEXT |
... | ... |
``
(2)removing columnsSchema提供了dropColumn()方法來刪除表中字段:
Route::get("drop_column", function () { IlluminateSupportFacadesSchema::table("accounts", function(IlluminateDatabaseSchemaBlueprint $table) { $table->dropColumn(["number", "status"]); }); });(3)renaming columns
Schema提供了renameColumn()來修改column名稱,不過如果該表中有字段類型為enum就不支持修改:
Route::get("rename_column", function () { IlluminateSupportFacadesSchema::table("accounts", function(IlluminateDatabaseSchemaBlueprint $table) { $table->renameColumn("name", "title"); }); });索引操作-index (1)simple index
Schema提供了index()方法來給column加索引,且索引名稱約定為table-name_column-name_index-type:
Route::get("index_column", function () { IlluminateSupportFacadesSchema::table("accounts", function(IlluminateDatabaseSchemaBlueprint $table) { $table->index("name"); }); });
同時,Schema提供了dropIndex("table-name_column-name_index")來刪除simple index。
(2)unique indexSchema提供了unique()方法來給column加索引,且索引名稱約定為table-name_column-name_index-type:
Route::get("unique_column", function () { IlluminateSupportFacadesSchema::table("accounts", function(IlluminateDatabaseSchemaBlueprint $table) { $table->unique(["title"]); }); });
同時,Schema提供了dropUnique("table-name_column-name_unique")來刪除unique index。
(3)foreign keySchema提供了foreign()->reference()->on() fluent api來設計foreign key,且索引名稱約定為table-name_column-name_index-type:
Route::get("foreign_key_column", function () { IlluminateSupportFacadesSchema::create("bills", function(IlluminateDatabaseSchemaBlueprint $table) { $table->increments("id"); $table->unsignedInteger("account_id"); $table->float("amount", 5, 5); $table->foreign("account_id") ->references("id") ->on("accounts") ->onUpdate("CASCADE") ->onDelete("CASCADE"); }); });
同時,Schema提供了dropForeign("table-name_column-name_foreign")來刪除foreign index。
總結:本篇主要學習下Laravel使用了Schema和Blueprint兩個類來設計database,中篇將以Schema::create()為例仔細研究下源碼是如何轉換為SQL并執行SQL語句的,下篇聊下Migration System的使用及其原理。到時見。
RightCapital招聘Laravel DevOps
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/21962.html
摘要:說明本文主要學習模塊的源碼。這里,就已經得到了鏈接器實例了,該中還裝著一個,下文在其使用時再聊下其具體連接邏輯。 說明:本文主要學習Laravel Database模塊的Query Builder源碼。實際上,Laravel通過Schema Builder來設計數據庫,通過Query Builder來CURD數據庫。Query Builder并不復雜或神秘,只是在PDO擴展的基礎上又開...
摘要:而且,與是一對多關系一個分類下有很多,一個只能歸屬于一個與是一對多關系一篇博客下有很多,一條只能歸屬于一篇與是多對多關系一篇有很多,一個下有很多。 說明:本文主要聊一聊Laravel測試數據填充器Seeder的小技巧,同時介紹下Laravel開發插件三件套,這三個插件挺好用哦。同時,作者會將開發過程中的一些截圖和代碼黏上去,提高閱讀效率。 備注:在設計個人博客軟件時,總會碰到有分類Ca...
摘要:抱歉,最近忙,本篇等有時間更新。引言本文基于框架做的一個生成和存儲,主要目的是學習使用框架。書籍基于的,學習時使用框架開發。開發環境備注一直想把這本書的個作為系列分享出來,供初學者學習玩玩。 抱歉,最近忙,本篇等有時間更新。 引言 本文基于Laravel框架做的一個URL生成和存儲demo,主要目的是學習使用Laravel框架。內容基于英文書籍《Packt.Laravel.Applic...
摘要:說明本文主要講述使用作為緩存加快頁面訪問速度。何不用來做緩存,等到該達到一定瀏覽頁面后再刷新下,效率也很高。可作緩存系統隊列系統。 說明:本文主要講述使用Redis作為緩存加快頁面訪問速度。同時,作者會將開發過程中的一些截圖和代碼黏上去,提高閱讀效率。 備注:作者最近在學習github上別人的源碼時,發現好多在計算一篇博客頁面訪問量view_count時都是這么做的:利用Laravel...
閱讀 3564·2023-04-26 00:05
閱讀 954·2021-11-11 16:55
閱讀 3522·2021-09-26 09:46
閱讀 3517·2019-08-30 15:56
閱讀 909·2019-08-30 15:55
閱讀 2934·2019-08-30 15:53
閱讀 1940·2019-08-29 17:11
閱讀 814·2019-08-29 16:52