<?php
namespace app\news\controller;
use app\login\model\News;
use think\facade\Cache;
/**
 * Class ViewCount
 * @package app\news\controller
 * 文章浏览量类
 */
class ViewCount extends News
{
    protected $redis = null;
    protected $hash_prefix; //浏览数hash前缀
    protected $field_prefix; //字段前缀
    protected $id;
    protected $date;
    public function __construct()
    {
        $this->redis = Cache::store('redis');
        $this->hash_prefix = 'news_view_counts_';
        $this->field_prefix = 'news_';
        $this->date = date('Y-m-d');
    }
 
    /**
     * 设置文章浏览数
     * 每天的文章浏览数存在redis hash,如news_view_counts_2020-07-13
     * hash字段存储的是每个文章的浏览数,如news_1
     * 获取hash字段的值,如存在+1,不存在设置1
     * @param int $id 文章id
     * @return bool
     *
     */
    public function viewCountIncrement($id)
    {
        if (empty($id)) {
            return false;
        }
        $this->id = $id;
        // 获取今日 Redis 哈希表名称,如:news_view_counts_2020-07-13
        $hash = $this->getHashFromDateString();
 
        // 字段名称,如:news_1
        $field = $this->getHashField();
 
        // 当前阅读数,如果存在就自增,否则就为 1
        $count = $this->redis->hGet($hash, $field);
        if ($count) {
            $count++;
        } else {
            $count = 1;
        }
 
        // 数据写入 Redis,字段已存在会被更新
        $this->redis->hSet($hash, $field, $count);
 
        return true;
    }
 
    /**
     * 获取文章浏览数
     * 获取redis hash中的浏览数+数据库中的
     * @param int $id  文章id
     * @param int $view_count  数据库浏览数
     * @return bool|int
     */
    public function getViewCount($id, $view_count = 0)
    {
        if (empty($id)) {
            return false;
        }
        $this->id = $id;
        // 获取今日对应的哈希表名称
        $hash = $this->getHashFromDateString();
 
        // 字段名称,如:news_1
        $field = $this->getHashField();
 
        // 三元运算符,获取Redis中的文章浏览数数据,
        $count = $this->redis->hGet($hash, $field) ?: 0;
 
        // 如果存在的话,返回数据库中的阅读数 加上 Redis 中的阅读数
        if ($count) {
            return $view_count + $count;
        } else {
            return $view_count;
        }
    }
 
    /**
     * 异步更新文章浏览量
     * hGetAll取出当天所有的数据,循环更新浏览数(数据库+redis)到mysql
     * 每天凌晨1点执行前一天的浏览数入库
     * @return bool|string
     */
    public function syncNewsViewCounts()
    {
        // 获取昨日的哈希表名称,如:news_view_counts_2020-10-12
        $yesterday = date('Y-m-d', strtotime('-1 day'));
        $this->date = $yesterday;
        $hash = $this->getHashFromDateString();
 
        // 从 Redis 中获取所有哈希表里的数据
        $counts = $this->redis->hGetAll($hash);
 
        // 如果没有任何数据直接 return
        if (count($counts) === 0) {
            return false;
        }
        try {
            // 遍历,并同步到数据库中
            foreach ($counts as $news_id => $view_count) {
                // 将 `news_1` 转换为 1
                $news_id = str_replace($this->field_prefix, '', $news_id);
 
                // 只有当文章存在时才更新到数据库中
                if ($news = News::find($news_id)) {
                    //print_r($news);die;
                    $news->view_count = intval($this->view_count + $view_count);
                    $news->save();
                }
            }
            //同步成功,删除redis数据
            $this->redis->del($hash);
            return '同步成功';
        } catch (\Exception $e) {
            return $e->getMessage();
        }
    }
 
    // Redis 哈希表的命名,如:news_view_counts_2020-07-13
    private function getHashFromDateString()
    {
        return $this->hash_prefix . $this->date;
    }
 
    // 字段名称,如:news_1
    private function getHashField()
    {
        return $this->field_prefix . $this->id;
    }
 
}