国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

快速入門

快速入門


Eloquent:入門

簡(jiǎn)介

Laravel 的 Eloquent ORM 提供了一個(gè)漂亮、簡(jiǎn)潔的 ActiveRecord 實(shí)現(xiàn)來和數(shù)據(jù)庫(kù)交互。每個(gè)數(shù)據(jù)庫(kù)表都有一個(gè)對(duì)應(yīng)的「模型」用來與該表交互。你可以通過模型查詢數(shù)據(jù)表中的數(shù)據(jù),以及在數(shù)據(jù)表中插入新記錄。

在開始之前,請(qǐng)確保在 config/database.php 中配置數(shù)據(jù)庫(kù)連接。更多關(guān)于數(shù)據(jù)庫(kù)配置的信息,請(qǐng)查看 文檔。

模型定義

首先,創(chuàng)建一個(gè) Eloquent 模型。 模型通常在 app 目錄中,但你可以根據(jù) composer.json 文件將他們放置在可以被自動(dòng)加載的任意位置。所有的 Eloquent 模型都繼承至 Illuminate\Database\Eloquent\Model 類。

創(chuàng)建模型最簡(jiǎn)單的方法就是使用 make:model Artisan 命令:

php artisan make:model Flight

如果要在生成模型的時(shí)候生成 數(shù)據(jù)庫(kù)遷移 ,可以使用 --migration-m 選項(xiàng):

php artisan make:model Flight --migration

php artisan make:model Flight -m

Eloquent 模型約定

現(xiàn)在,我們來看一個(gè) Flight 模型的示例,我們將用它從 flights 數(shù)據(jù)庫(kù)表中檢索和存儲(chǔ)數(shù)據(jù)信息:

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

數(shù)據(jù)表名稱

請(qǐng)注意,我們并沒有告訴 Eloquent 我們的 Flight 模型使用哪個(gè)數(shù)據(jù)表。 除非明確地指定了其它名稱,否則將使用類的復(fù)數(shù)形式「蛇形命名」來作為表名。因此,在這種情況下,Eloquent 將假設(shè) Flight 模型存儲(chǔ)的是 flights 數(shù)據(jù)表中的數(shù)據(jù)。你可以通過在模型上定義 table 屬性來指定自定義數(shù)據(jù)表:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{ 
    /**
     * 與模型關(guān)聯(lián)的表名
     *
     * @var string
     */  
   protected $table = 'my_flights';
 }

主鍵

Eloquent 也會(huì)假設(shè)每個(gè)數(shù)據(jù)表都有一個(gè)名為 id 的主鍵列。你可以定義一個(gè)受保護(hù)的 $primaryKey 屬性來重寫約定。

此外,Eloquent 假設(shè)主鍵是一個(gè)自增的整數(shù)值,這意味著默認(rèn)情況下主鍵會(huì)自動(dòng)轉(zhuǎn)換為 int 類型。如果您希望使用非遞增或非數(shù)字的主鍵則需要設(shè)置公共的  $incrementing 屬性設(shè)置為 false。如果你的主鍵不是一個(gè)整數(shù),你需要將模型上受保護(hù)的 $keyType 屬性設(shè)置為 string

時(shí)間戳

默認(rèn)情況下,Eloquent 預(yù)期你的數(shù)據(jù)表中存在 created_atupdated_at 。如果你不想讓 Eloquent 自動(dòng)管理這兩個(gè)列, 請(qǐng)將模型中的 $timestamps 屬性設(shè)置為 false

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{    
    /**
     * 指示模型是否自動(dòng)維護(hù)時(shí)間戳
     *
     * @var bool
     */    
   public $timestamps = false;
  }

如果需要自定義時(shí)間戳的格式,在你的模型中設(shè)置 $dateFormat 屬性。這個(gè)屬性決定日期屬性在數(shù)據(jù)庫(kù)的存儲(chǔ)方式,以及模型序列化為數(shù)組或者 JSON 的格式:

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

如果你需要自定義存儲(chǔ)時(shí)間戳的字段名,可以在模型中設(shè)置 CREATED_ATUPDATED_AT 常量的值來實(shí)現(xiàn):

<?php
    class Flight extends Model{
        const CREATED_AT = 'creation_date';    
        const UPDATED_AT = 'last_update';
     }

數(shù)據(jù)庫(kù)連接

默認(rèn)情況下,Eloquent 模型將使用你的應(yīng)用程序配置的默認(rèn)數(shù)據(jù)庫(kù)連接。如果你想為模型指定一個(gè)不同的連接,設(shè)置 $connection 屬性:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{   
     /**
     * 模型的連接名稱
     *
     * @var string
     */   
     protected $connection = 'connection-name';
   }

默認(rèn)屬性值

如果要為模型的某些屬性定義默認(rèn)值,可以在模型上定義 $attributes 屬性:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{  
      /**
     * 模型的默認(rèn)屬性值。
     *
     * @var array
     */  
      protected $attributes = [      
        'delayed' => false,   
         ];
      }

模型檢索

創(chuàng)建模型和 它關(guān)聯(lián)的數(shù)據(jù)庫(kù)表后,你就可以從數(shù)據(jù)庫(kù)中查詢數(shù)據(jù)了。將每個(gè) Eloquent 模型想象成一個(gè)強(qiáng)大的查詢構(gòu)造器 query builder ,你可以用它更快速的查詢與其相關(guān)聯(lián)的數(shù)據(jù)表。例如:

<?php
    $flights = App\Flight::all();
    foreach ($flights as $flight) {   
     echo $flight->name;
    }

附加約束

Eloquent 的 all 方法會(huì)返回模型中所有的結(jié)果。由于每個(gè) Eloquent 模型都充當(dāng)一個(gè)查詢構(gòu)造器,所以你也可以添加查詢條件,然后使用 get 方法獲取查詢結(jié)果:

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

{tip} 因?yàn)?Eloquent 模型也是查詢構(gòu)造器,所以你也應(yīng)當(dāng)閱讀 查詢構(gòu)造器可用的所有方法。你可以在 Eloquent 查詢中使用這些方法。

重新加載模型

你可以使用 freshrefresh 方法重新加載模型。 fresh 方法會(huì)重新從數(shù)據(jù)庫(kù)中檢索模型。現(xiàn)有的模型實(shí)例不受影響:

$flight = App\Flight::where('number', 'FR 900')->first();
$freshFlight = $flight->fresh();

refresh 方法使用數(shù)據(jù)庫(kù)中的新數(shù)據(jù)重新賦值現(xiàn)有模型。此外,已經(jīng)加載的關(guān)系會(huì)被重新加載:

$flight = App\Flight::where('number', 'FR 900')->first();
$flight->number = 'FR 456';$flight->refresh();
$flight->number;
 // "FR 900"

集合

對(duì)于 Eloquent 中的 allget 方法可以查詢多個(gè)結(jié)果,返回一個(gè) Illuminate\Database\Eloquent\Collection 實(shí)例。  Collection 類提供了 很多輔助函數(shù) 來處理 Eloquent 結(jié)果:

$flights = $flights->reject(function ($flight) { 
   return $flight->cancelled;
 });

你可以像數(shù)組一樣遍歷集合:

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

分塊結(jié)果

如果你需要處理數(shù)以千計(jì)的 Eloquent 結(jié)果,使用 chunk 命令。 chunk 方法會(huì)檢索 Eloquent 模型中的『分塊』將他們提供給指定的 Closure 處理。在處理大型結(jié)果集時(shí),使用  chunk 方法可以節(jié)省內(nèi)存:

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

傳遞到方法的第一個(gè)參數(shù)是希望每個(gè)『分塊』接收的數(shù)據(jù)量。閉包作為第二個(gè)參數(shù)傳遞,它在每次從數(shù)據(jù)庫(kù)中檢索分塊的時(shí)候調(diào)用。它將執(zhí)行數(shù)據(jù)庫(kù)查詢把檢索分塊的結(jié)果傳遞給閉包方法。

使用游標(biāo)

cursor 方法允許你使用游標(biāo)遍歷數(shù)據(jù)庫(kù),它只執(zhí)行一次查詢。處理大量的數(shù)據(jù)時(shí), cursor 方法可以大大減少內(nèi)存的使用量:

foreach (Flight::where('foo', 'bar')->cursor() as $flight) {
    //
 }

檢索單個(gè)模型 / 集合

除了從指定的數(shù)據(jù)表檢索所有記錄外,你可以使用 findfirst 方法來檢索單條記錄。這些方法返回單個(gè)模型實(shí)例,而不是返回模型集合:

// 通過主鍵檢索一個(gè)模型...
$flight = App\Flight::find(1);
// 檢索符合查詢限制的第一個(gè)模型...
$flight = App\Flight::where('active', 1)->first();

你也可以使用主鍵數(shù)組作為參數(shù)調(diào)用 find 方法,它將返回匹配記錄的集合:

$flights = App\Flight::find([1, 2, 3]);

『未找到』異常

有時(shí)你希望在未找到模型時(shí)拋出異常。這在控制器和路由中非常有用。 findOrFailfirstOrFail 方法會(huì)檢索查詢的第一個(gè)結(jié)果,如果未找到,將拋出 Illuminate\Database\Eloquent\ModelNotFoundException 異常:

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

如果沒有捕獲異常,則會(huì)自動(dòng)返回 404 響應(yīng)給用戶。也就是說,使用這些方法時(shí),沒有必要再寫個(gè)檢查來返回 404 響應(yīng)::

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

檢索集合

你還可以使用 查詢構(gòu)造器 提供的 count , sum, max, 和其他的聚合函數(shù)。這些方法只會(huì)返回適當(dāng)?shù)臉?biāo)量值而不是一個(gè)模型實(shí)例:

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

插入 & 更新模型

插入

要往數(shù)據(jù)庫(kù)新增一條記錄,先創(chuàng)建新模型實(shí)例,給實(shí)例設(shè)置屬性,然后調(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)建一個(gè)新的航班實(shí)例
     *
     * @param  Request  $request
     * @return Response
     */  
     public function store(Request $request)   
      {      
        // 校驗(yàn)請(qǐng)求...        
        $flight = new Flight;        
        $flight->name = $request->name;        
        $flight->save();  
        }
   }

在這個(gè)示例中,我們將 HTTP 請(qǐng)求參數(shù) name 賦值給了 App\Flight 模型實(shí)例的 name 屬性。當(dāng)調(diào)用 save 方法時(shí),將會(huì)插入一條新記錄。 created_atupdated_at 時(shí)間戳將會(huì)自動(dòng)設(shè)置,不需要手動(dòng)賦值。

更新

save 方法也可以用來更新數(shù)據(jù)庫(kù)已經(jīng)存在的模型。更新模型,你需要先檢索出來,設(shè)置要更新的屬性,然后調(diào)用 save 方法。同樣, updated_at 時(shí)間戳?xí)詣?dòng)更新,所以也不需要手動(dòng)賦值:

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

批量更新

也可以更新匹配查詢條件的多個(gè)模型。在這個(gè)示例中,所有的 active 和  destinationSan Diego 的航班會(huì)標(biāo)記為延誤:

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

update 方法接受一個(gè)鍵為字段名稱數(shù)據(jù)為值的數(shù)組。

{note} 通過 Eloquent 批量更新時(shí), 更新的模型不會(huì)觸發(fā) savedupdated 事件。因?yàn)樵谂扛聲r(shí),從不會(huì)去檢索模型。

批量賦值

你也可以使用 create 方法來保存新模型,此方法會(huì)返回模型實(shí)例。不過,在使用之前,你需要在模型上指定 fillableguarded 屬性,因?yàn)樗械?Eloquent 模型都默認(rèn)不可進(jìn)行批量賦值。

當(dāng)用戶通過 HTTP 請(qǐng)求傳入一個(gè)意外的參數(shù),并且該參數(shù)更改了數(shù)據(jù)庫(kù)中你不需要更改的字段時(shí)。比如:惡意用戶可能會(huì)通過 HTTP 請(qǐng)求傳入 is_admin  參數(shù),然后將其傳給 create 方法,此操作能讓用戶將自己升級(jí)成管理員。

所以,在開始之前,你應(yīng)該定義好模型上的哪些屬性是可以被批量賦值的。你可以通過模型上的 $fillable 屬性來實(shí)現(xiàn)。 例如:讓 Flight 模型的 name 屬性可以被批量賦值:

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

一旦我們?cè)O(shè)置好了可以批量賦值的屬性,就可以通過 create 方法插入新數(shù)據(jù)到數(shù)據(jù)庫(kù)中了。 create 方法將返回保存的模型實(shí)例:

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

如果你已經(jīng)有一個(gè)模型實(shí)例,你可以傳遞一個(gè)數(shù)組給 fill 方法來賦值:

$flight->fill(['name' => 'Flight 22']);

保護(hù)屬性

$fillable 可以看作批量賦值的「白名單」, 你也可以使用 $guarded 屬性來實(shí)現(xiàn)。 $guarded 屬性包含的是不允許批量賦值的數(shù)組。也就是說, $guarded 從功能上將更像是一個(gè)「黑名單」。注意:你只能使用 $fillable$guarded 二者中的一個(gè),不可同時(shí)使用。下面這個(gè)例子中,除了 price 屬性,其他的屬性都可以批量賦值:

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

如果你想讓所有屬性都可以批量賦值, 你可以將 $guarded 定義成一個(gè)空數(shù)組:

/**
 * 不可以批量賦值的屬性。
 *
 * @var array
 */
 protected $guarded = [];

其他創(chuàng)建方法

firstOrCreate/ firstOrNew

這里有兩個(gè)你可能用來批量賦值的方法: firstOrCreatefirstOrNewfirstOrCreate 方法會(huì)通過給定的 列 / 值 來匹配數(shù)據(jù)庫(kù)中的數(shù)據(jù)。如果在數(shù)據(jù)庫(kù)中找不到對(duì)應(yīng)的模型, 則會(huì)從第一個(gè)參數(shù)的屬性乃至第二個(gè)參數(shù)的屬性中創(chuàng)建一條記錄插入到數(shù)據(jù)庫(kù)。

firstOrNew 方法像 firstOrCreate 方法一樣嘗試通過給定的屬性查找數(shù)據(jù)庫(kù)中的記錄。不同的是,如果 firstOrNew 方法找不到對(duì)應(yīng)的模型,會(huì)返回一個(gè)新的模型實(shí)例。注意 firstOrNew 返回的模型實(shí)例尚未保存到數(shù)據(jù)庫(kù)中,你需要手動(dòng)調(diào)用 save 方法來保存:

// 通過 name 來查找航班,不存在則創(chuàng)建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);
// 通過 name 查找航班,不存在則使用 name 和 delayed 屬性創(chuàng)建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10'], ['delayed' => 1]);
//  通過 name 查找航班,不存在則創(chuàng)建一個(gè)實(shí)例...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);
// 通過 name 查找航班,不存在則使用 name 和 delayed 屬性創(chuàng)建一個(gè)實(shí)例...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10'], ['delayed' => 1]);

updateOrCreate

你還可能遇到希望更新現(xiàn)有模型或在不存在的情況下則創(chuàng)建新的模型的情景。 Laravel 提供了 updateOrCreate 方法僅一個(gè)步驟就可以實(shí)現(xiàn)。跟 firstOrCreate 方法一樣,updateOrCreate 匹配到對(duì)應(yīng)模型,所以不需要調(diào)用 save() 方法:

// 如果有從奧克蘭到圣地亞哥的航班,則價(jià)格定為99美元。
// 如果沒匹配到存在的模型,則創(chuàng)建一個(gè)。
$flight = App\Flight::updateOrCreate( 
   ['departure' => 'Oakland', 'destination' => 'San Diego'],    
   ['price' => 99]
 );

刪除模型

可以在模型實(shí)例上調(diào)用 delete 方法來刪除實(shí)例:

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

通過主鍵刪除模型

在上面的例子中,在調(diào)用 delete 之前需要先去數(shù)據(jù)庫(kù)中查找對(duì)應(yīng)的模型。事實(shí)上,如果你知道了模型的主鍵,你可以直接使用 destroy 方法來刪除模型,而不用先去數(shù)據(jù)庫(kù)中查找。 destroy 方法除了接受單個(gè)主鍵作為參數(shù)之外,還接受多個(gè)主鍵,或者使用數(shù)組,集合來保存多個(gè)主鍵:

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

通過查詢刪除模型

你也可以在模型上運(yùn)行刪除語(yǔ)句。在這個(gè)例子中,我們將刪除所有標(biāo)記為非活躍的航班。與批量更新一樣,批量刪除不會(huì)為刪除的模型啟動(dòng)任何模型事件:

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

{note} 通過 Eloquent 執(zhí)行批量刪除語(yǔ)句時(shí),不會(huì)觸發(fā)  deletingdeleted 模型事件。因此,在執(zhí)行刪除語(yǔ)句時(shí),從不檢索模型示例。

軟刪除

除了真實(shí)刪除數(shù)據(jù)庫(kù)記錄, Eloquent  也可以「軟刪除」模型。軟刪除的模型并不是真的從數(shù)據(jù)庫(kù)中刪除了。事實(shí)上,是在模型上設(shè)置了 deleted_at 屬性并將其值寫入數(shù)據(jù)庫(kù)。如果 deleted_at 值非空,代表這個(gè)模型已被軟刪除。如果要開啟模型軟刪除功能,你需要在模型上使用 Illuminate\Database\Eloquent\SoftDeletes trait:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\SoftDeletes;
    class Flight extends Model{
        use SoftDeletes;
       }

{tip}  SoftDeletes trait 會(huì)自動(dòng)將 deleted_at 屬性轉(zhuǎn)換成  DateTime / Carbon 實(shí)例

當(dāng)然,你需要把 deleted_at 字段添加到數(shù)據(jù)表中。 Laravel 的 數(shù)據(jù)庫(kù)遷移 有創(chuàng)建這個(gè)字段的方法:

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

那現(xiàn)在,當(dāng)你在模型實(shí)例上使用 delete 方法, 當(dāng)前日期時(shí)間會(huì)寫入 deleted_at 字段。同時(shí),查詢出來的結(jié)果也會(huì)自動(dòng)排除已被軟刪除的記錄。

你可以使用 trashed 方法來驗(yàn)證當(dāng)前模型是否軟刪除:

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

查詢軟刪除模型

包括已軟刪除的模型

前面提到,查詢結(jié)果會(huì)自動(dòng)剔除已被軟刪除的結(jié)果。當(dāng)然,你可以使用 withTrashed 方法來獲取包括軟刪除模型在內(nèi)的模型:

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

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

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

檢索軟刪除模型

onlyTrashed 方法   獲取已軟刪除的模型:

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

恢復(fù)軟刪除模型

有時(shí)會(huì)對(duì)軟刪除模型進(jìn)行 「撤銷」,在已軟刪除的數(shù)據(jù)上使用 restore 方法即可恢復(fù)到有效狀態(tài):

$flight->restore();

你也可以在查詢中使用 restore 方法,從而快速恢復(fù)多個(gè)模型。和其他批量」操作一樣,這個(gè)操作不會(huì)觸發(fā)模型的任何事件:

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

類似 withTrashed 方法, restore 方法也用在 關(guān)聯(lián)上:

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

永久刪除

要真實(shí)刪除數(shù)據(jù)時(shí),使用 forceDelete 方法即可:

// 單個(gè)模型實(shí)例的永久刪除...
$flight->forceDelete();
// 關(guān)聯(lián)模型的永久刪除...
$flight->history()->forceDelete();

查詢作用域

全局作用域

全局作用域可以給模型的查詢都添加上約束。Laravel 的  軟刪除 功能就是利用此特性從數(shù)據(jù)庫(kù)中獲取 「未刪除」的模型。 你可以編寫你自己的全局作用域,很簡(jiǎn)單、方便的為每個(gè)模型查詢都加上約束條件:

編寫全局作用域

編寫全局作用域很簡(jiǎn)單。定義一個(gè)實(shí)現(xiàn) Illuminate\Database\Eloquent\Scope 接口的類,并實(shí)現(xiàn) apply 這個(gè)方法。 根據(jù)你的需求,在 apply 方法中加入查詢的 where 條件:

<?php
    namespace App\Scopes;
    use Illuminate\Database\Eloquent\Scope;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Builder;
    class AgeScope implements Scope{  
      /**
     * 把約束加到 Eloquent 查詢構(gòu)造中。
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */  
      public function apply(Builder $builder, Model $model)  
        {       
         $builder->where('age', '>', 200);   
         }
      }

{tip} 如果需要在 select 語(yǔ)句里添加字段,應(yīng)使用 addSelect 方法,而不是 select 方法。 這將有效防止無意中替換現(xiàn)有 select 語(yǔ)句的情況。

應(yīng)用全局作用域

要將全局作用域分配給模型,需要重寫模型的 boot 方法并使用 addGlobalScope 方法:

<?php
    namespace App;use App\Scopes\AgeScope;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model{  
      /**
     *  模型的 「啟動(dòng)」 方法.
     *
     * @return void
     */  
     protected static function boot()  
       {     
          parent::boot();        
          static::addGlobalScope(new AgeScope);  
        }
   }

添加作用域后,對(duì) User::all() 的查詢會(huì)生成以下 SQL 查詢語(yǔ)句:

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

匿名全局作用域

Eloquent 同樣允許使用閉包定義全局作用域,這樣就不需要為一個(gè)簡(jiǎn)單的作用域而編寫一個(gè)單獨(dú)的類:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Builder;
    class User extends Model{  
      /**
     *模型的「啟動(dòng)」方法.
     *
     * @return void
     */  
     protected static function boot()   
      {      
        parent::boot();        
        static::addGlobalScope('age', function (Builder $builder) {  
                  $builder->where('age', '>', 200);       
                }); 
       }
   }

取消全局作用域

如果需要對(duì)當(dāng)前查詢?nèi)∠肿饔糜颍枰褂?withoutGlobalScope 方法。 該方法僅接受全局作用域類名作為它唯一的參數(shù):

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

或者,如果使用閉包定義全局作用域的話:

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

如果你需要取消部分或者全部的全局作用域的話,需要使用  withoutGlobalScopes 方法:

// 取消所有的全局作用域...
User::withoutGlobalScopes()->get();
// 取消部分全局作用域...
User::withoutGlobalScopes([ 
   FirstScope::class, SecondScope::class
 ])->get();

本地作用域

本地作用域允許定義通用的約束集合以便在應(yīng)用程序中重復(fù)使用。例如,你可能經(jīng)常需要獲取所有 「流行」的用戶。 要定義這樣一個(gè)范圍,只需要在對(duì)應(yīng)的 Eloquent 模型方法前添加 scope 前綴:

作用域總是返回一個(gè)查詢構(gòu)造器實(shí)例:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model{  
      /**
     * 只查詢受歡迎的用戶的作用域.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */   
      public function scopePopular($query)  
        {      
          return $query->where('votes', '>', 100);   
        }    
     /**
     * 只查詢 active 用戶的作用域.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */  
      public function scopeActive($query)  
        {      
          return $query->where('active', 1);  
         }
      }

使用本地作用域

一旦定義了作用域,就可以在查詢?cè)撃P蜁r(shí)調(diào)用作用域方法。不過,在調(diào)用這些方法時(shí)不必包含 scope 前綴。甚至可以鏈?zhǔn)秸{(diào)用多個(gè)作用域,例如:

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

借助 or 查詢運(yùn)行符整合多個(gè) Eloquent 模型,可能需要使用閉包回調(diào):

$users = App\User::popular()->orWhere(function (Builder $query) {
    $query->active();
   })->get();

因?yàn)檫@樣可能會(huì)有點(diǎn)麻煩,Laravel 提供了「高階的」 orWhere 方法,它允許你在鏈?zhǔn)秸{(diào)用作用域時(shí)不使用閉包:

$users = App\User::popular()->orWhere->active()->get();

動(dòng)態(tài)作用域

有時(shí)可能地希望定義一個(gè)可以接受參數(shù)的作用域。把額外參數(shù)傳遞給作用域就可以達(dá)到此目的。作用域參數(shù)要放在 $query 參數(shù)之后:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model{   
     /**
     * 將查詢作用域限制為僅包含給定類型的用戶。
     *
     * @param  \Illuminate\Database\Eloquent\Builder $query
     * @param  mixed $type
     * @return \Illuminate\Database\Eloquent\Builder
     */   
    public function scopeOfType($query, $type)  
      {      
        return $query->where('type', $type);   
       }
      }

這樣就可以在調(diào)用作用域時(shí)傳遞參數(shù)了:

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

模型比較

有時(shí)可能需要判斷兩個(gè)模型是否「相同」。 is 方法可以用來快速校驗(yàn)兩個(gè)模型是否擁有相同的主鍵、表和數(shù)據(jù)庫(kù)連接:

if ($post->is($anotherPost)) { 
   //
 }

事件

Eloquent 模型觸發(fā)幾個(gè)事件,允許你掛接到模型生命周期的如下節(jié)點(diǎn): retrieved、 creatingcreated、 updating、 updated、 saving、 saved、 deletingdeleted、 restoringrestored。事件允許你每當(dāng)特定模型保存或更新數(shù)據(jù)庫(kù)時(shí)執(zhí)行代碼。每個(gè)事件通過其構(gòu)造器接受模型實(shí)例。

retrieved 事件在現(xiàn)有模型從數(shù)據(jù)庫(kù)中查找數(shù)據(jù)時(shí)觸發(fā)。當(dāng)新模型每一次保存時(shí), creatingcreated 事件被觸發(fā)。如果數(shù)據(jù)庫(kù)中已經(jīng)存在模型并且調(diào)用了 save 方法, updating / updated 事件被觸發(fā)。這些情況下, saving / saved 事件也被觸發(fā)。

{note} 通過 Eloquent 進(jìn)行批量更新時(shí),被更新模型的 savedupdated 事件不會(huì)被觸發(fā)。這是因?yàn)榕扛聲r(shí),并沒有真的獲取模型。

首先,在 Eloquent 模型上定義一個(gè) $dispatchesEvents 屬性,將 Eloquent 模型生命周期的幾個(gè)節(jié)點(diǎn)映射到你自己的 event 類 :

<?php
    namespace App;
    use App\Events\UserSaved;
    use App\Events\UserDeleted;
    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    class User extends Authenticatable{  
      use Notifiable;   
       /**
     * 為模型事件。
     *
     * @var array
     */ 
      protected $dispatchesEvents = [    
          'saved' => UserSaved::class,        
          'deleted' => UserDeleted::class,   
           ];
       }

定義并且映射了 Eloquent 事件,就可以使用 event 監(jiān)聽器 listeners 處理這些事件了。

觀察者

定義觀察者

如果在一個(gè)模型上監(jiān)聽了多個(gè)事件,可以使用觀察者來將這些監(jiān)聽器組織到一個(gè)單獨(dú)的類中。觀察者類的方法名映射到你希望監(jiān)聽的 Eloquent 事件。 這些方法都以模型作為其唯一參數(shù)。 make:observer Artisan 命令可以快速建立新的觀察者類:

php artisan make:observer UserObserver --model=User

此命令將在 App/Observers 文件夾放置新的觀察者類。如果這個(gè)目錄不存在,Artisan 將替你創(chuàng)建。使用如下方式開啟觀察者:

<?php
    namespace App\Observers;
    use App\User;
    class UserObserver{   
     /**
     * 處理 User 「新建」事件。
     *
     * @param  \App\User  $user
     * @return void
     */   
      public function created(User $user) 
         {      
           //  
          }   
     /**
     * 處理 User 「更新」 事件。
     *
     * @param  \App\User  $user
     * @return void
     */   
      public function updated(User $user)  
        {      
          //   
         }   
     /**
     * 處理 User 「刪除」 事件。
     *
     * @param  \App\User  $user
     * @return void
     */   
     public function deleted(User $user) 
        {   
             //   
         }
   }

在你希望觀察的模型上使用 observe 方法注冊(cè)觀察者。也可以在服務(wù)提供者的 boot 方法注冊(cè)觀察者。下面是在 AppServiceProvider 中注冊(cè)觀察者的示例:

<?php
    namespace App\Providers;
    use App\User;use App\Observers\UserObserver;
    use Illuminate\Support\ServiceProvider;
    class AppServiceProvider extends ServiceProvider{  
      /**
     * 啟動(dòng)應(yīng)用服務(wù)。
     *
     * @return void
     */   
      public function boot()  
       {       
         User::observe(UserObserver::class);   
       }  
    /**
     * 注冊(cè)服務(wù)提供者。
     *
     * @return void
     */  
     public function register() 
        {      
          //   
         }
      }
本文章首發(fā)在 LearnKu.com 網(wǎng)站上。