آموزش ذخیره و بازیابی کش لاراول بر پایه Query String

ساخت وبلاگ

یکی از مزیت های لاراول سیستم کش آن است منظور از کش (Cache) ، ذخیره موقت داده هایی است که به طور مرتب نیاز به دریافت از منابعی مثل دیتابیس ، API و … دارند. بدین ترتیب اولین بار داده ها دریافت و ذخیره می شوند و دفعات بعدی به جای آن منبع اصلی،داده ها از کش خوانده می شوند. پس سرعت سیستم عملکرد چشمگیری پیدا می کند. پروژه شما از هر نوع که باشد (Restful API, برنامه تحت وب و …) سیستم Cache لاراول پاسخگوی نیازهای شماست. در کل لاراول می تواند هر نوع داده ای که شما بفرستید، با تاریخ انقضای مشخص، داخل کش ذخیره کند. مثل HTML, JSON, collection, Eloquent و …

بریم سر اصل مطلب. یک نمونه کد برای ذخیره پاسخ در کش لاراول شبیه این خواهد بود :

return Cache::remember($rememberKey, $minutes , function() use ($data) {
return $data;
});

کد ساده به نظر می رسه وساده هم هست. متد جالب remember را می بینید که باعث می شود داده های موجود برگشت داده شوند و اگر از قبل وجود ندارند، ساخته شوند یعنی دو کار مهم را با هم انجام می دهد. از $rememberKey برای تشخیص داده مربوطه از بین داده های موجود در کش استفاده می شود و از $minutes برای تعیین طول عمر داده ها در کش.

سوال اینجاست که “لاراول چطور تشخیص می دهد که داده را چه موقع باید در کش ذخیره کند؟

برای پاسخ به این سوال باید سراغ عنصر مهم یعنی rememberKey برویم. بسته به مقدار متغیر $rememberKey، لاراول می فهمد که آیا این داده قبلا کش شده است یا نه.بنابراین این مقدار خیلی مهم است و اگر شما برای کش کردن همه داده ها از یک اسم ($rememberKey) مشابه استفاده کنید، تا زمان منقضی شدن کش، همیشه یک پاسخ واحد دریافت خواهید کرد. این واضحه.

در همین رابطه :   لاراول 5.4 به صورت رسمی منتشر شد + امکانات جدید

متاسفانه برای سناریوهای دیگر خیلی واضح نیست. چون شما از اهمیت مقدار یکتا برای $rememberKey آگاه هستید، تصمیم می گیرید از آدرس فعلی صفحه به عنوان $rememberKey استفاده کنید.مثل این:

$url = request()->url();
return Cache::remember($url, $minutes, function () use ($data) {
return $data;
});

تقریبا مثل قبلی است، اما حالا $rememberKey همان آدرس فعلی صفحه است و بدین ترتیب شما تا حدودی می توانید از متفاوت بودن $rememberKey برای هر صفحه مطمئن بشید.

برای مثال، اگر کاربری صفحه yourdomain.com/products را باز کند، کش با همین آدرس داده ها را ذخیره می کند. هر زمان که کاربر به آدرس دیگری رفت مثل yourdomain.com/categories، می توانید مطمئن باشیدکه سیستم کش لاراول، مقادیر مربوطه را به درستی ذخیره کرده یا از کش می خواند.

اما ، یه دقیقه صبر کن! فرض کن در صفحات از پارامترهایی بنام Query String برای آدرس استفاده می کنید مثل : yourdomain.com/products?page=2&sort_by=price . در این مورد، وقتی شما آدرس را از طریق کد $url = request()->url() می گیرید، این کد پارامترهای آدرس را بر نمی گرداند و فقط آدرس اصلی را برگشت می دهد، بنابراین تغییراتی که این پارامترها باید در نتیجه برگشتی از دیتابیس ایجاد کنند، ایجاد نمی شود و همان نتیجه بدون پارامتر را خواهید دید.

Query String به همه پارامترهایی گفته می شود که در آدرس صفحه، بعد از علامت ? می آیند.

مشکلی نیست، شما باید پارامترهای موجود در آدرس را هم بازی دهید و همه چیز دوباره گل و بلبل می شود.درسته ؟ مثل این:

$fullUrl = request()->fullUrl();
return Cache::remember($fullUrl, $minutes, function () use ($data) {
return $data;
});

اوکی حله! یا نه ؟! صب کن یه دقیقه. اجازه بدین یه تست انجام بدیم. اگر کاربر به صفحه yourdomain.com/products?page=2&sort_by=price برود ، باعث کش شدن داده ها و برگشت دادن پاسخ می شود. اگر کاربر به آدرس yourdomain.com/products?page=1&sort_by=name برود با هم داده ها کش شده و نتیجه برگشت می شود. خوب عالیه! سیستم می تونه پاسخ های متفاوت رو کش و برگشت بدهد. حالا برای تست نهایی، کاربر به این آدرس می ره yourdomain.com/products?page=2&sort_by=price و بعد به این آدرس yourdomain.com/products?sort_by=price&page=2 . اینها درخواست های متفاوتی هستند بنابراین سیستم کش همه داده های مربوط به این دو درخواست را به صورت جداگانه ذخیره می کند.فقط یک مشکل کوچک! این دو درخواست در حقیقت یک درخواست هستند فقط ترتیب پارامترها عوض شده است. ترتیب پارامترها هم مهم نیست اصلا ولی سیستم ما متوجه یکی بودن درخواست ها نیست و فقط چون آدرس ها عین هم نیستند، این دو درخواست به صورت جداگانه کش می شوند که اصلا درست نیست.

در همین رابطه :   لاراول 5.6 از الگوریتم هش رمز عبور جدید Argon2i پشتیبانی خواهد کرد!

خوب حالا چیکار کنیم؟ به نظر می رسه راه حل ساده ای نداریم. ما باید پارامترهای کوئری موجود در آدرس را مرتب کنیم.

این کد همین کار را می کند:

$url = request()->url();
$queryParams = request()->query();
//Sorting query params by key (acts by reference)
ksort($queryParams);
//Transforming the query array to query string
$queryString = http_build_query($queryParams);
$fullUrl = "{$url}?{$queryString}";
return Cache::remember($fullUrl, $minutes, function () use ($data) {
return $data;
});

خوب جادوی کار کجاست؟ ما پارامترهای آدرس را به صورت آرایه انجمنی با استفاده از متد query() گرفتیم و آن ها را با متد ksort بر اساس نام پارامتر مرتب کردیم (نه مقدار). در نهایت با استفاده از پارامترهای مرتب شده، کوئری آدرس را با http_build_query دوباره مونتاژ می کنیم و آدرس کامل را می سازیم تا به عنوان کلید کش (remember key) ازش استفاده کنیم.

بعد از این اگر کاربر به آدرس yourdomain.com/products?sort_by=price&page=2 برود، انگار به آدرس yourdomain.com/products?page=2&sort_by=price رفته است و بدین ترتیب می توان برای درخواست های یکسان، از کش یکسان استفاده کرد حتی اگر کمی در چینش پارامترها با هم فرق داشته باشند.

اگر می خواهید کمی کد تجملی تر بنویسید می توانید آدرس کامل را هش کنید مثل این:

$url = request()->url();
$queryParams = request()->query();
ksort($queryParams);
$queryString = http_build_query($queryParams);
$fullUrl = "{$url}?{$queryString}";
$rememberKey = sha1($fullUrl);
return Cache::remember($rememberKey, $minutes, function () use ($data) {
return $data;
});

منبع

دیجیاتو آپارات...
ما را در سایت دیجیاتو آپارات دنبال می کنید

برچسب : نویسنده : عباس قلی بزرگی بازدید : 355 تاريخ : پنجشنبه 10 اسفند 1396 ساعت: 13:36

خبرنامه