【Laravel】カウントと並び替えでランキングを作る方法

# はじめに
今回は、Laravelの**withCountメソッド**と**クエリビルダ**を使ってランキング機能を実装するまでの流れを解説していきます。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [やりたいこと](#Chapter1)
2. [コントローラー](#Chapter2)
3. [モデル](#Chapter3)
4. [ビュー](#Chapter4)
6. [参考](#reference) 

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# やりたいこと

##### タグランキングの作成
- タグに紐付けられた記事数をカウントして多い順に並び替えます
    - 以下のテーブルを**多対多**(articles:tags)の関係で使用する
        - 記事テーブル（articles）
        - タグテーブル（tags）
        - 中間テーブル（article_tag）


##### ユーザーランキングの作成
- ユーザーが投稿した記事のうち "status" カラムが "success" である記事をカウントして多い順に並び替えます
    - 以下のテーブルを**1対多**(users:articles)の関係で使用する
        - ユーザーテーブル（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

<a id="#Chapter2"></a>
# コントローラー

```php: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);
    }
}

```
<a id="#Chapter3"></a>
# モデル

**リレーション結果の件数を実際にレコードを読み込むことなく知りたい場合は、withCountメソッドを使います。件数は結果のモデルの{リレーション名}_countカラムに格納されます。**
([Laravel 6.x Eloquent：リレーション](https://search.readouble.com/?query=6.x+withCount)参照)

{リレーション名}_countカラムをテーブルに作成しなくて良いので、非常に便利です。

また、ユーザーランキングでは、Laravelの**クエリビルダ**を活用しました。
([Laravel 6.x データベース：クエリビルダ](https://search.readouble.com/?query=6.x+%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%93%E3%83%AB%E3%83%80)参照)


```php:Tag.php
class Tag extends Model
{
    public function tagsRanking()
    {
        $query = Tag::withCount('articles')->orderBy('articles_count', 'desc')->limit(5)->get();

        return $query;
    }
}
```

```php: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;
    }
}
```

<a id="#Chapter4"></a>
# ビューを作成

```php: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>
{{-- ユーザーランキング --}}

```

<a id="#reference"></a>
# 参考

https://qiita.com/hareku/items/8cef12d5a9a4c18beae8

https://qiita.com/Ioan/items/bac58de02b826ae8e9e9

https://www.techpit.jp/courses/11