Eloquent ORM
- 介紹
- 基本使用
- 大量指定
- 新增、更新及刪除
- 微刪除
- 時間戳記
- 查詢範圍
- 關聯
- 查詢關聯
- 預先加載
- 新增相關模組
- 碰觸母節點時間戳記
- 使用數據透視表
- 聚集
- 存取及修改器
- 日期設置器
- 模組事件
- 模組觀察
- 轉換成陣列/JSON
介紹
Eloquent ORM 是 Laravel 提供的一個優雅、簡單的 ActiveRecord 實作資料庫的操作的方法,每個資料表有一個相對應的 "模型 (Model)" ,讓你可以對相對應的資料表進行互動操作。
在開始之前,要先確定你有在 app/config/database.php
檔案中設定好資料庫的連線資訊。
基本使用
在開始要建立 Eloquent 模型時,通常這些模型的檔案都放在 app/models
目錄下,但你也可以放在任何你想放的地方,只要能夠透過 composer.json
檔案中的設定去載入模型即可。
定義 Eloquent 模型
class User extends Eloquent {}
你會注意到,我們並沒有告訴 Eloquent 我們的 User
模型是要用哪一個資料表去做存取控制,除非你有另外指定要使用的資料表名稱,否則 Eloquent 將會使用類別名稱的"小寫"及"複數"的單字去當作預設的資料表名稱,所以在這個例子中, Eloquent 會假設 User
模型的資料是存放在 users
資料表中,你也可以在你的模型中使用 table
變數去指定你想要的使用的資料表名稱:
class User extends Eloquent {
protected $table = 'my_users';
}
注意: Eloquent 會假設每一個資料表的主鍵 (primary key) 名稱為
id
,你也可以使用primaryKey
變數去複寫原來的規則,同樣的,你也可以定義connection
變數去複寫你想要在這個模型中使用的資料庫連線。
只要模型一定義完成,你就可以開始取得或建立資料到你的資料表了,但這裡必須注意到,預設的情況下,你必須在資料表中建立 updated_at
及 created_at
這兩個欄位,用來記錄資料的建立時間及更新時間,如果你不希望模型去幫你自動維護資料建立時間及更新時間,在你的模型中你只要將 $timestamps
變數設定為 false
即可。
取得所有模型的資料
$users = User::all();
透過主鍵 (Primary Key) 取得單筆資料
$user = User::find(1);
var_dump($user->name);
注意: 所有在 Query產生器 的方法,在使用 Eloquent 模型時也可以使用。
透過主鍵 (Primary Key) 取得單筆資料,或丟出例外狀況
假如模型沒有找到指定的資料,有時你可能想要丟出例外狀況,讓你的例外狀況可以讓 App::error
捕捉到,並且呈現 404 頁面給使用者。
$model = User::findOrFail(1);
$model = User::where('votes', '>', 100)->firstOrFail();
傾聽 ModelNotFoundException
可以註冊一個模型錯誤處理器
use Illuminate\Database\Eloquent\ModelNotFoundException;
App::error(function(ModelNotFoundException $e)
{
return Response::make('Not Found', 404);
});
使用 Eloquent 模型進行查詢
$users = User::where('votes', '>', 100)->take(10)->get();
foreach ($users as $user)
{
var_dump($user->name);
}
當然你也可以使用查詢產生器去整合這些函式。
Eloquent 整合
$count = User::where('votes', '>', 100)->count();
大量指定
當建立模型時,你傳遞一個陣列屬性到模型建構子,這些屬性會經由大量指定 (mass-assignment) 的方式去指定到模型中,這樣是相當方便的,但是,當綁定使用者傳入的資料到模型中,也可能是一個 嚴重 的安全性問題,假如使用者傳入的資料綁定到模型,使用者就可以任意的修改 任何 (any) 和 所有 (all) 模型中的屬性,出於這個原因,所有的 Eloquent 模型預設會避免及保護資料不會被大量指定的方式所覆寫。
為了使用大量指定的功能,你必須在你的模型設定 fillable
或 guarded
變數資料。
fillable
變數指定那些欄位可以使用被大量指定功能指定資料,可以設定類別 (class) 或 實例 (instance) 層級的變數。
定義可大量指定的屬性欄位到模型
class User extends Eloquent {
protected $fillable = array('first_name', 'last_name', 'email');
}
在這個範例,只有清單中的三個變數屬性資料可以被使用大量指定方式修改
在 fillable
的反義屬性就是 guarded
,這屬性可以設定 "黑名單" 而不只是設定 "白名單" :
定義受保護的屬性欄位到模型
class User extends Eloquent {
protected $guarded = array('id', 'password');
}
在上述範例 id
及 password
屬性將不會被大量指定方式修改原模型的變數資料,所有除了這兩個變數外的變數,都可以被使用大量指定方式指定去修改資料,你也可以保護 所有 的屬性都不會被大量指定的方式修改資料值:
封鎖所有變數不被大量指定方式修改資料內容
protected $guarded = array('*');
新增、更新及刪除
為了透過模型建立一筆新的資料到資料庫,只需要建立新的模型實例後,並且呼叫 save
方法即可。
儲存新的模型資料
$user = new User;
$user->name = 'John';
$user->save();
注意: 通常你的 Eloquent 模型都會有一個自動增加的鍵值 (key),但你如果想要指定你自己的鍵值在模型中有自動增加的屬性,只要將
incrementing
設定為自動增加 (incrementing)
即可。
你可以使用 create
方法在單一行去儲存資料到模型中,插入 (INSERT) 的模型實例將會被回傳,但是在使用這樣的方式去儲存資料前,你需要在模型中指定 fillable
或 guarded
屬性,這樣 Eloquent 模型會保護你的模型不被大量指定方式所攻擊。
設定保護 (Guarded) 屬性到模型中
class User extends Eloquent {
protected $guarded = array('id', 'account_id');
}
使用模型的新增 (Create) 方法
$user = User::create(array('name' => 'John'));
為了更新資料,你需要取得資料後,並改變一個你要更新的屬性欄,並使用 save
方法即可更新資料:
更新一個已取得資料的模型
$user = User::find(1);
$user->email = 'john@foo.com';
$user->save();
有時你會須希望不僅儲存模型中的資料,也希望能夠儲存所有關聯的資料,你可以使用 push
的方法,去達到這樣的目的:
儲存模型資料及關連的資料
$user->push();
你也可以對一個集合的模型資料進行更新:
$affectedRows = User::where('votes', '>', 100)->update(array('status' => 2));
只需要在模型實例使用 delete
方法,即可刪除模型的資料:
刪除一存在的模型資料
$user = User::find(1);
$user->delete();
透過鍵值刪除一存在的模型資料
User::destroy(1);
User::destroy(1, 2, 3);
單然你也可以對一模型資料集合執行刪除的動作:
$affectedRows = User::where('votes', '>', 100)->delete();
如果你只想要更新模型的時間戳記,你可以使用 touch
方法去進行更新:
僅更新模型的時間戳記
$user->touch();
微刪除
當微刪除模型資料時,資料不會真的從資料庫中移除,而是會去更新 deleted_at
時間戳記欄位,在模型中設定 softDelete
變數,就可以讓模型開啟微刪除的功能:
class User extends Eloquent {
protected $softDelete = true;
}
你可以在 Migration 中使用 softDeletes
方法,在資料表中加入 deleted_at
欄位:
$table->softDeletes();
現在當你在模型中呼叫 delete
方法時,資料表中的 deleted_at
欄位值會被設定為現在的時間戳記,當使用微刪除的模型在對資料庫進行查詢撈取資料時,被 "微刪除 (deleted)" 的資料將不會被撈取出來,如果要強制模型去撈取被微刪除的資料,在查詢過程中使用 withTrashed
方法即可:
強制微刪除的資料也出現在查詢結果中
$users = User::withTrashed()->where('account_id', 1)->get();
如果你 只 (only) 希望撈取微刪除的資料出來,你可以使用 onlyTrashed
去達成這件事:
$users = User::onlyTrashed()->where('account_id', 1)->get();
使用 restore
方法,可以回復原本被微刪除的資料:
$user->restore();
你可以在查詢過程中使用 restore
方法:
User::withTrashed()->where('account_id', 1)->restore();
restore
方法也可以用在關聯的資料上:
$user->posts()->restore();
使用 forceDelete
方法,可以真的將資料從資料庫中移除:
$user->forceDelete();
forceDelete
方法也可以用在關聯資料上:
$user->posts()->forceDelete();
使用 trashed
方法,可以知道模型中是否有被微刪除的資料:
if ($user->trashed())
{
//
}
時間戳記
預設的情況下, Eloquent 會自動在你的資料表加入並維護 created_at
及 updated_at
這兩個欄位資料,欄位會被設定為 datetime
的資料型態,這兩個欄位的資料異動都交給 Eloquent 去處理,若你不希望 Eloquent 去幫你維護這兩個欄位的資料,在你的模型中將參數 $timestamps
設定為 false
即可,如下範例所示::
關閉自動維護時間戳記功能
class User extends Eloquent {
protected $table = 'users';
public $timestamps = false;
}
如果你希望自訂時間戳記格式,你可以在模型中使用 freshTimestamp
方法去複寫原始設定的格式:
提供自訂時間戳記格式
class User extends Eloquent {
public function freshTimestamp()
{
return time();
}
}
查詢範圍
Scopes 允許你容易地在模型中去重複使用查詢邏輯,只要使用 scope
當作模型中方法的前綴字,即可定義 Scope:
定義查詢 Scope
class User extends Eloquent {
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
}
使用查詢 Scope
$users = User::popular()->orderBy('created_at')->get();
關聯
當然,你的資料表總會關連到其他資料表的資料,舉例來說,一篇部落格文章會有數個文章評論,或者會有不同的使用者資料放到不同的排序資料中, Eloquent 可以讓你容易的管理這些關聯關係, Laravel 支援四種不同型態的關聯:
一對一 (One To One)
一對一的關聯資料是非常基本的關聯,舉例來說 User
模型中的使用,有一筆 Phone
模型中的電話資料,我們可以在 Eloquent 定義這個關聯關係:
定義一對一關聯
class User extends Eloquent {
public function phone()
{
return $this->hasOne('Phone');
}
}
傳送給 hasOne
方法的第一個參數是要關聯的模組名稱,只要關聯定義完成,你可以使用 Eloquent 的 動態屬性 去取得被關聯的資料:
$phone = User::find(1)->phone;
SQL 將會執行下列的語法去做查詢:
select * from users where id = 1
select * from phones where user_id = 1
這裡要注意到, Eloquent 認定要做關聯的外來鍵 (foreign key) 是基於模組名稱去做設定的,在這個例子中, Phone
模型會被認定要用 user_id
做關聯時的外來鍵,假如你要變更這個預設的外來鍵名稱設定,你可以在 hasOne
方法中的第二個參數傳送你要自訂的外來鍵名稱:
return $this->hasOne('Phone', 'custom_key');
我們可以使用 belongsTo
方法,在 Phone
模型中定義反向的關聯:
定義反向關聯
class Phone extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
一對多 (One To Many)
一對多關聯的範例,就像一個部落格文章有"多"個評論,所以我們可以在模型中定義這個關聯關係:
class Post extends Eloquent {
public function comments()
{
return $this->hasMany('Comment');
}
}
現在我們可以透過 動態屬性 去存取部落格文章的評論資料了:
$comments = Post::find(1)->comments;
如果需要在取得的評論資料中家更多的限制,可以呼叫 comments
方法,並持續使用方法鏈 (chain) 的方式,做更多的條件的設定:
$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first();
只要在 hasMany
第二個參數傳送外來鍵的名稱,即可複寫預設的外來鍵名稱:
return $this->hasMany('Comment', 'custom_key');
我們可以使用 belongsTo
方法,在 Comment
模型中定義反向的關聯:
定義反向關聯
class Comment extends Eloquent {
public function post()
{
return $this->belongsTo('Post');
}
}
多對多 (Many To Many)
多對多關聯是一個較複雜的關連類型,舉例來說,像使用者有多種腳色,而相同的腳色可能有數個不同的使用者扮演,就像許多使用者有 "管理者 (Admin)" 的腳色,資料庫中需要三個資料表去表示之間的關係: users
、 roles
及 role_user
這三個資料表,其中 role_user
資料表名稱,是根據關聯的兩個資料表 ( users 及 roles)的字母順序去做命名,在 role_user
資料表中需要有 user_id
及 role_id
這兩個欄位。
我們可以使用 belongsToMany
方法,去定義多對多的關係:
class User extends Eloquent {
public function roles()
{
return $this->belongsToMany('Role');
}
}
現在我們可以透過 User
模型,去取得使用者的腳色資料:
$roles = User::find(1)->roles;
在 belongsToMany
方法的第二個參數你可以傳入資料表名稱,使用非預設的名稱當作關聯資料表的名稱:
return $this->belongsToMany('Role', 'user_roles');
你也可以複寫預設使用的關聯鍵值 (associated keys):
return $this->belongsToMany('Role', 'user_roles', 'user_id', 'foo_id');
你也可以在 Role
模型中定義反向的關聯:
class Role extends Eloquent {
public function users()
{
return $this->belongsToMany('User');
}
}
多型態的關聯 (Polymorphic Relations)
多型態的關聯,允許模型可以關聯數個其他的模型,舉例來說,你有一個 photo 模型的資料,其資料是屬於 staff 或 Order 模型,我們可以這樣定義彼此的關聯:
class Photo extends Eloquent {
public function imageable()
{
return $this->morphTo();
}
}
class Staff extends Eloquent {
public function photos()
{
return $this->morphMany('Photo', 'imageable');
}
}
class Order extends Eloquent {
public function photos()
{
return $this->morphMany('Photo', 'imageable');
}
}
我們可以用 staff 或 order 資料去取得 photos 模型的資料:
Retrieving A Polymorphic Relation
$staff = Staff::find(1);
foreach ($staff->photos as $photo)
{
//
}
然而,"多型態關聯" 神奇的地方在於,你可以透過 Photo
模型去取得 staff 或 order 模型的資料:
取得擁有多型態關聯的資料
$photo = Photo::find(1);
$imageable = $photo->imageable;
在 Photo
模型中 imageable
關聯將會回傳 Staff
或 Order
模型實例,取決於哪個類型的模型擁有這個 photo 的資料。
為了幫助你了解"多型態關聯"是如何運作的,讓我們來多型態關聯中探索資料庫的結構:
多型態關聯資料表結構
staff
id - integer
name - string
orders
id - integer
price - integer
photos
id - integer
path - string
imageable_id - integer
imageable_type - string
在 photos
資料比中的關鍵欄位在 imageable_id
及 imageable_type
上,可以提醒資料是屬於哪個模型的資料, imageable_id
將會包含關聯模型的 ID 值,在這個例子中,擁有者是 staff 或 order 模型,所以 imageable_type
資料會是擁有的模型名稱,這可以讓 ORM 去決定 imageable
關聯將回傳哪個模型的實例。
查詢關聯
當存取模型的資料時,你或許想限制關聯資料存取的筆數,舉例來說,你可能想撈取所有的部落格文章,其中文章至少要有一個以上的評論,你可以使用 has
的方法,去達到這樣的目的:
在撈取資料時檢查關聯
$posts = Post::has('comments')->get();
你也可以指定運算子及筆數
$posts = Post::has('comments', '>=', 3)->get();
動態屬性
Eloquent 允許你透過動態屬性去存取關聯的資料, Eloquent 將會自動替你建立關聯關係,也可以很聰明地呼叫 get
(一對多的關聯關係) 或 first
(一對一的關聯關係) 方法去取得關聯資料,以下列的 $phone
模型舉例:
class Phone extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
$phone = Phone::find(1);
取代像列印使用者的 email:
echo $phone->user()->first()->email;
可以被簡化為:
echo $phone->user->email;
預先加載
預先加載的存在是為了減輕N +1查詢問題。例如,考慮一個書模型,是關係到作者。關係定義,像這樣:
預先加載是為了減輕 N + 1 個查詢問題,舉例來說,考慮讓 Book
模型關聯到 Author
模型,其關聯關係可定義成像這樣:
class Book extends Eloquent {
public function author()
{
return $this->belongsTo('Author');
}
}
現在我們來考慮下列的程式:
foreach (Book::all() as $book)
{
echo $book->author->name;
}
這個迴圈會執行 1 次查詢去取得 "books" 資料表中所有的書籍,而另外一個查詢是去取得其書籍的作者,所以在我們有 25 本書的情況下,這個迴圈將會執行 26 次的查詢。
值得慶幸的是,我們可以用預先加載查詢的數量大幅減少。通過與方法的關係,應該是急於裝可以指定:
值得慶幸的是,我們可以使用預先加載去減少查詢數量,可以使用 with
方法在關聯中去完成預先加載:
foreach (Book::with('author')->get() as $book)
{
echo $book->author->name;
}
在上列的迴圈,只有兩個查詢會被執行:
select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)
明智的使用預先加載,可以大大提高你應用程式的效能。
當然你也可以一次就加載數個關聯的資料:
$books = Book::with('author', 'publisher')->get();
你也可以預先加載巢狀的關聯:
$books = Book::with('author.contacts')->get();
在上述的範例中,author
關聯將會被預先加載,而 author 的 contacts
關聯也會被預先加載。
預先加載限制
有時你會希望預先加載關聯資料,並且可以指定加載的條件,這裡有使用範例:
$users = User::with(array('posts' => function($query)
{
$query->where('title', 'like', '%first%');
}))->get();
在這個範例中,我們可以預先加載使用者的文章,但只加載文章標題欄位有 "first" 字串的欄位。
懶人預先加載
也可以從存在的模型集合中直接預先加載資料,這樣可以根據所需,動態決定是否加載關聯的模型資料,或是快取的組合。
$books = Book::all();
$books->load('author', 'publisher');
新增相關模組
你經常需要新增新的資料到關聯的模組中,舉例來說,你也許希望新增一則評論到文章時,能夠幫你自動將 post_id
外來鍵新增到模型當中,你可以透過母模型 Post
去直接新增一則評論到文章中,來達到自動新增外來鍵到模型中的目的:
附加關聯模型
$comment = new Comment(array('message' => 'A new comment.'));
$post = Post::find(1);
$comment = $post->comments()->save($comment);
在這個範例中,post_id
欄位將會自動的設定到評論的關聯文章資料中。
關聯模型 - 屬於 (Belongs To)
當更新一個 屬於 (belongsTo)
關係的關聯資料時,你可以使用 associate
方法去實作,這個方法將會設定外來鍵到子模型中:
$account = Account::find(10);
$user->account()->associate($account);
$user->save();
新增關聯模型 - 多對多 (Many To Many)
你可能會新增資料到 "多對多 (many-to-many)" 關聯模型當中,讓我們用 User
及 Role
模型來當作範例,我們可以使用 attach
方法,附加一個新的腳色給使用者::
附加多對多模型
$user = User::find(1);
$user->roles()->attach(1);
你也可以傳送一個屬性陣列資料,儲存關聯資料到資料表中:
$user->roles()->attach(1, array('expires' => $expires));
當然,attach
的反向方法就是 detach
:
$user->roles()->detach(1);
你也可以使用 sync
方法去附加關聯模型資料,sync
方法接收編號陣列資料,並將編號資料存放到關聯資料中,在操作完成後,陣列中的編號將會建立到關聯資料模型中:
使用同步附加多對多模型
$user->roles()->sync(array(1, 2, 3));
除了關聯給予的陣列編號外,你也可以將其他的資料儲存到關聯模型中:
同步時加入關聯資料
$user->roles()->sync(array(1 => array('expires' => true)));
有時你可能希望新增一個新的資料到關聯的模型中,並同時在一行指令中附加新的關聯資料,在這個操作中,你可以使用 save
方法去完成這樣的需求:
$role = new Role(array('name' => 'Editor'));
User::find(1)->roles()->save($role);
在這個範例中,新的 Role
模型資料將會被儲存,並附加到使用者模型中,你也可以傳遞一屬性陣列值,將此陣列值的資料,也一併存放到關聯資料中:
User::find(1)->roles()->save($role, array('expires' => $expires));
碰觸母節點時間戳記
當模型 屬於 (belongsTo)
另外一個模型時,像 Comment
模型是附屬在 Post
模型下,如果子模型被更新時,也能夠更新母模型,對應用程式運作是相當方便的,舉例來說,當 Comment
模型被更新,你或許想要自動更新擁有它 Post
模型的 更新時間 (updated_at)
欄位,Eloquent可以讓這樣的功能變得相當容易,只需要在子模型中加入 touches
屬性,其中屬性包含有關連到子模型的母模型名稱:
class Comment extends Eloquent {
protected $touches = array('post');
public function post()
{
return $this->belongsTo('Post');
}
}
現在當你更新 Comment
模型的資料時,擁有它的 Post
模型 updated_at
欄位將會自動更新:
$comment = Comment::find(1);
$comment->text = '編輯這個評論!';
$comment->save();
使用數據透視表
就像你已經學過的,實做多對多關係需要中介的資料表,Eloquent 提供了非常好用的方法,幫助我們與中介資料表做互動,舉例來說,假設 User
物件有多個相關的 Role
物件,我們可以在模型中透過存取 pivot
來存取這個關係資料表:
$user = User::find(1);
foreach ($user->roles as $role)
{
echo $role->pivot->created_at;
}
這邊會注意到每個 Role
模型會自動被指定一個 pivot
屬性,這個屬性會包含模型的中介資料表,且可能也會被其他的 Eloquent 模型存取。
pivot
屬性在預設的情況下只有包含 "鍵值 (Key)",如果你想要讓你的 pivot 資料表包含其他的屬性,則必須要在定義模型關係時,去指定要額外存取的屬性:
return $this->belongsToMany('Role')->withPivot('foo', 'bar');
現在 foo
及 bar
屬性可以在 Role
模型中的 pivot
物件中存取了。
如果你想要你的 pivot 資料表可以自動維護 created_at
及 updated_at
這兩個欄位的時間戳記,可以在定義關係時使用 withTimestamps
方法即可:
return $this->belongsToMany('Role')->withTimestamps();
使用 detach
方法可以刪除模型在 pivot 資料表的所有紀錄:
刪除在 Pivot 資料表的紀錄
User::find(1)->roles()->detach();
注意到這個操作不會刪除 roles
資料表的紀錄,僅有移除在 pivot 資料表的紀錄。
聚集
所有多結果的集合可以經由 Eloquent 的 get
方法或模型關係回傳 Eloquent 集合 (Collection)
物件,這個物件實做了 PHP 的 IteratorAggregate
介面,所以可以像陣列一樣遞迴存取,然而物件也有其他各種的方法去存取這個資料集合。
舉例來說,我們可以使用 contains
方法,判斷集合資料中是否有指定的 "主鍵 (primary key)" 資料:
檢查集合是否包含鍵值資料
$roles = User::find(1)->roles;
if ($roles->contains(2))
{
//
}
資料集合也可以轉換成 陣列 或 JSON 格式:
$roles = User::find(1)->roles->toArray();
$roles = User::find(1)->roles->toJson();
假如集合轉換成字串,則會回傳 JSON 格式的資料:
$roles = (string) User::find(1)->roles;
Eloquent 集合也包含一些有用的方法,可以遞迴或是過濾資料集合:
遞迴 & 過濾資料集合
$roles = $user->roles->each(function($role)
{
});
$roles = $user->roles->filter(function($role)
{
});
實做回呼函式到每個集合的物件
$roles = User::find(1)->roles;
$roles->each(function($role)
{
//
});
排序集合資料
$roles = $roles->sortBy(function($role)
{
return $role->created_at;
});
有時你可能會想要在你自己加入的方法中,回傳自訂的集合物件,你可以在 Eloquent 中去定義覆寫 newCollection
的方法:
回傳自訂集合類型
class User extends Eloquent {
public function newCollection(array $models = array())
{
return new CustomCollection($models);
}
}
存取及修改器
Eloquent 提供一個便利的方法讓你可以在"取得"或"設定"屬性時,轉換模型中的屬性,只要簡單的在模型中定義 getFooAttribute
方法當作存取器,這裡需要記住的是方法名稱必須遵循 駝峰式大小寫 (camelCase)
,即便你的資料表欄位名稱規則是 蛇底式小寫 (snake_case)
:
定義屬性存取器
class User extends Eloquent {
public function getFirstNameAttribute($value)
{
// 將第一個字母轉換為大寫
return ucfirst($value);
}
}
在上述範例中,first_name
欄位會有一個存取器,欄位資料將會傳送給存取器。
修改器的定義也很類似:
定義修改器
class User extends Eloquent {
public function setFirstNameAttribute($value)
{
$this->attributes['first_name'] = strtolower($value);
}
}
日期設置器
Eloquent 預設會將 created_at
、 updated_at
及 deleted_at
欄位轉換為 Carbon 實例,該實例提供了各種好用的處理時間方法,且繼承了 PHP 原生的 DateTime
類別。
你可以在模型 (Model) 中透過 getDates
方法,自訂那些欄位要自動被變異,或是要關閉這些變異:
public function getDates()
{
return array('created_at');
}
當欄位是日期格式時,你可以將此欄位設定為 UNIX 時間戳記、日期字串 (Y-m-d
),日期時間字串 (Datetime
),且必然是 DateTime
/ Carbon
的實例。
為了完全的關閉這些欄位變異,只要在 getDates
方法中簡單的回傳空陣列即可:
public function getDates()
{
return array();
}
模組事件
Eloquent 模型會驅動數個事件,允許你藉由下列方法 creating
、 created
、 updating
、 updated
、 saving
、 saved
、 deleting
、 deleted
,去取得模型的生命週期中的不同事件點,假如 creating
、 updating
或 saving
事件回傳 false
,則原事件的動作將會被取消:
透過事件取消儲存操作
User::creating(function($user)
{
if ( ! $user->isValid()) return false;
});
Eloquent 模型也包含靜態的 boot
方法,提供一個地方可以放置及註冊你的事件綁定動作。
設定模型 Boot 方法
class User extends Eloquent {
public static function boot()
{
parent::boot();
// 設定事件綁定...
}
}
模組觀察
為了保護模型事件的處理,你可以註冊一個模型觀察器,觀察器類別有與模型事件相符的方法,舉例來說觀察器中會有 creating
、 updating
、 saving
的方法,除了這些方法,還有其他模型事件的名稱的方法。
所以舉例來說,模型觀察器會長得像這樣:
class UserObserver {
public function saving($model)
{
//
}
public function saved($model)
{
//
}
}
你可以使用 observe
方法去註冊一個觀察器的實例:
User::observe(new UserObserver);
轉換成陣列/JSON
當建立 JSON 格式的 API,你會經常需要將模型或關係的資訊轉換成 "陣列" 或 "JSON" 格式,所以 Eloquent 也包含了這些資料格式的轉換方法,你可以使用 toArray
方法,將 "模型 (Model)" 及模型載入的 "關係資料 (Relationship)" 成為陣列格式的資料:
轉換模型為陣列格式資料
$user = User::with('roles')->first();
return $user->toArray();
這裡要注意到,整個模型的集合都會被轉換成陣列格式的資料:
return User::all()->toArray();
可以使用 toJson
方法,將模型轉換為 JSON 資料格式:
轉換模型為 JSON 格式資料
return User::find(1)->toJson();
注意,當模型或集合被轉換為字串時,則都會被轉換為 JSON 資料格式,意思是你可以直接在應用程式的路由,回傳整個 Eloquent 物件!
從路由回傳模型物件
Route::get('users', function()
{
return User::all();
});
有時你可能會想要限制模型轉換成 "陣列" 或 "JSON" 格式時的屬性資料有哪些,像是密碼欄位資料不想要轉換輸出,可以在你的模型加入 hidden
屬性,來達到這樣的目的:
在陣列或JSON資料格式轉換時隱藏屬性欄位
class User extends Eloquent {
protected $hidden = array('password');
}
另外,你也可以使用 visible
屬性去定義可以轉換輸出的白名單屬性欄位:
protected $visible = array('first_name', 'last_name');