使用Laravel计算页面浏览量

使用Laravel计算页面浏览量,laravel,laravel-5,Laravel,Laravel 5,我想在我的应用程序中实现页面查看计数器。到目前为止,我所做的是使用这种方法: public function showpost($titleslug) { $post = Post::where('titleslug','=',$titleslug)->firstOrFail(); $viewed = Session::get('viewed_post', []); if (!in_array($post->id, $viewed))

我想在我的应用程序中实现页面查看计数器。到目前为止,我所做的是使用这种方法:

public function showpost($titleslug) {
        $post = Post::where('titleslug','=',$titleslug)->firstOrFail();
        $viewed = Session::get('viewed_post', []);
        if (!in_array($post->id, $viewed)) {
            $post->increment('views');
            Session::push('viewed_post', $post->id);
        }
        return view('posts/show', compact('post', $post));
    }
我检索热门帖子列表,如下所示:

$popular_posts = Post::orderBy('views', 'desc')->take(10)->get();

然而,我想知道是否有更好的方法来做到这一点?用我目前的方法,我能得到过去24小时内浏览次数最多的帖子列表吗?就这些,谢谢

正如@milo526的评论中所引用的,您可以以一种独特的方式记录页面的所有点击量,而不是增量。有了它,你可以搜索访问信息,包括按浏览次数排序的帖子列表

创建一个表以保存视图记录:

Schema::create("posts_views", function(Blueprint $table)
        {
            $table->engine = "InnoDB";

            $table->increments("id");
            $table->increments("id_post");
            $table->string("titleslug");
            $table->string("url");
            $table->string("session_id");
            $table->string("user_id");
            $table->string("ip");
            $table->string("agent");
            $table->timestamps();
        });
然后,创建相应的模型:

<?php namespace App\Models;

class PostsViews extends \Eloquent {

    protected $table = 'posts_views';

    public static function createViewLog($post) {
            $postsViews= new PostsViews();
            $postsViews->id_post = $post->id;
            $postsViews->titleslug = $post->titleslug;
            $postsViews->url = \Request::url();
            $postsViews->session_id = \Request::getSession()->getId();
            $postsViews->user_id = \Auth::user()->id;
            $postsViews->ip = \Request::getClientIp();
            $postsViews->agent = \Request::header('User-Agent');
            $postsViews->save();
    }

}
要搜索过去24小时内浏览次数最多的帖子,请执行以下操作:

$posts = Posts::join("posts_views", "posts_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'))
            ->get(array(DB::raw('COUNT(posts.id) as total_views'), 'posts.*'));
$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.*']);

注意,在PsStVIEW中,如果您不想从同一个会话中考虑命中,则您可以拥有可以进一步过滤列表的数据,例如会话ID。 您可能需要根据最终代码调整此解决方案的某些方面。

包可用于此目的。它提供了更灵活的方法来做类似的事情(计算页面浏览量)

注意:雄辩的可视包需要PHP7+和Laravel5.5+

使模型可见:

public function show(Post $post)
{
    $post->addView();

    return view('blog.post', compact('post'));
}
只需在模型定义中添加可查看的特征,如下所示:

use Illuminate\Database\Eloquent\Model;
use CyrildeWit\EloquentViewable\Viewable;

class Post extends Model
{
    use Viewable;

    // ...
}
然后在控制器中:

public function show(Post $post)
{
    $post->addView();

    return view('blog.post', compact('post'));
}
然后你可以做这样的事情:(

实现与公认答案中相同的想法,但提供更多功能和灵活性。

2020更新 首先,非常感谢“让·马科斯”的精彩回答。所有的功劳都归于他,我只是粘贴了一个稍加修改的答案,结合我对拉雷维尔的了解

创建一个表以保存视图记录,并用snake\u大写复数:post\u 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();
});
然后,创建相应的模型请注意,创建“camelCase”型号名称时,应使用首个大写字母和表格的单数形式,因此应如下所示:PostView

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PostView extends Model
{
    public static function createViewLog($post) {
        $postViews= new PostView();
        $postViews->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
    }
}
最后,您的方法:

public function showpost($titleslug)
{
    $post = PostsViews::where('titleslug', '=' ,$titleslug)->firstOrFail();

    PostsViews::createViewLog($post);

    //Rest of 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...
}
要搜索过去24小时内浏览次数最多的帖子,请执行以下操作:

$posts = Posts::join("posts_views", "posts_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'))
            ->get(array(DB::raw('COUNT(posts.id) as total_views'), 'posts.*'));
$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.*']);

注意,在PostView中,如果您不想从同一个会话中考虑命中,则您可以拥有可以进一步过滤列表的数据,例如会话ID。 您可能需要根据最终代码调整此解决方案的某些方面

因此,我想指出的是这些修改,您可能还需要添加一个列
client\u internet\u ip
,您可以在其中存储
\Request::ip()
,如果需要,它也可以用作过滤器

我希望它有助于拉威尔6号的2020年更新(2)/建立雄辩的关系

如果不想将包添加到应用程序中。基于“Jean Marcos”和“学习者”对问题的贡献以及我自己的研究,我开发了以下解决方案

所有的功劳都归于“Jean Marcos”和“Learner”,我觉得我应该像Learner一样,以对他人有益的方式更新代码

首先,确保数据库中有一个sessions表。否则,请按照Laravel文档中的步骤进行操作:

确保会话存储在表中。如果没有,请确保将.env设置处的SESSION_驱动程序变量更改为“database”而不是“file”,然后执行composer dump autoload

在那之后,你们都准备好出发了。可以从运行以下控制台命令开始:

php artisan make:model PostView -m 
这将生成模型和迁移文件

在迁移文件的内部放置以下架构。请注意列名称。例如,我的posts表有“slug”列标题名,而不是问题中提到的“titleslug”

  Schema::create('post_views', function (Blueprint $table) {

        $table->increments("id");
        $table->unsignedInteger("post_id");
        $table->string("titleslug");
        $table->string("url");
        $table->string("session_id");
        $table->unsignedInteger('user_id')->nullable();
        $table->string("ip");
        $table->string("agent");
        $table->timestamps();
    });
然后将以下代码放入PostView模型文件中

<?php

namespace App;

use App\Post;
use Illuminate\Database\Eloquent\Model;

class PostView extends Model
{

    public function postView()
    {
        return $this->belongsTo(Post::class);
    }

    public static function createViewLog($post) {
        $postViews= new PostView();
        $postViews->post_id = $post->id;
        $postViews->slug = $post->slug;
        $postViews->url = request()->url();
        $postViews->session_id = request()->getSession()->getId();
        $postViews->user_id = (auth()->check())?auth()->id():null; 
        $postViews->ip = request()->ip();
        $postViews->agent = request()->header('User-Agent');
        $postViews->save();
    }
}
在相同的Post模型中,您应该放置以下代码。如果用户未登录,代码将测试IP匹配。否则,它将测试会话ID和用户ID,因为每个用户可能有多个会话

public function showPost()
{
    if(auth()->id()==null){
        return $this->postView()
        ->where('ip', '=',  request()->ip())->exists();
    }

    return $this->postView()
    ->where(function($postViewsQuery) { $postViewsQuery
        ->where('session_id', '=', request()->getSession()->getId())
        ->orWhere('user_id', '=', (auth()->check()));})->exists();  
}
现在可以运行迁移了

php artisan migrate
当用户要求发布时。应在PostController文件中针对以下功能:

use App\PostView;

     public function show(Post $post)
        {
//Some bits from the following query ("category", "user") are made for my own application, but I felt like leaving it for inspiration. 
            $post = Post::with('category', 'user')->withCount('favorites')->find($post->id);

            if($post->showPost()){// this will test if the user viwed the post or not
                return $post;
            }

            $post->increment('views');//I have a separate column for views in the post table. This will increment the views column in the posts table.
            PostView::createViewLog($post);
            return $post;
        }
因为我在post表中有一个单独的视图列。要搜索过去24小时内浏览次数最多的帖子,请在控制器中编写以下代码。如果没有分页,请删除分页:

public function mostViwedPosts()
{
    return Posts::with('user')->where('created_at','>=', now()->subdays(1))->orderBy('views', 'desc')->latest()->paginate(5);
}

我希望这能帮助/节省一些时间。

首先感谢用户33192分享。只是想让其他人看了文档后更清楚。查看文档以安装软件包

在您的Post模型中执行此操作:

use Illuminate\Database\Eloquent\Model;
use CyrildeWit\EloquentViewable\InteractsWithViews;
use CyrildeWit\EloquentViewable\Viewable;

class Post extends Model implements Viewable
{
    use InteractsWithViews;

    // ...
}
在您的帖子控制器中,使用记录方法保存视图

public function show($slug)
{
    $post = Post::where('slug',$slug)->first();
    views($post)->record();
    return view('posts.show',compact('post'));
}
在您的视图中,您可以根据需要返回视图(我的是posts.show)。查看文档了解更多信息。我将只是一个职位的总意见

<button class="btn btn-primary">
    {{ views($post)->count() }} <i class="fa fa-eye"></i>
</button>

{{views($post)->count()}

如果你在查看页面时进行存储,你可以获得该信息,但如果你只使用计数器来计算文章的浏览次数,你就无法按最近x分钟内的浏览次数进行排序。“应用程序”(我会说网页)有多大,换句话说,峰值用户数是多少?或者如果您有统计数据,在峰值期间有多少req/m?您使用什么会话驱动程序?页面视图是否仅与显示大多数查看的页面相关,或者您稍后将使用数据(可能是“30天前前10篇文章/页面”等等)。这意味着我需要创建一个不同的表来存储视图数据@米洛526一点也不大,我正在建立一个博客,而且还在开发中,所以我还没有任何与访客相关的数据可供分析。我想使用查看计数器获取最受欢迎的帖子和趋势帖子(按过去x小时内浏览次数最多的帖子排序)@KyslikI会试试这个,b