下面由Laravel教程欄目帶大家推薦介紹關(guān)于Laravel存儲庫模式(Repository),希望對大家有所幫助!
- 1. Laravel 中的存儲庫模式(Repository)
- 2. 為什么要在 Laravel 中使用存儲庫模式(Repository)?
在大多數(shù) web 應(yīng)用程序中,訪問數(shù)據(jù)庫占了代碼庫的很大一部分。為了避免在我們應(yīng)用程序邏輯上摻雜 SQL 查詢,我們依賴抽象,它隱藏了 PHP 方法背后的數(shù)據(jù)訪問機(jī)制。
有幾種模式可以結(jié)構(gòu)化數(shù)據(jù)訪問,“Active Record” 和 “Repository” 是最著名的兩種。在這篇博文中,我將在 Laravel 框架 的背景下具體解釋它們。關(guān)于使用 Repository 模式的優(yōu)點(diǎn)和缺點(diǎn)的討論將在單獨(dú)的博客文章中進(jìn)行。
活動記錄
默認(rèn)情況下,Laravel 使用 Active Record 模式。每個 Laravel 程序員都直觀地使用它,因為它是在抽象的 Model 基類中實現(xiàn)的,而模型通常從它繼承而來。讓我們來看一個例子:
use IlluminateDatabaseEloquentModel; /** * @property int $id * @property string $first_name * @property string $last_name */ class Person extends Model { } // --- 使用: $person = new Person(); $person->first_name = 'Jack'; $person->last_name = 'Smith'; $person->save();
當(dāng)然,您可以讀寫您在 Person
上創(chuàng)建的屬性。 但是要保存模型,您也可以 直接在模型上調(diào)用方法。 不需要另一個對象——模型已經(jīng)提供了訪問相應(yīng)數(shù)據(jù)庫表的所有方法。
這意味著,域模型將您的自定義屬性和方法與同一類中的所有數(shù)據(jù)訪問方法相結(jié)合。 第二部分是通過繼承 Model
來實現(xiàn)的。
要點(diǎn):
- Active Record 結(jié)合 域模型與數(shù)據(jù)訪問功能。
- Laravel 使用 Active Record 模式并通過
Model
類實現(xiàn)它。
Repository
Repository 模式是 Active Record 模式的替代方案。它還提供了處理數(shù)據(jù)訪問的抽象。但更廣泛地說,它可以被視為域?qū)ο蟮母拍钚源鎯旎蚣稀?/strong>
與活動記錄模式相反,存儲模式將數(shù)據(jù)庫訪問與域模型分離。它提供了一個高級接口,你可以在其中創(chuàng)建、讀取、更新和刪除域模型,而不必考慮實際的底層數(shù)據(jù)存儲。
底層的存儲庫可以通過構(gòu)建和執(zhí)行 SQL 查詢訪問數(shù)據(jù)庫,通過 REST API
訪問遠(yuǎn)程系統(tǒng),或者僅僅管理包含所有域模型的內(nèi)存數(shù)據(jù)結(jié)構(gòu)。這對測試很有用。存儲庫模式關(guān)鍵部分是它為其余代碼提供的高級接口。
要點(diǎn):
- 存儲庫表示域?qū)ο蟮母拍罴稀?/li>
- 它只負(fù)責(zé)用高級接口封裝數(shù)據(jù)訪問。
- Laravel 沒有提供實現(xiàn)存儲庫模式的特定幫助程序
在 Laravel 中實現(xiàn) Repository 模式時,我主要看到兩種變體。
變體1:特定方法
在第一個變體中,存儲庫方法是重點(diǎn)和特定的。名稱解釋了調(diào)用者獲得的內(nèi)容,用于參數(shù)化底層查詢的選項是有限的。
class InvoiceRepository { public function findAllOverdue(Carbon $since, int $limit = 10): Collection { return Invoice::where('overdue_since', '>=', $since) ->limit($limit) ->orderBy('overdue_since') ->get(); } public function findInvoicedToCompany(string $companyId): Collection { return Invoice::where('company_id', $companyId) ->orderByDesc('created_at') ->get(); } }
這種方法的優(yōu)勢在于方法的表現(xiàn)力。閱讀代碼時,很清楚從方法中期望什么以及如何調(diào)用它們。這會導(dǎo)致更少的錯誤。 Repository 方法很容易測試,因為參數(shù)有限。
這種方法的一個缺點(diǎn)是,最終可能會在存儲庫中使用大量的方法。由于方法無法輕松重用,因此必須為新用例添加其他方法。
要點(diǎn):
- 存儲模式可以通過提供特定方法的類來實現(xiàn)
- 每個方法包裝一個查詢,只公開必要的參數(shù)
- 優(yōu)點(diǎn): 可讀性和可測試性
- 缺點(diǎn): 缺乏靈活性和較低的可重用性
變式2: 一般方法
另一方面的方法是提供一般的方法。這導(dǎo)致了方法的減少。但是這些方法有一個很大的 API 曲面,因為每個方法都可以使用不同的參數(shù)組合來調(diào)用。
其中的關(guān)鍵問題是參數(shù)表示。這種表示應(yīng)該引導(dǎo)調(diào)用方理解方法簽名并避免無效的輸入。為此,您可以引入一個特殊的類,例如使用 Query Object 模式。
但是我在實踐中經(jīng)??吹降氖菢?biāo)量參數(shù)和 PHP 數(shù)組的混合。調(diào)用方可以傳遞完全無效的輸入,僅類型數(shù)據(jù)并不能說明要傳遞什么。但是如果使用得當(dāng),這種輕量級的方法可以避免更繁瑣的抽象。
class InvoiceRepository { public function find(array $conditions, string $sortBy = 'id', string $sortOrder = 'asc', int $limit = 10): Collection { return Invoice::where($conditions) ->orderBy($sortBy, $sortOrder) ->limit($limit) ->get(); } } // --- 使用: $repo = new InvoiceRepository(); $repo->find(['overdue_since', '>=', $since], 'overdue_since', 'asc'); $repo->find(['company_id', '=', $companyId], 'created_at', 'asc', 100);
這種方法減輕了第一種方法的問題:你可以得到更少的 Repository 方法,這些方法更靈活,并且可以更頻繁地重用。
從消極的方面看,Repository 變得更加難以測試,因為有