laravel 基礎(chǔ)教程 —— Eloquent

Eloquent: 起步

簡(jiǎn)介

Laravel 的 Eloquent ORM 提供了一種漂亮簡(jiǎn)潔的關(guān)系映射的模型來(lái)與數(shù)據(jù)庫(kù)進(jìn)行交互侄榴。所有的數(shù)據(jù)庫(kù)表都有相應(yīng)的模型吠撮,這些模型被用來(lái)與表進(jìn)行交互笆载。模型允許你直接查詢(xún)數(shù)據(jù)庫(kù)表中的數(shù)據(jù)蜈漓,及插入新的記錄到數(shù)據(jù)表中蛹锰。

在開(kāi)始之前粘舟,你需要確保完成了 config/database.php 配置文件中的數(shù)據(jù)庫(kù)配置熔脂。對(duì)于更多的配置數(shù)據(jù)庫(kù)相關(guān)的信息,請(qǐng)參考 文檔柑肴。

定義模型

在開(kāi)始之前霞揉,讓我們先來(lái)創(chuàng)建一個(gè) Eloquent 模型。模型通常存放在 app 目錄下晰骑,但是你也可以自由的放置在任何地方适秩,只要它能夠根據(jù)你的 composer.json 文件的指導(dǎo)進(jìn)行自動(dòng)的加載。所有的 Eloquent 模型都繼承自 Illuminate\Database\Eloquent\Model 類(lèi)硕舆。

最簡(jiǎn)單的創(chuàng)建一個(gè)模型類(lèi)的方式就是使用 make:model Artisan 命令:

php artisan make:model User

如果你希望在你生成模型的同時(shí)生成一份數(shù)據(jù)庫(kù)遷移秽荞,你可以使用 --migration 或者 -m 選項(xiàng):

php artisan make:model User --migration

php artisan make:model User -m

Eloquent 模型約定

現(xiàn)在,讓我們來(lái)看一個(gè) Flight 模型的示例抚官,我們將通過(guò)它獲取和存儲(chǔ)數(shù)據(jù)庫(kù)中 flights 表的數(shù)據(jù):

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
  //
}

表名稱(chēng)

你需要注意我們上面的代碼中并沒(méi)有指出 Flight 模型使用哪個(gè)數(shù)據(jù)庫(kù)的表扬跋。如果你沒(méi)有明確的指出模型所對(duì)應(yīng)的表,那么 Eloquent 將使用類(lèi)的蛇形命名的復(fù)數(shù)形式來(lái)使用相應(yīng)的數(shù)據(jù)表凌节。所以钦听,在這個(gè)例子中,Eloquent 將會(huì)假定 Flight 模型存儲(chǔ)的記錄被放在 flights 表中倍奢。你可以使用 table 屬性來(lái)指定表名:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
  /**
   * The table associated with the model.
   *
   * @var string
   */
   protected $table = 'my_flights';
}

主鍵

Eloquent 也會(huì)假定所有表的主鍵列名為 id彪见。你也可使用 $primaryKey 屬性來(lái)手動(dòng)的指定表的主鍵。

另外娱挨,Eloquent 也會(huì)假定主鍵是一個(gè)自增的整型值余指,這意味著,在默認(rèn)情況下主鍵會(huì)被自動(dòng)的轉(zhuǎn)為 int。如果你希望使用非自增或者非數(shù)字的主鍵酵镜,那么你需要在模型中將公開(kāi)的 $incrementing 屬性設(shè)置為 false碉碉。

時(shí)間戳

默認(rèn)的,Eloquent 期望模型表中存在 created_atupdated_at 列淮韭,如果你不希望 Eloquent 自主的管理這兩列垢粮,你可以在模型中設(shè)置 $timestamps 屬性為 false:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
  /**
   * Indicates if the model should be timestamped.
   *
   * @var bool
   */
   public $timestamps = false;
}

如果你需要自定義時(shí)間戳的格式,你可以設(shè)置 $dateFormat 屬性靠粪。這個(gè)屬性用來(lái)決定日期屬性存儲(chǔ)在數(shù)據(jù)庫(kù)中的格式蜡吧,以及模型在進(jìn)行序列化為數(shù)組或者 JSON 時(shí)的顯示樣式:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
  /**
   * The storage format of the model's date columns.
   *
   * @var string
   */
   protected $dateFormat = 'U';
}

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

默認(rèn)的,所有的 Eloquent 模型都會(huì)使用應(yīng)用配置的默認(rèn)的數(shù)據(jù)庫(kù)連接占键。如果你希望模型使用不同的數(shù)據(jù)庫(kù)連接昔善,你可以使用 $connection 屬性:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
  /**
   * The connection name for the model.
   *
   * @var string
   */
   protected $connection = 'connection-name';
}

檢索多個(gè)模型

一旦你創(chuàng)建了模型和其相應(yīng)的數(shù)據(jù)表,你就為從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)做好了準(zhǔn)備畔乙。你可以把 Eloquent 模型作為一個(gè)強(qiáng)大的查詢(xún)生成器來(lái)使用君仆,它允許通過(guò)模型流暢的查詢(xún)相應(yīng)的表中的數(shù)據(jù)。比如:

<?php

namespace App\Http\Controllers;

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

class FlightController extends Controller
{
  /**
   * Show a list of all available flights.
   *
   * @return Response
   */
  public function index()
  {
    $flights = Flight::all();

    return view('flight.index', ['flights' => $flights]);
  }
}

訪(fǎng)問(wèn)列的值

如果你獲得了 Eloquent 模型的實(shí)例牲距,那么你可以通過(guò)模型中相應(yīng)的列名的屬性來(lái)訪(fǎng)問(wèn)表中列的值返咱。比如,讓我們循環(huán)查詢(xún)的結(jié)果牍鞠,并通過(guò)獲取的 Flight 實(shí)例來(lái)獲得 name 列的值:

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

添加額外的條件

Eloquent 的 all 方法會(huì)返回模型表中所有的記錄咖摹。由于所有的 Eloquent 模型都可以作為查詢(xún)生成器來(lái)進(jìn)行服務(wù),所以你可以在這些查詢(xún)中增加額外的條件难述,然后使用 get 方法來(lái)檢索結(jié)果:

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

注意:由于 Eloquent 模型也是查詢(xún)生成器萤晴,所以你可以回顧一下查詢(xún)生成器中所有可用的方法,因?yàn)樗鼈兺瑯涌梢栽?Eloquent 中進(jìn)行使用龄广。

集合

對(duì)于像 allget 這樣的 Eloquent 方法會(huì)返回多個(gè)結(jié)果硫眯,這將返回一個(gè) Illuminate\Database\Eloquent\Collection 實(shí)例蕴侧。Collection 類(lèi)提供了各種有用的方法與 Eloquent 結(jié)果進(jìn)行交互择同。當(dāng)然,你可以簡(jiǎn)單的對(duì)集合進(jìn)行循環(huán)净宵,因?yàn)樗麑?shí)現(xiàn)了 ArrayAccess 接口:

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

對(duì)結(jié)果進(jìn)行分塊

如果你需要處理數(shù)千條 Eloquent 記錄敲才,那么你可以使用 chunk 方法。chunk 方法會(huì)從 Eloquent 模型中檢索出一小塊記錄择葡,然后將其傳遞給 Closure 進(jìn)行處理紧武。使用 chunk 方法在處理大量結(jié)果集時(shí)可有有效的降低內(nèi)存的消耗:

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

傳遞到方法的第一個(gè)參數(shù)是你要設(shè)置進(jìn)行分塊的大小。而傳遞到第二個(gè)參數(shù)的閉包將會(huì)在從數(shù)據(jù)庫(kù)檢索出每塊內(nèi)容時(shí)進(jìn)行調(diào)用敏储。

檢索單個(gè)模型 / 統(tǒng)計(jì)

當(dāng)然阻星,除了可以從表中檢索出所有的記錄之外,你也可以使用 findfirst 方法來(lái)從數(shù)據(jù)庫(kù)中檢索出單條的數(shù)據(jù)。這將會(huì)返回一個(gè)單獨(dú)的模型實(shí)例:

// Retrieve a model by its primary key...
$flight = App\Flight::find(1);

// Retrieve the first model matching the query constraints...
$flight = App\Flight::where('active', 1)->first();

你也可以使用 find 方法時(shí)傳遞一個(gè)包含主鍵所組成的數(shù)組妥箕,這將返回所有匹配到記錄的集合:

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

未發(fā)現(xiàn)時(shí)的異常

有時(shí)候滥酥,你可能希望在沒(méi)有找到匹配的模型時(shí)拋出一個(gè)異常。這對(duì)路由或者控制器來(lái)說(shuō)尤其有用畦幢。findOrFailfirstOrFail 方法可以從查詢(xún)中檢索出首個(gè)匹配的結(jié)果坎吻,但是,如果結(jié)果中沒(méi)有匹配的項(xiàng)宇葱,那么會(huì)拋出一個(gè) Illuminate\Database\Eloquent\ModelNotFoundException 異常:

$model = App\Flight::findOrFail(1);

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

如果異常沒(méi)有被捕獲瘦真,那么會(huì)直接傳遞給用戶(hù)一個(gè) 404 HTTP 響應(yīng)。所以當(dāng)你在使用這些方法時(shí)是沒(méi)有必要編寫(xiě)明確的檢查并返回 404 響應(yīng)的:

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

檢索統(tǒng)計(jì)

當(dāng)然黍瞧,你可以使用 count诸尽,summax 和其他 查詢(xún)生成器 所提供的的 聚合函數(shù)雷逆。這些方法會(huì)返回適當(dāng)?shù)臄?shù)值弦讽,而不是完整的模型實(shí)例:

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

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

插入 & 更新模型

基礎(chǔ)插入

想要在數(shù)據(jù)庫(kù)中插入新的記錄,只需要簡(jiǎn)單的創(chuàng)建模型實(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
{
  /**
   * Create a new flight instance.
   *
   * @param Request $request
   * @return Response
   */
   public function store(Request $request)
   {
     // Validate the request...

     $flight = new Flight;

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

     $flight->save();
   }
}

在這個(gè)例子中,我們簡(jiǎn)單的從流入的 HTTP 請(qǐng)求中的 name 參數(shù)分配到 App\Flight 模型實(shí)例的 name 屬性上某宪。當(dāng)我們調(diào)用 save 方法時(shí)仿村,這條記錄將會(huì)插入到數(shù)據(jù)庫(kù)中,同時(shí) created_atupdated_at 時(shí)間戳也會(huì)自動(dòng)的被進(jìn)行設(shè)置兴喂,所以這并不需要進(jìn)行手動(dòng)的設(shè)置它們蔼囊。

基礎(chǔ)的更新

save 方法也可用來(lái)更新數(shù)據(jù)庫(kù)中已經(jīng)存在的數(shù)據(jù)模型。為了更新模型衣迷,你應(yīng)該首先檢索到它們畏鼓,然后設(shè)置任何你想要更新的屬性,接著調(diào)用 save 方法壶谒。這一次云矫,updated_at 時(shí)間戳?xí)詣?dòng)的進(jìn)行更新,所以你并不需要手動(dòng)的更新這個(gè)值:

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

$flight->name = 'New Flight Name';

$flight->save();

你也可以針對(duì)查詢(xún)匹配的多個(gè)模型進(jìn)行更新操作汗菜。比如让禀,所有 active 并且 destinationSan Diego 的航班將會(huì)被標(biāo)記為延遲:

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

update 方法接收一個(gè)想要更新的列的鍵值對(duì)數(shù)組。

批量賦值

你也可以使用 create 方法來(lái)在一行中存儲(chǔ)一個(gè)新的模型陨界。一個(gè)新增的模型實(shí)例將會(huì)從方法中返回巡揍。事實(shí)上,在開(kāi)始做這些之前菌瘪,你需要先指定模型的 fillable 或者 guarded 屬性腮敌,它們是針對(duì)批量賦值時(shí)的保護(hù)措施。

當(dāng)用戶(hù)通過(guò) HTTP 請(qǐng)求傳遞一些意外的參數(shù)時(shí),這可能會(huì)造成批量賦值時(shí)一些問(wèn)題的出現(xiàn)糜工,或許參數(shù)中存在一些你并不想改變的列值的參數(shù)斗这。比如,一個(gè)惡意的用戶(hù)可能會(huì)在請(qǐng)求中嵌入一個(gè) is_admin 參數(shù)啤斗,然后這些參數(shù)映射到你的 create 方法中表箭,這就使用戶(hù)將自己升級(jí)為了超級(jí)管理員。

所以钮莲,在開(kāi)始之前免钻,你需要先定義哪些模型屬性是可以進(jìn)行批量分配的。你可以使用模型 $fillable 屬性崔拥,讓我們?cè)?Flight 模型中添加允許 name 屬性的批量賦值:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Dlight extends Model
{
  /**
   * The attributes that are mass assignable.
   *
   * @var array
   */
   protected $fillable = ['name'];
}

一旦我們使一個(gè)屬性可以進(jìn)行批量賦值极舔。那么我們可以使用 create 方法直接的添加記錄到數(shù)據(jù)中。create 方法會(huì)返回存儲(chǔ)后的模型實(shí)例:

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

$fillable 就像是為批量賦值提供了一種白名單的機(jī)制链瓦。你也可以選擇使用 $guarded拆魏。$guarded 屬性應(yīng)該包含一個(gè)你不想要進(jìn)行批量賦值的屬性所組成的數(shù)組。所有不在這個(gè)數(shù)組中的屬性都將可以進(jìn)行批量賦值慈俯。所以渤刃,$guarded 就像一個(gè)黑名單的功能。當(dāng)然贴膘,你應(yīng)該只使用 $fillable 或者 $guarded 中的一個(gè)卖子,而不是全部:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
  /**
   * The attributes that aren't mass assignable.
   *
   * @var array
   */
   protected $guarded = ['price'];
}

在上面的例子中,除了 price刑峡,所有的屬性都可以進(jìn)行批量賦值洋闽。

其他創(chuàng)建方法

這里也有其他兩種方法可以使用批量賦值進(jìn)行模型的創(chuàng)建:firstOrCreatefirstOrNewfirstOrCreate 方法會(huì)嘗試根據(jù)給定的列的鍵值對(duì)從數(shù)據(jù)庫(kù)定位相關(guān)的模型突梦。如果相關(guān)的模型沒(méi)有找到诫舅,那么會(huì)根據(jù)給定的屬性在數(shù)據(jù)庫(kù)中新增一條記錄。

firstOrNew 方法和 firstOrCreate 方法一樣宫患,但是它在模型沒(méi)找到時(shí)只會(huì)返回一個(gè)新的模型實(shí)例刊懈,并不會(huì)在數(shù)據(jù)庫(kù)中新增一條記錄。你需要手動(dòng)的使用 save 方法來(lái)將其存儲(chǔ)到數(shù)據(jù)庫(kù)中:

// Retrieve the flight by the attributes, or create it if it doesn't exists...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);

// Retrieve the flight by the attributes, or instantiate a new instance...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);

刪除模型

你可以在模型實(shí)例中使用 delete 方法來(lái)刪除模型:

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

$flight->delete();

根據(jù)鍵刪除存在的模型

在上面的例子中撮奏,我們先從數(shù)據(jù)庫(kù)中檢索出相關(guān)的模型俏讹,然后才調(diào)用 delete 方法來(lái)進(jìn)行刪除当宴。事實(shí)上畜吊,如果你知道了模型的主鍵,那么你完全可以不用去檢索到它户矢。你可以直接使用 destroy 方法來(lái)進(jìn)行刪除:

App\Flight::destroy(1);

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

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

通過(guò)查詢(xún)刪除模型

當(dāng)然玲献,你也可以通過(guò)查詢(xún)刪除一個(gè)模型集。在這個(gè)例子中,我們將刪除所有標(biāo)記為未啟用的航班:

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

軟刪除

除了從數(shù)據(jù)庫(kù)中真實(shí)的刪除數(shù)據(jù)之外捌年,Eloquent 也可以進(jìn)行軟刪除操作瓢娜。當(dāng)模型是一個(gè)軟刪除模型時(shí),它們并不會(huì)真正的從數(shù)據(jù)庫(kù)中清除記錄礼预。實(shí)際上眠砾,它們會(huì)將模型的 deleted_at 屬性進(jìn)行設(shè)置,并且將其更新到數(shù)據(jù)庫(kù)中托酸。如果模型中的 deleted_at 的值不是 NULL褒颈,那么它就被標(biāo)記為軟刪除了。如果你需要啟用軟刪除模型励堡,你需要在模型中引入 Illuminate\Database\Eloquent\SoftDeletes trait谷丸,并且在模型的 $dates 屬性中添加 deleted_at 列:

<?php

namespace App;

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

class Flight extends Model
{
  use SoftDeletes;

  /**
   * The attributes that should be mutated to dates.
   *
   * @var array
   */
   protected $dates = ['deleted_at'];
}

當(dāng)然,你應(yīng)該在數(shù)據(jù)表中添加 deleted_at 列应结。Laravel 的 結(jié)構(gòu)生成器 中提供了生成該列的方法:

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

現(xiàn)在刨疼,當(dāng)我們調(diào)用 delete 方法時(shí),deleted_at 列會(huì)被設(shè)置為當(dāng)前時(shí)間鹅龄。并且揩慕,當(dāng)查詢(xún)啟用軟刪除的模型時(shí),已經(jīng)被軟刪除的模型將自動(dòng)從結(jié)果中剔除扮休。

你可以使用 trashed 方法來(lái)判斷所給定的模型是否已經(jīng)被軟刪除:

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

查詢(xún)軟刪除的模型

包含軟刪除的模型

就如上面我們所提到的漩绵,被軟刪除的模型將自動(dòng)的從結(jié)果中進(jìn)行剔除。事實(shí)上肛炮,你可以使用 withTrashed 方法來(lái)強(qiáng)制結(jié)果中顯示已經(jīng)被軟刪除的模型:

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

whitTrashed 方法也可以在關(guān)聯(lián)查詢(xún)中進(jìn)行使用:

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

只檢索被軟刪除的模型

onlyTrashed 方法會(huì)從數(shù)據(jù)庫(kù)中檢索被軟刪除的模型記錄:

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

還原被軟刪除的模型

有時(shí)候你可能會(huì)希望還原已經(jīng)被軟刪除的模型止吐,你可以使用 restore 方法來(lái)將模型從軟刪除中解除:

$flight->restore();

你也可以在查詢(xún)中使用 restore 方法來(lái)快速的重啟多個(gè)模型:

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

就像 withTrashed 方法一樣,restore 方法也可以在關(guān)聯(lián)查詢(xún)中使用:

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

永久的刪除模型

有時(shí)候你可能希望從數(shù)據(jù)庫(kù)中直接刪除這個(gè)模型侨糟。你可以使用 forceDelete 方法來(lái)將模型從數(shù)據(jù)庫(kù)中永久的刪除:

// Force deleting a single model instance...
$flight->forceDelete();

// Force deleting all related modls...
$flight->history()->forceDelete();

查詢(xún)區(qū)間

全局區(qū)間

全局區(qū)間允許你在給定的模型上的所有查詢(xún)進(jìn)行約束的添加碍扔。Laravel 自己的軟刪除功能就是利用了全局區(qū)間來(lái)從數(shù)據(jù)庫(kù)中拉取未刪除的數(shù)據(jù)。編寫(xiě)自己的全局區(qū)間可以方便的對(duì)給定模型的所有查詢(xún)進(jìn)行約束秕重。

編寫(xiě)全局區(qū)間

編寫(xiě)一個(gè)全局區(qū)間非常簡(jiǎn)單不同,你只需要定義一個(gè)實(shí)現(xiàn)了 Illuminate\Database\Eloquent\Scope 接口的類(lèi)。這個(gè)接口只要求你實(shí)現(xiàn)一個(gè)方法:apply溶耘。apply 方法可以在需要的時(shí)添加 where 約束:

<?Php

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

Laravel 沒(méi)有為區(qū)間預(yù)置存放的目錄二拐,所以你可以自由的創(chuàng)建自己的 Scopes 目錄來(lái)進(jìn)行管理。

應(yīng)用全局區(qū)間

你需要在給定的模型中復(fù)寫(xiě) boot 方法并且使用 addGlobalScope 方法來(lái)分配全局區(qū)間:

<?php

namespace 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()
   {
     paraent::boot();

     static::addGlobalScope(new AgeScope);
   }
}

在添加完區(qū)間之后凳兵,調(diào)用 User::all() 的查詢(xún)會(huì)產(chǎn)生下述的 SQL:

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

匿名全局區(qū)間

Eloquent 也允許你通過(guò)一個(gè)閉包來(lái)定義全局區(qū)間百新,這通常對(duì)于不需要分離到單獨(dú)一個(gè)類(lèi)文件中的簡(jiǎn)單區(qū)間尤其有用:

<?php

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

傳遞到 addGlobalScope() 方法的首個(gè)參數(shù)將作為區(qū)間的唯一標(biāo)識(shí),你可以通過(guò)標(biāo)識(shí)將其排除:

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

刪除全局區(qū)間

如果你希望從給定的查詢(xún)中移除全局區(qū)間庐扫,你可以使用 withoutGlobalScope 方法:

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

如果你希望刪除多個(gè)或者全部的全局區(qū)間饭望,你可以使用這么使用 withoutGlobalScopes 方法:

User::withoutGlobalScopes()->get();

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

當(dāng)前區(qū)間

當(dāng)前區(qū)間允許你在模型中定義一些可以復(fù)用的常用的約束仗哨。比如,你可能經(jīng)常需要檢索一些受歡迎的用戶(hù)铅辞。你可以簡(jiǎn)單的在模型方法中前置 scope 命名來(lái)定義一個(gè)區(qū)間.

區(qū)間應(yīng)該總是返回一個(gè)查詢(xún)生成器的實(shí)例:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
  /**
   * Scope a query to only include popular users.
   *
   * @return \Illuminate\Database\Eloquent\Builder
   */
   public function scopePopular($query)
   {
     return $query->where('votes', '>', 100);
   }

   /**
    * Scope a query to only include active users.
    *
    * @return \Illuminate\Database\Eloquent\Builder
    */
    public function scopePopular($query)
    {
      return $query->where('votes', '>', 100);
    }

    /**
     * Scope a query to only include active users.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
     public function scopeActive($query)
     {
       return $query->where('active', 1);
     }
}

利用區(qū)間查詢(xún)

一旦區(qū)間進(jìn)行了定義厌漂,你可以在模型進(jìn)行查詢(xún)時(shí)調(diào)用區(qū)間方法,事實(shí)上斟珊,你在調(diào)用區(qū)間方法時(shí)并不需要包含 scope 前綴苇倡。你甚至可以鏈?zhǔn)降恼{(diào)用其它的區(qū)間:

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

動(dòng)態(tài)區(qū)間

有時(shí)候你可能希望定義一個(gè)可以接收參數(shù)的區(qū)間。在開(kāi)始之前囤踩,你僅僅只需要在你的區(qū)間中添加一些額外的參數(shù)雏节。區(qū)間參數(shù)應(yīng)該在 $query 參數(shù)之后進(jìn)行定義:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
  /**
   * Scope a query to only include users of a given type.
   *
   * @return \Illuminate\Database\Eloquent\Builder
   */
   public function scopeOfType($query, $type)
   {
     return $query->where('type', $type);
   }
}

現(xiàn)在,你可以在調(diào)用區(qū)間時(shí)傳遞一些參數(shù)了:

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

事件

Eloquent 模型可以觸發(fā)多種事件高职,這允許你在模型的生命周期的各個(gè)關(guān)鍵點(diǎn)進(jìn)行 hook 操作钩乍。你可以使用下面的方法進(jìn)行 Hook:creatingcreated怔锌,updating寥粹,updatedsaving埃元,saved涝涤,deletingdeleted岛杀,restoring阔拳,restored。事件允許你輕松的在模型進(jìn)行存儲(chǔ)或更新操作時(shí)進(jìn)行執(zhí)行額外的操作类嗤。

基礎(chǔ)用法

當(dāng)一個(gè)新的模型首次進(jìn)行存儲(chǔ)操作時(shí)糊肠,會(huì)觸發(fā) creatingcreated 事件。如果模型已經(jīng)存在于數(shù)據(jù)庫(kù)中遗锣,并且調(diào)用 save 方法货裹,那么 updating / updated 事件將會(huì)被觸發(fā)。事實(shí)上精偿,在這兩種情況下弧圆,savingsaved 事件都會(huì)被觸發(fā)。

舉個(gè)示例笔咽,讓我們?cè)诜?wù)提供者中定義一個(gè) Eloquent 事件監(jiān)聽(tīng)器搔预。在我們的事件監(jiān)聽(tīng)器中,我們將在給定的模型中調(diào)用 isValid 方法叶组,當(dāng)模型并沒(méi)有通過(guò)驗(yàn)證時(shí)將返回 false拯田。如果從 Eloquent 事件監(jiān)聽(tīng)器中返回 false,那么將取消 save / update 操作:

<?php

namespace App\Providers;

use App\User;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
  /**
   * Bootstrap any application services.
   *
   * @return void
   */
   public function boot()
   {
     User::creating(function ($user) {
       if (! $user->isValid()) {
         return false;
       }
     });
   }

   /**
    * Register the service provider.
    *
    * @return void
    */
    public function register()
    {
      //
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扶叉,一起剝皮案震驚了整個(gè)濱河市勿锅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枣氧,老刑警劉巖溢十,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異达吞,居然都是意外死亡张弛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)酪劫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吞鸭,“玉大人,你說(shuō)我怎么就攤上這事覆糟】贪” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵滩字,是天一觀的道長(zhǎng)造虏。 經(jīng)常有香客問(wèn)我,道長(zhǎng)麦箍,這世上最難降的妖魔是什么漓藕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮挟裂,結(jié)果婚禮上享钞,老公的妹妹穿的比我還像新娘。我一直安慰自己诀蓉,他們只是感情好栗竖,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著渠啤,像睡著了一般划滋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埃篓,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天处坪,我揣著相機(jī)與錄音,去河邊找鬼架专。 笑死同窘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的部脚。 我是一名探鬼主播想邦,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼委刘!你這毒婦竟也來(lái)了丧没?” 一聲冷哼從身側(cè)響起鹰椒,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呕童,沒(méi)想到半個(gè)月后漆际,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夺饲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年奸汇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片往声。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡擂找,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浩销,到底是詐尸還是另有隱情贯涎,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布慢洋,位于F島的核電站柬采,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏且警。R本人自食惡果不足惜粉捻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斑芜。 院中可真熱鬧肩刃,春花似錦、人聲如沸杏头。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)醇王。三九已至呢燥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寓娩,已是汗流浹背叛氨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棘伴,地道東北人寞埠。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像焊夸,于是被迫代替她去往敵國(guó)和親仁连。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容