需求描述:用戶瀏覽文章記錄該篇文章的訪問量。
準 備:在文章表中加一個字段‘news_clicks’,用來存放訪問量。
完成效果:同一個用戶session有效時間內瀏覽文章記錄一次訪問量。
這個是關於文章的瀏覽數的實現,當用戶查看文章的時候文章的瀏覽數會增加1,用戶查看文章就是一個事件,有了事件,就需要一個事件監聽器,對監聽的事件發生後執行相應的操作(文章瀏覽數加1),其實這種監聽機制在 Laravel 中是通過觀察者模式實現的.
1、註冊事件以及監聽器
首先我們需要在 app/Providers/目錄下的EventServiceProvider.php中註冊事件監聽器映射關係,如下:
protected $listen = [
/*'App\Events\Event' => [
'App\Listeners\EventListener',
],*/
'App\Events\NewsView' => [
'App\Listeners\NewsViewListener',
],
];
2、然後項目根目錄下執行如下命令
php artisan event:generate
該命令完成後,會分別自動在 app/Events和app/Listensers目錄下生成 NewsView.php和NewsView
3、定義事件
<?php
namespace App\Events;
use App\http\model\index_news;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class NewsView
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(index_news $news)
{
//注入了一個 index_news實例
$this->news = $news;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
/*return new PrivateChannel('channel-name');*/
return [];
}
}
其實看到這些你會發現該事件類只是注入了一個News實例罷了,並沒有包含多餘的邏輯。
4、定義監聽器
事件監聽器在handle方法中接收事件實例,event:generate命令將會自動在handle方法中導入合適的事件類和類型提示事件。在handle方法內,你可以執行任何需要的邏輯以響應事件,我們的代碼實現如下:
<?php
namespace App\Listeners;
use App\Events\NewsView;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Session\Store;
class NewsViewListener
{
protected $session;
/**
* Create the event listener.
*
* @return void
*/
public function __construct(Store $session)
{
//
$this->session = $session;
}
/**
* Handle the event.
*
* @param NewsView $event
* @return void
*/
public function handle(NewsView $event)
{
//
$news = $event->news;
//先進行判斷是否已經查看過
if(!$this->hasViewedNews($news)){
//保存到數據庫
$news->news_clicks = $news->news_clicks + 1;
$news->save();
//看過之後將保存到Session
$this->storeViewedNews($news);
}
}
/**
* 判斷當前文章在session中是否已經存在瀏覽記錄
* @param $news
* @return bool
*/
protected function hasViewedNews($news){
return array_key_exists($news->id,$this->getViewsNews());
}
/**
* 從session中獲取瀏覽記錄
* @return mixed
*/
protected function getViewsNews(){
return $this->session->get('viewed_news',[]);
}
/**
* 存儲瀏覽記錄到session
* @param $news
*/
protected function storeViewedNews($news){
$key = 'viewed_news.'.$news->id;
$this->session->put($key,time());
}
}
註釋中也說明了一些邏輯
5、觸發事件
事件和事件監聽完成後,我們要做的就是實現整個監聽,即觸發用戶打開文章事件,觸發事件只需要斷言特定事件被分發,而不需要真正地觸發監聽器,如下:
class DetailController extends BaseController
{
//資訊詳情
public function newsDetail($id){
$news = index_news::find($id);
$menuId=$news->menu_id;
switch($menuId){
case(4):$title='院內新聞';break;
case(7):$title='通知公告';break;
case(6):$title='學術動態';break;
case(32):$title='健康知識';break;
case(34):$title='人才招聘';break;
}
/*觸發瀏覽記錄事件*/
\event(new NewsView($news));
return view('home.news.detail',compact('news','title'));
}
現在打開頁面發現數據庫中的‘news_clicks’已經正常加1了,這樣整個就完成了。