Laravel 实现文章浏览量次数统计

由于网上参考的两篇文章讲的不是特别适合自己,在下载和开发的过程中遇到不少的坑,所以就在前辈的基础上进行整理知识点。
浏览量统计的需求:
用户访问文章页面–>取得ip地址和文章id,存入数据库 再次访问时根据ip和文章id判断是否新增记录,
扩展工具:weboAp/Visitor
首先要用composer 加载weboAp/Visitor
在composer.json的require中添加,注意标点符号的遗漏和错误,

 {
    "require": {
        "weboap/visitor": "dev-master"
    }
}

2.然后在命令行执行 composer update ,我使用的是 PhpStorm ,所以可以用 alt+F12 调出命令行,输入即可。
composer update
3.将Service添加到 config/app.php的 providers中,同样注意标点符号的遗漏和错误:
'Weboap\Visitor\VisitorServiceProvider'
4.之后在命令行(phpstorm->ALT+F12)里执行下面两个命令:
php artisan vendor:publish
php artisan migrate
5.到 http://dev.maxmind.com/geoip/geoip2/geolite2 下载geoip包(GeoLite2-City.mmdb)将它解压之后放到以下目录, geo 文件夹 需要自己创建的storage/geo/
6.上面的步骤之后你将会得到一个表 visitor_registry,这里我们首先为 visitor_registry 添加一个字段 art_id 用于 One-To-Many 的关系。
php artisan make:migration add_art_id_to_visitor_registry --table='visitor_registry'
7.在项目的 database 文件夹找到新生成的表格,名字是 日期+add_article_id_to_visitor_registry 在里面的up方法中写入

public function up() 
{ 
Schema::table('visitor_registry', function (Blueprint $table) { 
$table->integer('art_id')->unsigned()->index(); 
$table->foreign('art_id')->references('id')->on('article')->onDelete('cascade'); 
}); 
} 

这边就是我遇到的坑之一,
首先
$table->integer('art_id')->unsigned()->index();
art_id是你文章表格的 id 列名 ,
这边是在 visitor_registry 添加字段. 用于添加外键使用的 ,所以这边改成你需要的属性,
$table->foreign('art_id')->references('id')->on('article')->onDelete('cascade');
这边是 visitor_registry 与你的表格添加外键,
这边也有一个坑,就是死活都无法添加进外键,
大概是这样↓↓↓好吧,我承认我暴走了= =翻来翻去找不到答案,
然后我就去睡了一觉,起来以后再翻翻stackoverflow,然后就解决了。
可能是你代码打错了,检查一下。
可能是主表的键没有设置无符号,这是国外友人提的,并被那个问主采纳了,那你就看看两个表的外键属性是否一致。
最后这是我遇到的原因,大概是咸丰年前(其实就一个星期前),我开发博客系统的时候,把表格的引擎都改成了MyISAM ,而通过 migrate 生成的表格是默认InnoDB ,所以,它!就!添!加!不!成!功!
如果还不能解决,那我也没办法帮你了,科学上网,翻墙后出去大型基佬聚会会所stackoverflow看看。
8.运行
php artisan migrate
9.接下来添加模型,
php artisan make:model VisitorRegistry
10.再接下来是在模型里面添加

protected $table = 'visitor_registry';
protected $fillable = ['clicks'];
public function articles()
{
    return $this->belongsTo('App\Article');
}

11.再接下来就在你要计算浏览数的那个模型,也就是文章展示的模型中添加一对多的关系

public function visitors()
   {
       return $this->hasMany('App\VisitorRegistry');
   }

12.我们在第7步中给原先的表格添加了一个属性,所以我们需要修改原来扩展包里面的log()方法
在方法中添加参数
public function log($art_id){}
在修改第二个If语句

if( $this->has( $ip ) && $this->hasArticle($art_id,$ip) )
        {
            //ip already exist in db.
            $visitor = VisitorRegistry::where('ip','=',$ip)->where('art_id','=',$art_id)->first();
            $visitor->update(['clicks'=>$visitor->clicks + 1]);
            return true;
        }

上面我们自己添加了一个 hasArticle($article_id,$ip),我们可以直接将这个方法写在 Visitor.php 中:

public function hasArticle($id,$ip)
    {
        return count(VisitorRegistry::where('art_id','=',$id)->where('ip','=',$ip)->get()) > 0;
    }

最后我们还要修改log()中的插入数据的数组数据$data

$data = array(
                    'ip'        => $ip,
                    'country'   => $country,
                    'clicks'    => 1,
                    'art_id' => $art_id,
                    'updated_at'    => c::now(),
                    'created_at'    => c::now()
                    );

完整的方法是:

 public function log($art_id)
    {
        $ip = $this->ip->get();
        if (!$this->ip->isValid($ip)) {
            return;
        }
        if ($this->has( $ip ) && $this->hasArticle($art_id,$ip) ) {
            //ip already exist in db.
            $visitor = VisitorRegistry::where('ip','=',$ip)->where('art_id','=',$art_id)->first();
            $visitor->update(['clicks'=>$visitor->clicks + 1]);
            return true;
        } else {
            $geo = $this->geo->locate($ip);
            $country = array_key_exists('country_code', $geo) ? $geo['country_code'] : null;
            //ip doesnt exist  in db
            $data = [
                'ip'        => $ip,
                'country'   => $country,
                'clicks'    => 1,
                'art_id' => $art_id,
                'updated_at'    => c::now(),
                'created_at'    => c::now()
            ];
            $this->storage->create($data);
        }
        // Clear the database cache
        $this->cache->destroy('weboap.visitor');
    }

好了,super 完美。

本作品采用《CC 协议》,转载必须注明作者和本文链接
刻意练习,每日精进
本帖由系统于 4年前 自动加精
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 6
GalaxyNo_1

额:earth_africa:

6年前 评论

@Seaony 百度的试过,但是感觉不是很理想

6年前 评论
TigerLin

你好!请教几个问题
1.下载到geo文件夹里的文件什么作用
2.修改log的方法在哪里找
3.能不能请你给我讲讲原理,新学着 理解有点难

5年前 评论
TigerLin

这句话的作用是什么 在我调用log()方法的时候,总是直接跳出了,而且 我刷新页面数据是不断新建的
$ip = $this->ip->get();
// if (!$this->ip->isValid($ip)) {
// return;
// }

5年前 评论

版本7,可以使用吗

3年前 评论
欲饮琵琶码上催 3年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!