掌握Laravel Eloquent需要了解的六個要點

掌握Laravel Eloquent需要了解的六個要點

Laravel 是一個開源、易用的 PHP 框架。它最強大的功能之一是 Eloquent,這是一種物件關係對映器(ORM),可簡化資料庫記錄處理。

Eloquent 可加快應用程式對資料庫進行建立、讀取、更新和刪除操作的速度。使用 Eloquent 時,您可以建立對映資料庫表的模型,並使用這些模型建立查詢。

本文探討了 Eloquent 最強大功能的六個要素:查詢作用域、關係、突變器和訪問器、集合、模型刪除和工廠。文章通過實際示例介紹了每個功能的作用。希望你能通過這些示例快速掌握 Laravel Eloquent

1. Eloquent 查詢範圍

在構建應用程式時,有時會遇到多次使用條件的情況。每次重寫程式碼都會增加出錯的機率,並使程式碼變得不整齊。Laravel 解決了這個問題,它將這些條件封裝在稱為作用域的可重用語句中。

查詢作用域是將資料庫邏輯新增到模型中並重復使用查詢邏輯的方法。

下面是一個查詢作用域的示例。假設您想為團隊建立一個軟體開發平臺,跟蹤已完成和正在進行的功能。您可以使用此條件只檢索正在進行的功能:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$onGoing = Project::where('ongoing', 1)->get();
$onGoing = Project::where('ongoing', 1)->get();
$onGoing = Project::where('ongoing', 1)->get();

您可能需要在其他應用程式頁面(如統計頁面)中使用此條件。查詢作用域允許頁面重複使用上述條件,從而簡化查詢並使程式碼更簡潔。

下面介紹如何在這種情況下使用查詢作用域:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Features extends Model
{
public function scopeOngoing($query)
{
return $query->where('ongoing', 0);
}
}
class Features extends Model { public function scopeOngoing($query) { return $query->where('ongoing', 0); } }
class Features extends Model
{
public function scopeOngoing($query)
{
return $query->where('ongoing', 0);
}
}

然後使用下面的程式碼執行該作用域:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$onGoing = Feature::ongoing()->get();
$onGoing = Feature::ongoing()->get();
$onGoing = Feature::ongoing()->get();

有兩種作用域:全域性作用域和區域性作用域。

全域性作用域

全域性作用域允許在模型內的所有查詢中新增限制條件。例如,您可以在模型內的所有查詢中新增一個條件,根據組長的姓名過濾特徵。

本地作用域

本地作用域允許定義通用約束,以實現可重用性。例如,您可能希望應用程式返回存在錯誤的功能。您的程式碼可能會這樣實現一個區域性作用域:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class User extends Model
{
public function scopeBugged($query)
{
return $query->where('bugged', '>', 1);
}
}
namespace AppModels; use IlluminateDatabaseEloquentModel; class User extends Model { public function scopeBugged($query) { return $query->where('bugged', '>', 1); } }
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class User extends Model
{
public function scopeBugged($query)
{
return $query->where('bugged', '>', 1);
}
}

上面的程式碼會返回所有存在未修復錯誤的功能。

2. Eloquent 關係

Eloquent 中的關係允許您輕鬆地將不同的表聯絡起來。例如,電子商務網站上的產品可能列出了庫存、價格、檢視和評論。有了 Eloquent,即使記錄在不同的表中,您也可以輕鬆管理這些關係。

您可以將關係定義為模型類上的方法,就像定義 Eloquent 模型一樣。一些常用的 Eloquent 關係包括一對一關係、逆關係和多型關係。

一對一

下面是一個將產品模型與庫存關聯起來的基本一對一關係示例。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public function Inventory()
{
return $this->hasOne('AppInventory');
}
public function Inventory() { return $this->hasOne('AppInventory'); }
public function Inventory()
{
return $this->hasOne('AppInventory');
}

在上面的程式碼中, Inventory() 方法呼叫了產品模型上的 hasOne() 方法。這將檢查產品當前是否可用。

反向關係

Eloquent 還允許您建立反向關係。例如,當您想根據檢視次數來獲取產品時。反向關係可以為您提供網站訪客最感興趣的產品。您可以使用 belongsTo() 方法,它是 hasOne() 的逆向方法。下面的程式碼說明了這一點。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public function product()
{
return $this->belongsTo('AppProduct');
}
public function product() { return $this->belongsTo('AppProduct'); }
public function product()
{
return $this->belongsTo('AppProduct');
}

在上面的程式碼中,Eloquent 會將 product_id 與所傳遞的檢視數量相匹配。然後,product_id 可以幫助獲取其他引數,如價格和庫存。

多型性

在應用程式開發中,關係並不總是那麼簡單。有時,一個模型屬於多個模型型別。例如,產品和庫存模型都可以與影象模型建立多型關係。

多型關係允許您在庫存和產品中使用相同的影象列表。下面是實現多型關係的程式碼片段。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Image extends Model
{
/**
* Getting the shared image.
*/
public function myimage()
{
return $this->morphTo();
}
}
class Product extends Model
{
/**
* Get the image to use on the product's page.
*/
public function image()
{
return $this->morphOne(Image::class, 'myimage');
}
}
class Inventory extends Model
{
/**
* Get the image to use on the inventory page.
*/
public function image()
{
return $this->morphOne(Image::class, 'myimage');
}
}
class Image extends Model { /** * Getting the shared image. */ public function myimage() { return $this->morphTo(); } } class Product extends Model { /** * Get the image to use on the product's page. */ public function image() { return $this->morphOne(Image::class, 'myimage'); } } class Inventory extends Model { /** * Get the image to use on the inventory page. */ public function image() { return $this->morphOne(Image::class, 'myimage'); } }
class Image extends Model
{
/**
* Getting the shared image.
*/
public function myimage()
{
return $this->morphTo();
}
}
class Product extends Model
{
/**
* Get the image to use on the product's page.
*/
public function image()
{
return $this->morphOne(Image::class, 'myimage');
}
}
class Inventory extends Model
{
/**
* Get the image to use on the inventory page.
*/
public function image()
{
return $this->morphOne(Image::class, 'myimage');
}
}

上面的程式碼使用 morphTo() 方法來檢索多型模型的父模型。

這只是這個主題的冰山一角。更多詳情,請參閱我們的 Laravel Eloquent 關係高階指南。

3. Eloquent 突變器和訪問器

突變器和訪問器允許你在儲存和檢索資料時修改資料。突變器在儲存資料前修改資料,而訪問器在檢索資料時修改資料。

如果想在資料庫中以小寫儲存姓名,可以建立一個突變器來執行這種轉換。如果想在應用程式頁面上將使用者的名和姓顯示為一個名字,可以建立一個訪問器來實現這一目的。

下面是一個突變器的示例,該突變器可在儲存名稱之前將其大寫。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class User extends Model
{
/**
* Mutators capitalizing first and last name.
*/
public function setFirstNameAttribute($value)
{
$this->attributes['first_name'] = ucfirst($value);
}
public function setLastNameAttribute($value)
{
$this->attributes['last_name'] = ucfirst($value);
}
}
class User extends Model { /** * Mutators capitalizing first and last name. */ public function setFirstNameAttribute($value) { $this->attributes['first_name'] = ucfirst($value); } public function setLastNameAttribute($value) { $this->attributes['last_name'] = ucfirst($value); } }
class User extends Model
{
/**
* Mutators capitalizing first and last name.
*/
public function setFirstNameAttribute($value)
{
$this->attributes['first_name'] = ucfirst($value);
}
public function setLastNameAttribute($value)
{
$this->attributes['last_name'] = ucfirst($value);
}
}

下面是一個訪問器的示例,該訪問器結合了使用者的名和姓。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class User extends Model
{
/**
* Accessor combining both names.
*/
public function getFullNameAttribute()
{
return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
}
}
class User extends Model { /** * Accessor combining both names. */ public function getFullNameAttribute() { return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name); } }
class User extends Model
{
/**
* Accessor combining both names.
*/
public function getFullNameAttribute()
{
return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
}
}

4. Eloquent 集合

Eloquent 集合用於處理返回多個模型結果的方法。該類可在 IlluminateDatabaseEloquentCollection 中找到。

與陣列一樣,可以對集合進行迭代。下面是一個簡單的迭代過程。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
use AppModelsProduct;
$products = Product::where('availability', 1)->get();
foreach ($products as $product) {
echo $product->name;
}
use AppModelsProduct; $products = Product::where('availability', 1)->get(); foreach ($products as $product) { echo $product->name; }
use AppModelsProduct;
$products = Product::where('availability', 1)->get();
foreach ($products as $product) {
echo $product->name;
}

集合比陣列更強大,因為您可以對它們執行更復雜的操作。例如,您可以顯示所有可用產品的列表,並跳過所有未 “啟用” 的產品。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$names = Product::all()->reject(function ($product) {
return $product->active === false;
})->map(function ($product) {
return $product->name;
});
$names = Product::all()->reject(function ($product) { return $product->active === false; })->map(function ($product) { return $product->name; });
$names = Product::all()->reject(function ($product) {
return $product->active === false;
})->map(function ($product) {
return $product->name;
});

以下是集合類提供的一些方法。

Contains

contains() 方法會檢查程式碼是否包含指定模式,如下程式碼所示:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$products->contains(1);
$products->contains(Product::find(1));
$products->contains(1); $products->contains(Product::find(1));
$products->contains(1);
$products->contains(Product::find(1));

All

all() 方法會返回集合中包含的模型,如下所示:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$collection = Product::all();
$collection = Product::all();
$collection = Product::all();

集合類還支援許多其他方法。

5. 刪除 Eloquent 模型

在 Eloquent 中,您可以建立模型來幫助構建查詢。不過,有時您需要刪除模型,以使應用程式更有效率。為此,請在模型例項上呼叫 delete

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
use AppModelsStock;
$stock = Stock::find(1);
$stock->delete();
use AppModelsStock; $stock = Stock::find(1); $stock->delete();
use AppModelsStock;
$stock = Stock::find(1);
$stock->delete();

上面的程式碼會從應用程式中刪除模型 Stock。這是永久刪除,無法撤銷。

軟刪除

Eloquent 的另一項功能是模型軟刪除功能。軟刪除模型時,不會將其從資料庫中刪除。

您可以使用 deleted_at 標記它,以指示軟刪除的時間和日期。當您想排除資料庫中的部分記錄(如不完整的記錄),而又不想永久刪除它們時,這一點非常重要。它有助於在不新增額外條件的情況下清理 Eloquent 的查詢結果。

您可以通過在模型中新增 softDeletes 特性,並在相關資料庫表中新增 deleted_at 列來啟用軟刪除功能。

在模型中新增軟刪除

如下所示,通過新增 IlluminateDatabaseEloquentSoftDeletes 特性來啟用模型軟刪除功能。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentSoftDeletes;
class Flight extends Model
{
use SoftDeletes;
}
namespace AppModels; use IlluminateDatabaseEloquentModel; use IlluminateDatabaseEloquentSoftDeletes; class Flight extends Model { use SoftDeletes; }
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentSoftDeletes;
class Flight extends Model
{
use SoftDeletes;
}

如何新增 delete_at 列

在開始使用軟刪除之前,你的資料庫應該有一個 delete_at 列。新增這一列需要使用 Laravel Schema 生成器的輔助方法,如下所示:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
Schema::table('users', function (Blueprint $table) {
$table->softDeletes();
});
Schema::table('users', function (Blueprint $table) {
$table->dropSoftDeletes();
});
use IlluminateDatabaseSchemaBlueprint; use IlluminateSupportFacadesSchema; Schema::table('users', function (Blueprint $table) { $table->softDeletes(); }); Schema::table('users', function (Blueprint $table) { $table->dropSoftDeletes(); });
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
Schema::table('users', function (Blueprint $table) {
$table->softDeletes();
});
Schema::table('users', function (Blueprint $table) {
$table->dropSoftDeletes();
});

這將新增一個 delete_at 列,在軟刪除操作成功的情況下,該列將用日期和時間更新。

如何包含軟刪除的模型

如果希望查詢結果包括軟刪除的模型,可以在查詢中新增 withTrashed() 方法。下面是一個示例:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$stocks = Stock::withTrashed()->where('stock_id', 20)->get();
$stocks = Stock::withTrashed()->where('stock_id', 20)->get();
$stocks = Stock::withTrashed()->where('stock_id', 20)->get();

上述查詢還將包括帶有 deleted_at 屬性的模型。

如何只檢索軟刪除的模型

Eloquent 還允許您只檢索軟刪除的模型。例如,您可以通過呼叫 onlyTrashed() 方法來做到這一點:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$Stock = Stock::onlyTrashed()->where('stock_id', 1)->get();
$Stock = Stock::onlyTrashed()->where('stock_id', 1)->get();
$Stock = Stock::onlyTrashed()->where('stock_id', 1)->get();

如何恢復軟刪除的模型

您也可以通過呼叫 restore() 方法來恢復軟刪除的模型。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$stocks = Stock::withTrashed()->where('stock_id', 20)->restore();
$stocks = Stock::withTrashed()->where('stock_id', 20)->restore();
$stocks = Stock::withTrashed()->where('stock_id', 20)->restore();

這會將軟刪除模型的 delete_at 欄位改為空。如果模型未被軟刪除,則該欄位保持不變。

6. Eloquent 工廠

Laravel 中的模型工廠可以建立虛擬資料,用於測試應用程式或為資料庫提供種子資料。為此,你需要在工廠類中建立一個模型,如下圖所示。程式碼片段建立了一個模型工廠,它可以生成產品及其價格的虛假供應商。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
namespace DatabaseFactories;
use IlluminateDatabaseEloquentFactoriesFactory;
use IlluminateSupportStr;
class StockFactory extends Factory
{
public function definition()
{
return [
'supplier_name' => fake()->name(),
'price' => fake()->numberBetween($min = 1500, $max = 6000),
];
}
}
namespace DatabaseFactories; use IlluminateDatabaseEloquentFactoriesFactory; use IlluminateSupportStr; class StockFactory extends Factory { public function definition() { return [ 'supplier_name' => fake()->name(), 'price' => fake()->numberBetween($min = 1500, $max = 6000), ]; } }
namespace DatabaseFactories;
use IlluminateDatabaseEloquentFactoriesFactory;
use IlluminateSupportStr;
class StockFactory extends Factory
{
public function definition()
{
return [
'supplier_name' => fake()->name(),
'price' => fake()->numberBetween($min = 1500, $max = 6000),
];
}
}

上例中的 definition() 方法會返回一組屬性值,供 Laravel 在構建模型時使用。偽助手幫助工廠訪問 PHP 庫 Faker

小結

Eloquent 簡化了在 Laravel 中開發應用程式的任務。藉助關係等實現方式,它在構建簡單或複雜查詢時同樣有效。使用工廠生成功能性虛擬資料的簡便性,使其成為希望為應用程式建立強大測試的開發人員的完美選擇。此外,Eloquent 的作用域還有助於簡化複雜的查詢,使程式碼更加整潔。

本文僅介紹了 Eloquent 的六項主要功能,但 Eloquent 還有其他強大的功能。可共享和可重用模型的使用使 Eloquent 成為開發人員最喜愛的功能,而 Eloquent 查詢的簡潔性則使 Laravel 成為對開發人員友好的框架–即使對初學者來說也是如此。

評論留言