鍍金池/ 教程/ PHP/ 起步
門面
Laravel Homestead
安裝及配置
測試
HTTP 中間件
加密
升級指南
幫助函數(shù)
應用目錄結(jié)構(gòu)
集合
新手入門指南-簡單任務管理系統(tǒng)
任務調(diào)度
查詢構(gòu)建器
視圖
驗證
Laravel Cashier(訂購&支付&發(fā)票)
本地化
隊列
調(diào)整器
分頁
文件系統(tǒng)/云存儲
貢獻代碼
哈希
HTTP 控制器
緩存
遷移
HTTP 請求
Laravel Elixir
發(fā)行版本說明
Envoy 任務運行器(SSH任務)
序列化
Session
起步
帶用戶功能的任務管理系統(tǒng)
起步
用戶授權(quán)
郵件
事件
填充數(shù)據(jù)
HTTP 路由
服務提供者
Blade 模板引擎
包開發(fā)
用戶認證
Artisan 控制臺
HTTP 響應
集合
服務容器
關(guān)聯(lián)關(guān)系
一次請求的生命周期
契約
Redis
錯誤&日志

起步

1、簡介

Laravel 自帶的 Eloquent ORM 提供了一個美觀、簡單的與數(shù)據(jù)庫打交道的 ActiveRecord 實現(xiàn),每張數(shù)據(jù)表都對應一個與該表進行交互的“模型”,模型允許你在表中進行數(shù)據(jù)查詢,以及插入、更新、刪除等操作。 在開始之前,確保在 config/database.php 文件中配置好了數(shù)據(jù)庫連接。更多關(guān)于數(shù)據(jù)庫配置的信息,請查看文檔。

2、定義模型

作為開始,讓我們創(chuàng)建一個 Eloquent 模型,模型通常位于 app 目錄下,你也可以將其放在其他可以被 composer.json 文件自動加載的地方。所有 Eloquent 模型都繼承自 Illuminate\Database\Eloquent\Model 類。 創(chuàng)建模型實例最簡單的辦法就是使用 Artisan 命令 make:model

php artisan make:model User

如果你想要在生成模型時生成數(shù)據(jù)庫遷移,可以使用--migration-m選項:

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

2.1 Eloquent 模型約定

現(xiàn)在,讓我們來看一個 Flight 模型類例子,我們將用該類獲取和存取數(shù)據(jù)表 flights 中的信息:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    //
}

2.1.1 表名

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

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 關(guān)聯(lián)到模型的數(shù)據(jù)表
     *
     * @var string
     */
    protected $table = 'my_flights';
}

2.1.2 主鍵

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

2.1.3 時間戳

默認情況下,Eloquent 期望 created_atupdated_at 已經(jīng)存在于數(shù)據(jù)表中,如果你不想要這些 Laravel 自動管理的列,在模型類中設置$timestamps 屬性為 false

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 表明模型是否應該被打上時間戳
     *
     * @var bool
     */
    public $timestamps = false;
}

如果你需要自定義時間戳格式,設置模型中的$dateFormat 屬性。該屬性決定日期被如何存儲到數(shù)據(jù)庫中,以及模型被序列化為數(shù)組或 JSON 時日期的格式:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 模型日期列的存儲格式
     *
     * @var string
     */
    protected $dateFormat = 'U';
}

3、獲取多個模型

創(chuàng)建完模型及其關(guān)聯(lián)的數(shù)據(jù)表后,就要準備從數(shù)據(jù)庫中獲取數(shù)據(jù)。將 Eloquent 模型看功能強大的查詢構(gòu)建器,你可以使用它來流暢的查詢與其關(guān)聯(lián)的數(shù)據(jù)表。例如:

<?php

namespace 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]);
    }
}

3.1 訪問列值

如果你有一個 Eloquent 模型實例,可以通過訪問其相應的屬性來訪問模型的列值。例如,讓我們循環(huán)查詢返回的每一個 Flight 實例并輸出 name 的值:

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

3.2 添加額外約束

Eloquent 的 all 方法返回模型表的所有結(jié)果,由于每一個 Eloquent 模型都是一個查詢構(gòu)建器,你還可以添加約束條件到查詢,然后使用 get 方法獲取對應結(jié)果:

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

注意:由于 Eloquent 模型本質(zhì)上就是查詢構(gòu)建器,你可以在 Eloquent 查詢中使用查詢構(gòu)建器的所有方法。

3.3 集合

對 Eloquent 中獲取多個結(jié)果的方法(比如 allget)而言,其返回值是 Illuminate\Database\Eloquent\Collection 的一個實例,Collection 類提供了多個有用的函數(shù)來處理 Eloquent 結(jié)果。當然,你可以像操作數(shù)組一樣簡單循環(huán)這個集合:

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

3.4 組塊結(jié)果集

如果你需要處理成千上萬個 Eloquent 結(jié)果,可以使用 chunk 命令。chunk方法會獲取一個“組塊”的 Eloquent 模型,并將其填充到給定閉包進行處理。使用 chunk方法能夠在處理大量數(shù)據(jù)集合時有效減少內(nèi)存消耗:

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

傳遞給該方法的第一個參數(shù)是你想要獲取的“組塊”數(shù)目,閉包作為第二個參數(shù)被調(diào)用用于處理每個從數(shù)據(jù)庫獲取的區(qū)塊數(shù)據(jù)。

4、獲取單個模型/聚合

當然,除了從給定表中獲取所有記錄之外,還可以使用 findfirst 獲取單個記錄。這些方法返回單個模型實例而不是返回模型集合:

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

Not Found 異常 有時候你可能想要在模型找不到的時候拋出異常,這在路由或控制器中非常有用,findOrFailfirstOrFail 方法會獲取查詢到的第一個結(jié)果。然而,如果沒有任何查詢結(jié)果,Illuminate\Database\Eloquent\ModelNotFoundException 異常將會被拋出:

$model = App\Flight::findOrFail(1);$model = App\Flight::where('legs', '>', 100)->firstOrFail();

如果異常沒有被捕獲,那么 HTTP 404 響應將會被發(fā)送給用戶,所以在使用這些方法的時候沒有必要對返回 404 響應編寫明確的檢查:

Route::get('/api/flights/{id}', function ($id) {
    return App\Flight::findOrFail($id);
});

4.1 獲取聚合

當然,你還可以使用查詢構(gòu)建器聚合方法,例如 count、summax,以及其它查詢構(gòu)建器提供的聚合方法。這些方法返回計算后的結(jié)果而不是整個模型實例:

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

5、插入/更新模型

5.1 基本插入

想要在數(shù)據(jù)庫中插入新的記錄,只需創(chuàng)建一個新的模型實例,設置模型的屬性,然后調(diào)用 save 方法:

<?php

namespace App\Http\Controllers;

use App\Flight;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class FlightController extends Controller{
    /**
     * 創(chuàng)建一個新的航班實例
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Validate the request...

        $flight = new Flight;

        $flight->name = $request->name;

        $flight->save();
    }
}

在這個例子中,我們只是簡單分配 HTTP 請求中的 name 參數(shù)值給 App\Flight 模型實例的那么屬性,當我們調(diào)用 save 方法時,一條記錄將會被插入數(shù)據(jù)庫。created_atupdated_at時間戳在 save 方法被調(diào)用時會自動被設置,所以沒必要手動設置它們。

5.2 基本更新

save 方法還可以用于更新數(shù)據(jù)庫中已存在的模型。要更新一個模型,應該先獲取它,設置你想要更新的屬性,然后調(diào)用 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 方法要求以數(shù)組形式傳遞鍵值對參數(shù),代表著數(shù)據(jù)表中應該被更新的列。

5.3 批量賦值

還可以使用 create方法保存一個新的模型。該方法返回被插入的模型實例。但是,在此之前,你需要指定模型的 fillableguarded屬性,因為所有 Eloquent 模型都通過 mass-assignment 進行保護。 當用戶通過 HTTP 請求傳遞一個不被期望的參數(shù)值時就會出現(xiàn) mass-assignment 隱患,然后該參數(shù)以不被期望的方式修改數(shù)據(jù)庫中的列值。例如,惡意用戶通過 HTTP 請求發(fā)送一個 is_admin 參數(shù),然后該參數(shù)映射到模型的 create 方法,從而允許用戶將自己變成管理員。 所以,作為開始,你應該定義模型屬性中哪些是可以進行賦值的,使用模型上的$fillable 屬性即可實現(xiàn)。例如,我們設置 Flight 模型上的 name 屬性可以被賦值:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 可以被批量賦值的屬性.
     *
     * @var array
     */
    protected $fillable = ['name'];
}

設置完可以被賦值的屬性之后,我們就可以使用 create 方法在數(shù)據(jù)庫中插入一條新的記錄。create 方法返回保存后的模型實例:

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

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

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 不能被批量賦值的屬性
     *
     * @var array
     */
    protected $guarded = ['price'];
}

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

5.3.1 其它創(chuàng)建方法

還有其它兩種可以用來創(chuàng)建模型的方法:firstOrCreatefirstOrNewfirstOrCreate 方法先嘗試通過給定列/值對在數(shù)據(jù)庫中查找記錄,如果沒有找到的話則通過給定屬性創(chuàng)建一個新的記錄。 firstOrNew 方法和 firstOrCreate 方法一樣先嘗試在數(shù)據(jù)庫中查找匹配的記錄,如果沒有找到,則返回一個的模型實例。注意通過 firstOrNew 方法返回的模型實例并沒有持久化到數(shù)據(jù)庫中,你還需要調(diào)用 save 方法手動持久化:

// 通過屬性獲取航班, 如果不存在則創(chuàng)建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);
// 通過屬性獲取航班, 如果不存在初始化一個新的實例...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);

6、刪除模型

要刪除一個模型,調(diào)用模型實例上的 delete 方法:

$flight = App\Flight::find(1);
$flight->delete();

6.1 通過主鍵刪除模型

在上面的例子中,我們在調(diào)用 delete 方法之前從數(shù)據(jù)庫中獲取該模型,然而,如果你知道模型的主鍵的話,可以直接刪除而不需要獲取它:

App\Flight::destroy(1);
App\Flight::destroy([1, 2, 3]);
App\Flight::destroy(1, 2, 3);

6.2 通過查詢刪除模型

當然,你還可以通過查詢刪除多個模型,在本例中,我們刪除所有被標記為無效的航班:

$deletedRows = App\Flight::where('active', 0)->delete();

6.3 軟刪除

除了從數(shù)據(jù)庫刪除記錄外,Eloquent 還可以對模型進行“軟刪除”。當模型被軟刪除后,它們并沒有真的從數(shù)據(jù)庫刪除,而是在模型上設置一個 deleted_at 屬性并插入數(shù)據(jù)庫,如果模型有一個非空 deleted_at 值,那么該模型已經(jīng)被軟刪除了。要啟用模型的軟刪除功能,可以使用模型上的 Illuminate\Database\Eloquent\SoftDeletestrait 并添加 deleted_at列到$dates屬性:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model{
    use SoftDeletes;

    /**
     * 應該被調(diào)整為日期的屬性
     *
     * @var array
     */
    protected $dates = ['deleted_at'];
}

當然,應該添加 deleted_at列到數(shù)據(jù)表。Laravel 查詢構(gòu)建器包含一個幫助函數(shù)來創(chuàng)建該列:

Schema::table('flights', function ($table) {
    $table->softDeletes();
});

現(xiàn)在,當調(diào)用模型的delete 方法時,deleted_at 列將被設置為當前日期和時間,并且,當查詢一個使用軟刪除的模型時,被軟刪除的模型將會自動從查詢結(jié)果中排除。 判斷給定模型實例是否被軟刪除,可以使用 trashed方法:

if ($flight->trashed()) {
    //
}

6.4 查詢被軟刪除的模型

6.4.1 包含軟刪除模型

正如上面提到的,軟刪除模型將會自動從查詢結(jié)果中排除,但是,如果你想要軟刪除模型出現(xiàn)在查詢結(jié)果中,可以使用 withTrashed方法:

$flights = App\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();

withTrashed 方法也可以用于關(guān)聯(lián)查詢中:

$flight->history()->withTrashed()->get();

6.4.2 只獲取軟刪除模型

onlyTrashed 方法之獲取軟刪除模型:

$flights = App\Flight::onlyTrashed()
                ->where('airline_id', 1)
                ->get();

6.4.3 恢復軟刪除模型

有時候你希望恢復一個被軟刪除的模型,可以使用 restore 方法:

$flight->restore();

你還可以在查詢中使用 restore 方法來快速恢復多個模型:

App\Flight::withTrashed()
        ->where('airline_id', 1)
        ->restore();

withTrashed 方法一樣,restore 方法也可以用于關(guān)系查詢:

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

6.4.4 永久刪除模型

有時候你真的需要從數(shù)據(jù)庫中刪除一個模型,可以使用 forceDelete 方法:

// 強制刪除單個模型實例...
$flight->forceDelete();
// 強制刪除所有關(guān)聯(lián)模型...
$flight->history()->forceDelete();

7、查詢作用域

作用域允許你定義一個查詢條件的通用集合,這樣就可以在應用中方便地復用。例如,你需要頻繁獲取最受歡迎的用戶,要定義一個作用域,只需要簡單的在 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);
    }
}

7.1 使用查詢作用域

作用域被定義好了之后,就可以在查詢模型的時候調(diào)用作用域方法,但調(diào)用時不需要加上 scope 前綴,你甚至可以在同時調(diào)用多個作用域,例如:

$users = App\User::popular()->women()->orderBy('created_at')->get();

7.2 動態(tài)作用域

有時候你可能想要定義一個可以接收參數(shù)的作用域,你只需要將額外的參數(shù)添加到你的作用域即可。作用域參數(shù)應該被定義在$query 參數(shù)之后:

<?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);
    }
}

現(xiàn)在,你可以在調(diào)用作用域時傳遞參數(shù)了:

$users = App\User::ofType('admin')->get();

8、事件

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

8.1 基本使用

一個新模型被首次保存的時候,creatingcreated 事件會被觸發(fā)。如果一個模型已經(jīng)在數(shù)據(jù)庫中存在并調(diào)用 save/方法,updating/updated 事件會被觸發(fā)。 舉個例子,我們在服務提供者中定義一個 Eloquent 事件監(jiān)聽器,在事件監(jiān)聽器中,我們會調(diào)用給定模型的 isValid 方法,如果模型無效會返回 false。如果從 Eloquent 事件監(jiān)聽器中返回 false 則取消 save/update 操作:

<?php

namespace 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()
    {
        //
    }
}
上一篇:HTTP 路由下一篇:驗證