はじめに
今回は、LaravelのwithCountメソッドとクエリビルダを使ってランキング機能を実装するまでの流れを解説していきます。
目次
やりたいこと
タグランキングの作成
- タグに紐付けられた記事数をカウントして多い順に並び替えます
- 以下のテーブルを多対多(articles:tags)の関係で使用する
- 記事テーブル(articles)
- タグテーブル(tags)
- 中間テーブル(article_tag)
- 以下のテーブルを多対多(articles:tags)の関係で使用する
ユーザーランキングの作成
- ユーザーが投稿した記事のうち "status" カラムが "success" である記事をカウントして多い順に並び替えます
- 以下のテーブルを1対多(users:articles)の関係で使用する
- ユーザーテーブル(users)
- 記事テーブル(articles)
- 以下のテーブルを1対多(users:articles)の関係で使用する
DB
users | articles | tags | article_tag |
---|---|---|---|
id | id | id | id |
name | user_id | name | article_id |
created_at | status | created_at | created_at |
updated_at | created_at | updated_at | updated_at |
updated_at |
コントローラー
ArticleController.php
class ArticleController extends Controller
{
public function index(Request $request)
{
//略
//タグランキング
$tags_ranking = app()->make(Tag::class)->tagsRanking();
//達成ランキング
$users_ranking = app()->make(User::class)->usersRanking();
$data = [
'tags_ranking' => $tags_ranking,
'users_ranking' => $users_ranking,
];
//略
return view('articles.index', $data);
}
}
モデル
リレーション結果の件数を実際にレコードを読み込むことなく知りたい場合は、withCountメソッドを使います。件数は結果のモデルの{リレーション名}_countカラムに格納されます。
(Laravel 6.x Eloquent:リレーション参照)
{リレーション名}_countカラムをテーブルに作成しなくて良いので、非常に便利です。
また、ユーザーランキングでは、Laravelのクエリビルダを活用しました。
(Laravel 6.x データベース:クエリビルダ参照)
Tag.php
class Tag extends Model
{
public function tagsRanking()
{
$query = Tag::withCount('articles')->orderBy('articles_count', 'desc')->limit(5)->get();
return $query;
}
}
User.php
use Illuminate\Database\Eloquent\Builder;
class User extends Authenticatable
{
public function usersRanking()
{
$query = User::withCount(['articles' => function (Builder $query) {
$query->where('status', 'success');
}])->orderBy('articles_count', 'desc')->limit(5)->get();
return $query;
}
}
ビューを作成
card.blade.php
{{-- タグランキング --}}
<div class="col-lg-8 col-md-10 col-sm-12 col-xs-12 mx-auto mt-5">
<div class="card mb-4 sidebar-content">
<div class="card-header text-center">
<i class="fas fa-tags mr-2">
</i>タグランキング
</div>
<div class="card-body main-tag-list py-3 mx-auto">
@foreach ($tags_ranking as $tag)
<a href="{{ route('tags.show', ['name' => $tag->name]) }}">
<div class="m-3">
{{ $tag->hashtag }}
<span>{{ $tag->articles_count }}</span>件
</div>
</a>
@endforeach
</div>
</div>
</div>
{{-- タグランキング --}}
{{-- ユーザーランキング --}}
<div class="col-lg-8 col-md-10 col-sm-12 col-xs-12 mx-auto mt-5">
<div class="card mb-4 sidebar-content">
<div class="card-header text-center">
<i class="fas fa-tags mr-2">
</i>ユーザーランキング
</div>
<div class="card-body main-tag-list py-3 mx-auto">
@foreach ($users_ranking as $user)
<div class="m-3">
<span>{{ $user->name }}</span>
<span>{{ $user->articles_count }}</span>件
</div>
@endforeach
</div>
</div>
</div>
{{-- ユーザーランキング --}}
参考