Счетчик просмотров страницы в Laravel

Добавлено: 05/11/2014 03:52 |  Обновлено: 19/08/2017 14:31 |  Добавил: nick |  Просмотры: 6036 Комментарии: 9
Вводная часть
Счетчик просмотров страницы в Laravel реализовать достаточно просто. Имеется ввиду простая функция подсчета количества загрузок страницы. В этом материале описывается реализация такой функции на примере простой заготовки сайта, созданной с нуля. Предполагается, что вы умеете загружать новый проект с ядром фреймворка на сервер и подключать к нему базу данных. Перед началом работы нужно будет это сделать, так как в материале это не описывается. Рассматриваются версии Laravel 4.2 и Laravel 5.4.

Содержание:

  1. Laravel 4.2
  2. Laravel 5.4

Laravel 4.2

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

Создадим миграцию для нашей таблицы, используя следующую команду:
php artisan migrate:make create_posts_table --create="posts"
Миграция будет помещена в папку app/database/migrations и будет содержать текущее время, которое позволяет библиотеке определять порядок применения миграций. Полное имя миграции будет таким: время_создания_create_posts_table.php.

Добавим несколько строк в файл миграции, в функцию "up", чтобы она выглядела следующим образом:
public function up()
{
  Schema::create('posts', function(Blueprint $table)
  {
    $table->increments('id');
    $table->string('title');
    $table->text('content');
    $table->integer('view_count')->default(0);
    $table->timestamps();
  });
}
Далее просто применим созданную миграцию, запустив команду:
php artisan migrate
После чего будет создана таблица с названием "posts". Как делается сидинг данных (seeding) в этой статье рассматривать не будем. Если вы об этом ничего не знаете, то можно просто вручную добавить новые строки в таблицу.

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

В первую очередь создадим простую модель "Post" в папке models, пример кода можно взять с сайта laravel.com, по адресу http://laravel.com/docs/4.2/eloquent. Конечный вариант модели будет выглядеть так:
<?php
//Файл: app/models/Post.php
class Post extends Eloquent {
  protected $table = 'posts';
}
Далее создадим заготовку контроллера с помощью команды:
php artisan controller:make PostController
После выполнения команды мы получим файл контроллера (PostController.php) в папке controllers. В файле будет куча методов, нужных для обработки и вывода данных(create, show, edit, update, и т.д.). Нам будет нужен только метод show для вывода единичной записи блога.

Откроем файл PostController.php и в секции функции "show($id)" добавим 2 строчки. Первая получает содержимое нужного нам поста из базы. Вторая передает это содержимое в вид. В итоге функция получится такой:
/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return Response
 */
public function show($id)
{
  $post = Post::find($id);
  return View::make('posts.show', compact('post'));
}
Далее пропишем маршрут в файле routes.php:
Route::resource('post', 'PostController');
И осталось нам еще создать вид. В контроллере мы указали "posts.show". То есть вид будет называться "show" и лежать в папке posts. Для чего мы должны ее создать в папке views, и назвать файл "show.blade.php". В нем мы просто выведем содержимое поста. Файл будет выглядеть следующим образом:
id: {{$post->id}}
<br>
Название поста: {{$post->title}}
<br>
Текст поста: {{$post->content}}
<br>
Количество просмотров: {{$post->view_count}}
<br>
Все. С подготовительной частью мы закончили. Можно перейти по адресу http://адрес_вашего_сайта/post/id_поста и на экран будет выведено содержимое записи блога с указанным id. Далее, наконец уже, реализуем сам подсчет просмотров страницы поста. Сделаем мы это с помощью системы событий. Документация об этом на английском языке есть на сайте фреймворка laravel.com, а русский вариант документации представлен на сайте laravel.ru.

Для начала откроем ранее созданный контроллер PostController.php, в секции функции "show" нужно добавить новую строку:
Event::fire('post.view', $post);
Окончательный вид функции будет таким:
/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return Response
 */
public function show($id)
{
  $post = Post::find($id);
  Event::fire('post.view', $post);
  return View::make('posts.show', compact('post'));
}
Добавленная строка отвечает за возбуждение события в данном месте. Обратите внимание, что строка события должна быть именно после получения данных из базы, то есть после строки $post = Post::find($id);

Теперь нужно создать файл events.php в папке приложения, он будет содержать код наблюдателя события, который после возбуждения события увеличит значение счетчика в базе данных на единицу. В итоге файл будет выглядеть так:
<?php
//Файл: app/events.php
Event::listen('post.view', function($post)
{
  $post->increment('view_count'); 
});
Но счетчик пока работать не будет так как его еще нужно подключить в файле global.php, в папке приложения (app/start/global.php). Открываем этот файл и инклудим в конец файла файл events.php. Добавить нужно следующий код:
/*
|--------------------------------------------------------------------------
| Require The Events File
|--------------------------------------------------------------------------
*/
require app_path().'/events.php';
Все, теперь можно попробовать поперезагружать страницу с любым постом из блога, в результате число в строке "Количество просмотров" должно инкрементироваться.
К содержанию

Комментарии

  • 27/06/2018 16:38 Andrey пишет:

    В PostController.php было бы неплохо заменить

    public function show($id) {

      $post = Post::find($id);

      return View::make('posts.show', compact('post'));

    }

    на

    public function show(Post $post) {

      return View::make('posts.show', compact('post'));

    }

    т. е., применяем Dependency Injection (если я правильно помню термин). Так мы сразу можем работать с моделью. Для данного примера это не суть важно, но в дальнейшем может пригодиться, особенно при апдейте записи.

    nick пишет:
    Да, вы правы, лучше всего сразу передать объект модели.

  • 08/04/2018 00:40 Алишер ( http://social.uz) пишет:

    Всем привет, аналогично как у пользователя с предыдущим комментарием была ситуация что счётчик увеличивался не на 1, а на 2 иногда даже на 4. Даже когда код инкрементирования поставил в контроллер была та же ситуация, проблема заключалась в Ajax запросе после загрузки страницы, а отправлял их PhpDebugBar, отключите или поставьте проверку в контроллере. 
    P.S не забываем проверку на накрутки просмотров
    Laravel 5.5


  • 28/11/2017 11:57 Иван пишет:

    Здравствуйте, делал всё на laravel 5.4

    Использовал второй способ и в итогде прибаляет аж по 4 цифры.

    В чём может быть проблема?

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

  • 23/10/2016 18:26 Андрей пишет:

    Я всё таки победил)

    Добавил в контроллер:

            $resources = Resources::findOrFail($id);
            event(new ResourcesHasViewed($resources));

    nick пишет:
    Дорогу осилит идущий;) Странно конечно, что с первым вариантом не работало.

  • 23/10/2016 18:13 Андрей пишет:

    В контроллере вот что прописано

    public function news($id, $alias) {
            $news = Resources::where('id', $id)
                   ->orderBy('createdon','DESC')
                   ->get();
            event(new ResourcesHasViewed($news));
            return view('news.news',compact('news'));
        }


  • 23/10/2016 16:45 Андрей пишет:

    Может у меня не правильно что-то прописано в файле ResourcesHasViewed.php

     

    namespace App\Events;

    use App\Resources;

    use Illuminate\Broadcasting\Channel;
    use Illuminate\Queue\SerializesModels;
    use Illuminate\Broadcasting\PrivateChannel;
    use Illuminate\Broadcasting\PresenceChannel;
    use Illuminate\Broadcasting\InteractsWithSockets;
    use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

    class ResourcesHasViewed
    {
        use InteractsWithSockets, SerializesModels;
        
        public $resources;

        /**
         * Create a new event instance.
         *
         * @return void
         */
        public function __construct(Resources $resources)
        {
            $this->resources = $resources;
        }

        /**
         * Get the channels the event should broadcast on.
         *
         * @return Channel|array
         */
        public function broadcastOn()
        {
            return new PrivateChannel('channel-name');
        }
    }

    или в файле Counter.php

     

    namespace App\Listeners;

    use App\Events\ResourcesHasViewed;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class Counter
    {
        /**
         * Create the event listener.
         *
         * @return void
         */
        public function __construct()
        {
            //
        }

        /**
         * Handle the event.
         *
         * @param  ResourcesHasViewed  $event
         * @return void
         */
        public function handle(ResourcesHasViewed $event)
        {
            $event->resources->increment('view_count');
        }
    }

    nick пишет:
    Все правильно. Посмотрите, чтобы в контроллере еще все правильно было.

  • 23/10/2016 13:48 Андрей пишет:

    Создавалось то всё через консоль, просто ваше решение хотелось интегрировать на тестовую версию https://test.haubau.pro/news/382-kindergartens-are-repaired-in-irkutsk-for-the-academic-year Listener и Events как раз были созданы через консоль командой php artisan event:generate

    nick пишет:
    Честно говоря не знаю в чем может быть проблема. Если у вас за вывод новостей отвечает ResourcesController.php и за работу с БД отвечает модель Resources, и версия фреймворка 5.3 по идее все должно работать. Можно попробовать напрямую прописать путь до модели в параметрах конструктора. В контроллере тоже кстати должен быть добавлен путь до модели, потому что именно из контроллера создается объект события.

  • 23/10/2016 12:27 Андрей пишет:

    Да, модель в файле события подключил от того и не пойму в чём может быть дело?! (((

    nick пишет:
    Хм...интересненько. И все-таки надо внимательно проверить все объявления пространств имен и трейтов, во всех редактируемых файлах, тем более если вы их вручную создавали, а не через консоль. Если вы использовали мои исходники, то лучше всего все делать с "чистого листа".

  • 22/10/2016 22:20 Андрей пишет:

    Версия Laravel 5.3 Изменил немного структуру, что-то не работает. Выдаёт ошибку:

    ErrorException in ResourcesHasViewed.php line 25:Argument 1 passed to App\Events\ResourcesHasViewed::__construct() must be an instance of App\Resources, instance of Illuminate\Database\Eloquent\Collection given, called in /var/www/haubaupro/data/www/test.haubau.pro/haubaupro/app/Http/Controllers/ResourcesController.php on line 60 and defined

    Не могу понять что делаю не так. Делал по вашему мануалу, но со своей моделью Resources.

    nick пишет:
    В файле ResourcesHasViewed.php добавили строчку use App\Resources? Просто он в конструкторе как раз вашу модель и требует.

Оставьте свой комментарий