ホームページ > 記事 > PHPフレームワーク > 最近人気のLaravelリポジトリパターン(Repository)
次のチュートリアルコラムでは、最近人気のLaravelリポジトリパターン(Repository) による 最近人気のLaravelリポジトリパターン(Repository) リポジトリモード (Repository) について紹介します。
- 1. 最近人気のLaravelリポジトリパターン(Repository) のリポジトリ パターン
- 2. 最近人気のLaravelリポジトリパターン(Repository) でリポジトリ パターン (リポジトリ) を使用する理由は何ですか?
ほとんどの Web アプリケーションでは、データベースへのアクセスがコード ベースの大部分を占めます。アプリケーション ロジックが SQL クエリで乱雑になるのを避けるために、PHP メソッドの背後にデータ アクセス メカニズムを隠す抽象化を利用します。
構造化データ アクセスにはいくつかのモードがあり、「アクティブ レコード」と「リポジトリ」の 2 つが最も有名です。このブログ投稿では、最近人気のLaravelリポジトリパターン(Repository) フレームワークのコンテキストでそれらを具体的に説明します。リポジトリ パターンを使用する利点と欠点については、別のブログ投稿で説明します。
デフォルトでは、最近人気のLaravelリポジトリパターン(Repository) はアクティブ レコード モードを使用します。 最近人気のLaravelリポジトリパターン(Repository) プログラマーは、これを直感的に使用できます。これは、モデルが通常そこから継承する抽象 Model 基本クラスに実装されているためです。例を見てみましょう:
use Illuminate\Database\Eloquent\Model; /** * @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();
もちろん、Person
で作成したプロパティの読み取りと書き込みが可能です。ただし、モデルを保存するには、モデル上で メソッドを直接呼び出すこともできます。別のオブジェクトは必要ありません。モデルは、対応するデータベース テーブルにアクセスするためのすべてのメソッドをすでに提供しています。
これは、ドメイン モデルがカスタム プロパティとカスタム メソッドを同じクラス内のすべてのデータ アクセス メソッドと組み合わせるということを意味します。 2 番目の部分は、Model
を継承することによって実現されます。
キーポイント:
クラスを通じてそれを実装します。
しかし、より広義には、概念的なリポジトリまたはドメイン オブジェクトのコレクションとみなすことができます。
アクティブ レコード モードとは対照的に、ストレージ モードはデータベース アクセスをドメイン モデルから分離します。実際の基盤となるデータ ストアを気にすることなく、ドメイン モデルを作成、読み取り、更新、削除できる高レベルのインターフェイスを提供します。 基盤となるリポジトリは、SQL クエリを構築および実行してデータベースにアクセスしたり、REST API を介してリモート システムにアクセスしたり、すべてのドメイン モデルを含むメモリ内のデータ構造を単純に管理したりできます。これはテストに役立ちます。リポジトリ パターンの重要な部分は、コードの残りの部分に提供される高レベルのインターフェイスです。
重要なポイント:
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(); } }この方法の利点は、その表現力にあります。コードを読むと、メソッドに何を期待するか、そしてそれらを呼び出す方法が明確になります。これにより、エラーが少なくなります。リポジトリ メソッドはパラメータが制限されているため、テストが簡単です。 このアプローチの欠点の 1 つは、リポジトリ内で多数のメソッドを使用することになる可能性があることです。メソッドは簡単に再利用できないため、新しい使用例には追加のメソッドを追加する必要があります。
キーポイント:
ただし、これらのメソッドはパラメーターのさまざまな組み合わせで呼び出すことができるため、API サーフェスが大きくなります。
重要な問題はパラメータの表現です。この表現は、呼び出し元がメソッド シグネチャを理解し、無効な入力を回避するのに役立ちます。これを行うには、たとえばクエリ オブジェクト パターンを使用して特別なクラスを導入します。
但是我在实践中经常看到的是标量参数和 PHP 数组的混合。调用方可以传递完全无效的输入,仅类型数据并不能说明要传递什么。但是如果使用得当,这种轻量级的方法可以避免更繁琐的抽象。
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 变得更加难以测试,因为有更多的案例需要覆盖。方法签名更难理解,正因为如此,调用者可能会犯更多错误。此外,还将引入某种查询对象表示形式。无论它是显式的还是隐式的(比如数组),您的 Repository 实现及其调用者都将与它耦合。
要点:
当然,这两种方法可以结合起来使用。也许你想要一些特定的方法用于复杂的查询,而一些通用的方法用于简单的 where
查询。
现在,我们来谈谈如何实现方法体。
在上面的例子中,我使用了 Model
类的方法来获得对 Eloquent 查询构造器的访问。所以 Repository 的实现实际上使用了 Active Record 模式作为实现。
你不需要这样做。你可以使用 DB
facade 来获得一个查询构建器,同时避免使用 Model
类。或者你可以直接编写 SQL 查询:
class InvoiceRepository { public function findAllOverdue(Carbon $since, int $limit = 10): Collection { return DB::table('invoices') ->where('overdue_since', '>=', $since) ->limit($limit) ->orderBy('overdue_since') ->get(); } public function findInvoicedToCompany(string $companyId): Collection { return DB::select('SELECT * FROM invoices WHERE company_id = ? ORDER BY created_at LIMIT 100', [$companyId]); } }
存储模式的优点是,实现可以是任何东西,只要它满足接口。你还可以管理内存中的对象或者包(和缓存)一个 API。
但是最常见的是,底层数据存储是一个 SQL 数据库。要访问它,你可以根据每个方法选择最佳实现。对于性能关键的或者复杂的查询,你可能希望直接使用 SQL 语句。更简单的查询可以使用 Eloquent 查询生成器。
当你没有使用 模型
类来实现你的 Repository ,你可能会考虑在模型中不继承它。但是这个方法违反了很多内置的 最近人気のLaravelリポジトリパターン(Repository) 魔术方法,在我看来并不是一个好的方法。
要点:
你的另一个选择是,是否要引入一个接口。上面的例子可以用一个接口和一个或多个实现来分隔:
// --- 接口: public interface InvoiceRepositoryInterface { public function findAllOverdue(Carbon $since, int $limit = 10): Collection; public function findInvoicedToCompany(string $companyId): Collection; } // --- 具体的类,实现了该接口 class InvoiceRepository implements InvoiceRepositoryInterface { public function findAllOverdue(Carbon $since, int $limit = 10): Collection { // 实现 } public function findInvoicedToCompany(string $companyId): Collection { // 实现 } }
添加接口是一种额外的间接方法,并不一定是好的。如果您的应用程序是 Repository 的唯一用户,并且您不希望它有多个实现,那么我不认为引入接口有什么意义。对于测试,Repository 可以用 PHPUnit 模拟,只要它不被标记为 final
。
如果你知道你将有多个实现,你应该使用一个接口。如果你正在编写一个将在多个项目中使用的 包。或者你想要测试一个特殊的 Repository 实现,那么可能会发生不同的实现。
为了从 最近人気のLaravelリポジトリパターン(Repository) 的依赖注入中获益,你必须将具体的实现绑定到接口上。这必须在服务提供者的注册方法中完成。
use Illuminate\Support\ServiceProvider; class RepositoryServiceProvider extends ServiceProvider { public function register(): void { $this->app->bind(InvoiceRepositoryInterface::class, InvoiceRepository::class); } }
要点:
原文地址:https://dev.to/davidrjenni/repository-pattern-in-laravel-1pph
译文地址:https://learnku.com/laravel/t/62587
以上が最近人気のLaravelリポジトリパターン(Repository)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。