Количество просмотров в Laravel

Опубликовано 2 комментариев 1197 просмотров
Количество просмотров в Laravel

Привет.

Реализовать учет просмотров в Laravel не самая трудная задача. Данный материал существует уже довольно давно и успел кардинально измениться несколько раз. Последняя его модификация, которую вы читаете сейчас - максимально простая и безопасная (если сравнивать с прошлыми редакциями, разумеется).

Благодаря добавленному слою кеширования в Redis, который инициирует обновление данных в базе не каждый раз при обращении к странице а лишь раз в несколько часов, способ поможет решить проблему, из-за которой будет создана повышенная нагрузка на БД.

Требования: Laravel > 5.3, любая БД, Redis в качестве кеш-драйвера.

Начнем. Добавим в таблицу с записями, учет просмотров которых вы планируете вести новую колонку.

$ php artisan make:migration update_posts_table
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UpdatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function(Blueprint $table) {
            $table->integer('views')
                ->default(0)
                ->after('column_name'); // существующая колонка
        });
    }
}

Запустим миграции.

Прошлый вариант заключался в том, что на каждый хит в базу посылался UPDATE с новым значением колонки views. Текущий же содержит чуть больше кода, но и выглядит куда интересней.

Перейдем к редактированию метода контроллера, отвечающего за вывод страницы с записью. Если вы еще не кешируете данные - пришла пора этим заняться. Предположим, у нас есть простой метод который по ID записи возвращает View с ней. Закешируем участок, достающий запись из хранилища.

$post = \Cache::tags(['posts', 'single'])
    ->remember($id, 120, function() use ($id) {
        $post = Post::findOrFail($id);

        return $post;
    });

Сначала займемся обновлением данных в хранилище. В функции добавим:

$viewsCache = \Cache::tags(['posts', 'views']);

// Если число в кеше больше числа в хранилище - обновляем данные.
if(($views = $viewsCache->get($post->id, 0)) > $post->views) {
    $post->views = $views;
    $post->timestamps = false;
    $post->save();
    $post->timestamps = true;
}

Этот участок кода будет выполняться только в моменты, когда кеш с таким ключем просрочен или не существует - не чаще раза в несколько часов, если не сбрасывать кеш вручную.

На случай если запись только создана - добавим или обновим закешированное число.

$viewsCache->forever($post->id, $post->views);

С частью, перенесенной в кеш все. За ее пределами нам необходимо выполнить две вещи: при каждом открытии страницы увеличивать на 1 число в кеше и обновлять соответствующий атрибут у модели для актуализации.

$viewsCache->increment($post->id); // +1 просмотр
$post->views = $viewsCache->get($post->id); // поместим актуальное число в модель

Как все будет работать. Открыв страницу, пользователь запишет в кеш текущее число просмотров. С каждым последующим обновлением страницы число в кеше будет увеличиваться на 1. Спустя какое-то время кеш с информацией о записи устареет и открытие страницы приведет к тому, что в хранилище упадет новое число, которое сохранено в кеше.

Конечный код метода контроллера из примера выглядит так:

public function show(int $id)
{
    $viewsCache = \Cache::tags(['posts', 'views']);

    $post = \Cache::tags(['posts', 'single'])
        ->remember($id, $this->cacheTime, function() use ($id, $viewsCache) {
            // получаем запись
            $post = Post::findOrFail($id);

            // пишем в базу число из кеша
            if(($views = $viewsCache->get($post->id, 0)) > $post->views) {
                $post->views = $views;
                $post->timestamps = false;
                $post->save();
                $post->timestamps = true;
            }

            // добавялем число в кеш
            $viewsCache->forever($post->id, $post->views);

            return $post;
        });

    $viewsCache->increment($post->id); // +1 просмотр
    $post->views = $viewsCache->get($post->id); // поместим актуальное число в модель

    return view('post.show')
        ->with(compact('post'));
}

Надеюсь, вам помогло мое решение. Удачи.

  • СергейК

    СергейК

    хм. cacheTime куда девать? Undefined property: App\Http\Controllers\PostController::$cacheTime

  • gtxtymt

    gtxtymt

    СергейК,

    \Cache::tags(['posts', 'single'])->remember($id, $this->cacheTime, function() use ($id, $viewsCache)

    cacheTime - свойство, в котором я храню время жизни кеша.

В ответ на сообщение

Доступна разметка Markdown. А еще вы можете использовать крутой пак эмоций.

Нажимая на кнопку «Отправить» вы даете свое согласие на обработку персональных данных в соответствии с законом №152-ФЗ «О персональных данных» от 27.07.2006 и принимаете условия Политики конфеденциальности.