# Eloquent: 入門
- [簡介](#introduction)
- [定義模型](#defining-models)
- [Eloquent 模型約定](#eloquent-model-conventions)
- [取回多個模型](#retrieving-models)
- [集合](#collections)
- [分塊結果](#chunking-results)
- [取回單個模型或集合](#retrieving-single-models)
- [取回集合](#retrieving-aggregates)
- [添加和更新模型](#inserting-and-updating-models)
- [基本添加](#inserts)
- [基本更新](#updates)
- [批量賦值](#mass-assignment)
- [其他創建方法](#other-creation-methods)
- [刪除模型](#deleting-models)
- [軟刪除](#soft-deleting)
- [查詢被軟刪除的模型](#querying-soft-deleted-models)
- [查詢作用域](#query-scopes)
- [全局作用域](#global-scopes)
- [本地作用域](#local-scopes)
- [事件](#events)
- [觀察器](#observers)
<a name="introduction"></a>
## 簡介
Laravel 的 Eloquent ORM 提供了漂亮、簡潔的 ActiveRecord 實現來和數據庫進行交互。每個數據庫表都有一個對應的「模型」可用來跟數據表進行交互。你可以通過模型查詢數據表內的數據,以及將記錄添加到數據表中。
在開始之前,請確認你已在 `config/database.php` 文件中設置好了數據庫連接。更多數據庫的設置信息請查看 [數據庫設置](/docs/{{version}}/database#configuration) 文檔。
<a name="defining-models"></a>
## 定義模型
開始之前,讓我們先來創建一個 Eloquent 模型。模型通常放在 `app` 目錄中,不過你可以將他們隨意放在任何可通過 `composer.json` 自動加載的地方。所有的 Eloquent 模型都繼承自 `Illuminate\Database\Eloquent\Model` 類。
創建模型實例的最簡單方法是使用 `make:model` [Artisan 命令](/docs/{{version}}/artisan):
php artisan make:model User
當你生成一個模型時想要順便生成一個 [數據庫遷移](/docs/{{version}}/migrations),可以使用 `--migration` 或 `-m` 選項:
php artisan make:model User --migration
php artisan make:model User -m
<a name="eloquent-model-conventions"></a>
### 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`。 如果你想使用非遞增或者非數字的主鍵,你必須在你的模型 public `$incrementing` 屬性設置為`false`。
#### 時間戳
默認情況下,Eloquent 會認為在你的數據庫表有 `created_at` 和 `updated_at` 字段。如果你不希望讓 Eloquent 來自動維護這兩個字段,可在模型內將 `$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
{
/**
* 此模型的連接名稱。
*
* @var string
*/
protected $connection = 'connection-name';
}
<a name="retrieving-models"></a>
## 取回多個模型
一旦你創建并 [關聯了一個模型到數據表](/docs/{{version}}/schema) 上,那么你就可以從數據庫中獲取數據。可把每個 Eloquent 模型想像成強大的 [查詢構造器](/docs/{{version}}/queries),它讓你可以流暢地查詢與模型關聯的數據表。例如:
<?php
use App\Flight;
$flights = App\Flight::all();
foreach ($flights as $flight) {
echo $flight->name;
}
#### 增加額外的限制
Eloquent 的 `all` 方法會返回在模型數據表中的所有結果。由于每個 Eloquent 模型都可以當作一個 [查詢構造器](/docs/{{version}}/queries),所以你可以在查詢中增加規則,然后使用 `get` 方法來獲取結果:
$flights = App\Flight::where('active', 1)
->orderBy('name', 'desc')
->take(10)
->get();
> {tip} 由于 Eloquent 模型是查詢構造器,因此你應當去閱讀 [查詢構造器](/docs/{{version}}/queries) 中所有可用的方法。你可在 Eloquent 查詢中使用這其中的任何方法。
<a name="collections"></a>
### 集合
類似 `all` 以及 `get` 之類的可以取回多個結果的 Eloquent 方法,將會返回一個 `Illuminate\Database\Eloquent\Collection` 實例。`Collection` 類提供 [多種輔助函數](/docs/{{version}}/eloquent-collections#available-methods) 來處理你的 Eloquent 結果。
$flights = $flights->reject(function ($flight) {
return $flight->cancelled;
});
當然,你也可以簡單地像數組一樣來遍歷集合:
foreach ($flights as $flight) {
echo $flight->name;
}
<a name="chunking-results"></a>
### 分塊結果
如果你需要處理數以千計的 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) {
//
}
<a name="retrieving-single-models"></a>
## 取回單個模型/集合
當然,除了從指定的數據表取回所有記錄,你也可以通過 `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();
如果該異常沒有被捕獲,則會自動返回 HTTP `404` 響應給用戶,因此當使用這些方法時,你沒有必要明確的編寫檢查來返回 `404` 響應:
Route::get('/api/flights/{id}', function ($id) {
return App\Flight::findOrFail($id);
});
<a name="retrieving-aggregates"></a>
### 取回集合
當然,你也可以使用 `count`、`sum`、`max`,和其它 [查詢構造器](/docs/{{version}}/queries) 提供的 [聚合函數](/docs/{{version}}/queries#aggregates)。這些方法會返回適當的標量值,而不是一個完整的模型實例:
$count = App\Flight::where('active', 1)->count();
$max = App\Flight::where('active', 1)->max('price');
<a name="inserting-and-updating-models"></a>
## 添加和更新模型
<a name="inserts"></a>
### 基本添加
要在數據庫中創建一條新記錄,只需創建一個新模型實例,并在模型上設置屬性和調用 `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` 方法,就會添加一條記錄到數據庫中。當 `save` 方法被調用時,`created_at` 以及 `updated_at` 時間戳將會被自動設置,因此我們不需要去手動設置它們。
<a name="updates"></a>
### 基本更新
`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`模型事件將不會被更新后的模型代替。這是因為批量更新時,模型從來沒有被取回。
<a name="mass-assignment"></a>
### 批量賦值
你也可以使用 `create` 方法通過一行代碼來保存一個新模型。被插入數據庫的模型實例將會返回給你。不過,在這樣做之前,你需要先在你的模型上定義一個 `fillable` 或 `guarded` 屬性,因為所有的 Eloquent 模型都針對批量賦值(Mass-Assignment)做了保護。
當用戶通過 HTTP 請求傳入了非預期的參數,并借助這些參數更改了數據庫中你并不打算要更改的字段,這時就會出現批量賦值(Mass-Assignment)漏洞。例如,惡意用戶可能會通過 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']);
如果你已經有一個 `model` 實例,你可以使用一個數組傳遞給 `fill` 方法:
? ?$flight->fill(['name' => 'Flight 22']);
#### Guarding Attributes
`$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 = [];
<a name="other-creation-methods"></a>
### 其它創建的方法
#### `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()` :
// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.
$flight = App\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99]
);
<a name="deleting-models"></a>
## 刪除模型
要刪除模型,必須在模型實例上調用 `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` 模型事件不會在被刪除模型實例上觸發。因為刪除語句執行時,不會檢索回模型實例。
<a name="soft-deleting"></a>
### 軟刪除
除了從數據庫中移除實際記錄,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 [結構生成器](/docs/{{version}}/migrations) 包含了一個用來創建此字段的輔助函數:
Schema::table('flights', function ($table) {
$table->softDeletes();
});
現在,當你在模型上調用 `delete` 方法時,`deleted_at` 字段將會被設置成目前的日期和時間。而且,當查詢有啟用軟刪除的模型時,被軟刪除的模型將會自動從所有查詢結果中排除。
要確認指定的模型實例是否已經被軟刪除,可以使用 `trashed` 方法:
if ($flight->trashed()) {
//
}
<a name="querying-soft-deleted-models"></a>
### 查詢被軟刪除的模型
#### 包含被軟刪除的模型
如上所述,被軟刪除的模型將會自動從所有的查詢結果中排除。不過,你可以通過在查詢中調用 `withTrashed` 方法來強制查詢已被軟刪除的模型:
$flights = App\Flight::withTrashed()
->where('account_id', 1)
->get();
`withTrashed` 方法也可以被用在 [關聯](/docs/{{version}}/eloquent-relationships) 查詢:
$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` 方法也可以被用在 [關聯](/docs/{{version}}/eloquent-relationships) 查詢上:
$flight->history()->restore();
#### 永久地刪除模型
有時候你可能需要真正地從數據庫移除模型。要永久地從數據庫移除一個已被軟刪除的模型,則可使用 `forceDelete` 方法:
// 強制刪除單個模型實例...
$flight->forceDelete();
// 強制刪除所有相關模型...
$flight->history()->forceDelete();
<a name="query-scopes"></a>
## 查詢作用域
<a name="global-scopes"></a>
### 全局作用域
全局作用域允許我們為給定模型的所有查詢添加條件約束。Laravel 自帶的 [軟刪除功能](#soft-deleting) 就使用了全局作用域來從數據庫中拉出所有沒有被刪除的模型。編寫自定義的全局作用域可以提供一種方便的、簡單的方式,來確保給定模型的每個查詢都有特定的條件約束。
#### 編寫全局作用域
自定義全局作用域很簡單,首先定義一個實現 `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
{
/**
* 應用作用域
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
return $builder->where('age', '>', 200);
}
}
> {tip} Laravel 沒有規定你需要把這些類放置于哪個文件夾,你可以自由在 `app` 文件夾下創建 `Scopes` 文件夾來存放。
#### 應用全局作用域
要將全局作用域分配給模型,需要重寫給定模型的 `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
{
/**
* 數據模型的啟動方法
*
* @return void
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope('age', function(Builder $builder) {
$builder->where('age', '>', 200);
});
}
}
我們還可以通過以下方式,利用 `age` 標識符來移除全局作用:
User::withoutGlobalScope('age')->get();
#### 移除全局作用域
如果想要在給定查詢中移除指定全局作用域,可以使用 `withoutGlobalScope`:
User::withoutGlobalScope(AgeScope::class)->get();
如果你想要移除某幾個或全部全局作用域,可以使用 `withoutGlobalScopes` 方法:
User::withoutGlobalScopes()->get();
User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get();
<a name="local-scopes"></a>
### 本地作用域
本地作用域允許我們定義通用的約束集合以便在應用中復用。例如,你可能經常需要獲取最受歡迎的用戶,要定義這樣的一個作用域,只需簡單在對應 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
{
/**
* 限制查詢只包括指定類型的用戶。
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeOfType($query, $type)
{
return $query->where('type', $type);
}
}
現在,你可以在范圍調用時傳遞參數:
$users = App\User::ofType('admin')->get();
<a name="events"></a>
## 事件
Eloquent 模型會觸發許多事件,讓你在模型的生命周期的多個時間點進行監控:
`creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `restoring`, `restored`.
事件讓你每當有特定的模型類在數據庫保存或更新時,執行代碼。
當一個新模型被初次保存將會觸發 `creating` 以及 `created` 事件。如果一個模型已經存在于數據庫且調用了 `save` 方法,將會觸發 `updating` 和 `updated` 事件。在這兩種情況下都會觸發 `saving` 和 `saved` 事件。
開始前,在你的 Eloquent 模型上定義一個 `$events` 屬性,將 Eloquent 模型的生命周期的多個點映射到你的 [服務提供者](/docs/{{version}}/providers) 。
<?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,
];
}
<a name="observers"></a>
### 觀察者
如果你在一個給定的模型中監聽許多事件,您可以使用觀察者將所有監聽器變成一個類。觀察者類里的方法名應該反映Eloquent想監聽的事件。 每種方法接收 model 作為其唯一的參數。 Laravel不包括觀察者默認目錄,所以你可以創建任何你喜歡你的目錄來存放:
<?php
namespace App\Observers;
use App\User;
class UserObserver
{
/**
* 監聽用戶創建的事件。
*
* @param User $user
* @return void
*/
public function created(User $user)
{
//
}
/**
* 監聽用戶刪除事件。
*
* @param 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()
{
//
}
}
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@sml2h3](https://github.com/sml2h3) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/12218_1488347757.jpeg?imageView2/1/w/200/h/200"> | 翻譯 | [歡迎訪問個人博客→瘋狂極客](https://www.fkgeek.com) |
---
> {note} 歡迎任何形式的轉載,但請務必注明出處,尊重他人勞動共創開源社區。
>
> 轉載請注明:本文檔由 Laravel China 社區 [laravel-china.org](https://laravel-china.org) 組織翻譯,詳見 [翻譯召集帖](https://laravel-china.org/topics/5756/laravel-55-document-translation-call-come-and-join-the-translation)。
>
> 文檔永久地址: https://d.laravel-china.org
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- HomeStead
- Valet
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- 門面(Facades)
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- 重定向
- Session
- 表單驗證
- 錯誤與日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- 用戶認證
- API認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 交流說明