فصل ۷: Request Facade و مدیریت داده‌ها در لاراول

06 آبان 1397
درسنامه درس 8 از سری لاراول
Laravel-Main-request-facade

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

مقدمه

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

Request Facade

یکی از معمول‌ترین روش‌ها برای دریافت داده‌های کاربران و دسته‌بندی آنها در لاراول استفاده از Request Facade می‌باشد. این دستور به کاربران اجازه می‌دهد که یک فرم ورودی را پر کرده و اطلاعات را در بستر متد POST یا JSON‌ و GET‌ به کنترلر ارسال کنند. در ادامه به انواع متدهای Request اشاره خواهیم کرد:

Request::all

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

به مثال زیر توجه کنید:

// GET route form view at /get-route
<form method="post" action="/post-route?utm=12345">
	{{ csrf_field() }}
	<input type="text" name="firstName">
	<input type="submit">
</form>

// POST route at /post-route
var_dump(Request::all());

همانطور که در مثال بالا مشاهده می‌کنید یک فرم ایجاد کرده و آن را در بستر متد POST پس از وارد کردن اطلاعات توسط کاربر و کلیک روی دکمه‌ی submit ارسال خواهیم کرد. سپس با استفاده از تابع var_dump‌ اطلاعات دسته بندی شده در خروجی را مشاهده خواهیم کرد. و در نهایت خروجی به صورت زیر خواهد بود:

// Outputs:
/**
    * [
    * '_token' => 'CSRF token here',
    * 'firstName' => 'value',
    * 'utm' => 12345
    * ]
*/

حال این سوال برای شما بوجود می‌آید که منظور از csrf_token چیست؟ در اینجا توضیح مختصری خدمت شما عزیزان ارائه می‌کنیم:

CSRF Token

عبارت CSRF مخفف Cross Site Request Forgery که ترجمه معادل آن: «عبور درخواست‌های جعلی سایت» می‌باشد. در ادامه با ذکر یک مثل مفهوم CSRF را برای شما عزیزان روشن‌تر می‌کنیم:

فرض کنید یک وب سایت تراکنش بانکی طراحی کرده‌ایم که آدرس آن به صورت www.banksite.com  است حال برای انجام یک تراکنش مالی اقدام می‌کنیم بنابراین صفحه آدرس تراکنش ما پس از انجام عملیات به صورت www.banksite.com/transfer?to=871237 حال این آدرس در مرورگر ما ذخیره می‌شود یا به عبارتی درون Cookie جمع‌آوری می‌شود. سپس وارد یک سایت دیگری برای انجام فعالیت‌های روزانه خواهیم شد (این سایت برای برداشت اطلاعات شما برنامه‌ریزی کرده است). با ورود به وب سایت هدف به آدرس فرضی www.hacksite.com اطلاعات مرورگر شما برداشته شده و در دیتابیس این سایت ذخیره می‌شود. سپس شما از سایت خارج می‌شوید ولی هکر همواره اطلاعات مرورگر شما که شامل آدرس تراکنش است در اختیار دارد. این آدرس همان www.banksite.com/transfer?to=871237 می‌باشد. حال در صورتیکه برای حملات CSRF تدبیری نیاندیشیده باشید هکر، آدرس را مجددا در مرورگر خود وارد می‌کند و یکبار دیگر درخواست به سرور ارسال شده و مجددا تراکنش انجام می‌شود. اما برای جلوگیری از این موضوع یک فیلد تحت عنوان token_ در فرم‌ها به صورت hidden ایجاد می‌شود تا یک رشته‌ی تصادفی را بعد از هر تراکنش و یا ثبت فرم به آدرس شما اضافه کند. در این حالت آدرس شما پس از ذخیره سازی به صورت زیر خواهد بود:

www.banksite.com/transfer?to=871237?token=139asd7zxfs8324792387923781 حال این رشته تنها یکبار تولید شده و به عبارت دیگر یکبار مصرف است و هکر هیچگاه نمی‌تواند با وارد کردن مجدد اطلاعات را بازیابی و یا دستور مشابه را به سرور ارسال کند.

csrf_token معمولا در تگ فرم و یا متا تگ ها تعریف می‌شود. هنگامیکه بخواهیم csrf_token را برای تمام فرم‌های یک صفحه اعمال کنیم بهتر است از متاتگ استفاده شود در زیر نمونه‌ی کدهای مشابه را در خدمت شما عزیزان قرار داده‌ایم:

// csrf در یک فرم مشخص
<input type="hidden" name="_toke" value="{{ csrf_token }}>

// csrf در کل صفحه با استفاده از متا تگ
<meta name="csrf_token" content="{{ csrf_token }}">

در ادامه به توضیح Request Facade ها می‌پردازیم:

Request::except

درصورتیکه بخواهیم تنها یک سری فیلدهای خاص را به کنترلر ارسال کنیم از دستور Request::expect استفاده خواهیم کرد. این دستور دارای یک آرگومان است که رشته یا آرایه‌ای از فیلدها را می‌پذیرد. به‌طور عامیانه این دستور فرمان می‌دهد که تمام فیلدها استخراج شوند بجر فیلدهایی که داخل آرگومان است:

var_dump(Request::expect('_token'));

// Outputs:
/**
* [
* 'firstName' => 'masoud',
* 'lastName' => 'salehi'
* ]
*/

Request::only

این دستور دقیقا عکس دستور except عمل می‌کند. یعنی تنها فیلد یا فیلدهایی که داخل آرگومان تعریف می‌شوند را به کنترلر ارسال و یا در خروجی نمایش می‌دهد:

// POST route at /post-route
var_dump(Request::only(['firstName', 'lastName']));

// Outputs:
/**
* [
* 'firstName' => 'Masoud',
* 'lastName' => 'Salehi'
* ]
*/

Request::has

با استفاده از این دستور متوجه خواهیم شد که آیا فیلد و یا فیلدهای موردنظر دارای مقدار هستند؟

// POST route at /post-route
if (Request::has('firstName')) {
    // Do some analytics work
}

Request::exists

با استفاده از این دستور می‌توان تشخیص داد که آیا فیلد موردنظر دارای مقدار است یا خیر؟ اگر مقداری نداشت عبارت TRUE بازگردانده خواهد شد:

// POST route at /post-route
if (Request::exists('firstName')) {
    // Do some analytics work
}

Request::input

برای دستیابی به تنها و تنها یک ورودی می‌توان از این دستور استفاده کرد. این دستور دو پارامتر دارد که پارامتر اول نام فیلد و پارامتر دوم به صورت اختیاری است که مقدار پیشفرض را در صورتیکه فیلد موردنظر مقداری نداشته باشد را ارسال می‌کند:

// POST route at /post-route
$userName = Request::input('name', 'masoud');

آرایه‌های ورودی

توجه به این نکته ضروری است که می‌توان با استفاده از دستور input‌ آرایه‌ای از فیلدها را در اختیار داشت. برای دسترسی به هر فیلد باید از عبارت . (دات) در کنار نام فیلد استفاده کرد. به مثال زیر توجه کنید:

// GET route form view at /get-route
<form method="post" action="/post-route">
    {{ csrf_field() }}
    <input type="text" name="employees[0][firstName]">
    The Request façade | 87
    <input type="text" name="employees[0][lastName]">
    <input type="text" name="employees[1][firstName]">
    <input type="text" name="employees[1][lastName]">
    <input type="submit">
</form>

// POST route at /post-route
$employeeZeroFirstName = Request::input('employees.0.firstName');
$allLastNames = Request::input('employees.*.lastName');
$employeeOne = Request::input('employees.1');

Output
// If forms filled out as "Jim" "Smith" "Bob" "Jones":
// $employeeZeroFirstName = 'Jim';
// $allLastNames = ['Smith', 'Jones'];
// $employeeOne = ['firstName' => 'Bob', 'lastName' => 'Jones']

اطلاعات JSON

گاهی نیاز است که اطلاعات وارد شده توسط کاربر را به صورت json‌ در اختیار کنترلر قرار دهیم که در اینصورت از دستور request::input بهره می‌بریم. استفاده کردن از روش مزیتی را فراهم می‌کند: در صورتیکه در سربرگ صفحه شما عبارت Application/json وجود نداشته باشد خود به خود آن را اضافه کرده و اطلاعات را در اختیار می‌گذارد:

POST /post-route HTTP/1.1
Content-Type: application/json
{"firstName":"Joe","lastName":"Schmoe","spouse":{"firstName":"Jill","lastName":"Schmoe"}}

// post-route
$firstName = Request::input('firstName');
$spouseFirstname = Request::input('spouse.firstName');

همانطور که ملاحظه کردید با استفاده از یک . (دات) و Request::input به اطلاعات جیسون دسترسی پیدا کردیم.

Request::isMethod

از این دستور برای چک کردن متد‌های پروتکل HTTP‌ استفاده می‌شود در صورتیکه نحوه‌ی ارسال با متد موردنظر بود عبارت True بازگردانده خواهد شد:

if (Request::isMethod('post')){
      // Do Somethings
}

Request::flash

داده‌های فلش یا Flash Data روشی بسیار عالی جهت ذخیره کردن اطلاعات درون یک Session برای استفاده در درخواست‌های Request بعدی است. این کار برای استفاده مجدد از مقادیر داخل فیلدهایی که توسط کابران پر شده‌اند، بسیار مفید است.

return Request::flash()

همچنین از دستورهای flashOnly و flashExcept می‌توان مشابه Request::except, Request::only استفاده کرد:

$request->flashOnly(['username', 'email']);

$request->flashExcept('password');

Request::old

هرگاه بخواهیم اطلاعاتی که داخل Session ذخیره شده‌اند را درون درخواست دیگری اعمال کنیم از دستور Request::old استفاده می‌کنیم. با این کار اطلاعات Session جدید با Session قبلی برابر خواهد بود:

$username = Request::old('username');

حال برای نمایش دادن این اطلاعات درون یک قالب Blade می‌توان به صورت زیر عمل کرد:

<input type="text" name="username" value="{{ old('username') }}">

Redirect withInput

گاهی می‌خواهیم علاوه بر ریدایرکت شدن یک صفحه تمام فیلدهای ورودی را داخل یک Session ذخیره کنیم در اینصورت از دستور زیر استفاده می‌کنیم:

return redirect('form')->withInput();

همچنین اگر بخواهیم تمام فیلدها را انتخاب کنیم بغیر از یک یا چند فیلد خاص از دستور except استفاده خواهیم کرد:

return redirect('form')->withInput(
    $request->except('password')
);

Request::cookie

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

$value = Request::cookie('name');

 

فایل‌ها

لاراول در یک فرم برای دریافت فایل از کاربران و ارسال آن به سمت سرور تدابیری لحاظ کرده است که در ادامه به هر یک از آنها به همراه توضیحات می‌پردازیم:

Request::file

اگر برای دریافت یک فایل از دستورهای Request::all یا Request::input استفاده کنیم مقادیر خالی null را باز می‌گردانند در نهایت لاراول ابزاری به نام Request::file‌ در اختیار کابران قرار داده است تا با استفاده از آن بتوانند فایل‌ها را از کاربر دریافت کرده و به کنترلر ارسال کنند:

<form method="post" enctype="multipart/form-data">
    {{ csrf_field() }}
    <input type="text" name="name">
    <input type="file" name="profile_picture">
    <input type="submit">
</form>

// In controller/route Closure
var_dump(Request::all());

// Output:
// [
// "_token" => "token here"
// "name" => "asdf"
// "profile_picture" => UploadedFile {}
// ]

همچنین با استفاده از دستور hasFile می‌توان چک کرد که آیا کاربر فایلی برای آپلود انتخاب کرده است یا خیر؟

if (Request::hasFile('profile_picture')) {
    var_dump(Request::file('profile_picture'));
}
// Output:
// UploadedFile (details)

و برای چک کردن اینکه آیا فایل با موفقیت آپلود شده است یا نه می‌توان از دستور isValid استفاده کرد:

if (Request::isValid('profile_picture')) {
    var_dump(Request::file('profile_picture'));
}
// Output:
// UploadedFile (details)

برای تکمیل کردن مبحث فایل‌ها باید متدهایی را به شما عزیزان معرفی کنیم تا به راحتی بتوانید از فایل‌های آپلود شده استفاده کنید لذا تمام متدها را در دسته‌بندی‌های زیر معرفی خواهیم کرد:

guessExtentions()

متدی‌ست که پسوند فایل را باز می‌گرداند و درصورتیکه پسوند ناشناخته باشد مقدار null برگردانده می‌شود.

getMimeType()

متدی‌ست که Mime type یک فایل (مثلا application / pdf) را باز می‌گرداند.

move($directory, $newName = null)

متدی‌ست جهت انتقال دادن فایل به یک directory یا پوشه جدید.

getClientOriginalName()

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

getClientOriginalExtentions()

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

getClientMimeType()

متدی‌ست که Mime Type فایلی که کاربر در سیستم داشته است را باز می‌گرداند.

gussClientExtention()

متدی‌ست که پسوند فایل موجود در کامپیوتر شخص را بر اساس Mime type تشخیص داده و باز می‌گرداند. توجه دارید، پسوندی که از طریق این متد استخراج می‌شود صحت و دقت بالایی ندارد.

getClientSize()

متدی‌ست که حجم فایل را باز می‌گرداند.

getError()

متدی‌ست که خطای آپلود فایل را باز می‌گرداند. اگر فایل با موفقیت آپلود شده باشد یک ثابت تحت عنوان UPLOADERROK و در غیر این‌صورت عبارت UPLOADERRXXX را در اختیار می‌گذارد.

getMaxFileSize()

تابعی که ماکزیمم سایز آپلودی را از php.ini باز می‌گرداند.

بسیار عالی! به شما عزیزان تبریک می‌گوییم. حال شما قادر هستید که درخواست‌های داینامیک خود را مدیریت کرده و از آنها در کنترلر استفاده کنید. در جلسه‌ی آینده نحوه‌ی پاسخ (Response) به این درخواست‌ها را مطرح خواهیم کرد تا شما عزیزان بتوانید تمام اطلاعات را آنطور که تمایل دارید به خروجی ارسال کنید. همچنین مبحث Redirect هم برای شما همکاران و دانش‌پژوهان عزیز ارائه خواهیم داد.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری لاراول توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (7 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

Ghazal
29 آبان 1399
Guess not guss

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

امین
22 مهر 1398
Request::expect این دستور اشتباه وارد شده باید Request::except باشه

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

sadra
20 اردیبهشت 1398
عالی بود فقط تو متن به جای except ==> expect بنویسید

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

PixyBoy
12 بهمن 1397
بخاطر در اختیار گذاشتن دانش بصورت رایگان صمیمانه از تیمتون تشکر میکنم. همیشه موفق باشین

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

ابوالفضل
20 آذر 1397
توی قسمت exists این متن (گر مقداری نداشت عبارت TRUE بازگردانده خواهد شد:) فکر کنم بر عکس این عمل انجام میشه ، اگه مقداری داشت عبارت true بارگردانده خواهد شد ، ممنون

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مهرداد
20 آذر 1397
Application/json وجود نداشته باشد اشتباه است وجود داشته باشد درست است

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

amir
12 اسفند 1396
بسیار عالی!

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.