Laravelアプリケーションでリポジトリパターンを使うには
読む所要時間: 15 分
リポジトリは、ドメインとデータマッピングレイヤー間の抽象化レイヤーとして定義できます。これにより、コレクション的なインターフェイスを通じてドメインオブジェクトにアクセスして両者の仲介手段を提供します。
LaravelやSymfonyなど、最新のPHPフレームワークは、オブジェクトリレーショナルマッパー(ORM)を介してデータベースを操作します。SymfonyのデフォルトORMはDoctrineで、LaravelはEloquentを使用します。
ともに、データベース操作のために異なるアプローチがとられます。Eloquentの場合、データベーステーブルごとにモデルが生成され、操作の基盤が形成されます。一方、Doctrineはリポジトリパターンを使用します。各エンティティには対応するリポジトリがあり、データベースを操作するヘルパー関数が格納されています。Laravelには標準でこの機能は提供されませんが、Laravelプロジェクトでリポジトリパターンを使用することが可能です。
リポジトリパターンを使う主なメリットは、依存性逆転の原則(具体化でなく抽象化コード)を使用できる点です。これにより、例えば後でEloquentがサポートしないデータソースに変更を決めた場合などに、変更の影響を受けにくいコードを作成できます。
データベース関連のロジックが一つの場所に維持され、コードの構成を維持して重複を避けることにもつながります。このようなメリットは小規模のプロジェクトではすぐに実感できませんが、長年かけて維持が必要な大規模プロジェクトでより顕著に感じることができます。
この記事では、Laravelアプリケーションにリポジトリパターンを実装する方法を紹介します。そのために、会社のクライアントから受けた注文を管理するAPIを作成します。
必要条件
はじめましょう
新規Laravelプロジェクトを作成し、次のようにcdコマンドでディレクトリを変更します。
データベースのセットアップ
このチュートリアルでは、データベースにMySQLを使用します。このために.envファイルのデータベース関連のパラメーターを次のように変更します。
最後に、お好きなデータベース管理アプリケーションを使用し、新しいデータベースorder_api
を作成します。
データベース初期データの作成
注文管理アプリケーションを作成するために、次のコマンドを実行してモデルを作成します。
-a
引数により、ArtisanにOrderモデルのマイグレーションファイル、シーダー、ファクトリー、コントローラーを作成することを指示します。
上記のコマンドにより5つの新しいファイルが作成されます。
- コントローラー - app/Http/Controllers/OrderController.php
- データベースファクトリー - database/factories/orderFactory.php
- マイグレーションファイル - database/migrations/YYYY_MM_DD_HHMMSS_create_orders_table.php
- モデル - app/Models/Order.php
- シーダーファイル - database/seeders/OrderSeeder.php
database/migrations/YYYY_MM_DD_HHMMSS_create_orders_table.phpのup
関数を次のとおり変更します。
マイグレーションファイルに従い、order
テーブルには次の列が含まれます。
- ID。テーブルの1次キーになります。
- 注文の詳細。
- 発注したクライアントの名前。
- 注文処理の完了と未了。
- 注文の作成と更新時の
created_at
とupdated_at
(timestamps
関数により提供)。
次にOrderFactory
を更新し、データベースに入力するダミーの注文を作成します。database/factories/OrderFactory.phpのdefinition
関数を次のとおり変更します。
次に、database/seeders/OrderSeeder.phpを開き、run
関数を次のとおり変更します。
これにより、OrderFactory
はデータベースに50個の注文を作成します。
src/database/seeders/DatabaseSeeder.phpのrun
関数に以下を追加します。
これにより、Artisanのdb:seed
コマンドを実行したときにQuoteSeeder
が実行されます。
最後に、マイグレーションを実行し、次のコマンドでデータベースにデータを格納します。
これでordersテーブルを開くと、新しく追加された注文が含まれています。
リポジトリの作成
Order
モデルのリポジトリを作成する前に、リポジトリによる宣言が必要なすべてのメソッドを指定するインターフェイスを定義します。直接リポジトリクラスを使う代わりに、コントローラー(と今後作成する注文コンポーネント)はこのインターフェイスを使用して操作を行います。
これにより、今後変更の必要がある場合にコントローラーは影響を受けず、柔軟なコードを作成できます。例えば、注文管理をサードパーティアプリケーションにアウトソースする場合、OrderRepositoryInterface
の署名に準拠する新しいモデルを作成してバインディング宣言を置き換えれば、コントローラーのコードを一行も変更することなく、コントローラーが正しく機能します。
appディレクトリに新しいフォルダInterfacesを作成します。続いて、Interfacesに新しいファイルOrderRepositoryInterface.phpを作成して次のコードを追加します。
次に、appフォルダに新しいフォルダRepositoriesを作成します。このフォルダに新しいファイルOrderRepository.phpを作成して次のコードを追加します。
インターフェイスが持つ柔軟性とは別に、このようにクエリーをカプセル化することにより、アプリケーション全体でクエリーの重複を避けられるメリットも得られます。
今後、getAllOrders()
関数で受注処理が未了の注文のみを取得することがあれば、変更は一カ所だけでよいため、Order::all()
が宣言されたすべての箇所を探す必要はなく、見落とすリスクが避けられます。
コントローラーの作成
リポジトリができたところで、コントローラーにコードを追加します。app/Http/Controllers/OrderController.phpを開き、コードを次のように変更します。
このコードにより、コンストラクタからOrderRepositoryInterface
インスタンスが注入され、それぞれのコントローラーメソッドで関連オブジェクトのメソッドが使用されます。
まず、index()
メソッドがorderRepository
に定義されたgetAllOrders()
メソッドを呼び出し、注文のリストを取得してJSON形式の応答を返します。
次にstore()
メソッドがorderRepository
からcreateOrder()
メソッドを呼び出し、新しい注文を作成します。配列として作成する注文詳細が取得され、成功すると後で応答が返されます。
コントローラーのshow()
メソッドには、ルートから一意の注文Id
が取得され、パラメーターとしてgetOrderById()
に渡されます。これにより、データベースからIdの一致する注文の詳細が取得され、JSON形式の応答が返されます。
続いて、作成済みの注文の詳細を更新するために、リポジトリからupdateOrder()
メソッドが呼び出されます。これにより、注文の一意のidと更新が必要な詳細の2つのパラメーターを取得します。
最後に、destroy()
メソッドがルートから注文の一意のidを取得し、リポジトリからdeleteOrder()
メソッドを呼び出してこれを削除します。
ルートの追加
コントローラーに定義された各メソッドを個々のルートにマップするために、routes/api.phpに次のコードを追加します。
インターフェイスと実装のバインド
最後に、OrderRepository
をLaravelサービスコンテナのOrderRepositoryInterface
にバインドする必要があります。これは、サービスプロバイダーを使用して行います。次のコマンドを使用して作成します。
app/Providers/RepositoryServiceProvider.phpを開き、register
関数を次のように変更します。
最後に、config/app.phpのproviders
配列に新しいサービスプロバイダーを追加します。
アプリケーションのテスト
次のコマンドを使用してアプリケーションを実行します。
デフォルトで、ターゲットのアプリケーションはhttp://127.0.0.1:8000/を使用します。PostmanかcURLを使用し、新しく作成したAPIにリクエストを実行します。
次のコマンドを実行し、cURLを使用して/api/orders
エンドポイントをテストします。
ターミナルに次のようなJSONの出力が表示されます。例は、見やすいように右端が切断してあります。
Laravelアプリケーションのリポジトリパターンの使い方の紹介の終わりに
この記事では、リポジトリパターンについて、Laravelアプリケーションでの使い方を紹介しました。大規模プロジェクトにおけるいくつかのメリットとして、具体化した実装でなく疎結合されたコードによる抽象化があることも見ていただきました。
一つ最後に注意を記しておきます。小規模のプロジェクトでは、このアプローチは多くの作業が必要で、複数の場所で繰り返される定型コード(ボイラープレートコード)が発生し、すぐにメリットが得られないように感じます。このため、このアプローチをとる前に、プロジェクトの規模を適切に考慮する必要があります。
チュートリアルで使用したすべてのコードベースはGitHubで入手できます。いろいろ調べてみてください。コーディングを楽しみましょう!
Oluyemi氏は、電気通信工学のバックグラウンドを持つ技術愛好家です。ユーザーが直面する日々の問題を解決することに強い関心を持ち、プログラミングの道に進んで以来、Webとモバイルの両方のソフトウェア開発で問題解決能力を磨いてきました。
Oluyemi氏は、知識の共有に情熱を注ぐフルスタックのソフトウェアエンジニアであり、いくつかのブログで多数の技術記事とコンテンツをインターネットに公開しています。技術にも精通しており、趣味は新しいプログラミング言語とフレームワークを試すことです。