2015年11月20日 星期五

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


reference : http://kejyun.github.io/Laravel-4-Documentation-Traditional-Chinese/docs/eloquent/

沒有留言:

wibiya widget