🦓

[Laravel]閲覧回数を表示する

2023/11/03に公開

はじめに

Laravelで投稿のアクセス数・閲覧回数が分かるように実装していきます。

環境

PHP 8.x
Laravel 10.x
MySQL 8.x

tl;dr

  1. テーブルを作成する
  2. $fillableプロパティを定義する
  3. コントローラーに閲覧回数をカウントするロジックを追加する
  4. モデルのアソシエーションを設定する
  5. ビューに表示する

テーブルを作成する

閲覧回数を記録する用テーブルを作成します。

php artisan make:model ListingView -m

   INFO  Model [app/Models/ListingView.php] created successfully.  

   INFO  Migration [database/migrations/2023_11_03_170015_create_listing_views_table.php] created successfully.  

カラムを定義する

database/migrations/2023_11_03_170015_create_listing_views_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('listing_views', function (Blueprint $table) {
            $table->id();
            $table->string('ip_address', 55);
            $table->string('user_agent', 255);
            $table->foreignId('listing_id')->constrained()->onDelete('cascade');
            $table->foreignId('user_id')->nullable()->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('listing_views');
    }
};

php artisan migrateでマイグレーションを実行します。

➜   php artisan migrate

   INFO  Running migrations.  

  2023_11_03_170015_create_listing_views_table .................... 818ms DONE

$fillableプロパティを定義する

app/views/ListingView.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class ListingView extends Model
{
    use HasFactory;

    protected $fillable = [
        'ip_address',
        'user_agent',
        'listing_id',
        'user_id'
    ];
}

コントローラーに閲覧回数をカウントするロジックを追加する

app/http/controllers/ListingController.php
<?php

namespace App\Http\Controllers;

use App\Models\Listing;
use App\Models\ListingView;

class ListingController extends Controller
{
    public function show(string $id, Request $request)
    {
        $listing = Listing::find($id);

        $user = $request->user();
        
        ListingView::create([
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'listing_id' => $id,
            'user_id' => $user?->id
        ]);

        return view('listings.show', compact('listing'));
    }
}

'ip_address' => $request->ip(): リクエストからIPアドレスを取得し、ip_addressというデータベースカラムに設定します。

'user_agent' => $request->userAgent(): リクエストからユーザーエージェント情報を取得し、user_agentというデータベースカラムに設定します。ユーザーがどのブラウザや端末からアクセスしているかを表示します。

'user_id' => $user?->id: $user?->id?はオプショナルプロパティアクセス演算子です。$userが存在しない場合にエラーが出ません。ログインしてないユーザーのアクセス数もカウントしたいので使ってます。

user_idカラムが無くても成立しますが、投稿のおすすめ機能やよくみらている記事機能などを追加する時に便利なので入れてみました。

投稿をクリックし、アクセス数がカウントされていることを確認します。

モデルのアソシエーションを設定する

一つの投稿の閲覧回数を取得したいのでモデルのアソシエーションを設定します。

app/models/Listing.php
<?php

namespace App\Models;

use App\Models\ListingView;

class Listing extends Model
{
...
    public function views()
    {
        return $this->hasMany(ListingView::class);
    }
}
app/models/ListingView.php
<?php

namespace App\Models;

use App\Models\Listing;


class ListingView extends Model
{
...
    public function listing()
    {
        return $this->belongsTo(Listing::class);
    }
}

ビューに表示する

コンポーネントを作成し、投稿にアクセスされた回数を表示します。

resources/views/components/listing-view.blade.php
{{ $listing->views->count() }}

投稿一覧に閲覧回数の多い順で投稿を表示したり、ユーザーごとの閲覧履歴を表示したりなどDBを活用しいろんな情報を表示できますねー

終わりに

閲覧回数をカウント&表示することができました。
ページをリロードする度にレコード数が増えてしまうのでフィルタリングした方が良いと思いました。同じIPアドレスからの直近1時間以内の重複したアクセスがカウントされないようにするのも良さそうです。

Discussion