Eloquentとリポジトリテンプレートについて話すのをやめてください

私は定期的に「Eloquentでリポジトリテンプレートを使用する方法」というスタイルの記事を見ています(そのうちの1つは最近のPHPダイジェストに入りました )。 通常のコンテンツ:インターフェースPostRepositoryInterfaceEloquentPostRepositoryクラスを作成し、それらを依存関係コンテナーにうまくバインドし、標準のEkoventメソッドの代わりにsavefindを使用しましょう。







なぜこのテンプレートが必要なのか、時にはまったく書かない(「これはテンプレートです!十分ではないのですか?」) そのようなテンプレートをそのような記事の通常のLaravelプロジェクトに導入することの利点は理解するのが困難です。







何が何であるかを理解してみましょうか? リポジトリテンプレートを使用すると、特定のストレージシステム(通常はデータベースとして使用)から抽象化して、エンティティのコレクションの抽象概念を提供できます。







Eloquent Repositoryの例は、2つのタイプに分けられます。







  1. デュアルEloquentアレイのバリエーション
  2. 純然たるリポジトリ


デュアルEloquentアレイのバリエーション



最初の例(ランダムな記事から引用):







<?php interface FaqRepository { public function all($columns = array('*')); public function newInstance(array $attributes = array()); public function paginate($perPage = 15, $columns = array('*')); public function create(array $attributes); public function find($id, $columns = array('*')); public function updateWithIdAndInput($id, array $input); public function destroy($id); } class FaqRepositoryEloquent implements FaqRepository { protected $faqModel; public function __construct(Faq $faqModel) { $this->faqModel = $faqModel; } public function newInstance(array $attributes = array()) { if (!isset($attributes['rank'])) { $attributes['rank'] = 0; } return $this->faqModel->newInstance($attributes); } public function paginate($perPage = 0, $columns = array('*')) { $perPage = $perPage ?: Config::get('pagination.length'); return $this->faqModel ->rankedWhere('answered', 1) ->paginate($perPage, $columns); } public function all($columns = array('*')) { return $this->faqModel->rankedAll($columns); } public function create(array $attributes) { return $this->faqModel->create($attributes); } public function find($id, $columns = array('*')) { return $this->faqModel->findOrFail($id, $columns); } public function updateWithIdAndInput($id, array $input) { $faq = $this->faqModel->find($id); return $faq->update($input); } public function destroy($id) { return $this->faqModel->destroy($id); } }
      
      





allfindpaginateメソッドは Eloquentオブジェクトを返しますが、 createupdateWithIdAndInputは配列を待っています。







updateWithIdAndInputという名前自体 、この「リポジトリ」がCRUD操作にのみ使用されることを意味します。







通常のビジネスロジックは想定されていませんが、最も単純なものを実装しようとします。







 <?php class FaqController extends Controller { public function publish($id, FaqRepository $repository) { $faq = $repository->find($id); //...-   $faq->... $faq->published = true; $repository->updateWithIdAndInput($id, $faq->toArray()); } }
      
      





そして、リポジトリがない場合:







 <?php class FaqController extends Controller { public function publish($id) { $faq = Faq::findOrFail($id); //...-   $faq->... $faq->published = true; $faq->save(); } }
      
      





2倍簡単。







なぜ複雑にするだけの抽象化をプロジェクトに導入するのですか?









純然たるリポジトリ



Eloquentのみで動作するリポジトリの例(1つの記事にもあります):







 <?php interface PostRepositoryInterface { public function get($id); public function all(); public function delete($id); public function save(Post $post); } class PostRepository implements PostRepositoryInterface { public function get($id) { return Post::find($id); } public function all() { return Post::all(); } public function delete($id) { Post::destroy($id); } public function save(Post $post) { $post->save(); } }
      
      





この記事では、不要な接尾辞Interfaceを scりません。







この実装は、テンプレートの説明の内容に少し似ています。







最も単純なロジックの実装は、もう少し自然に見えます。







 <?php class FaqController extends Controller { public function publish($id, PostRepositoryInterface $repository) { $post = $repository->find($id); //...-   $post->... $post->published = true; $repository->save($post); } }
      
      





ただし、最も簡単なブログ投稿用のリポジトリを実装することは、子供たちが楽しむためのおもちゃです。







もっと複雑なものを試してみましょう。







サブエンティティを持つ単純なエンティティ。 たとえば、可能な回答を含む調査(サイトまたはチャットでの定期的な投票)。







そのような調査の対象を作成する場合。 2つのオプション:









同じ疑問が生じます。なぜこれがすべてなのでしょうか?

Eloquentが提供するよりも多くの抽象化をストレージシステムから取得します-動作しません。







ユニットテスト?







これが私の本からの可能な単体テストの例です-https://gist.github.com/adelf/a53ce49b22b32914879801113cf79043

単純な操作のためにこのような巨大な単体テストを行うことは、ほとんどの人にはわからないでしょう。







私は、プロジェクト内のそのようなテストが中止されることをほぼ確信しています。







誰も彼らをサポートしたくありません。 私はそのようなテストのあるプロジェクトに参加していました。







機能テストに集中する方がはるかに簡単で正確です。

特にAPIプロジェクトの場合。







ビジネスロジックが非常に複雑で、テストでカバーしたい場合は、 Doctrineのようなデータマッパーライブラリを使用して、ビジネスロジックを他のアプリケーションから完全に分離することをお勧めします。 単体テストは10倍簡単になります。







あなたのEloquentプロジェクトで、デザインパターンに夢中になりたい場合は、次の記事でリポジトリテンプレートを部分的に適用し、それから利益を得る方法を示します。








All Articles