در حال بارگزاری ...

هایلایت محتوای جدید برای بازدید کنندگان بازگشتی در لاراول

توسط سميه شفيعي
آخرین به روز رسانی سه شنبه 14 مرداد 1399

در این قسمت از آموزش در لیداوب به بررسی نحوه برجسته کردن محتوا جدید برای بازدید کنندگان در حال بازگشت می‌پردازیم. با ما همراه باشید. نحوه برجسته کردن محتوا جدید برای بازدید کنندگان در حال

در این قسمت از آموزش در لیداوب به بررسی نحوه برجسته کردن محتوای جدید برای بازدید کنندگان بازگشتی در لاراول می‌پردازیم. در ادامه مقاله با ما همراه باشید.


 هایلایت محتوای جدید برای بازدید کنندگان بازگشتی در لاراول

هدف از این درس راه اندازی مکانیسمی است که با استفاده از آن می‌توان محتوای جدیدی را برای بازگشت بازدید کنندگان وب سایت برجسته کرد. به عنوان مثال، فرض کنید که یک کاربر از سایت بازدید می‌کند و تمام موضوعات موجود در صفحه اول را می‌خواند و سپس سایت را ترک می‌کند. پس از آن، یک بازدید کننده متفاوت از سایت بازدید می‌کند و پاسخ جدیدی برای گفتن سه موضوع مختلف اضافه می‌کند. هنگام که کاربر اول دوباره به سایت بازمی‌گردد، آن سه موضوع با پاسخ‌های جدید باید به نوعی برجسته شوند. شاید بتوانیم برای برجسته کردن متن برای کاربر یک فونت bold را به موضوعاتی که محتوای جدید دارند اضافه کنیم. 

برجسته کردن محتوای جدید با استفاده از حافظه کش (Cache)

تمام مدل‌های لاراول از یک فیلد updated_at   در بانک اطلاعاتی استفاده می‌کنند. این به این معنی است که ما بدانیم که جدیدترین بروزرسانی در موضوع خاصی چه بوده است. این به این معنی است که اگر ما زمان بازدید کاربر از یک موضوع خاص را در یک نشانه‌گر زمانی (timestamp) ثبت کنیم، می‌توانیم آن نشانگر زمان را با مقدار updated_at مقایسه کنیم تا ببینیم کدام یک جدیدتر است. اگر نشانگر زمان بازدید‌ شده کاربر جدیدتر از نشانگر زمان updated_at  باشد، بنابراین، نیازی به برجسته سازی محتوا نیست. از طرف دیگر، اگر مقدار updated_at از  نشانگر زمان کش (cache timestamp) آخرین بازدید کاربر جدیدتر باشد، این بدان معنی است که محتوای جدیدی وجود دارد که باید برای کاربر برجسته شود.

ثبت بازدید‌های کاربر

اگر ما منطق مقایسه یک مقدار زمان از حافظه کش در برابر آنچه در پایگاه داده است را دنبال می‌کنیم. پس از بازدید کاربر از صفحه خاصی، ما به روشی برای ثبت نیاز داریم. شاید ما بتوانیم دو متد اضافه کنیم. در زیر متدهای read()   و visitedThreadCacheKey()  در مدل کاربر برجسته شده است. متد visitedThreadCacheKey() جایی است که اصل این ویژگی اتفاق می‌افتد. یک رشته منحصر به فرد به عنوان کلید، برای استفاده در هنگام ذخیره کردن رکورد بازدید در حافظه کش (cache)، تعریف می‌شود. با کار با متد read()، ما کلید جدیدی را در حافظه نهان ذخیره می‌کنیم که مطابق با Carbon::now() برابر با زمان جاری است.

<?php
 
namespace App;
 
use Carbon\Carbon;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
 
class User extends Authenticatable
{
    use Notifiable;
 
    protected $fillable = [
        'name', 'email', 'password',
    ];
 
    protected $hidden = [
        'password', 'remember_token', 'email'
    ];
 
    public function getRouteKeyName()
    {
        return 'name';
    }
 
    public function threads()
    {
        return $this->hasMany(Thread::class)->latest();
    }
 
    public function activity()
    {
        return $this->hasMany(Activity::class);
    }
 
    public function read($thread)
    {
        cache()->forever(
            $this->visitedThreadCacheKey($thread),
            Carbon::now()
        );
    }
 
    public function visitedThreadCacheKey($thread)
    {
        return sprintf("users.%s.visits.%s", $this->id, $thread->id);
    }
}

بررسی برای بروزرسانی‌ها روی Thread Model

متدهایی که در حال انجام heavy lifting برای این ویژگی هستند، اکنون در مدل کاربر تعریف شده‌اند. اکنون ما می‌توانیم متدی را به مدل Thread اضافه کنیم که بروزرسانی‌های جدید را برای کاربر بررسی می‌کند. توجه داشته باشید که در زیر متد hasUpdatesFor () در مدل Thread برجسته شده است.

<?php
 
namespace App;
 
use App\Events\ThreadReceivedNewReply;
use Illuminate\Database\Eloquent\Model;
use App\User;
 
class Thread extends Model
{
    use RecordsActivity;
 
    protected $guarded = [];
 
    protected $with = ['creator', 'channel'];
 
    protected $appends = ['isSubscribedTo'];
 
    protected static function boot()
    {
        parent::boot();
 
        static::addGlobalScope('replyCount', function ($builder) {
            $builder->withCount('replies');
        });
 
        static::deleting(function ($thread) {
            $thread->replies->each->delete();
        });
    }
 
    public function path()
    {
        return '/threads/' . $this->channel->slug . '/' . $this->id;
    }
 
    public function replies()
    {
        return $this->hasMany(Reply::class);
    }
 
    public function creator()
    {
        return $this->belongsTo(User::class, 'user_id');
    }
 
    public function channel()
    {
        return $this->belongsTo(Channel::class);
    }
 
    public function addReply($reply)
    {
        $reply = $this->replies()->create($reply);
 
        event(new ThreadReceivedNewReply($reply));
 
        return $reply;
    }
 
    public function scopeFilter($query, $filters)
    {
        return $filters->apply($query);
    }
 
    public function subscribe($userId = null)
    {
        $this->subscriptions()->create([
            'user_id' => $userId ?: auth()->id()
        ]);
        return $this;
    }
 
    public function unsubscribe($userId = null)
    {
        $this->subscriptions()
            ->where('user_id', $userId ?: auth()->id())
            ->delete();
    }
 
    public function subscriptions()
    {
        return $this->hasMany(ThreadSubscription::class);
    }
 
    public function getIsSubscribedToAttribute()
    {
        return $this->subscriptions()
            ->where('user_id', auth()->id())
            ->exists();
    }
 
    public function hasUpdatesFor(User $user)
    {
        $key = $user->visitedThreadCacheKey($this);
        
        return $this->updated_at > cache($key);
    }
}

آنچه متد hasUpdatesFor () برای ما انجام می‌دهد، این است که زمانی که آخرین بازدید کاربر از موضوع مورد نظر است را در حافظه نهان برای نشانگر زمان بررسی می‌کند. سپس، ما یک مقایسه ایجاد می‌کنیم. ما در حال بررسی این موضوع هستیم که آیا نشانگر زمانی updated_at از مقدار نشانگر زمانی که در حافظه پنهان یافت می‌شود بزرگتر است یا خیر. اگر بزرگتر از آن باشد، سپس اتفاقی مانند یک پاسخ جدید برای بروزرسانی موضوع (thread) رخ داده است. این بدان معنی است که کاربر باید محتوای برجسته شده جدید را ببیند تا تابع true را بازگرداند. ثبت واقعی بازدید از کجا انجام خواهد شد؟ منطقی است که در ThreadsController، متد show()  همان چیزی است که برای نمایش موضوع به کاربر استفاده می‌شود. بنابراین، اگر کاربر وارد شده از یک موضوع بازدید کند، این متدی است که آن را برای آن‌ها نمایش می‌دهد. قطعه کد برجسته‌سازی زیر، یک بررسی سریع را انجام می‌دهد تا ببیند کاربر وارد سیستم شده است یا خیر. اگر جواب true بود، سپس  ما متد read() را که در مدل کاربر در کد بالا تعریف کردیم، فراخوانی می‌کنیم. وقتی این متد read()  شروع به کار کرد، به متد visitedThreadCacheKey()  تکیه می‌کند تا بتواند با استفاده از Carbon::now() به عنوان نشانگر زمان، یک کلید را در حافظه کش ذخیره کند.

<?php
 
namespace App\Http\Controllers;
 
use App\Filters\ThreadFilters;
use App\Thread;
use App\Channel;
use Illuminate\Http\Request;
 
class ThreadsController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth')->except(['index', 'show']);
    }
 
    public function index(Channel $channel, ThreadFilters $filters)
    {
        $threads = $this->getThreads($channel, $filters);
        if (request()->wantsJson()) {
            return $threads;
        }
        return view('threads.index', compact('threads'));
    }
 
    public function create()
    {
        return view('threads.create');
    }
 
    public function store(Request $request)
    {
        $this->validate($request, [
            'title' => 'required',
            'body' => 'required',
            'channel_id' => 'required|exists:channels,id'
        ]);
 
        $thread = Thread::create([
            'user_id' => auth()->id(),
            'channel_id' => request('channel_id'),
            'title' => request('title'),
            'body' => request('body')
        ]);
 
        return redirect($thread->path())
            ->with('flash', 'Your thread was published!');
    }
 
    public function show($channel, Thread $thread)
    {
        if (auth()->check()) {
            auth()->user()->read($thread);
        }
 
        return view('threads.show', [
            'thread' => $thread
        ]);
    }
 
    public function edit(Thread $thread)
    {
        //
    }
 
    public function update(Request $request, Thread $thread)
    {
        //
    }
 
    public function destroy($channel, Thread $thread)
    {
        $this->authorize('update', $thread);
 
        $thread->delete();
 
        if (request()->wantsJson()) {
            return response([], 204);
        }
 
        return redirect('/threads');
    }
 
    protected function getThreads(Channel $channel, ThreadFilters $filters)
    {
        $threads = Thread::latest()->filter($filters);
 
        if ($channel->exists) {
            $threads->where('channel_id', $channel->id);
        }
 
        $threads = $threads->get();
        return $threads;
    }
}

اضافه کردن منطق در Blade  برای برجسته کردن محتوا

اکنون همه چیز موجود است تا این کار عملی شود. تنها کاری که باید انجام دهیم این است که فایل نمایه /index.blade.php را برای برجسته کردن محتوای جدید بروزرسانی کنیم. چگونه این کار را خواهیم کرد؟ این جایی است که ما می‌توانیم از آن متد hasUpdatesFor () تعریف شده در مدل Thread استفاده کنیم.  کد زیر بررسی می‌کند که آیا این موضوع دارای محتوای جدیدی برای کاربر معتبر است که در حال حاضر به وب سایت وارد شده است یا خیر. اگر true را بازگردانند. سپس عنوان موضوع در تگ‌های <strong>  را پوشش می‌دهد تا نشان دهد محتوای جدیدی وجود دارد تا کاربر بتواند از آن استفاده کند. اگر true را بازنگردانند، سپس عنوان موضوع با فونت معمولی در صفحه نمایش داده می‌شود. 

@extends('layouts.app')
 
@section('content')
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                @forelse($threads as $thread)
                    <div class="panel panel-default">
                        <div class="panel-heading">
                            <div class="level">
                                <h4 class="flex">
                                    <a href="{{ $thread->path() }}">
                                        @if (auth()->check() && $thread->hasUpdatesFor(auth()->user()))
                                            <strong>
                                                {{ $thread->title }}
                                            </strong>
                                        @else
                                            {{ $thread->title }}
                                        @endif
                                    </a>
                                </h4>
                                <a href="{{$thread->path()}}">
                                    <strong>{{$thread->replies_count}} {{ str_plural('reply', $thread->replies_count) }}</strong>
                                </a>
                            </div>
                        </div>
                        <div class="panel-body">
                            <div class="body">
                                {{ $thread->body }}
                            </div>
                        </div>
                    </div>
                @empty
                    <p>There are no results yet</p>
                @endforelse
            </div>
        </div>
    </div>
@endsection

دیدن محتوای جدید برجسته در Action

ما به عنوان کاربری با نام نیکولا تسلا وارد شده‌ایم و از تمام موضوعات موجود در صفحه اصلی وب سایت بازدید‌کرده ایم. بنابراین، در زیر می‌توانیم مشاهده کنیم که هیچ موضوع برجسته نشده است.

نحوه برجسته کردن محتوا جدید برای بازدید کنندگان در حال بازگشت

تام وارد سایت می‌شود  و تصمیم می‌گیرد که پاسخی به موضوع !Holy Guacamole اضافه کند.

نحوه برجسته کردن محتوا جدید برای بازدید کنندگان در حال بازگشت

  خوب، در این مرحله، اکنون محتوای جدیدی در سایت داریم و باید بتواند محتوای جدید را برجسته کند. به عبارت دیگر، هنگامی که نیکولا تسلا به عنوان یک بازدید کننده به وب سایت باز‌می‌گردد، عنوان موضوع Holy Guacamole! باید برجسته ظاهر شود. 

نحوه برجسته کردن محتوا جدید برای بازدید کنندگان در حال بازگشت

توجه کنید که اگر در کار کردن با این مشکل دارید، در متد addReply()  از مدل Thread یک فراخوانی را به $this->touch();  اضافه کنید. این اطمینان حاصل می کند که ستون updated_at هنگام افزودن  یک پاسخ جدید، به درستی بروزرسانی می شود.

 می‌توانیم تستی را برای این ویژگی محتوای جدید در اینجا اضافه کنیم. در زیر تست برجسته شده است.

<?php
 
namespace Tests\Unit;
 
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
 
class ThreadTest extends TestCase
{
    use DatabaseMigrations;
 
    protected $thread;
 
    public function setUp()
    {
        parent::setUp();
        $this->thread = $thread = factory('App\Thread')->create();
    }
 
    public function test_a_thread_can_make_a_string_path()
    {
        $thread = create('App\Thread');
 
        $this->assertEquals('/threads/' . $thread->channel->slug . '/' . $thread->id, $thread->path());
    }
 
    public function test_a_thread_has_replies()
    {
        $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $this->thread->replies);
    }
 
    public function test_a_thread_has_a_creator()
    {
        $this->assertInstanceOf('App\User', $this->thread->creator);
    }
 
    public function test_a_thread_can_add_a_reply()
    {
        $this->thread->addReply([
            'body' => 'Chipoltle',
            'user_id' => 1
        ]);
 
        $this->assertCount(1, $this->thread->replies);
    }
 
    public function test_a_thread_belongs_to_a_channel()
    {
        $thread = create('App\Thread');
 
        $this->assertInstanceOf('App\Channel', $thread->channel);
    }
 
    public function test_a_thread_can_be_subscribed_to()
    {
        $thread = create('App\Thread');
        $thread->subscribe($userId = 1);
        $this->assertEquals(
            1,
            $thread->subscriptions()->where('user_id', $userId)->count()
        );
    }
 
    public function test_a_thread_can_be_unsubscribed_from()
    {
        $thread = create('App\Thread');
        $thread->subscribe($userId = 1);
        $thread->unsubscribe($userId);
        $this->assertCount(0, $thread->subscriptions);
    }
 
    public function test_a_thread_can_check_if_the_authenticated_user_has_read_all_replies()
    {
        $this->signIn();
        $thread = create('App\Thread');
        tap(auth()->user(), function ($user) use ($thread) {
            $this->assertTrue($thread->hasUpdatesFor($user));
            $user->read($thread);
            $this->assertFalse($thread->hasUpdatesFor($user));
        });
    }
}

و اجرای تست تأیید می‌کند که عملکرد به همان صورت طراحی شده کار می‌کند.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_a_thread_can_check_if_the_authenticated_user_has_read_all_replies

PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

 .                                                                   1 / 1 (100%)

 Time: 1.16 seconds, Memory: 8.00MB

 OK (1 test, 2 assertions)

نتیجه گیری

این کار می‌توانست از جهات مختلفی انجام شود. اگر می‌خواهید برای بازدید کننده‌هایی که به وب سایت خود باز می‌گردانید، محتوای جدید را برجسته کنید. ابتدا باید آخرین باری که آن‌ها آن محتوای خاص را بررسی کردن را ثبت کنید. سپس، شما منطق را تنظیم می‌کنید تا ببینید که چه زمانی این محتوا برورسانی شده است وقتی که کاربر آخرین بار مطالب را مشاهده کرد. براساس این منطق، شما می‌خواهید یک نشانه زیبا برای کاربر ارائه دهید که آیا محتوای جدیدی برای کاربر وجود دارد یا خیر.

در اینجا این آموزش از آموزش‌های لیداوب به پایان رسید. در آموز‌های بعدی با ما همراه باشید.

دیدگاه ها

دیدگاه ها : 0


متاسفانه فقط اعضای سایت قادر به ثبت دیدگاه هستند

رایگان

اشتراک گذاری در
سورس خرید و فروش ارزهای دیجیتال
ثبت امتیاز
5 (1 رای)

   لطفا صبر کنید ...