[ Laravel 5.2 文檔 ] Eloquent ORM -- 起步

來源:互聯網
上載者:User

1、簡介

Laravel內建的 EloquentORM 提供了一個美觀、簡單的與資料庫打交道的 ActiveRecord 實現,每張資料表都對應一個與該表進行互動的“模型”,模型允許你在表中進行資料查詢,以及插入、 更新、刪除等操作。

在開始之前,確保在 config/database.php檔案中配置好了資料庫連接。更多關於資料庫配置的資訊,請查看文檔。

2、定義模型

作為開始,讓我們建立一個 Eloquent 模型,模型通常位於 app目錄下,你也可以將其放在其他可以被 composer.json檔案自動載入的地方。所有Eloquent模型都繼承自 Illuminate\Database\Eloquent\Model類。

建立模型執行個體最簡單的辦法就是使用 Artisan 命令 make:model:

php artisan make:model User

如果你想要在產生模型時產生資料庫遷移,可以使用 --migration或 -m選項:

php artisan make:model User --migrationphp artisan make:model User -m

Eloquent 模型約定

現在,讓我們來看一個 Flight模型類例子,我們將用該類擷取和存取資料表 flights中的資訊:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    //}

表名

注意我們並沒有告訴 Eloquent 我們的 Flight模型使用哪張表。預設規則是模型類名的複數作為與其對應的表名,除非在模型類中明確指定了其它名稱。所以,在本例中,Eloquent 認為 Flight模型儲存記錄在 flights表中。你也可以在模型中定義 table屬性來指定自訂的表名:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 關聯到模型的資料表     *     * @var string     */    protected $table = 'my_flights';}

主鍵

Eloquent 預設每張表的主鍵名為 id,你可以在模型類中定義一個 $primaryKey屬性來覆蓋該約定。

時間戳記

預設情況下,Eloquent 期望 created_at和 updated_at已經存在於資料表中,如果你不想要這些 Laravel 自動管理的列,在模型類中設定 $timestamps屬性為 false:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{ /** * 表明模型是否應該被打上時間戳記 * * @var bool */ public $timestamps = false;}

如果你需要自訂時間戳記格式,設定模型中的 $dateFormat屬性。該屬性決定日期被如何儲存到資料庫中,以及模型被序列化為數組或 JSON 時日期的格式:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 模型日期列的儲存格式     *     * @var string     */    protected $dateFormat = 'U';}

資料庫連接

預設情況下,所有的 Eloquent 模型使用應用配置中的預設資料庫串連,如果你想要為模型指定不同的串連,可以通過 $connection屬性來設定:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * The connection name for the model.     *     * @var string     */    protected $connection = 'connection-name';}

3、擷取多個模型

建立完模型及其關聯的資料表後,就要準備從資料庫中擷取資料。將Eloquent模型看作功能強大的查詢構建器,你可以使用它來流暢的查詢與其關聯的資料表。例如:

<?phpnamespace App\Http\Controllers;use App\Flight;use App\Http\Controllers\Controller;class FlightController extends Controller{    /**     * 顯示所有有效航班列表     *     * @return Response     */    public function index()    {        $flights = Flight::all();        return view('flight.index', ['flights' => $flights]);    }}

訪問列值

如果你有一個 Eloquent 模型執行個體,可以通過訪問其相應的屬性來訪問模型的列值。例如,讓我們迴圈查詢返回的每一個 Flight執行個體並輸出 name的值:

foreach ($flights as $flight) {    echo $flight->name;}

添加額外約束

Eloquent 的 all方法返回模型表的所有結果,由於每一個Eloquent模型都是一個查詢構建器,你還可以添加約束條件到查詢,然後使用 get方法擷取對應結果:

$flights = App\Flight::where('active', 1)               ->orderBy('name', 'desc')               ->take(10)               ->get();

注意:由於 Eloquent 模型本質上就是查詢構建器,你可以在Eloquent查詢中使用查詢構建器的所有方法。

集合

對 Eloquent 中擷取多個結果的方法(比如 all和 get)而言,其傳回值是 Illuminate\Database\Eloquent\Collection的一個執行個體, Collection類提供了多個有用的函數來處理Eloquent結果。當然,你可以像運算元組一樣簡單迴圈這個集合:

foreach ($flights as $flight) {    echo $flight->name;}

組塊結果集

如果你需要處理成千上萬個 Eloquent 結果,可以使用 chunk命令。 chunk方法會擷取一個“組塊”的 Eloquent 模型,並將其填充到給定閉包進行處理。使用 chunk方法能夠在處理大量資料集合時有效減少記憶體消耗:

Flight::chunk(200, function ($flights) {    foreach ($flights as $flight) {        //    }});

傳遞給該方法的第一個參數是你想要擷取的“組塊”數目,閉包作為第二個參數被調用用於處理每個從資料庫擷取的區塊資料。

4、擷取單個模型/彙總

當然,除了從給定表中擷取所有記錄之外,還可以使用 find和 first擷取單個記錄。這些方法返回單個模型執行個體而不是返回模型集合:

// 通過主鍵擷取模型...$flight = App\Flight::find(1);// 擷取匹配查詢條件的第一個模型...$flight = App\Flight::where('active', 1)->first();

Not Found 異常

有時候你可能想要在模型找不到的時候拋出異常,這在路由或控制器中非常有用, 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);});

擷取彙總

當然,你還可以使用查詢構建器彙總方法,例如 count、 sum、 max,以及其它查詢構建器提供的彙總方法。這些方法返回計算後的結果而不是整個模型執行個體:

$count = App\Flight::where('active', 1)->count();$max = App\Flight::where('active', 1)->max('price');

5、插入/更新模型

基本插入

想要在資料庫中插入新的記錄,只需建立一個新的模型執行個體,設定模型的屬性,然後調用 save方法:

<?phpnamespace 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)    {        // Validate the request...        $flight = new Flight;        $flight->name = $request->name;        $flight->save();    }}

在這個例子中,我們只是簡單分配HTTP請求中的 name參數值給 App\Flight模型執行個體的那麼屬性,當我們調用 save方法時,一條記錄將會被插入資料庫。 created_at和 updated_at時間戳記在 save方法被調用時會自動被設定,所以沒必要手動設定它們。

基本更新

save方法還可以用於更新資料庫中已存在的模型。要更新一個模型,應該先擷取它,設定你想要更新的屬性,然後調用 save方法。同樣, updated_at時間戳記會被自動更新,所以沒必要手動設定其值:

$flight = App\Flight::find(1);$flight->name = 'New Flight Name';$flight->save();

更新操作還可以同時修改給定查詢提供的多個模型執行個體,在本例中,所有有效且 destination=San Diego的航班都被標記為延遲:

App\Flight::where('active', 1)          ->where('destination', 'San Diego')          ->update(['delayed' => 1]);

update方法要求以數組形式傳遞索引值對參數,代表著資料表中應該被更新的列。

批量賦值

還可以使用 create方法儲存一個新的模型。該方法返回被插入的模型執行個體。但是,在此之前,你需要指定模型的 fillable或 guarded屬性,因為所有Eloquent模型都通過批量賦值(Mass Assignment)進行保護。

當使用者通過 HTTP 要求傳遞一個不被期望的參數值時就會出現安全隱患,然後該參數以不被期望的方式修改資料庫中的列值。例如,惡意使用者通過 HTTP 要求發送一個 is_admin參數,然後該參數映射到模型的 create方法,從而允許使用者將自己變成管理員。

所以,你應該在模型中定義哪些屬性是可以進行賦值的,使用模型上的 $fillable屬性即可實現。例如,我們設定 Flight模型上的 name屬性可以被賦值:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 可以被批量賦值的屬性.     *     * @var array     */    protected $fillable = ['name'];}

設定完可以被賦值的屬性之後,我們就可以使用 create方法在資料庫中插入一條新的記錄。 create方法返回儲存後的模型執行個體:

$flight = App\Flight::create(['name' => 'Flight 10']);

$fillable就像是可以被賦值屬性的“白名單”,還可以選擇使用 $guarded。 $guarded屬性包含你不想被賦值的屬性數組。所以不被包含在其中的屬性都是可以被賦值的,因此,$guarded方法就像“黑名單”。當然,你只能同時使用其中一個——而不是一起使用:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 不能被批量賦值的屬性     *     * @var array     */    protected $guarded = ['price'];}

在這個例子中,除了 $price之外的所有屬性都是可以被賦值的。

其它建立方法

還有其它兩種可以用來建立模型的方法: firstOrCreate和 firstOrNew。 firstOrCreate方法先嘗試通過給定列/值對在資料庫中尋找記錄,如果沒有找到的話則通過給定屬性建立一個新的記錄。

firstOrNew方法和 firstOrCreate方法一樣先嘗試在資料庫中尋找匹配的記錄,如果沒有找到,則返回一個的模型執行個體。注意通過 firstOrNew方法返回的模型執行個體並沒有持久化到資料庫中,你還需要調用 save方法手動持久化:

// 通過屬性擷取航班, 如果不存在則建立...$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);// 通過屬性擷取航班, 如果不存在初始化一個新的執行個體...$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);

6、刪除模型

要刪除一個模型,調用模型執行個體上的 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();

虛刪除

除了從資料庫刪除記錄外,Eloquent還可以對模型進行“虛刪除”。當模型被虛刪除後,它們並沒有真的從資料庫刪除,而是在模型上設定一個 deleted_at屬性並插入資料庫,如果模型有一個非空 deleted_at值,那麼該模型已經被虛刪除了。要啟用模型的虛刪除功能,可以使用模型上的 Illuminate\Database\Eloquent\SoftDeletestrait並添加 deleted_at列到 $dates屬性:

<?phpnamespace 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 Schema構建器包含一個協助函數來建立該列:

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方法也可以用於關聯查詢中:

$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方法也可以用於關聯查詢:

$flight->history()->restore();

永久刪除模型

有時候你真的需要從資料庫中刪除一個模型,可以使用 forceDelete方法:

// 強制移除單個模型執行個體...$flight->forceDelete();// 強制移除所有關聯模型...$flight->history()->forceDelete();

7、查詢範圍

全域範圍

全域範圍允許我們為給定模型的所有查詢添加條件約束。Laravel 內建的虛刪除功能就使用了全域範圍來從資料庫中拉出所有沒有被刪除的模型。編寫自訂的全域範圍可以提供一種方便的、簡單的方式來確保給定模型的每個查詢都有特定的條件約束。

編寫全域範圍

自訂全域範圍很簡單,首先定義一個實現 Illuminate\Database\Eloquent\Scope介面的類,該介面要求你實現一個方法:apply。需要的話可以在 apply方法中添加 where條件到查詢:

<?phpnamespace App\Scopes;use Illuminate\Database\Eloquent\Scope;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Builder;class AgeScope implements Scope{    /**     * Apply the scope to a given Eloquent query builder.     *     * @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);    }}

應用全域範圍

要將全域範圍分配給模型,需要重寫給定模型的 boot方法並使用 addGlobalScope方法:

<?phpnamespace App;use App\Scopes\AgeScope;use Illuminate\Database\Eloquent\Model;class User extends Model{    /**     * The "booting" method of the model.     *     * @return void     */    protected static function boot()    {        parent::boot();        static::addGlobalScope(new AgeScope);    }}

添加範圍後,如果使用 User::all()查詢則會產生如下SQL語句:

select * from `users` where `age` > 200

匿名的全域範圍

Eloquent還允許我們使用閉包定義全域範圍,這在實現簡單範圍的時候特別有用,這樣的話,我們就沒必要定義一個單獨的類了:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Builder;class User extends Model{    /**     * The "booting" method of the model.     *     * @return void     */    protected static function boot()    {        parent::boot();        static::addGlobalScope('age', function(Builder $builder) {            $builder->where('age', '>', 200);        });    }}

我們還可以通過以下方式移除全域作用:

User::withoutGlobalScope('age')->get();

移除全域範圍

如果想要在給定查詢中移除指定全域範圍,可以使用 withoutGlobalScope:

User::withoutGlobalScope(AgeScope::class)->get();

如果你想要移除某幾個或全部全域範圍,可以使用 withoutGlobalScopes方法:

User::withoutGlobalScopes()->get();User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get();

本地範圍

本地範圍允許我們定義通用的約束集合以便在應用中複用。例如,你可能經常需要擷取最受歡迎的使用者,要定義這樣的一個範圍,只需簡單在對應Eloquent模型方法前加上一個 scope首碼,範圍總是返回查詢構建器:

<?phpnamespace 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參數之後:

<?phpnamespace 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();

8、事件

Eloquent模型可以觸發事件,允許你在模型生命週期中的多個時間點調用如下這些方法: creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored。事件允許你在一個指定模型類每次儲存或更新的時候執行代碼。

基本使用

一個新模型被首次儲存的時候, creating和 created事件會被觸發。如果一個模型已經在資料庫中存在並調用 save方法, updating/updated事件會被觸發,無論是建立還是更新,saving/saved事件都會被調用。

舉個例子,我們在服務提供者中定義一個Eloquent事件監聽器,在事件監聽器中,我們會調用給定模型的 isValid方法,如果模型無效會返回 false。如果從Eloquent事件監聽器中返回 false則取消 save/update操作:

<?phpnamespace App\Providers;use App\User;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{    /**     * 啟動所有應用服務     *     * @return void     */    public function boot()    {        User::creating(function ($user) {            if ( ! $user->isValid()) {                return false;            }        });    }    /**     * 註冊服務提供者.     *     * @return void     */    public function register()    {        //    }}
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.