您好,登錄后才能下訂單哦!
小編給大家分享一下Laravel5.7 Eloquent ORM怎么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
Laravel 內置的 Eloquent ORM 提供了一個美觀、簡單的與數據庫打交道的 ActiveRecord 實現,每張數據表都對應一個與該表進行交互的模型(Model),通過模型類,你可以對數據表進行查詢、插入、更新、刪除等操作。
在開始之前,確保在 config/database.php 文件中配置好了數據庫連接。
我們從創建一個 Eloquent 模型開始,模型類通常位于 app 目錄下,你也可以將其放在其他可以被 composer.json 文件自動加載到的地方。所有 Eloquent 模型都繼承自 Illuminate\Database\Eloquent\Model 類。
創建模型實例最簡單的辦法就是使用 Artisan 命令 make:model:
php artisan make:model Flight
如果你想要在生成模型時生成數據庫遷移,可以使用 --migration 或 -m 選項:
php artisan make:model Flight --migration php artisan make:model Flight -m
Eloquent 模型約定
現在,讓我們來看一個 Flight 模型的例子,我們將用該類獲取和存取數據表 flights 中的信息:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { // }
表名
注意我們并沒有告訴 Eloquent 我們的 Flight 模型使用哪張表,默認規則是小寫的模型類名復數格式作為與其對應的表名(除非在模型類中明確指定了其它名稱)。所以,在本例中,Eloquent 認為 Flight 模型存儲記錄在 flights 表中。你也可以在模型中定義 table 屬性來指定自定義的表名:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** * 關聯到模型的數據表 * * @var string */ protected $table = 'my_flights'; }
主鍵
Eloquent 默認每張表的主鍵名為 id,你可以在模型類中定義一個 $primaryKey 屬性來覆蓋該約定。
此外,Eloquent 默認主鍵字段是自增的整型數據,這意味著主鍵將會被自動轉化為 int 類型,如果你想要使用非自增或非數字類型主鍵,必須在對應模型中設置 $incrementing 屬性為 false,如果主鍵不是整型,還要設置 $keyType 屬性值為 string。
時間戳
默認情況下,Eloquent 期望 created_at 和 updated_at 已經存在于數據表中,如果你不想要這些 Laravel 自動管理的數據列,在模型類中設置 $timestamps 屬性為 false:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** * 表明模型是否應該被打上時間戳 * * @var bool */ public $timestamps = false; }
如果你需要自定義時間戳格式,設置模型中的 $dateFormat 屬性。該屬性決定日期被如何存儲到數據庫中,以及模型被序列化為數組或 JSON 時日期的格式:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** * 模型日期列的存儲格式 * * @var string */ protected $dateFormat = 'U'; }
如果你需要自定義用于存儲時間戳的字段名稱,可以在模型中設置 CREATED_AT 和 UPDATED_AT 常量:
<?php class Flight extends Model { const CREATED_AT = 'creation_date'; const UPDATED_AT = 'last_update'; }
數據庫連接
默認情況下,所有的 Eloquent 模型使用應用配置中的默認數據庫連接,如果你想要為模型指定不同的連接,可以通過 $connection 屬性來設置:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** * The connection name for the model. * * @var string */ protected $connection = 'connection-name'; }
創建完模型及其關聯的數據表后,就可以從數據庫中獲取數據了。將 Eloquent 模型看作功能強大的查詢構建器,你可以使用它來流暢的查詢與其關聯的數據表。例如:
<?php use App\Flight; $flights = App\Flight::all(); foreach ($flights as $flight) { echo $flight->name; }
添加額外約束
Eloquent 的 all 方法返回模型表的所有結果,由于每一個 Eloquent 模型都是一個查詢構建器,你還可以添加約束條件到查詢,然后使用 get 方法獲取對應結果:
$flights = App\Flight::where('active', 1) ->orderBy('name', 'desc') ->take(10) ->get();
注:由于 Eloquent 模型本質上就是查詢構建器,你可以在 Eloquent 查詢中使用查詢構建器的所有方法。
集合
對 Eloquent 中獲取多個結果的方法(比如 all 和 get)而言,其返回值是 Illuminate\Database\Eloquent\Collection 的一個實例,Collection 類提供了多個有用的函數來處理 Eloquent 結果集:
$flights = $flights->reject(function ($flight) { return $flight->cancelled; });
當然,你也可以像數組一樣循環遍歷該集合:
foreach ($flights as $flight) { echo $flight->name; }
組塊結果集
如果你需要處理數據量很大的 Eloquent 結果集,可以使用 chunk 方法。chunk 方法會獲取一個指定數量的 Eloquent 模型“組塊”,并將其填充到給定閉包進行處理。使用 chunk 方法在處理大量數據集合時能夠有效減少內存消耗:
Flight::chunk(200, function ($flights) { foreach ($flights as $flight) { // } });
傳遞給該方法的第一個參數是你想要獲取的“組塊”數目,閉包作為第二個參數被傳入用于處理每個從數據庫獲取的組塊數據。
使用游標
cursor 方法允許你使用游標迭代處理數據庫記錄,一次只執行單個查詢,在處理大批量數據時,cursor 方法可大幅減少內存消耗:
foreach (Flight::where('foo', 'bar')->cursor() as $flight) { // }
當然,除了從給定表中獲取所有記錄之外,還可以使用 find 和 first 獲取單個記錄。這些方法返回單個模型實例而不是模型集合:
// 通過主鍵獲取模型... $flight = App\Flight::find(1); // 獲取匹配查詢條件的第一個模型... $flight = App\Flight::where('active', 1)->first();
還可以通過傳遞主鍵數組來調用 find 方法,這將會返回匹配記錄集合:
$flights = App\Flight::find([1, 2, 3]);
Not Found 異常
有時候你可能想要在模型找不到的時候拋出異常,這在路由或控制器中非常有用,findOrFail 和 firstOrFail 方法會獲取查詢到的第一個結果。不過,如果沒有任何查詢結果,Illuminate\Database\Eloquent\ModelNotFoundException 異常將會被拋出:
$model = App\Flight::findOrFail(1); $model = App\Flight::where('legs', '>', 100)->firstOrFail();
如果異常沒有被捕獲,那么 HTTP 404 響應將會被發送給用戶,所以在使用這些方法的時候沒有必要對返回 404 響應編寫額外的檢查:
Route::get('/api/flights/{id}', function ($id) { return App\Flight::findOrFail($id); });
獲取聚合結果
當然,你還可以使用查詢構建器提供的聚合方法,例如 count、sum、max,以及其它查詢構建器提供的聚合函數。這些方法返回計算后的結果而不是整個模型實例:
$count = App\Flight::where('active', 1)->count(); $max = App\Flight::where('active', 1)->max('price');
插入
想要在數據庫中插入新的記錄,只需創建一個新的模型實例,設置模型的屬性,然后調用 save 方法:
<?php namespace App\Http\Controllers; use App\Flight; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class FlightController extends Controller{ /** * 創建一個新的航班實例 * * @param Request $request * @return Response * @translator laravelacademy.org */ public function store(Request $request) { // 驗證請求... $flight = new Flight; $flight->name = $request->name; $flight->save(); } }
在這個例子中,我們只是簡單分配 HTTP 請求中的 name 參數值給 App\Flight 模型實例的 name 屬性,當我們調用 save 方法時,一條記錄將會被插入數據庫。created_at 和 updated_at 時間戳在 save 方法被調用時會自動被設置,所以沒必要手動設置它們。
更新
save 方法還可以用于更新數據庫中已存在的模型。要更新一個模型,應該先獲取它,設置你想要更新的屬性,然后調用 save 方法。同樣,updated_at 時間戳會被自動更新,所以沒必要手動設置其值:
$flight = App\Flight::find(1); $flight->name = 'New Flight Name'; $flight->save();
批量更新
更新操作還可以同時修改給定查詢提供的多個模型實例,在本例中,所有有效且 destination=San Diego 的航班都被標記為延遲:
App\Flight::where('active', 1) ->where('destination', 'San Diego') ->update(['delayed' => 1]);
update 方法要求以數組形式傳遞鍵值對參數,代表著數據表中應該被更新的列。
注:通過 Eloquent 進行批量更新時,saved 和 updated 模型事件將不會在更新模型時觸發。這是因為在進行批量更新時并沒有從數據庫獲取模型。
批量賦值
還可以使用 create 方法保存一個新的模型。該方法返回被插入的模型實例。但是,在此之前,你需要指定模型的 fillable 或 guarded 屬性,因為所有 Eloquent 模型都通過批量賦值(Mass Assignment)進行保護,這兩個屬性分別用于定義哪些模型字段允許批量賦值以及哪些模型字段是受保護的,不能顯式進行批量賦值。
當用戶通過 HTTP 請求傳遞一個不被期望的參數值時就會出現安全隱患,然后該參數以不被期望的方式修改數據庫中的字段值。例如,惡意用戶通過 HTTP 請求發送一個 is_admin 參數,然后該參數映射到模型的 create 方法,從而允許用戶將自己變成管理員。
所以,你應該在模型中定義哪些屬性是可以進行賦值的,使用模型上的 $fillable 屬性即可實現。例如,我們設置 Flight 模型上的 name 屬性可以被賦值:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** * 可以被批量賦值的屬性. * * @var array */ protected $fillable = ['name']; }
設置完可以被賦值的屬性之后,我們就可以使用 create 方法在數據庫中插入一條新的記錄。create 方法返回保存后的模型實例:
$flight = App\Flight::create(['name' => 'Flight 10']);
如果你已經有了一個模型實例,可以使用 fill 方法通過數組屬性來填充:
$flight->fill(['name' => 'Flight 22']);
黑名單屬性
$fillable 就像是可以被賦值屬性的“白名單”,還可以選擇使用 $guarded。$guarded 屬性包含你不想被賦值的屬性數組。所以不被包含在其中的屬性都是可以被賦值的,因此,$guarded 功能就像“黑名單”。當然,這兩個屬性你只能同時使用其中一個而不能一起使用,因為它們是互斥的。下面的例子中,除了 price 之外的所有屬性都是可以賦值的:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** * 不能被批量賦值的屬性 * * @var array */ protected $guarded = ['price']; }
如果你想要讓所有屬性都是可批量賦值的,可以將 $guarded 屬性設置為空數組:
/** * The attributes that aren't mass assignable. * * @var array */ protected $guarded = [];
其它創建方法
firstOrCreate/firstOrNew
還有其它兩種可以用來創建模型的方法:firstOrCreate 和 firstOrNew。firstOrCreate 方法先嘗試通過給定列/值對在數據庫中查找記錄,如果沒有找到的話則通過給定屬性創建一個新的記錄。
firstOrNew 方法和 firstOrCreate 方法一樣先嘗試在數據庫中查找匹配的記錄,如果沒有找到,則返回一個新的模型實例。需要注意的是,通過 firstOrNew 方法返回的模型實例并沒有持久化到數據庫中,你還需要調用 save 方法手動持久化:
// 通過屬性獲取航班, 如果不存在則創建... $flight = App\Flight::firstOrCreate(['name' => 'Flight 10']); // 通過name獲取航班,如果不存在則通過name和delayed屬性創建... $flight = App\Flight::firstOrCreate( ['name' => 'Flight 10'], ['delayed' => 1] ); // 通過屬性獲取航班, 如果不存在初始化一個新的實例... $flight = App\Flight::firstOrNew(['name' => 'Flight 10']); // 通過name獲取,如果不存在則通過name和delayed屬性創建新實例... $flight = App\Flight::firstOrNew( ['name' => 'Flight 10'], ['delayed' => 1] );
updateOrCreate
與此類似的,你還會碰到如果模型已存在則更新,否則創建新模型的場景,Laravel 提供了一個 updateOrCreate 方法來一步完成。和 firstOrCreate 方法一樣,updateOrCreate 方法會持久化模型,所以無需調用 save():
// 如果有從奧克蘭到圣地亞哥的航班則將價格設置為 $99 // 如果沒有匹配的模型則創建之 $flight = App\Flight::updateOrCreate( ['departure' => 'Oakland', 'destination' => 'San Diego'], ['price' => 99] );
要刪除一個模型,調用模型實例上的 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 進行批量刪除時,deleting 和 deleted 模型事件在刪除模型時不會被觸發,這是因為在進行模型刪除時不會獲取模型。
軟刪除
除了從數據庫物理刪除記錄外,Eloquent 還可以對模型進行“軟刪除”。當模型被軟刪除后,它們并沒有真的從數據庫刪除,而是在模型上設置一個 deleted_at 屬性并插入數據庫,如果模型有一個非空 deleted_at 值,那么該模型已經被軟刪除了。要啟用模型的軟刪除功能,可以使用模型上的Illuminate\Database\Eloquent\SoftDeletes trait 并添加 deleted_at 列到 $dates 屬性:
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Flight extends Model { use SoftDeletes; /** * 應該被調整為日期的屬性 * * @var array */ protected $dates = ['deleted_at']; }
當然,應該添加 deleted_at 列到數據表。Laravel Schema 構建器包含一個輔助函數來創建該數據列:
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();
全局作用域
全局作用域允許我們為給定模型的所有查詢添加條件約束。Laravel 自帶的軟刪除功能就使用了全局作用域來從數據庫中拉出所有沒有被刪除的模型。編寫自定義的全局作用域可以提供一種方便的、簡單的方式來確保給定模型的每個查詢都有特定的條件約束。
編寫全局作用域
自定義全局作用域很簡單,首先定義一個實現 Illuminate\Database\Eloquent\Scope 接口的類,該接口要求你實現一個方法:apply。需要的話可以在 apply 方法中添加 where 條件到查詢:
<?php namespace App\Scopes; use Illuminate\Database\Eloquent\Scope; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; class AgeScope implements Scope { /** * 應用作用域到給定的Eloquent查詢構建器. * * @param \Illuminate\Database\Eloquent\Builder $builder * @param \Illuminate\Database\Eloquent\Model $model * @return void * @translator laravelacademy.org */ public function apply(Builder $builder, Model $model) { return $builder->where('age', '>', 200); } }
Laravel 應用默認并沒有為作用域預定義文件夾,所以你可以按照自己的喜好在 app 目錄下創建 Scopes 目錄。
注:如果你的全局作用域需要添加列到查詢的 select 子句,需要使用 addSelect 方法來替代 select,這樣就可以避免已存在的 select 查詢子句造成影響。
應用全局作用域
要將全局作用域應用到模型,需要重寫給定模型的 boot 方法并使用 addGlobalScope 方法:
<?php namespace App; use App\Scopes\AgeScope; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * 模型的“啟動”方法. * * @return void */ protected static function boot() { parent::boot(); static::addGlobalScope(new AgeScope); } }
添加作用域后,如果使用 User::all() 查詢則會生成如下 SQL 語句:
select * from `users` where `age` > 200
匿名的全局作用域
Eloquent 還允許我們使用閉包定義全局作用域,這在實現簡單作用域的時候特別有用,這樣的話,我們就沒必要定義一個單獨的類了:
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; class User extends Model{ /** * The "booting" method of the model. * * @return void */ protected static function boot() { parent::boot(); static::addGlobalScope('age', function(Builder $builder) { $builder->where('age', '>', 200); }); } }
移除全局作用域
如果想要在給定查詢中移除指定全局作用域,可以使用 withoutGlobalScope 方法,該方法接收全局作用域的類名作為其唯一參數:
User::withoutGlobalScope(AgeScope::class)->get();
或者,如果你使用閉包定義的全局作用域的話:
User::withoutGlobalScope('age')->get();
如果你想要移除某幾個或全部全局作用域,可以使用 withoutGlobalScopes 方法:
// 移除所有全局作用域 User::withoutGlobalScopes()->get(); //移除某些全局作用域 User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get();
本地作用域
本地作用域允許我們定義通用的約束集合以便在應用中復用。例如,你可能經常需要獲取最受歡迎的用戶,要定義這樣的一個作用域,只需簡單在對應 Eloquent 模型方法前加上一個 scope 前綴。
作用域總是返回查詢構建器實例:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * 只包含活躍用戶的查詢作用域 * * @return \Illuminate\Database\Eloquent\Builder */ public function scopePopular($query) { return $query->where('votes', '>', 100); } /** * 只包含激活用戶的查詢作用域 * * @return \Illuminate\Database\Eloquent\Builder */ public function scopeActive($query) { return $query->where('active', 1); } }
使用本地作用域
作用域被定義好了之后,就可以在查詢模型的時候調用作用域方法,但調用時不需要加上 scope 前綴,你甚至可以同時調用多個作用域,例如:
$users = App\User::popular()->active()->orderBy('created_at')->get();
動態作用域
有時候你可能想要定義一個可以接收參數的作用域,你只需要將額外的參數添加到你的作用域即可。作用域參數應該被定義在 $query 參數之后:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * 讓查詢只包含給定類型的用戶 * * @param \Illuminate\Database\Eloquent\Builder $query * @param mixed $type * @return \Illuminate\Database\Eloquent\Builder */ public function scopeOfType($query, $type) { return $query->where('type', $type); } }
現在,你可以在調用作用域時傳遞參數了:
$users = App\User::ofType('admin')->get();
有時候你可能需要確定兩個模型是否是一樣的,is 方法可用于快速驗證兩個模型是否有相同的主鍵、數據表、以及數據庫連接:
if ($post->is($anotherPost)) { // }
事件
Eloquent 模型可以觸發事件,允許你在模型生命周期中的多個時間點調用如下這些方法:retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored。事件允許你在一個指定模型類每次保存或更新的時候執行代碼。
retrieved 事件會在從數據庫中獲取已存在模型時觸發。當一個新模型被首次保存的時候,creating 和 created 事件會被觸發。如果一個模型已經在數據庫中存在并調用 save 方法,updating/updated 事件會被觸發,無論是創建還是更新,saving/saved 事件都會被觸發。
注:通過 Eloquent 進行批量更新時,模型事件 saved 和 updated 不會在更新模型上觸發,這是因為這些模型在進行批量更新時沒有真正檢索過。
舉個例子,在 Eloquent 模型中定義一個 $dispatchesEvents 屬性來映射模型生命周期中多個時間點與對應事件類:
<?php namespace App; use App\Events\UserSaved; use App\Events\UserDeleted; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use Notifiable; /** * The event map for the model. * * @var array */ protected $dispatchesEvents = [ 'saved' => UserSaved::class, 'deleted' => UserDeleted::class, ]; }
觀察者
定義觀察者
如果你在給定模型中監聽多個事件,可以使用觀察者來對所有監聽器分組到一個類中,觀察者類擁有反射你想要監聽的 Eloquent 事件對應的方法名,每個方法接收模型作為唯一參數。Artisan 命令 make:observer 是創建新的觀察者類的最簡單的方法:
php artisan make:observer UserObserver --model=User
該命令會將新的觀察者生成到 App/Observers 目錄,如果這個目錄不存在,Artisan 會自動創建。剛創建的觀察者類代碼如下:
<?php namespace App\Observers; use App\User; class UserObserver { /** * Handle to the User "created" event. * * @param \App\User $user * @return void */ public function created(User $user) { // } /** * Handle the User "updated" event. * * @param \App\User $user * @return void */ public function updated(User $user) { // } /** * Handle the User "deleted" event. * * @param \App\User $user * @return void */ public function deleted(User $user) { // } }
要注冊觀察者,使用你想要觀察模型的 observe 方法,你可以在某個服務提供者的 boot 方法中注冊觀察者,在本例中,我們在 AppServiceProvider 中注冊觀察者:
<?php namespace App\Providers; use App\User; use App\Observers\UserObserver; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { User::observe(UserObserver::class); } /** * Register the service provider. * * @return void */ public function register() { // } }
以上是“Laravel5.7 Eloquent ORM怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。