تقریبا در هر برنامه تحت وب که تعداد قابل توجهی کاربر دارد به کش (cache) نیاز داریم. چه به خاطر تجربه کاربری بهتر و کمک به سئو و چه به خاطر کاهش هزینه‌ها یا استفاده بهینه از منابع سرور.

در این مطلب یاد میگیریم که در لاراول چطور از cache استفاده کنیم.

چرا به کش کردن اطلاعات در نرم افزار نیاز داریم؟

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

یکی از راه حل های این مسئله استفاده از cache است. یعنی اینکه این پاسخی که قرار است از سرور دریافت کنیم یکبار پردازش شود و در مراجعه بعدی کاربران به آن آدرس دیگر مرحله پردازش اطلاعات وجود نداشته باشد.
حالا سرور تنها کاری که می‌کند نمایش اطلاعات از قبل ذخیره شده است. به همین خاطر سرعت نرم افزار بالاتر می‌رود.

چه چیزهایی را باید در یک نرم افزار تحت وب کش کنیم؟

  • کوئری‌هایی که به دیتابیس می‌زنیم و نتیجه آن ها دیر به دیر تغییر می کند(مثلا دریافت یک دسته بندی خاص از محصولات).
  • تنظیمات نرم افزار.
  • اطلاعات صفحاتی که معمولا ثابت هستند مثل صفحه اصلی سایت یا صفحات وبلاگ که مقالات در آن قرار دارند.

نحوه کار باcache در لاراول

قبل از استفاده از کش باید یک درایور برای آن تعریف کنیم. یعنی مشخص کنیم این کش توسط چه ابزاری انجام می‌شود.

لاراول به صورت پیشفرض از فایل برای کش کردن اطلاعات استفاده می‌کند. این را می‌توانیم در فایل تنظیمات کش در مسیرconfig/cache.php تغییر بدهیم.

اگر نگاهی به فایل cache.php بندازید یک ثابت به شکل زیر تعریف شده است.

    'default' => env('CACHE_DRIVER', 'file'),

شما می توانید در فایل .env با تغییر مقدار CACHE_DRIVER از redis یا database هم استفاده کنید. dynamodb هم که برای آمازون است و استفاده از آن در ایران رایج نیست.

برای کار با redis باید یک مطلب جداگانه نوشت. اما اینجا به file و database اشاره خواهیم کرد.

برای استفاده از file برای cache تنها کافی است که مقدار default CACHE_DRIVER را به file تغییر بدهیم.

اما برای استفاده از database به cache، باید یک جدول بسازیم.

ایجاد جدول برای کش در دیتابیس

با استفاه از دستور php artisan cache:table یک migration جدید برای کش درست می شود.

Schema::create('cache', function ($table) {
    $table->string('key')->unique();
    $table->text('value');
    $table->integer('expiration');
});

اطلاعاتی که در دیتابیس کش می‌شوند در این جدول قرار می‌گیرند.

بعد از این کهمشخص کردیم اطلاعات موجد در کش کجا قرار بگیرند حالا می رویم سراغ نحوه کار با cache.

برای کار با کش در لاراول از یک Facade به نام Cache استفاده می‌کنیم.

ذخیره یک مقدار در کش

با متد put یک آیتم را در کش ذخیره می‌کنیم.

use Illuminate\Support\Facades\Cache;
public function index(){
$products = Product::all();
Cache::put('products',$products,3600);
}

اینجا محصولات را با کلید products به مدت 3600 ثانیه کش کردیم.

اگر پارامتر سوم یعنی زمان را ذکر نکنیم. بدون محدودیت زمانی در کش خواهد ماند.

دریافت یک مقدار از کش

فرض می‌کنیم یک مقدار در کش ذخیره شده. با متد get آن را دریافت می‌کنیم.

use Illuminate\Support\Facades\Cache;

class ProductController extends controller
{
       public function index(){
       $products = Cache::get('products');
}

}

کلاس Cache یک متد get دارد که یک پارامتر می‌پذیرد. هر مقداری که در کش ذخیره می شود یک key دارد که با استفاده از آن مقدار کش را دریافت می‌کنیم. اگر مقداری که دنبال آن می‌گردید وجود نداشته باشد null برگشت داده می‌شود. در چنین شرایطی می‌توانید یک مقدار پیشفرض بگذارید تا جای null قرار بگیرد.

Cache::get('key','default');

یک closure هم به عنوان مقدار پیشفرض می‌توانیم قرار بدهیم.

مثال:

use Illuminate\Support\Facades\Cache;

class ProductContoller extends Controller
{  
   public function index(){
    $result = Cache::get('products',function(){
return App\Models\Product::all();
});
   }

در این مثال اگر در کلید products اطلاعاتی ذخیره نشده بود مقدار خروجی داخل closure برگشت داده می‌شود

دریافت و ذخیره همزمان از کش

با متد Remember می توانیم دو کار را همزمان انجام دهیم. یک مقدار را از کش دریافت کنیم و اگر وجود نداشت آن را بگیریم و در کش ذخیره کنیم.

Cache::remember('products',$seconds,function(){
return App\Models\Product::all();
});

پارامتر دوم زمان ماندن در کش بر حسب ثانیه است. اگر به جای remember از rememberForever استفاده کنیم. مقدار برای همیشه ذخیره خواهد شد.

مثال:

use Illuminate\Support\Facades\Cache;

class ProductContoller extends Controller
{
   public function index(){

    Cache::remember('products',60,function(){
        return Product::all();
        });
        $products = Cache::get('products');
        dd($products);
  
   }
}

چک کنیم که آیا چنین مقداری در کش هست یا خیر

برای چک کردن موجودی در کش از متد has استفاده می‌کنیم. مقدار بازگشتی true یا false خواهد بود.

if(Cache::has('key')){
   //do something
}

دریافت از کش و حذف مقدار

متد pull یک مقدار را از کش می‌گیرد و بعد آن را حذف می کند.

Cache::pull(products);

مثال:

 //controller
   public function index(){

    Cache::remember('products',60,function(){
        return Product::all();
        });
        $products = Cache::pull('products');

        $has_cache = Cache::has('products');

        dd($products,$has_cache);


  
   }

در مثال بالا اول مقدار products را در کش قرار دادیم بعد با متد pull آن را در متغیر $products گذاشتیم و همزمان از cache حذف کردیم.

الان باید cache از این مقدار خالی شده باشد ولی در متغیر $products وجود داشته باشد. با تابع dd هر دو مورد را تست کردیم و نتیجه درست بود.

حذف یک مقدار از کش

ذخیره در کش اگر مقدار مورد نظرمان وجود ندارد

با متد add اگر مقداری که می‌خواهیم در کش نبود آن را ذخیره می‌کنیم.

Cache::add('key','value',$seconds);

حذف مقدار از کش

متد forever یک مقدار را از برای همیشه در cache ذخیره می‌کند. اگر دیگر به آن مقدار نیاز نداشتید باید به صورت دستی حذفش کنید.

Cache::forever('products',$products);

پاک کردن همه مقادیر استفاده شده در cache

متد flush همه مقادیری که در cache ذخیره کرده‌ایم را پاک خواهد کرد.

Cache::flush();

تگ گذاری کش‌ها

می‌توانیم برای مقادیری که در کش ذخیره می‌کنیم تگ یا برچسب بگذاریم. با این کار آن‌ها را دسته بندی می‌کنیم.

Cache::tags(['product'])->put('books',$books,3600);
Cache::tags(['product'])->put('notebooks',$notebooks,3600);

در کد بالا هم مقدار books و هم مقدار notebooks در تگ product قرار گرفتند.

چه مواقعی به تگ گذاری کش ها نیاز داریم؟

کاربرد اصلی تگ گذاری برای وقتی است که می‌خواهیم مجموعه‌ای از مقادیر مربوط به هم در cache را حذف کنیم.
به این مثال توجه کنید:

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

Cache::tags(['products'])->flush();

دریافت مقدار با تگ مشخص

برای دریافت مقدارهایی که تگ گذاری شده‌اند تگ های آنها را به متد tags پاس می‌دهیم بعد با متد get آن مقدار را دریافت می‌کنیم.

Cache::tags(['products'])->get('books');

در متد tags می توایم چند برچسب را به عنوان پارامتر قرار بدهیم.

جمع بندی

دیدیم که کار با cache در لاراول خیلی ساده است اما وقتی تصمیم می گیریم از کش استفاده کنیم این نکته را یادمان باشد:

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