Counting page views with Laravel

前端 未结 5 851
北荒
北荒 2021-02-01 10:02

I want to implement page view counter in my app. What I\'ve done so far is using this method :

public function showpost($titleslug) {
        $post = Post::where         


        
5条回答
  •  难免孤独
    2021-02-01 10:18

    2020 Update

    First of all, thanks a lot "Jean Marcos" for his awesome answer. All credit goes to him, I am just pasting a slightly modified answer combining my knowledge of Laravel as well.

    Create a table to save your view records and name it with snake_case plural: post_views

    Schema::create("post_views", function(Blueprint $table)
    {
          $table->engine = "InnoDB";//this is basically optional as you are not using foreign key relationship so you could go with MyISAM as well
    
          $table->increments("id");
          
          //please note to use integer NOT increments as "Jean Marcos' answer" because it will throw error "Incorrect table definition; there can be only one auto column and it must be defined as a key" when running migration.
          $table->unsignedInteger("post_id");//note that the Laravel way of defining foreign keys is "table-singular-name_id", so it's preferable to use that
          
          $table->string("titleslug");
          $table->string("url");
          $table->string("session_id");
          $table->unsignedInteger('user_id')->nullable();//here note to make it nullable if your page is accessible publically as well not only by logged in users. Also its more appropriate to have "unsignedInteger" type instead of "string" type as mentioned in Jean Marcos' answer because user_id will save same data as id field of users table which in most cases will be an auto incremented id.
          $table->string("ip");
          $table->string("agent");
          $table->timestamps();
    });
    

    Then, create the corresponding model. Please note to create "camelCase" model name with the first capital letter and singular form of the table so it should be like: PostView

    listing_id = $post->id;
            $postViews->url = \Request::url();
            $postViews->session_id = \Request::getSession()->getId();
            $postViews->user_id = (\Auth::check())?\Auth::id():null; //this check will either put the user id or null, no need to use \Auth()->user()->id as we have an inbuild function to get auth id
            $postViews->ip = \Request::getClientIp();
            $postViews->agent = \Request::header('User-Agent');
            $postViews->save();//please note to save it at lease, very important
        }
    }
    

    Then run the migration to generate this table

    php artisan migrate
    

    Finally, your method:

    public function showpost($titleslug)
    {
        $post = PostView::where('titleslug', '=' ,$titleslug)->firstOrFail();
    
        \App\PostView::createViewLog($post);//or add `use App\PostView;` in beginning of the file in order to use only `PostView` here 
    
        //Rest of method...
    }
    

    To search the most viewed posts in the last 24 hours:

    $posts = Posts::join("post_views", "post_views.id_post", "=", "posts.id")
                ->where("created_at", ">=", date("Y-m-d H:i:s", strtotime('-24 hours', time())))
                ->groupBy("posts.id")
                ->orderBy(DB::raw('COUNT(posts.id)'), 'desc')//here its very minute mistake of a paranthesis in Jean Marcos' answer, which results ASC ordering instead of DESC so be careful with this line
                ->get([DB::raw('COUNT(posts.id) as total_views'), 'posts.*']);
    

    Note that in PostView, you have data that can help further filter your listing, such as the session id, in case you do not want to consider hits from the same session.

    You may need to adapt some aspects of this solution to your final code.

    So those were few modifications I wanted to point out, also you might want to put an additional column client_internet_ip in which you can store \Request::ip() which can be used as a filter as well if required.

    I hope it helps

提交回复
热议问题