<h1>Laravel 5.2 实现浏览文章统计次数</h1>
<h2>一、安装 weboAp/Visitor</h2>
<p>先按官方提供的<a href="https://github.com/weboAp/Visitor">文档</a>安装好,并测试。
测试方法:</p>
<pre><code class="language-php">// app/Http/Controllers/ArticleController.php
use Weboap\Visitor\Facades\VisitorFacade; // 使用切面
class ArticleController extends Controller
{
/**
* 文章详情页
*
* @return \Illuminate\Http\Response
*/
public function show($id)
{
VisitorFacade::log();
}
}</code></pre>
<p>浏览器访问:<code>http://localhost/article/1</code> 看数据库表 <code>visitor_registry</code> 是否插入了一条数据。有则表明安装 <code>weboAp/Visitor</code> 成功,如果没有,请按官方文档再跑一遍。</p>
<h2>二、定制</h2>
<h3>改表名</h3>
<p>官方预定的表名是 <code>visitor_registry</code>,我要改为的是 <code>article_clicks</code>.</p>
<ol>
<li>
<p>改 <code>migration</code>
文件内容如下:</p>
<pre><code class="language-php">// database/migrations/2014_02_09_225721_create_article_clicks.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateArticleClicks extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('article_clicks', function (Blueprint $table) {
$table->increments('id');
$table->string('ip', 32);
$table->string('country', 4)->nullable();
$table->string('city', 20)->nullable(); // 新增
$table->integer('article_id'); // 新增
$table->integer('clicks')->unsigned()->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('article_clicks');
}
}</code></pre>
<p>改完之后,手动去数据库删除 <code>visitor_registry</code> 表。重新执行 <code>php artisan migrate</code>。</p>
</li>
<li>
<p>config/visitor.php</p>
<pre><code class="language-php"><?php
return [
'table' => 'article_clicks', // 改这里
];
</code></pre>
</li>
</ol>
<h3>覆盖 <code>Visitor</code> 类的 <code>log</code> 方法,使其支持传入文章 id。改动后的使用方法为:<code>VisitorFacade::log($article->id)</code>;</h3>
<ol>
<li>
<p>新建自定义 <code>Visitor</code> 类且继承 <code>Visitor</code></p>
<pre><code class="language-php"><?php
namespace App\Visitor;
use Weboap\Visitor\Visitor as WeVisitor;
use Carbon\Carbon as c;
use App\ArticleClick;
class Visitor extends WeVisitor {
public function log($articleId = NULL)
{
$ip = $this->ip->get();
if (!$this->ip->isValid($ip)) {
return;
}
if ($this->has($ip) && $this->hasArticle($articleId, $ip)) {
$visitor = ArticleClick::where('ip', $ip)
->where('article_id', $articleId)
->whereDate('updated_at', '!=', c::today())
->first();
if ($visitor) {
$visitor->update(['clicks'=>$visitor->clicks + 1]);
}
return;
} else {
$geo = $this->geo->locate($ip);
$country = array_key_exists('country_code', $geo) ? $geo['country_code'] : null;
$city = array_key_exists('city', $geo) ? $geo['city'] : null;
// ip doesnt exist in db
$data = [
'ip' => $ip,
'country' => $country,
'city' => $city,
'clicks' => 1,
'article_id' => $articleId,
'updated_at' => c::now(),
'created_at' => c::now(),
];
$this->storage->create($data);
}
// Clear the database cache
$this->cache->destroy('weboap.visitor');
}
public function hasArticle($id, $ip) {
return count(ArticleClick::where('article_id', $id)->where('ip', $ip)->get()) > 0;
}
}</code></pre>
</li>
<li>
<p>新建 <code>VisitorServiceProvider</code> 并继承 <code>VisitorServiceProvider</code></p>
<pre><code class="language-php">// app/Providers/VisitorServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Weboap\Visitor\VisitorServiceProvider as VS;
use App\Visitor\Visitor;
class VisitorServiceProvider extends VS
{
public function register()
{
parent::register();
}
public function RegisterVisitor()
{
$this->app->singleton('visitor', function ($app) {
return new Visitor( // 这是替换后的类
$app['Weboap\Visitor\Storage\VisitorInterface'],
$app['Weboap\Visitor\Services\Geo\GeoInterface'],
$app['ip'],
$app['Weboap\Visitor\Services\Cache\CacheInterface']
);
});
$this->app->bind('App\Visitor\Visitor', function ($app) { // 关键在这里,狸猫换太子。
return $app['visitor'];
});
}
}</code></pre>
</li>
<li>
<p>注册两个自定义的类。</p>
<pre><code class="language-php">// composer.json
"autoload": {
"classmap": [
"database",
"app/Visitor/Visitor.php" // 增加这行
],
"psr-4": {
"App\\": "app/"
}
},</code></pre>
<pre><code class="language-php"> // config/app.php
providers: [
...
App\Providers\VisitorServiceProvider::class // 增加这行
]</code></pre>
<h3>最终结果</h3>
<p><img src="//www.pcdeng.com/uploads/article-clicks.png" alt="统计结果" /></p>
</li>
</ol>
<h2>参考</h2>
<p><a href="https://learnku.com/articles/7637/statistics-of-the-number-of-times-in-laravel">Laravel 实现文章浏览量次数统计</a>
<a href="https://stackoverflow.com/questions/47925618/laravel-5-5-override-vendor-class">Laravel 重写第三方类的方法</a></p>
详情