回到最上方

文件

Eloquent ORM

介紹

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_atcreated_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 模型預設會避免及保護資料不會被大量指定的方式所覆寫。

為了使用大量指定的功能,你必須在你的模型設定 fillableguarded 變數資料。

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');

}

在上述範例 idpassword 屬性將不會被大量指定方式修改原模型的變數資料,所有除了這兩個變數外的變數,都可以被使用大量指定方式指定去修改資料,你也可以保護 所有 的屬性都不會被大量指定的方式修改資料值:

封鎖所有變數不被大量指定方式修改資料內容

protected $guarded = array('*');

新增、更新及刪除

為了透過模型建立一筆新的資料到資料庫,只需要建立新的模型實例後,並且呼叫 save 方法即可。

儲存新的模型資料

$user = new User;

$user->name = 'John';

$user->save();

注意: 通常你的 Eloquent 模型都會有一個自動增加的鍵值 (key),但你如果想要指定你自己的鍵值在模型中有自動增加的屬性,只要將 incrementing 設定為 自動增加 (incrementing) 即可。

你可以使用 create 方法在單一行去儲存資料到模型中,插入 (INSERT) 的模型實例將會被回傳,但是在使用這樣的方式去儲存資料前,你需要在模型中指定 fillableguarded 屬性,這樣 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_atupdated_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)" 的腳色,資料庫中需要三個資料表去表示之間的關係: usersrolesrole_user 這三個資料表,其中 role_user 資料表名稱,是根據關聯的兩個資料表 ( users 及 roles)的字母順序去做命名,在 role_user 資料表中需要有 user_idrole_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 關聯將會回傳 StaffOrder 模型實例,取決於哪個類型的模型擁有這個 photo 的資料。

為了幫助你了解"多型態關聯"是如何運作的,讓我們來多型態關聯中探索資料庫的結構:

多型態關聯資料表結構

staff
    id - integer
    name - string

orders
    id - integer
    price - integer

photos
    id - integer
    path - string
    imageable_id - integer
    imageable_type - string

photos 資料比中的關鍵欄位在 imageable_idimageable_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)" 關聯模型當中,讓我們用 UserRole 模型來當作範例,我們可以使用 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');

現在 foobar 屬性可以在 Role 模型中的 pivot 物件中存取了。

如果你想要你的 pivot 資料表可以自動維護 created_atupdated_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_atupdated_atdeleted_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 模型會驅動數個事件,允許你藉由下列方法 creatingcreatedupdatingupdatedsavingsaveddeletingdeleted,去取得模型的生命週期中的不同事件點,假如 creatingupdatingsaving 事件回傳 false,則原事件的動作將會被取消:

透過事件取消儲存操作

User::creating(function($user)
{
    if ( ! $user->isValid()) return false;
});

Eloquent 模型也包含靜態的 boot 方法,提供一個地方可以放置及註冊你的事件綁定動作。

設定模型 Boot 方法

class User extends Eloquent {

    public static function boot()
    {
        parent::boot();

        // 設定事件綁定...
    }

}

模組觀察

為了保護模型事件的處理,你可以註冊一個模型觀察器,觀察器類別有與模型事件相符的方法,舉例來說觀察器中會有 creatingupdatingsaving 的方法,除了這些方法,還有其他模型事件的名稱的方法。

所以舉例來說,模型觀察器會長得像這樣:

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');

討論