* * * * *
[TOC]
## 簡介
Laravel 的 Eloquent ORM 提供了漂亮、簡潔的 ActiveRecord 實現來和數據庫交互。每個數據庫表都有一個對應的「模型」用來與該表交互。你可以通過模型查詢數據表中的數據,并將新記錄添加到數據表中。
在開始之前,請確保在?`config/database.php`?中配置數據庫連接。更多關于數據庫的配置信息,請查看?[文檔](http://www.hmoore.net/tonyyu/laravel_5_6/786260#_11)。
## 定義模型
首先,創建一個 Eloquent 模型,生成的模型通常放在?`app`?目錄中,但你可以通過?`composer.json`?文件隨意地將它們放在可被自動加載的地方。所有的 Eloquent 模型都繼承了?`Illuminate\Database\Eloquent\Model`?類。
創建模型實例的最簡單方法是使用?[Artisan 命令](http://www.hmoore.net/tonyyu/laravel_5_6/786238)?`make:model`:
~~~
php artisan make:model User
~~~
如果要在生成模型時生成?[數據庫遷移](http://www.hmoore.net/tonyyu/laravel_5_6/786263)?,可以使用?`--migration`?或?`-m`?選項:
~~~
php artisan make:model User --migration
php artisan make:model User -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`?的主鍵字段。你可以定義一個訪問權限為`protected`的?`$primaryKey`?屬性來覆蓋這個約定。
另外,Eloquent 假定主鍵是一個遞增的整數值,這意味著在默認情況下主鍵會自動轉換為?`int`?。如果希望使用非遞增或者非數字的主鍵,則必須在模型上設置?`public $incrementing = false`?。如果主鍵不是一個整數,你應該在模型上設置?`protected $keyType = string`?。
#### 時間戳
默認情況下,Eloquent 會默認數據表中存在?`created_at`?和?`updated_at`?這兩個字段。如果你不需要這兩個字段,則需要在模型內將?`$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';
}
~~~
#### 數據庫連接
默認情況下,所有的模型使用應用配置中的默認數據庫連接。如果你想要為模型指定不同的連接,可以通過`$connection`?屬性來設置:
~~~
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* 數據模型專屬的數據庫連接
*
* @var string
*/
protected $connection = 'connection-name';
}
~~~
## 獲取模型
創建完模型及其?[關聯數據表](http://www.hmoore.net/tonyyu/laravel_5_6/786263)?之后,就可以從數據庫中獲取數據了。將每個 Eloquent 模型想像成強大的?[查詢構造器](http://www.hmoore.net/tonyyu/laravel_5_6/786261),你可以使用它來流暢的查詢與其關聯的數據表。例如:
~~~
<?php
use App\Flight;
$flights = App\Flight::all();
foreach ($flights as $flight) {
echo $flight->name;
}
~~~
#### 添加其他約束
Eloquent 的?`all`?方法會返回模型表中的所有結果。由于每個 Eloquent 模型都可以當作一個?[查詢構造器](http://www.hmoore.net/tonyyu/laravel_5_6/786261)?,因此你還可以在查詢中添加約束,然后使用?`get`?來獲取結果:
~~~
$flights = App\Flight::where('active', 1)
->orderBy('name', 'desc')
->take(10)
->get();
~~~
> {tip} Eloquent 模型是查詢構造器,因此你應當去閱讀?[查詢構造器](http://www.hmoore.net/tonyyu/laravel_5_6/786261)?提供的所有方法,以便你可以在 Eloquent 查詢中使用。
### 集合
使用 Eloquent 中的?`all`?和?`get`?方法可以檢索多個結果,并會返回一個?`Illuminate\Database\Eloquent\Collection`?實例。?`Collection`?類提供了?[很多輔助函數](http://www.hmoore.net/tonyyu/laravel_5_6/786274#_31)?來處理 Eloquent 結果。
~~~
$flights = $flights->reject(function ($flight) {
return $flight->cancelled;
});
~~~
你也可以像數組一樣簡單地來遍歷集合:
~~~
foreach ($flights as $flight) {
echo $flight->name;
}
~~~
### 分塊結果
如果你需要處理數千個 Eloquent 結果,可以使用?`chunk`?命令。?`chunk`?方法會檢索 Eloquent 模型的『分塊』,將它們提供給指定的?`Closure`?進行處理。在處理大型結果集時,使用?`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]);
~~~
#### 『找不到』異常
如果你希望在找不到模型時拋出異常,可以使用?`findOrFail`?以及?`firstOrFail`?方法。這些方法會檢索查詢的第一個結果,如果沒有找到相應的結果,就會拋出一個?`Illuminate\Database\Eloquent\ModelNotFoundException`?:
~~~
$model = App\Flight::findOrFail(1);
$model = App\Flight::where('legs', '>', 100)->firstOrFail();
~~~
如果沒有對異常進行捕獲,則會自動返回?`404`?響應給用戶。也就是說,在使用這些方法時,不需要另外寫個檢查來返回?`404`?響應:
~~~
Route::get('/api/flights/{id}', function ($id) {
return App\Flight::findOrFail($id);
});
~~~
### 檢索集合
你還可以使用?[查詢構造器](http://www.hmoore.net/tonyyu/laravel_5_6/786261)?提供的?`count`?、?`sum`?、?`max`?以及其它?[聚合函數](http://www.hmoore.net/tonyyu/laravel_5_6/786261#_106)?。這些方法只會返回適當的標量值而不是整個模型實例:
~~~
$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
*/
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();
~~~
#### 批量更新
也可一并更新查詢到的多個模型。這個例子中,所有?`active`?和?`destination`?為?`San Diego`?的航班都被更新為延誤:
~~~
App\Flight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]);
~~~
`update`?方法接受一個字段為鍵、更新數據為值的數組。
> {note} Eloquent 的批量更新不會觸發?`saved`?和?`updated`?事件。這是因為批量更新時,從不去檢索模型。
### 批量賦值
你也可以使用?`create`?方法來保存新模型, 方法會返回模型實例。不過,在使用之前,你需要先在模型上指定?`fillable`?或?`guarded`?屬性,因為所有的 Eloquent 模型在默認情況下都不能進行批量賦值。
當用戶通過 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`?從功能上講更像是一個『黑名單』。注意,在使用上,只能是?`$fillable`?或?`$guarded`?二選一。 下面這個例子中,**除了?`price`**?所有的屬性都可以被批量賦值:
~~~
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* 不可被批量賦值的屬性。
*
* @var array
*/
protected $guarded = ['price'];
}
~~~
將?`$guarded`?定義為空數組,則所有屬性都可以被批量賦值
~~~
/**
* 不可被批量賦值的屬性。
*
* @var array
*/
protected $guarded = [];
~~~
### 其它創建方法
#### `firstOrCreate`/?`firstOrNew`
這里有兩個可能被用的別的方法,你可以通過批量分配屬性來創建模型:?`firstOrCreate`?和?`firstOrNew`?。?`firstOrCreate`?方法將嘗試使用給定的列/值來查找數據庫。如果在數據庫找不到該模型,則會從第一個參數的屬性乃至第二個參數的屬性中創建一條記錄插入到數據庫。
`firstOrNew`?方法像?`firstOrCreate`?方法一樣將嘗試在與給定屬性相匹配的數據庫中查找記錄。不同的是,如果未找到模型,則會返回一個新的模型實例。注意?`firstOrNew`?返回的模型尚未被保存到數據庫中。你需要手動調用?`save`?方法保存:
~~~
// 通過 name 查找航班,不存在則創建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);
// 通過 name 查找航班,不存在則使用 name 和 delayed 屬性創建...
$flight = App\Flight::firstOrCreate(
['name' => 'Flight 10'], ['delayed' => 1]
);
// 通過 name 查找航班,不存在則創建一個實例...
$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();
~~~
> {note} 通過 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 的?[表結構構造器](http://www.hmoore.net/tonyyu/laravel_5_6/786263)?提供了一個輔助方法來生成這個字段:
~~~
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`?方法也可以用在?[關聯](http://www.hmoore.net/tonyyu/laravel_5_6/786273)?查詢:
~~~
$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`?方法,[關聯](http://www.hmoore.net/tonyyu/laravel_5_6/786273)?也可使用`restore`:
~~~
$flight->history()->restore();
~~~
#### 永久刪除
要真實刪除數據時,使用?`forceDelete`?方法即可把軟刪除模型從數據里永久刪除:
~~~
// 單個模型實例的永久刪除
$flight->forceDelete();
// 關聯模型的永久刪除
$flight->history()->forceDelete();
~~~
## 查詢作用域
### 全局作用域
全局作用域可以給模型的查詢都添加上約束。Laravel 的?[軟刪除](http://www.hmoore.net/tonyyu/laravel_5_6/786272#_470)?功能就是利用了「未刪除」的全局作用域。自定義全局作用域使用起來更方便、簡單,同時保證了每一個模型的查詢都受到特定約束。
#### 編寫全局作用域
編寫全局作用域非常簡單。定義一個實現?`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
*/
public function apply(Builder $builder, Model $model)
{
$builder->where('age', '>', 200);
}
}
~~~
> {tip} 如果需要在 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()`?的查詢語句如下:
~~~
select * from `users` where `age` > 200
~~~
#### 匿名的全局作用域
Eloquent 也可用閉包定義全局作用域,這樣就不必要再為一個簡單的作用域而編寫一個完整的類:
~~~
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class User extends 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
{
/**
* 只查詢受歡迎的用戶.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
/**
* 只查詢 active 的用戶.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @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();
~~~
## 事件
Eloquent 模型會觸發許多事件,讓你在模型的生命周期的多個時間點進行監控:?`retrieved`,?`creating`,?`created`,?`updating`,?`updated`,?`saving`,?`saved`,?`deleting`,?`deleted`,?`restoring`,?`restored`。 事件讓你在每當有特定模型類進行數據庫保存或更新時,執行代碼。
當從數據庫檢索現有模型時,會觸發`retrieved`?事件。當模型第一次被保存時,?`creating`?和?`created`?事件會被觸發。若數據庫中已存在此模型,并調用?`save`?方法,`updating`?/?`updated`?事件會被觸發。 這兩種情況下,`saving`?/?`saved`?事件都會被觸發。
開始前,先在你的 Eloquent 模型上定義一個?`$dispatchesEvents`?屬性,將 Eloquent 模型的生命周期的多個點映射到你的?[事件類](http://www.hmoore.net/tonyyu/laravel_5_6/786242):
~~~
<?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;
/**
* 此模型的事件映射.
*
* @var array
*/
protected $dispatchesEvents = [
'saved' => UserSaved::class,
'deleted' => UserDeleted::class,
];
}
~~~
### 觀察者
如果你在一個給定模型中監聽許多事件,你可以使用觀察者將所有的監聽添加到一個類。觀察者類里的方法名應該反映 Eloquent 想監聽的事件。 每個方法接受 model 作為唯一參數。Laravel 不包含觀察者的默認目錄,所以你可以創建任何你喜歡的目錄來存放觀察者類:
~~~
<?php
namespace App\Observers;
use App\User;
class UserObserver
{
/**
* 監聽創建用戶事件.
*
* @param \App\User $user
* @return void
*/
public function created(User $user)
{
//
}
/**
* 監聽刪除用戶事件.
*
* @param \App\User $user
* @return void
*/
public function deleting(User $user)
{
//
}
}
~~~
要注冊一個觀察者,需要用模型中的?`observe`?方法去觀察。 你可以在你得服務提供者之一的?`boot`?方法中注冊觀察者。在這個例子中,我們將在?`AppServiceProvider`?中注冊觀察者:
~~~
<?php
namespace App\Providers;
use App\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* 運行所有應用服務.
*
* @return void
*/
public function boot()
{
User::observe(UserObserver::class);
}
/**
* 注冊服務提供.
*
* @return void
*/
public function register()
{
//
}
}
~~~
- 前言
- 翻譯說明
- 發行說明
- 升級指南
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- Homestead
- Valet
- 部署
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- Facades
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- URL
- Session
- 表單驗證
- 錯誤
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全相關
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試相關
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Scout 全文搜索
- Socialite 社會化登錄