PostRepo.php 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. <?php
  2. namespace App\Repos;
  3. use App\Models\Post;
  4. use Illuminate\Support\Facades\Redis;
  5. class PostRepo
  6. {
  7. protected Post $post;
  8. protected string $trendingPostsKey = 'popular_posts';
  9. public function __construct(Post $post)
  10. {
  11. $this->post = $post;
  12. }
  13. public function getById(int $id, array $columns = ['*'])
  14. {
  15. $cacheKey = 'post_' . $id;
  16. if (Redis::exists($cacheKey)) {
  17. return unserialize(Redis::get($cacheKey));
  18. }
  19. $post = $this->post->select($columns)->find($id);
  20. if (!$post) {
  21. return null;
  22. }
  23. Redis::setex($cacheKey, 1 * 60 * 60, serialize($post)); // 缓存 1 小时
  24. return $post;
  25. }
  26. public function getByManyId(array $ids, array $columns = ['*'], callable $callback = null)
  27. {
  28. $query = $this->post->select($columns)->whereIn('id', $ids);
  29. if ($query) {
  30. $query = $callback($query);
  31. }
  32. return $query->get();
  33. }
  34. public function addViews(Post $post)
  35. {
  36. $post->increment('views');
  37. if ($post->save()) {
  38. // 将当前文章浏览数 +1,存储到对应 Sorted Set 的 score 字段
  39. Redis::zincrby('popular_posts', 1, $post->id);
  40. }
  41. return $post->views;
  42. }
  43. // 热门文章排行榜
  44. public function trending($num = 10)
  45. {
  46. $cacheKey = $this->trendingPostsKey . '_' . $num;
  47. if (Redis::exists($cacheKey)) {
  48. return unserialize(Redis::get($cacheKey));
  49. }
  50. $postIds = Redis::zrevrange($this->trendingPostsKey, 0, $num - 1);
  51. if (!$postIds) {
  52. return null;
  53. }
  54. $idsStr = implode(',', $postIds);
  55. $posts = $this->getByManyId($postIds, ['*'], function ($query) use ($idsStr) {
  56. return $query->orderByRaw('field(`id`, ' . $idsStr . ')');
  57. });
  58. Redis::setex($cacheKey, 10 * 60, serialize($posts)); // 缓存 10 分钟
  59. return $posts;
  60. }
  61. }