- 初め!!!
Laravelを使う時、色々なやり方があると思います。良いか良くないかケースバイケースですが、良いやり方を本チップシリーズにまとめたいので、これからどんどん紹介します。 - Eager Loading
開発の時、一対N関係のモデルを良く使うと思います。
例えば:
・LaravelのPostモデルでpostsテブールに投稿一覧を格納する
・ユーザーと投稿の関係は一対Nである
その時に、投稿一覧及び各投稿の作ったユーザーをViewで表示したい場合は、以下のサンプルで実装できます。// Post model class Post { public function user() { return $this->belongsTo(User::class); } }
// Controller $posts = Post::all(); foreach ($posts as $post) { {{ $post->title }} {{ $post->user->name }} }
上記のソースに、ユーザー取得するために、 定義したbelongsTo関係より投稿のユーザーが取得できますが、クエリ発行についてはデメリットがあります。
・各投稿に対して、ユーザー取得クエリ発行が必要となるので、投稿数が多い場合、発行クエリも多いです。
・各投稿に対するユーザー取得のため、同じユーザーなのに、クエリ再発行が必要となります。
改善のために、 LaravelにはEager loadingを使います。// Eager Loading $posts = Post::with('user')->all(); // Lazy Eager Loading $posts = Post::all(); $posts->load('user');
with()またload()を使う場合に、全て投稿の全てユーザーが一回で取得できるので、発行クエリ数が減らせます。なのでEager loadingをよく使いましょう。もっと深い使い方は、Laravelのドキュメントを参照してください。
- メソッドとプロパティ
開発の時、メソッドとプロパティはどちらが使った方が良いかという質問がありますね。
例えば:
カテゴリーと投稿の関係クラス:// Category Model public function posts() { return $this->hasMany(Post::class); }
その場合に各カテゴリーの投稿数取得方は二つあります。
// Method based $category->posts()->count();
// Property based $category->posts->count();
具体的に、上記の取得方法を分析しましょう。
・メソッドに基づく場合は、まずカテゴリーインスタンスのpostsメソッドを呼び出して、$this->hasMany(Post::class)でカテゴリーインスタンスを戻します。次にEloquentのcountメソッドが実行され、データベース用のカウントクエリを生成し、実行します。
・プロパティに基づく場合は、まずカテゴリーにpostsというプロパティがないのに、どのように Laravelは$category->postsが実行できるかMagic Methodで参照してください。基本的に$category->posts実行するのは$category->posts()->get()と同様であり、特にLaravelの方は1回のみ当カテゴリーの投稿取得クエリ生成し、実行しますので、実行結果はCollectionとしてプロパティに格納します。次はCollectionのカウントメソッドを実行して、投稿数を戻します。
ここまで、メソッドとプロパティの違いがわかりましたね。
つまりで:
・投稿数のみ取得したい場合はメソッドを使った方が良いです
・投稿数だけではなく、投稿情報も取得したい場合はプロパティを使った方が良いです - Repository Design Pattern
私はLaravelを最初に勉強する時、基本のフローとしてはControllerにModelを呼びだし、Viewへ反映します。以下のサンプルように実装することがよくあります。// Without repository <?php namespace Acme\Controllers; use Acme\Models\Post; class PostController extends BaseController { public function index() { $posts = Post::paginate(20); return View::make('post.index', compact('posts')); } public function show($id) { $post = Post::findOrFail($id); return View::make('post.show', compact('post')); } }
でもそれはデメリットがあります。
・Controllerに直接Modelを使うから、ControllerとModelの依存性が”硬い”となる
・Model及びControllerにビジネスを実装するため、再使用性が低い。
・Controllerのテスト書きにくくなってしまう。
なので、ControllerとModelの間にRepositoryを使う方が良いと思います。// Repository class <?php namespace Acme\Storage; use Acme\Models\Post; class PostRepository { public function paginate($perPage = null, $columns = array('*')) { return Post::paginate($perPage, $columns); } public function findOrFail($id, $columns = array('*')) { return Post::findOrFail($id, $columns); } }
// Controller <?php namespace Acme\Controllers; use Acme\Storage\PostRepository; class PostController extends BaseController { private $postRepository; public function __construct(PostRepository $postRepository = null) { $this->postRepository = ($postRepository === null) ? new PostRepository : $postRepository; } public function index() { $posts = $this->postRepository->paginate(20); return View::make('post.index', compact('posts')); } public function show($id) { $posts = $this->postRepository->findOrFail($id); return View::make('post.show', compact('post')); } }
Repositoryのメリットを明確するために、上記のソースコードを分析しましょう。
・ControllerにRepositoryを使うのは、ビジネスの実装とControllerが別々になり、将来にMySqlに変えてMongoDBなど使ったら、Controllerを修正するのが不要です。
・Controllerのテスト書きやすくなる。<?php use Mockery as m; class PostControllerTest extends PHPUnit_Framework_Testcase { private $postRepository; private $postController; public function setUp() { parent::setup(); $this->postRepository = m::mock('Acme\Storage\PostRepository'); $this->postController = new Acme\Controllers\PostController($this->postRepository); } public function tearDown() { m::close(); parent::tearDown(); } public function testIndex() { $this->postRepository->shoudlReceive('paginate')->once()->andReturn(array()); $response = $this->postController->index(); $this->assertEqual(array(), $response); } }
もちろん上記は単純なRepositoryの使い方ですけど、Repositoryを使った方が良いということが見えますが本投稿はここまでです。
- まとめ
Laravelはとても強いフーレムワークですが、色々なやり方があると思います。良い方か悪い方かケースバイケースなので、良く理解して、正しく使いましょう。
次のチップシリーズにはLaravelにデザインパターンを使う方について紹介する予定ですが、当シリーズが有用であれば、いいねつけていただければ幸いです。 - 参考
Laravel Collections
Laravel Eager Loading
PHP Magic Method
Using Repository In Laravel