Eloquent: 入門- Laravel - 為網頁藝術家創造的PHP 框架

文章推薦指數: 80 %
投票人數:10人

所有的Eloquent 模型都繼承 Illuminate\Database\Eloquent\Model 類別。

建立模型實例的最簡單的方法是使用 make:model Artisan 指令: php artisan make:model ... Laravel 文件 Laracasts News Forge Ecosystem GitHub Envoyer Lumen Spark Forums Jobs Podcast Slack Twitter 5.2 Master 5.3 5.2 5.1 5.0 4.2 ☰ 首頁 文件 Laracasts News Forge Ecosystem GitHub Envoyer Lumen Spark Forums Jobs Podcast Slack Twitter 文件 前言 發行說明 升級導引 貢獻導引 API文件 環境設定 安裝 設定 Homestead 教學 初級任務清單 中級任務清單 基本功能 路由 中介層 控制器 請求 回應 視圖 Blade模板 系統架構 請求的生命週期 應用程式結構 服務提供者 服務容器 Facades 系統服務 認證 授權 Artisan指令列 交易 快取 集合 Elixir 加密 錯誤與日誌 事件 檔案系統與雲端儲存 雜湊 輔助方法 在地化 郵件 套件開發 分頁 隊列 Redis Session SSH任務 任務排程 測試 驗證 資料庫 入門 查詢建構器 遷移 資料填充 EloquentORM 入門 關聯 集合 存取器 序列化 前言 發行說明 升級導引 貢獻導引 API文件 環境設定 安裝 設定 Homestead 教學 初級任務清單 中級任務清單 基本功能 路由 中介層 控制器 請求 回應 視圖 Blade模板 系統架構 請求的生命週期 應用程式結構 服務提供者 服務容器 Facades 系統服務 認證 授權 Artisan指令列 交易 快取 集合 Elixir 加密 錯誤與日誌 事件 檔案系統與雲端儲存 雜湊 輔助方法 在地化 郵件 套件開發 分頁 隊列 Redis Session SSH任務 任務排程 測試 驗證 資料庫 入門 查詢建構器 遷移 資料填充 EloquentORM 入門 關聯 集合 存取器 序列化 Eloquent:入門 簡介 定義模型 Eloquent模型慣例 取回多個模型 取回單一模型或集合 取回集合 新增和更新模型 基本新增 基本更新 批量賦值 刪除模型 軟刪除 查詢被軟刪除的模型 查詢範圍 全域範圍 查詢範圍 事件 簡介 Laravel的EloquentORM提供了漂亮、簡潔的ActiveRecord實作來和資料庫互動。

每個資料庫表有一個對應的「模型」可以用來跟資料表互動。

你可以透過模型查詢資料表內的資料,以及新增記錄到資料表中。

在開始之前,請確認有設定你的資料庫連結在config/database.php檔案內。

更多資料庫的設定資訊,請查看資料庫設定。

定義模型 開始之前,讓我們先建立一個Eloquent模型。

模型通常放在app目錄,不過你可以自由地把他們放在任何可以透過你的composer.json自動載入的地方。

所有的Eloquent模型都繼承Illuminate\Database\Eloquent\Model類別。

建立模型實例的最簡單的方法是使用make:modelArtisan指令: phpartisanmake:modelUser 假設當你生成一個模型時,想要產生一個資料庫遷移,可以使用--migration或-m選項: phpartisanmake:modelUser--migration phpartisanmake:modelUser-m Eloquent模型慣例 現在,讓我們來看一個Flight模型類別的例子,我們將會用它來從flights資料表取回與儲存資訊:
除非明確地指定其他名稱,不然類別的小寫、底線、複數形式會拿來當作資料表的表單名稱。

所以,這個案例中,Eloquent將會假設Flight模型儲存記錄在flights資料表。

你可以在模型上定義一個table屬性,用來指定自訂的資料表:
* *@varstring */ protected$table='my_flights'; } 主鍵 Eloquent也會假設每個資料表有一個主鍵欄位叫做id。

你可以定義一個$primaryKey屬性來覆寫這個慣例。

時間戳記 預設情況下,Eloquent預期你的資料表會有created_at和updated_at欄位。

如果你不希望讓Eloquent來自動維護這兩個欄位,在你的模型內將$timestamps屬性設定為false:
* *@varbool */ public$timestamps=false; } 如果你需要客製化你的時間戳記格式,在你的模型內設定$dateFormat屬性。

這個屬性決定日期如何在資料庫中儲存,以及當模型被序列化成陣列或是JSON時的格式:
* *@varstring */ protected$dateFormat='U'; } 資料庫連接 預設情況下,所有的Eloquent模型會使用你應用程式中預設的資料庫連接設定。

如果你想為模型指定不同的連接,可以使用$connection屬性:
* *@varstring */ protected$connection='connection-name'; } 取回多個模型 一旦你建立了一個模型並且將模型關連到資料表,你就可以從資料庫中取得資料。

把每個Eloquent模型想像成強大的查詢建構器,讓你可以流暢地查詢與模型關聯的資料表。

例如:
* *@returnResponse */ publicfunctionindex() { $flights=Flight::all(); returnview('flight.index',['flights'=>$flights]); } } 存取欄位的值 假設你有一個Eloquent模型的實例,你可以透過相對應的屬性來存取模型的欄位值。

例如,讓我們遍歷查詢所返回的每個Flight實例,並且印出name欄位的值: foreach($flightsas$flight){ echo$flight->name; } 增加額外的限制 Eloquent的all方法會回傳在模型資料表中所有的結果。

由於每個Eloquent模型可以當作一個查詢建構器,所以你可以在查詢中增加規則,然後透過get方法來取得結果: $flights=App\Flight::where('active',1) ->orderBy('name','desc') ->take(10) ->get(); 注意:由於Eloquent模型是查詢建構器,應該檢閱所有查詢建構器可用的方法。

你可以在你的Eloquent查詢中使用這其中的任何方法。

集合 像是all以及get之類可以取回多筆結果的Eloquent方法,將會回傳一個Illuminate\Database\Eloquent\Collection實例。

Collection類別提供多樣的輔助方法用來處理你的Eloquent結果。

當然,你也可以簡單地像陣列一樣遍歷你的集合: foreach($flightsas$flight){ echo$flight->name; } 分塊結果 如果你需要處理上千筆Eloquent查詢結果,可以使用chunk命令。

chunk方法將會取得一個Eloquent模型的「分塊」,將它們送到給定的閉包(Closure)進行處理。

當你在處理大量的結果時,使用chunk方法可以節省記憶體: Flight::chunk(200,function($flights){ foreach($flightsas$flight){ // } }); 傳遞到方法的第一個參數是表示你希望每次「分塊」要接收的資料數量。

閉包則作為第二個參數傳遞,它將會在每次從資料取出分塊時被呼叫。

取回單一模型/集合 當然,除了從給定的資料表取回所有記錄,你也可以透過find和first取回單一的記錄。

這些方法回傳單一模型的實例,而不是回傳模型的集合: //藉由主鍵取回一個模型... $flight=App\Flight::find(1); //取回符合查詢限制的第一個模型... $flight=App\Flight::where('active',1)->first(); 找不到的例外 有時候你可能希望在找不到模型時拋出例外,這在路由或是控制器內特別有用。

findOrFail以及firstOrFail方法會取回查詢的第一個結果。

而如果沒有找到結果,將會拋出一個Illuminate\Database\Eloquent\ModelNotFoundException: $model=App\Flight::findOrFail(1); $model=App\Flight::where('legs','>',100)->firstOrFail(); 如果沒有捕捉到例外,會自動地送回HTTP404回應給使用者,所以當使用這些方法時,沒有必要明確的撰寫檢查已回傳404回應 Route::get('/api/flights/{id}',function($id){ returnApp\Flight::findOrFail($id); }); 取回集合 當然,你也可以使用count、sum、max,和其他查詢建構器提供的聚合函式。

這些方法會回傳適當的純量值,而不是一個完整的模型實例: $count=App\Flight::where('active',1)->count(); $max=App\Flight::where('active',1)->max('price'); 新增和更新模型 基本新增 要在資料庫中建立一筆新記錄,只要建立一個新模型實例,並在模型上設定屬性,再呼叫save方法:
* *@paramRequest$request *@returnResponse */ publicfunctionstore(Request$request) { //驗證請求... $flight=newFlight; $flight->name=$request->name; $flight->save(); } } 在這個範例中,我們把進來的HTTP請求的name參數簡單地指定給App\Flight模型實例的name屬性。

當我們呼叫save方法,就會新增一筆記錄到資料庫中。

當save方法被呼叫時,created_at以及updated_at時間戳記將會自動被設定,所以不需要手動去設定它們。

基本更新 save方法也可以用於更新資料庫中已經存在的模型。

要更新模型,你必須先取回模型,設定任何你希望更新的屬性,接著呼叫save方法。

同樣的,updated_at時間戳記將會自動被更新,所以不需要手動設定它的值: $flight=App\Flight::find(1); $flight->name='NewFlightName'; $flight->save(); 也可以針對符合給定查詢的任意數量模型執行更新。

在這個範例中,所有active並且destination為SanDiego的航班,將會被標記為延遲: App\Flight::where('active',1) ->where('destination','SanDiego') ->update(['delayed'=>1]); update方法預期收到一個欄位與值成對的陣列,來代表應該被更新的欄位。

批量賦值 你也可以使用create方法來在一行間儲存一個新的模型。

被新增的模型實例將會從你的方法回傳。

然而,在這樣做之前,你需要在你的模型上指定一個fillable或guarded屬性,因為所有的Eloquent模型有針對批量賦值(Mass-Assignment)做保護。

當使用者透過HTTP請求傳入非預期的參數,並透過這些參數更改了資料庫中你不打算要改的欄位,就發生了批量賦值(Mass-Assignment)的漏洞。

例如,惡意使用者可能會透過HTTP請求傳送is_admin參數,然後對應到你模型的create方法,這讓該使用者把自己升級為一個管理者。

所以,在開始之前,你應該定義你希望哪些模型屬性是可以被批量賦值的。

你可以在模型上藉由$fillable屬性達到這個。

例如,讓我們來使Flight模型的name屬性可以被批量賦值:
* *@vararray */ protected$fillable=['name']; } 一旦我們已經設定屬性為可以被批量賦值的,我們可以使用create方法來新增一筆新記錄到資料庫。

create方法回傳已經被儲存的模型實例: $flight=App\Flight::create(['name'=>'Flight10']); $fillable作為一個可以被批量賦值的屬性的「白名單」,然而你也可以選擇使用$guarded。

$guarded屬性應該包含一個屬性的陣列,是你不想要被批量賦值的。

所有不在陣列裡面的其他屬性將會是可以被批量賦值的。

所以,$guarded的功能像是一個「黑名單」。

當然,你應該使用$fillable或$guarded-而不是兩者:
* *@vararray */ protected$guarded=['price']; } 在上面的範例當中,所有屬性除了price以外,都可以被批量賦值。

其他建立的方法 還有兩種其他方法,你可以用來透過屬性批量賦值建立你的模型:firstOrCreate和firstOrNew。

firstOrCreate方法將會使用給定的欄位/值對,來嘗試尋找資料庫中的記錄。

如果在資料庫找不到模型,將會用給定的屬性來新增一筆記錄。

firstOrNew方法類似firstOrCreate,會嘗試使用給定的屬性在資料庫中尋找符合的紀錄。

然而,假設找不到模型,將會回傳一個新的模型實例。

請注意firstOrnew回傳的模型還尚未保存到資料庫。

你需要透過手動呼叫save方法來保存它 //用屬性取回航班,或如果不存在則建立它... $flight=App\Flight::firstOrCreate(['name'=>'Flight10']); //用屬性取回航班,或實例化一個新實例... $flight=App\Flight::firstOrNew(['name'=>'Flight10']); 刪除模型 要刪除模型,必須在模型實例上呼叫delete方法: $flight=App\Flight::find(1); $flight->delete(); 透過鍵來刪除現有的模型 在上面的範例中,我們在呼叫delete方法之前,先從資料庫取回了模型。

然而,如果你知道模型中的主鍵,你可以不取回模型就直接刪除它。

如果要這麼做,請呼叫destroy方法: App\Flight::destroy(1); App\Flight::destroy([1,2,3]); App\Flight::destroy(1,2,3); 透過查詢來刪除模型 當然,你也可以在一組模型上執行刪除查詢。

在這個範例中,我們將會刪除所有被標記為不活躍的航班: $deletedRows=App\Flight::where('active',0)->delete(); 軟刪除 除了實際從資料庫中移除記錄,Eloquent也可以「軟刪除」模型。

當模型被軟刪除時,它們不是真的從資料庫中被移除。

而是deleted_at屬性被設定在模型上並新增到資料庫。

如果模型有一個非空值的deleted_at,代表模型已經被軟刪除了。

要在模型啟動軟刪除,必須在模型上使用Illuminate\Database\Eloquent\SoftDeletestrait並新增deleted_at欄位到你的$dates屬性:
* *@vararray */ protected$dates=['deleted_at']; } 當然,你應該添加deleted_at欄位到你的資料表。

Laravel結構產生器包含了一個輔助的方法用來建立這個欄位: Schema::table('flights',function($table){ $table->softDeletes(); }); 現在,當你在模型上呼叫delete方法,deleted_at欄位將會被設定成目前的日期和時間。

而且,當查詢有啟用軟刪除的模型時,被軟刪除的模型將會自動從所有的查詢結果中排除。

要確認給定的模型實例是否已經被軟刪除,可以使用trashed方法: if($flight->trashed()){ // } 查詢被軟刪除的模型 包含被軟刪除的模型 如上面所述,被軟刪除的模型將會自動從所有的查詢結果中排除。

然而,你可以藉由在查詢上呼叫withTrashed方法,強迫被軟刪除的模型出現在查詢結果: $flights=App\Flight::withTrashed() ->where('account_id',1) ->get(); withTrashed方法也可以被用在關聯查詢: $flight->history()->withTrashed()->get(); 只取得被軟刪除的模型 onlyTrashed方法會只取得被軟刪除的模型: $flights=App\Flight::onlyTrashed() ->where('airline_id',1) ->get(); 恢復被軟刪除的模型 有時候你可能希望「取消刪除」一個被軟刪除的模型。

要恢復一個被軟刪除的模型回到有效狀態,必須在模型實例上使用restore方法: $flight->restore(); 你也可以在查詢上使用restore方法來快速地恢復多個模型: App\Flight::withTrashed() ->where('airline_id',1) ->restore(); 與withTrashed方法類似,restore方法也可以被用在關聯: $flight->history()->restore(); 永久地刪除模型 有時候你可能需要真正地從資料庫移除模型。

要永久地從資料庫移除一個被軟刪除的模型,必須使用forceDelete方法: //強制刪除單一模型實例... $flight->forceDelete(); //強制刪除所有相關模型... $flight->history()->forceDelete(); 查詢範圍 全域範圍 全域範圍讓你可以增加條件到all查詢至給定的模型。

Laravel本身的軟刪除功能利用全域範圍從資料庫只拉回「不刪除」的模型。

撰寫你自己的全域範圍可以提供方便、簡單的方式來確保給定模型的每個搜尋都取得條件的約束。

撰寫全域範圍 撰寫全域範圍是很簡單的。

定義一個類別並實作Illuminate\Database\Eloquent\Scope介面。

這個介面要求你實作一個方法:apply。

apply方法可以根據需求來增加where搜尋條件:
* *@param\Illuminate\Database\Eloquent\Builder$builder *@param\Illuminate\Database\Eloquent\Model$model *@returnvoid */ publicfunctionapply(Builder$builder,Model$model) { return$builder->where('age','>',200); } } 在預設的Laravel應用程式裡沒有預先定義範圍(scpoes)的資料夾,所以你可以自由地在Laravel應用程式的app目錄中建立自己的Scopes資料夾。

使用全域範圍 要分配一個全域範圍到模型,你應該覆寫給定的模型的boot方法和使用addGlobalScope方法:
* *@returnvoid */ protectedstaticfunctionboot() { parent::boot(); static::addGlobalScope(newOldScope); } } 在增加範圍之後,User::all()查詢將會產生以下的SQL: select*from`users`where`age`>200 匿名全域範圍 Eloquent還允許你使用Closures來定義全域範圍,這在簡單的作用域內相當的有用,但是不保證在獨立的類別內:
* *@returnvoid */ protectedstaticfunctionboot() { parent::boot(); static::addGlobalScope('old',function(Builder$builder){ $builder->where('age','>',200) }); } } addGlobalScope()第一個參數用來當作移除範圍的識別: User::withoutGlobalScope('old')->get(); 移除全域範圍 如果你想要移除在全域範圍內給定的查詢,你可以使用withoutGlobalScope方法: User::withoutGlobalScope(OldScope::class)->get(); 如果你想要移除幾個甚至所有的全域範圍,你可以使用withoutGlobalScopes方法: User::withoutGlobalScopes()->get(); User::withoutGlobalScopes([FirstScope::class,SecondScope::class])->get(); 局部範圍 局部範圍讓你定義限制的共用集合,它可以輕鬆地在你的應用程式重複使用。

例如,你可能需要頻繁地取得所有被認為是「受歡迎的」使用者。

要定義範圍,必須簡單地在Eloquent模型方法前面加上前綴scope 範圍應總是回傳查詢建構器的實例:
* *@return\Illuminate\Database\Eloquent\Builder */ publicfunctionscopePopular($query) { return$query->where('votes','>',100); } /** *限制查詢只包括活躍的使用者。

* *@return\Illuminate\Database\Eloquent\Builder */ publicfunctionscopeActive($query) { return$query->where('active',1); } } 利用查詢範圍 一旦定義了範圍,你可以在查詢模型時呼叫範圍方法。

然而,當你呼叫方法時,你不需要加上scope前綴。

你甚至能串接不同的範圍呼叫,例如: $users=App\User::popular()->active()->orderBy('created_at')->get(); 動態範圍 有時候,你可能希望定義一個接受參數的範圍。

只要在你的範圍加上額外的參數即可。

範圍參數應該被定義在$query參數之後:
* *@return\Illuminate\Database\Eloquent\Builder */ publicfunctionscopeOfType($query,$type) { return$query->where('type',$type); } } 現在,你可以在呼叫範圍時傳遞參數: $users=App\User::ofType('admin')->get(); 事件 Eloquent模型會觸發許多事件,讓你可以藉由以下的方法,在模型的生命週期的多個時間點進行操作:creating、created、updating、updated、saving、saved、deleting、deleted、restoring、restored。

事件讓你可以在每次特定的模型類別在資料庫被儲存或更新時,簡單地執行程式碼。

基本用法 當一個新模型初次被儲存,將會觸發creating以及created事件。

如果一個模型已經存在於資料庫而且呼叫了save方法,將會觸發updating和updated事件。

然而,在這兩個狀況下,都將會觸發saving和saved事件。

例如,讓我們來在服務提供者中定義一個Eloquent事件監聽器。

在我們的事件監聽器中,我們會在給定的模型上呼叫isValid方法,並在模型無效的時候回傳false。

從Eloquent事件監聽器回傳false會取消save和update的操作:
* *@returnvoid */ publicfunctionboot() { User::creating(function($user){ if(!$user->isValid()){ returnfalse; } }); } /** *註冊服務提供者。

* *@returnvoid */ publicfunctionregister() { // } }



請為這篇文章評分?